To build a FHIR Coverage resource from insurance cards, put the member ID in subscriberId or a member-number identifier, the group, plan and pharmacy numbers in class entries, the cardholder in subscriber and the patient in beneficiary. Then supply what the card never prints, such as status and a payor reference, from your own records.
Treat this as a mapping guide for your own integration. Schema Care produces no Coverage resources: it offers no API, SDK, webhooks, FHIR, X12 or 275 output, and it does not read insurance cards. The card, family, plan and every identifier below are invented, and the server is fhir.example.com.
Insurance card fields mapped onto FHIR Coverage elements
Each printed insurance card field has one home in the FHIR R4 Coverage resource. The member ID goes to subscriberId or identifier, the payer to payor, the group and plan to class, the cardholder to subscriber, the patient to beneficiary, and a dependent suffix to dependent. Copays are the only field with a doubtful home.
The HL7 FHIR R4 Coverage resource page defines each element. Three are required in the base resource: status (1..1), beneficiary (1..1) and payor (1..*). Everything else is optional, which is why a card alone can fill most of a Coverage but never all of it.
The fictional card for this post belongs to a family plan. The subscriber is Marcus Example; the patient is his daughter, Ava Example, age 9, who has her own card with a dependent suffix.
| Printed card field | Example value on the card | Coverage element |
|---|---|---|
| Member ID | EXM55120934 | subscriberId, and identifier with type MB |
| Dependent suffix | 02 | dependent |
| Member name | AVA EXAMPLE | beneficiary (a reference to her Patient) |
| Subscriber | MARCUS EXAMPLE | subscriber (a reference to a RelatedPerson) |
| Group number | EXG-40018 | class with type group |
| Plan name | EX Gold HMO | class with type plan, and class.name |
| RxBIN, RxPCN, RxGroup | 999002, EXRX2, EXRXG40 | class with types rxbin, rxpcn, rxgroup |
| Payer name | Example Health Plan | payor (a reference to an Organization) |
| Network label | EX Select | network |
| Copays | Office $20, Specialist $40 | Possibly costToBeneficiary; see below |
How the card fields themselves come out of a photo, with confidence scores and nulls, is described in the guide to an insurance card OCR API. Which FHIR resource fits each kind of medical document, beyond cards, is covered in the section on which FHIR resources match each medical document type.
The annotated Coverage, as an example
The JSON below is the fictional card above turned into a Coverage. The table after it labels each element with the card field it came from.
{
"resourceType": "Coverage",
"id": "ex-cov-ava",
"identifier": [{
"type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "MB" }] },
"system": "https://fhir.example.com/sid/example-health-plan-member",
"value": "EXM55120934-02"
}],
"status": "active",
"subscriber": { "reference": "RelatedPerson/ex-rp-marcus" },
"subscriberId": "EXM55120934",
"beneficiary": { "reference": "Patient/ex-pat-ava" },
"dependent": "02",
"relationship": {
"coding": [{ "system": "http://terminology.hl7.org/CodeSystem/subscriber-relationship", "code": "child" }]
},
"payor": [{ "reference": "Organization/ex-org-example-health-plan" }],
"class": [
{ "type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/coverage-class", "code": "group" }] }, "value": "EXG-40018" },
{ "type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/coverage-class", "code": "plan" }] }, "value": "EX-GOLD-HMO", "name": "EX Gold HMO" },
{ "type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/coverage-class", "code": "rxbin" }] }, "value": "999002" },
{ "type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/coverage-class", "code": "rxpcn" }] }, "value": "EXRX2" },
{ "type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/coverage-class", "code": "rxgroup" }] }, "value": "EXRXG40" }
],
"network": "EX Select"
}
| Element | Came from |
|---|---|
identifier.value | Member ID plus dependent suffix, as printed on Ava's card |
status | Not on the card; set by your system after an eligibility check |
subscriber | Subscriber name line |
subscriberId | Member ID without the suffix |
beneficiary | Member name line, matched to Ava's existing Patient record |
dependent | Dependent suffix 02 |
relationship | Not on the card; from the intake form's relationship question |
payor | Payer name and logo, matched to an Organization you maintain |
class entries | Group, plan name and the three pharmacy fields |
network | Network label |
Which Coverage class types hold group, plan and Rx numbers?
The FHIR Coverage class element holds the insurer's group, plan and pharmacy numbers as a list of typed entries. Each entry has a required type code, a required value string and an optional name. Use the code group for the group number, plan for the plan, and rxbin, rxpcn, rxgroup and rxid for the pharmacy fields.
The codes come from the HL7 FHIR coverage class value set, which takes every code from the code system http://terminology.hl7.org/CodeSystem/coverage-class. It lists eleven codes:
| Code | HL7 definition | Card field it suits |
|---|---|---|
group | An employee group | Group number |
subgroup | A sub-group of an employee group | Only if the card labels it |
plan | A specific suite of benefits | Plan name or plan code |
subplan | A subset of a specific suite of benefits | Only if the card labels it |
class | A class of benefits | Only if the card labels it |
subclass | A subset of a class of benefits | Only if the card labels it |
sequence | A sequence number for a short-term continuance of coverage | Only if the card labels it |
rxbin | The pharmacy benefit manager's Business Identification Number | RxBIN |
rxpcn | A pharmacy benefit manager's Processor Control Number | RxPCN |
rxid | A pharmacy benefit manager's member ID | Rx ID, when it differs from the member ID |
rxgroup | A pharmacy benefit manager's group number | RxGroup |
The Coverage page shows class.type bound to these codes at extensible strength, so use them whenever one fits. Because class.value is required, never add a class entry for a field the card leaves blank. A card with no group number gets no group entry, not an entry with an empty value.
Keep the medical group and the RxGroup apart. They are different numbers with different codes, and a card can print both. When the card prints a plan name but no plan code, put the printed name in both value and name, or use your own stable plan code in value, and record which you chose.
Subscriber, beneficiary and relationship in a Coverage resource
In a Coverage resource, subscriber is the person who holds the policy, beneficiary is the patient it covers, and relationship says how the patient is related to the subscriber. On a dependent's card, the subscriber is usually the parent or spouse and the beneficiary is the patient. When they are the same person, use self.
The Coverage page defines subscriber as a reference to a Patient or RelatedPerson, and beneficiary as a reference to a Patient only. When the subscriber is not a patient of your practice, a RelatedPerson is the right target. The HL7 FHIR R4 RelatedPerson page requires a patient reference on every RelatedPerson, so Marcus is recorded in relation to Ava:
{
"resourceType": "RelatedPerson",
"id": "ex-rp-marcus",
"patient": { "reference": "Patient/ex-pat-ava" },
"relationship": [{
"coding": [{ "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", "code": "FTH" }]
}],
"name": [{ "family": "Example", "given": ["Marcus"] }],
"birthDate": "1985-06-21"
}
That example is fictional, and the subscriber's birth date usually comes from the intake form, not the card.
The relationship element on Coverage uses the HL7 subscriber relationship codes: child, parent, spouse, common, other, self and injured. These describe the beneficiary's relationship to the subscriber, so Ava's Coverage says child, not parent. Getting that direction wrong is a common mapping error.
Who counts as the subscriber when a child, a spouse or a guardian is involved is explained in the section on who the subscriber on an insurance card is.
Should copays printed on the card become Coverage costToBeneficiary?
Copays printed on an insurance card can become costToBeneficiary entries, but only when the text is clear about the service and the amount. Short labels like "Office $20" map cleanly. Labels like "Spec 20%/$40 after ded" carry conditions the element cannot express, so leave those out rather than store a value that misstates the benefit.
The Coverage page defines costToBeneficiary as optional and repeating. Each entry has an optional type, a required value[x] that is either a Quantity (for a percentage) or Money, and optional exception entries. The type is bound at extensible strength to the HL7 coverage copay type codes, which include gpvisit, spvisit, emergency, inpthosp, televisit, urgentcare, copaypct, copay, deductible and maxoutofpocket.
The two copays on the fictional card would look like this:
"costToBeneficiary": [
{ "type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/coverage-copay-type", "code": "gpvisit" }] },
"valueMoney": { "value": 20.00, "currency": "USD" } },
{ "type": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/coverage-copay-type", "code": "spvisit" }] },
"valueMoney": { "value": 40.00, "currency": "USD" } }
]
Ask three questions before writing a copay:
- Does the label name one service type? "Office" fits
gpvisit; "Visit" alone may not. - Is it one amount? A range or "after deductible" is a condition, not a value.
- Will anyone read it? If billing always uses the eligibility response for patient cost, a card copay adds a second, older answer.
Printed copays are a snapshot from the day the card was made. The payer's eligibility response describes current benefits, so prefer it whenever you have it.
Coverage resource gaps: required elements an insurance card does not print
A Coverage resource needs some elements that no insurance card prints. The card shows no status, nothing a payor reference can point to on its own, and often no coverage period. US Core adds a required relationship. Fill these from eligibility results, the intake form and your own payer table, never from guesses.
Each gap has a better source:
| Element | Required? | Why the card falls short | Where to get it |
|---|---|---|---|
status | 1..1 in base R4 | Cards carry no status | active after an eligibility check confirms it; otherwise draft |
payor | 1..* in base R4 | The card has a name, not a resource | An Organization you maintain for each payer, matched from the printed name |
beneficiary | 1..1 in base R4 | The card has a name, not a Patient record | Your patient matching step |
relationship | 1..1 in US Core | The card may not say | The intake form's relationship-to-insured question |
period | Optional | The card may print no dates | The eligibility response, or leave it out |
type | Optional, Must Support in US Core | Plan type is often only implied | Your payer table, using the US Core payer type codes |
Use draft honestly. The Coverage status codes are active, cancelled, draft and entered-in-error, so a Coverage built from a card that nobody has verified is fairly described as draft until a check confirms it.
When a new card replaces one already on file, end the old Coverage instead of overwriting it. The process for that is in the section on how updated patient insurance on file should replace the old coverage.
Cards often arrive inside a paper intake packet rather than as a photo. Schema Care reads that route: the insurance, demographics, history and consent checkbox sections of patient intake forms, each field scored and the uncertain ones sent to a reviewer, as listed with the other document types on the homepage. Your integration would then build the Coverage. The intake packet itself can be modeled as a FHIR QuestionnaireResponse, which the guide to FHIR QuestionnaireResponse for intake forms covers.
Validating a card-derived Coverage resource against US Core
Validate a card-derived Coverage resource against the US Core Coverage profile, which adds rules the base resource does not have. US Core requires a relationship, exactly one payor, and a member ID in either identifier or subscriberId. It also marks group and plan class entries, coverage type and period as Must Support.
The US Core Coverage profile, in US Core version 9.0.0 (STU 9), lists what each Coverage must have and what systems must support:
| Rule | US Core 9.0.0 requirement |
|---|---|
status | 1..1 |
beneficiary | 1..1, a reference to a US Core Patient |
relationship | 1..1, extensible binding to the subscriber relationship codes |
payor | 1..1, a reference to a US Core Organization, Patient or RelatedPerson |
| Member ID | Constraint us-core-15: a member ID in Coverage.identifier or Coverage.subscriberId SHALL be present |
identifier:memberid | Type MB from the v2-0203 code system |
class:group, class:plan | Must Support, each with type and value |
type, period | Must Support |
Common failures with card-derived resources:
- No relationship. The card did not say, and nobody asked. Ask on the intake form.
- Two payor references. Base R4 allows several; US Core allows one.
- A payor pointing at a placeholder. The Organization must exist and meet the US Core Organization profile.
- An empty class value. A blank group number produced a
groupentry with no value. - The member ID only in a note. It must be in
identifierorsubscriberIdto satisfy us-core-15.
Run the validation when the resource is built, before it reaches a server, and send failures to a person with the card image beside them. If coverage documents later travel with a claim as supporting paperwork, that exchange uses a different standard, described in the guide to X12 275 claim attachments.