Flexpa
Developer PortalFeedbackContact usOnboard

Guides

  • Home
  • Quickstart
  • Financial Data

Network

  • Network guide
  • Directory
  • Updates

Consent

  • Link SDK
  • Patient access

Records

  • FHIR API
  • Node SDK
  • FHIR Introduction
  • Usage
  • Terminology

Misc

  • Changelog
  • Support
  • Flexpa OS
  • We're hiring

Financial data guide

Calculating financial details like liability or payments is a common need for requesters of claims data. Both financial liability and payments information can be calculated from fields in the Explanation of Benefit (EOB) resource.

This guide covers the following popular topics in claims data:

  • Liability and payments
  • Deductibles and accumulators
  • Adjudication codes
  • Code normalization

#Liability

In the context of care or treatment, the following 3 parties are collectively responsible for the cost of a service or drug:

  1. The member (aka. patient)
  2. The insurer (aka. payer)
  3. The provider (aka. healthcare service provider)

In other words, the cost of the service or drug must be paid by someone, whether it is the member, the insurer, or the provider. Financial liability is the amount a given party is responsible for paying, not necessarily the amount that anyone has paid at any given time.

The amount billed represents the total cost or liability for the service. This amount is shared among the provider, the insurer, and the member. In fact, the total liability for a given service is the sum of the provider's liability, the insurer's liability and the member's liability. The primary equation for calculating liability is as follows:

Top level equation

#Calculate liability

We calculate liabilities for each party in an ExplanationOfBenefit resource.

Get liabilities by referencing the relevant field in the total[] array.

Basic Example

Javascript
  const ACCESS_TOKEN="flexpa-link-access-token"

  const response = await fetch("https://api.flexpa.com/fhir/ExplanationOfBenefit/123", {
    headers: {
      "content-type": "application/json",
      "authorization": `Bearer ${ACCESS_TOKEN}`,
    },
  });

  const eob = await response.json();

  const findValueByCode = (total, code) => {
    return total.find((total) => total.category.coding
      .some((coding) => coding.code === code))
      .amount?.value;
  };

  const providerLiability = findValueByCode(eob.total, "discount");
  const insurerLiability = findValueByCode(eob.total, "benefit");
  const memberLiability = findValueByCode(eob.total, "memberliability");
  
  console.log(providerLiability);
  // Output: 15.00

  console.log(insurerLiability);
  // Output: 80.00

  console.log(memberLiability);
  // Output: 5.00

However in practice, payers do not always explicitly provide submitted, discount, benefit, and memberliability values in the ExplanationOfBenefit resource. For select payers, Flexpa ensures that all codes are present in the data via a normalization process.

For other payers, we will need to infer these values from other provided adjudication values. There are multiple paths to calculate adjudication values in an ExplanationOfBenefit resource. The following equations describe other relationships between adjudication values.

#Adjudication Equation

Simply put, an insurer will need to decide the eligible amount for reimbursement. The eligible amount is equal to or less than the amount submitted by the provider. Sometimes, insurers will receive a discount from the healthcare provider as part of a pre-negotiated contract. The noncovered amount is the amount that the insurer deems to be not covered by the plan.

Adjudication equation

#Member Liability Equation

The member is liable for all costs that are noncovered by the insurer. Additionally, the member may have to pay a copay or coinsurance amount. The deductible is the amount the member must pay before hitting the deductible minimum amount, as defined in their plan benefits summary. The memberliability is the sum of these elements.

Member liability equation

To better understand these adjudication codes, see the Adjudication codes section below.


#Payments

Payments are the amounts that have been paid by the insurer, the member, or the provider at a given point in time. For example, payments can have a status of paid, denied, or partiallypaid. These values should be considered in the context of the timeline of care.

For example, a typical interaction could look something like this:

  1. The provider renders a service to the member.
  2. The provider submits a claim to the insurer.
  3. The insurer processes the claim and determines the amount it will pay.
  4. The insurer sends reimbursement payments to the provider.
  5. The member receives a bill and pays the provider the amount they owe.

Or in the context of a pharmacy claim:

  1. The member buys and pays for a drug from the provider (aka. the pharmacy).
  2. The provider submits a claim to the insurer.
  3. The insurer processes the claim and determines the amount it will pay.
  4. The insurer sends reimbursement payments to the member and pharmacy.

#Calculate payments

In the context of care or treatment, the following 2 parties will make payments for a service or drug:

  1. The insurer (aka. payer)
  2. The member (aka. patient)

#Insurer Payments

To calculate the amount paid by the insurer at the time of ExplanationOfBenefit creation, you can use the following equation:

Insurer payment equation

#Member Payments

To calculate the amount paid by the member at the time of ExplanationOfBenefit creation, you can use the following equation:

Member payment equation

For more detail on these codes, see the Adjudication codes section below.


#Accumulators

In health insurance, an accumulator is a running total of the amount of money that the member has paid towards the following two plan milestones in a benefit year:

  • Deductible Minimum - The amount the member must pay for covered services before the insurer starts to pay. You can think of this as a member spend floor.
  • Out of Pocket Maximum - The maximum amount the member must pay before the insurer pays 100% of covered services. You can think of this as a member spend ceiling.
Out of Pocket Diagram

#What counts towards an accumulator?

Importantly, accumulators only apply to covered services. For example, if a member pays for a service that is not covered (ie. noncovered) by their plan, that amount will be excluded from the accumulator. The calculation also excludes any premiums paid by the member.

Rather the accumulator amount is determined by looking at the deductible, copay, and coinsurance amounts paid by the member.

DeductibleCopayCo-insuranceNon coveredPremiums
Counts towards Deductible Min?
Counts towards OOP Max?

Typically insurers do not charge copay or co-insurance amounts before the deductible minimum is met. For example, let's say your plan's eligible cost for a doctor's office visit is $100. Your copay for a doctor's visit is $20.

  • If you have not met your deductible: You pay $100, the full eligible amount for the visit and no copay amount.
  • If you have met your deductible: You pay a copay of $20, usually at the time of the visit.
  • If you have met your out-of-pocket maximum: You pay $0, not even a copay amount.

#What is a benefit year?

A benefit year is a 12-month period during which a member's health insurance plan provides coverage. The benefit year can start on any date.

  • You can find the benefit year start date in the period field of the Coverage resource.
  • Then calculating the benefit year end date is simple: Add 1 year to the benefit year start date.

While Coverage.period.end is a valid FHIR field, based on analysis of real data, the Coverage.period.start field is the most reliable field to derive both the benefit year start and end dates. This is because payers do not always make Coverage.period.end present, and the value in Coverage.period.end field is not always observed to be same as the benefit year end date.

Not all health insurance plans have a 12-month period. Many health plans offer coverage for a year, but some plans, called short-term limited duration plans, offer coverage for less than 12 months. These plans are often designed to fill gaps in coverage and may offer fewer benefits and less consumer protection than other plans. For simplicity, we assume a 12-month benefit year in this guide.

Finding the benefit year

const ACCESS_TOKEN = "flexpa-link-access-token";

const response = await fetch("https://api.flexpa.com/fhir/Coverage", {
  headers: {
    "content-type": "application/json",
    "authorization": `Bearer ${ACCESS_TOKEN}`,
  },
});

const bundle = await response.json();

const getYearStart = (start: string | undefined) => start && new Date(start);
const getYearEnd = (start: string | undefined) => {
  if (!start) return;
  const end = new Date(start);
  end.setFullYear(getYearStart(start).getFullYear() + 1);
  return end;
};
const formatDate = (date: Date) => date.toISOString().split('T')[0];

const currentCoverage = bundle.entry.find((entry) => {
  const start = getYearStart(entry.resource.period.start);
  const end = getYearEnd(entry.resource.period.start);
  return start.getTime() <= Date.now() && end.getTime() >= Date.now();
})?.resource;
const benefitYearStart = currentCoverage && getYearStart(currentCoverage.period?.start);
const benefitYearEnd = currentCoverage && getYearEnd(currentCoverage.period?.start);

console.log(benefitYearStart && formatDate(benefitYearStart));
// Output: 2024-04-01

console.log(benefitYearEnd && formatDate(benefitYearEnd));
// Output: 2025-04-01

#Sum accumulators

To sum accumulator amounts across multiple ExplanationOfBenefit resources, we need to search over the benefit year and use the following:

  • accumulators.deductible = Σ deductible
  • accumulators.oop = Σ (copay + coinsurance + deductible)

Where accumulators.deductible is the member's covered plan spend towards the deductible minimum and accumulators.oop is the member's covered plan spend towards the out-of-pocket maximum. Accumulators are typically calculated for a benefit year, so it's suggested to only use EOBs during that period.

Using a reduce function, we can sum the accumulators across multiple ExplanationOfBenefit resources.

Try this code against ExplanationOfBenefit resources from Humana's test patient.

JSON
{
  "accumulators": {
    "deductible": 210,
    "oop": 500
  }
}

Summing accumulators across ExplanationOfBenefit resources

Typescript
  type Accumulators = {
    dedudctible: number;
    oop: number;
  };

  if (!benefitYearStart || !benefitYearEnd) {
    throw new Error('Benefit year could not be calculated');
  }

  const eobResponse = await fetch(
    `https://api.flexpa.com/fhir/ExplanationOfBenefit
    ?created=gte${formatDate(benefitYearStart)}
    &created=lt${formatDate(benefitYearEnd)}`, {
    headers: {
      "content-type": "application/json",
      "authorization": `Bearer ${ACCESS_TOKEN}`,
    },
  });

  const eobBundle = await eobResponse.json();

  const findValueByCode = (total, code) => {
    return total.find((total) => total.category.coding
      .some((coding) => coding.code === code))
      .amount?.value;
  };

  const accumulators = bundle.reduce(
    (acc: Accumulators, eob: ExplanationOfBenefit & { total: ExplanationOfBenefitTotal[] }) => {
      const deductible = findValueByCode(eob.total, "deductible");
      const copay = findValueByCode(eob.total, "copay");
      const coinsurance = findValueByCode(eob.total, "coinsurance");
      const oop = copay + coinsurance + deductible;

      return {
        deductible: acc.deductible + deductible,
        oop: acc.oop + oop,
      };
    },
    {
      deductible: 0,
      oop: 0,
    },
  );

  console.log({ accumulators });

#Accumulators by claim type

Summing accumulators values by claim type is a common practice to calculate financial information. For example, you might be interested in how insurer liability and member liability differ between institutional, professional and pharmacy claims.

Types of claims can be found in the type field of the ExplanationOfBenefit resource. The type field is a Coding data type with a system of http://terminology.hl7.org/CodeSystem/claim-type. The type field can have the following values:

CodeTitleDescription
institutionalInstitutionalClaims for services provided in an institutional setting, such as a hospital or nursing facility.
pharmacyPharmacyClaims for prescription drugs.
professionalProfessionalClaims for services provided by a healthcare professional, such as a doctor or nurse.
visionVisionClaims for vision services, such as eye exams or glasses.
oralOralClaims for oral health services, such as dental exams or cleanings.

#Adjudication codes

The ExplanationOfBenefit resource provides adjudication codes that can be used to calculate financial liability and payment information. Adjudication codes contain a breakdown of the adjudication details from the processing of a claim.


#What are the adjudication codes?

Payers generally standardly encode adjudication codes according to the CARIN Blue Button 2.0 Adjudication Value Set, which is a combination of adjudication code systems from base FHIR and CARIN BB.

#Liability codes

CodeTitleDescription
submittedSubmitted AmountThe total submitted amount for the claim or group or line item.
noncoveredNoncoveredThe portion of the cost of this service that was deemed not eligible by the insurer because the service or member was not covered by the subscriber contract.
eligibleEligible AmountAmount of the change which is considered for adjudication.
discountDiscountThe amount of the discount that the payer has pre-negotiated with the provider.
benefitBenefit AmountAmount payable under the coverage.
coinsuranceCoinsuranceThe amount the insured individual pays, as a set percentage of the cost of covered medical services, as an out-of-pocket payment to the provider. Example: Insured pays 20% and the insurer pays 80%.
copayCoPayThe amount the insured individual pays, as a set amount for a covered medical service, as an out-of-pocket payment to the provider. Example: A doctor's visit has a copay of $20, payable during your visit.
deductibleDeductibleAmount deducted from the eligible amount prior to adjudication.
memberliabilityMember liabilityThe amount of the member's liability.
drugcostDrug costPrice paid for the drug excluding mfr or other discounts. It typically is the sum of the following components: ingredient cost, dispensing fee, sales tax, and vaccine administration

#Payment codes

CodeTitleDescription
priorpayerpaidPrior payer paidThe reduction in the payment amount to reflect the carrier as a secondary payer.
paidtopatientPaid to patientThe amount paid to patient.
paidtoproviderPaid to providerThe amount paid to the provider.
paidbypatientPaid by patientThe total amount paid by the patient without specifying the source.
paidbypatientcashPaid by patient - cashThe amount paid by the patient using cash, check, or other personal account.
paidbypatientotherPaid by patient - otherThe amount paid by the patient using a method different than cash (cash, check, or personal account) or health account.
paidbypatienthealthaccountPaid by patient - health accountThe amount paid by the patient using another method like HSA, HRA, FSA or other type of health account.

#Flexpa codes

Additionally, Flexpa has added the following payment adjudication codes for convenience. These codes are not part of the CARIN BB Adjudication Value Set, and have the code system http://flexpa.com/fhir/adjudication.

CodeTitleDescription
paidbypayerPaid by payerThe total amount paid by the payer without specifying who was paid.
owedbypatientOwed by patientThe amount owed by the patient. In other words, the patient's payable amount.
owedbypayerOwed by payerThe amount owed by the payer. In other words, the payer's payable amount.

#Where are adjudication codes located?

Adjudication codes are potentially available in 3 different locations within an ExplanationOfBenefit resource:

FHIR PathDescriptionFill rate in real data
total[]Sum of all line items96%
item.adjudication[]Adjudication per line item88%
adjudication[]Header-level27%

The total[] array is the most reliable way to calculate financial information in an ExplanationOfBenefit, given that it is present in over 96% of ExplanationOfBenefit resources analyzed by Flexpa.

Additionally, to obtain adjudication values per line item in an ExplanationOfBenefit, item.adjudication[] is a feasible option, as it is present in over 88% of ExplanationOfBenefit resources analyzed by Flexpa.

The header-level adjudication[] array, present in only 27% of ExplanationOfBenefit resources analyzed by Flexpa, has been observed to typically contain codes from http://hl7.org/fhir/us/carin-bb/CodeSystem/C4BBAdjudicationDiscriminator with qualitative information about reasons for adjudication.

The location of the adjudication values in an ExplanationOfBenefit resource can vary depending on the payer and the type of claim. We recommend checking each location to ensure you have the most complete set of adjudication values.

Locate adjudication values

Javascript
const ACCESS_TOKEN = "flexpa-link-access-token";

const response = await fetch("https://api.flexpa.com/fhir/ExplanationOfBenefit/123", {
  headers: {
    "content-type": "application/json",
    "authorization": `Bearer ${ACCESS_TOKEN}`,
  },
});

const eob = await response.json();

let adjudicationValues;
if(eob.total.length > 0) {
  adjudicationValues = eob.total;
} else if(eob.item.length > 0) {
  adjudicationValues = eob.item.flatMap((item) => item.adjudication);
} else {
  adjudicationValues = eob.adjudication;
}

#Code normalization

Fortunately, the Flexpa API normalizes financial codes in Explanation of Benefit (EOB) resources so that you don't have to. Behind the scenes, Flexpa completes the following steps:
  1. Parses the payer's original ExplanationOfBenefit resource to extract adjudication values.
  2. Translates the adjudication codes provided by each payer to a standard set of codes.
  3. Calculates missing financial data based on the Liability and Payment Equations.
  4. Inserts the calculated values into the ExplanationOfBenefit resource.
  5. Returns the normalized ExplanationOfBenefit resource to you.
This process makes it easier for you to access financial information from ExplanationOfBenefit resources.

This feature currently supports the following endpoints:

LabelName
Aetnaaetna-test
Aetnaaetna
Anthemanthem
Blue Cross Blue Shield of North Carolinabcbs-north-carolina
Cignacigna
Cignacigna-test
Elevance Testelevance-test
Flexpa Live Mode Sample Patientmedplum-live
Flexpa Test Mode Sample Patientmedplum-test
Healthy Bluehealthy-blue
Humanahumana
Humanahumana-test
Kaiser Permanentekaiser-permanente-test
Kaiser Permanentekaiser-permanente
United Healthcareunited-healthcare
UnitedHealthcareunited-healthcare-test

Flexpa's Financial Normalization is a complex process that requires a deep understanding of the FHIR standard, the CARIN BB Adjudication Value Set, and analysis of real-world data. We are working to expand this feature to more payers.

Status TwitterGitHub

© 2025 Flexpa. All rights reserved.