Skip to main content

Insurance and Benefits Eligibility Checks

This guide explains how to model your FHIR resources for the Stedi integration to send and receive eligibility and benefits checks.

Overview

The Stedi integration allows you to perform insurance eligibility checks by sending a a CoverageEligibilityRequest resource and receiving a CoverageEligibilityResponse resource with the benefits information. This workflow is handled by our Insurance Eligibility Bot. Please contact the Medplum team to get access to this bot.

For more general information about eligibility checks, please see our Insurance Eligibility Checks guide.

Creating the Eligibility Check

The following diagram shows the resources that are involved to make an insurance eligibility check with our Stedi integration.

CoverageEligibilityRequest

FieldDescriptionRequired
insurerReference to the payer OrganizationYes
providerReference to the provider OrganizationYes
subscriberReference to the subscriber PatientYes
insuranceArray of Coverages. If there are more than one, the array item labeled as the focal will be used for the eligibility checkYes
servicedPeriod.startService period start dateNo (defaults to current date if not provided)
itemArray of details about the eligibility being checked. This includes what procedure, product, or service is being provided as well as why it is being provided. item.category is what selects the service types the check asks about, described below.No (defaults to service type code 30)

Service type codes

note

Most payers respond to only a small subset of the X12 service type codes, and many return general benefits no matter what was requested, so treat a specific code as a request rather than a guarantee.

Each item.category.coding entry with the system https://x12.org/codes/service-type-codes adds a service type to the check. You can supply several codings, or several item entries, and all of them are sent together on a single eligibility check. If no X12 service type coding is present, the check defaults to 30 (Health Benefit Plan Coverage). A code that Stedi does not accept is rejected before the request reaches the payer, and the error names the item and coding it came from.

These are the codes most implementations start with.

CodeDisplay
30Health Benefit Plan Coverage
12Durable Medical Equipment Purchase
35Dental Care
47Hospital
48Hospital - Inpatient
50Hospital - Outpatient
88Pharmacy
98Professional (Physician) Visit - Office
ALVision (Optometry)
MHMental Health
UCUrgent Care

For the complete set of accepted codes, see the service type codes section of Stedi's eligibility code lists. Stedi also publishes guidance on choosing service type codes, and the codes themselves are maintained as the X12 Service Type Codes.

This example asks about both durable medical equipment and mental health benefits.

item: [
{
category: {
coding: [
{
system: 'https://x12.org/codes/service-type-codes',
code: '12',
display: 'Durable Medical Equipment Purchase',
},
{
system: 'https://x12.org/codes/service-type-codes',
code: 'MH',
display: 'Mental Health',
},
],
},
},
],

:::

Organization (Payer)

FieldDescriptionRequired
identifierSystem must be https://www.stedi.com/healthcare/networkYes
nameOrganization nameYes
info

If you are using an Organization from the Medplum Payer Directory, it will have the correct Payer identifier, so you can just use that.

Organization (Provider)

FieldDescriptionRequired
identifierSystem must be http://hl7.org/fhir/sid/us-npiYes
nameOrganization nameYes

Patient (Subscriber)

FieldDescriptionRequired
name.familyLast nameYes
name.givenFirst nameYes
birthDateDate of birthYes
identifierSystem http://hl7.org/fhir/sid/us-ssnNo (but recommended)

Coverage

FieldDescriptionRequired
subscriberIdInsurance subscriber IDYes
statusShould be "active"Yes
subscriberReference to a Patient or RelatedPersonYes
beneficiaryReference to a Patient or RelatedPersonYes
payorReference to the payer OrganizationYes

Executing the Eligibility Check

The Insurance Eligibility Bot runs the Stedi (X12 270/271) eligibility check and returns a CoverageEligibilityResponse. Invoke the $stedi-check-eligibility custom operation on CoverageEligibilityRequest in either of these ways:

  • Instance level — on a stored request: POST {base}/fhir/R4/CoverageEligibilityRequest/{id}/$stedi-check-eligibility
  • Type level — with a CoverageEligibilityRequest in the request body: POST {base}/fhir/R4/CoverageEligibilityRequest/$stedi-check-eligibility

Instance level (after you have created and stored the CoverageEligibilityRequest):

const response = await medplum.post(
medplum.fhirUrl('CoverageEligibilityRequest', coverageEligibilityRequest.id, '$stedi-check-eligibility')
);

Or via the FHIR REST API:

POST {base}/fhir/R4/CoverageEligibilityRequest/{id}/$stedi-check-eligibility

Stedi sandbox testing

note

The Stedi sandbox successfully validates only a few payloads. We recommend using the transaction Bundle below when testing against the sandbox.

Example transaction Bundle (recommended for Stedi sandbox testing)
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:a1c2d3e4-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"resource": {
"resourceType": "Patient",
"name": [
{
"family": "Doe",
"given": ["John"]
}
],
"birthDate": "1994-04-04"
},
"request": {
"method": "POST",
"url": "Patient"
}
},
{
"fullUrl": "urn:uuid:b2d3e4f5-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"resource": {
"resourceType": "Organization",
"name": "Provider Name",
"identifier": [
{
"system": "http://hl7.org/fhir/sid/us-npi",
"value": "1999999984"
}
]
},
"request": {
"method": "POST",
"url": "Organization"
}
},
{
"fullUrl": "urn:uuid:c3e4f5a6-7b8c-4d9e-af1a-2b3c4d5e6f7a",
"resource": {
"resourceType": "Organization",
"name": "Aetna",
"identifier": [
{
"system": "https://www.stedi.com/healthcare/network",
"value": "68069"
}
],
"type": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
"code": "ins",
"display": "Insurance Company"
}
]
}
]
},
"request": {
"method": "POST",
"url": "Organization"
}
},
{
"fullUrl": "urn:uuid:d4f5a6b7-8c9d-4e0f-b1a2-3c4d5e6f7a8b",
"resource": {
"resourceType": "Coverage",
"status": "active",
"subscriberId": "AMBETTER123",
"subscriber": {
"reference": "urn:uuid:a1c2d3e4-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"display": "John Doe"
},
"beneficiary": {
"reference": "urn:uuid:a1c2d3e4-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"display": "John Doe"
},
"payor": [
{
"reference": "urn:uuid:c3e4f5a6-7b8c-4d9e-af1a-2b3c4d5e6f7a",
"display": "Aetna"
}
]
},
"request": {
"method": "POST",
"url": "Coverage"
}
},
{
"fullUrl": "urn:uuid:e5a6b7c8-9d0e-4f1a-82b3-4d5e6f7a8b9c",
"resource": {
"resourceType": "CoverageEligibilityRequest",
"status": "active",
"purpose": ["benefits"],
"patient": {
"reference": "urn:uuid:a1c2d3e4-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"display": "John Doe"
},
"created": "2026-03-16",
"provider": {
"reference": "urn:uuid:b2d3e4f5-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"display": "Provider Name"
},
"insurer": {
"reference": "urn:uuid:c3e4f5a6-7b8c-4d9e-af1a-2b3c4d5e6f7a",
"display": "Aetna"
},
"insurance": [
{
"coverage": {
"reference": "urn:uuid:d4f5a6b7-8c9d-4e0f-b1a2-3c4d5e6f7a8b"
},
"focal": true
}
],
"item": [
{
"category": {
"coding": [
{
"system": "https://x12.org/codes/service-type-codes",
"code": "30",
"display": "Health Benefit Plan Coverage"
}
]
}
}
]
},
"request": {
"method": "POST",
"url": "CoverageEligibilityRequest"
}
}
]
}

Receiving the Eligibility Response

After the eligibility check is sent, the Insurance Eligibility Bot will create and return a CoverageEligibilityResponse resource. This new CoverageEligibilityResponse will reference all of the resources from the request.

It will also contain the benefits information for the coverage in it's insurance.item field.

CoverageEligibilityResponse.insurance.item field will contain the benefits information about the patient's coverage. Read more about Receiving a CoverageEligibilityResponse.

Each insurance.item entry describes a benefit the payer reported, and its category.coding records the X12 service type codes that benefit applies to, using the system https://x12.org/codes/service-type-codes. Benefits scoped to general coverage also carry a http://terminology.hl7.org/CodeSystem/ex-benefitcategory coding for code 30. A payer may report benefits for service types beyond the ones you asked about, and a benefit the payer did not scope to any service type has no category at all.

Example CoverageEligibilityResponse from a STEDI insurance and benefits eligibility check
{
"resourceType": "CoverageEligibilityResponse",
"status": "active",
"outcome": "complete", // Eligibility check was successful
"patient": {
"reference": "Patient/12345678-1234-5678-9abc-123456789abc",
"display": "Jordan Doe"
},
"insurer": {
"reference": "Organization/87654321-4321-8765-cdef-987654321def",
"display": "Aetna" // Insurance company
},
"insurance": [
{
"coverage": {
"reference": "Coverage/abcdef12-5678-9012-3456-abcdef123456"
},
"inforce": true, // Coverage is active
"benefitPeriod": {
"start": "2024-01-01T00:00:00.000Z", // Coverage period
"end": "2024-12-31T00:00:00.000Z"
},
"item": [
// COPAY - Fixed dollar amount per visit (in-network)
{
"category": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/ex-benefitcategory",
"code": "30",
"display": "Health Benefit Plan Coverage"
},
{
"system": "https://x12.org/codes/service-type-codes",
"code": "30",
"display": "Health Benefit Plan Coverage"
}
]
},
"network": {
"coding": [
{
"system": "https://www.stedi.com/in-network-indicator",
"code": "Y",
"display": "Yes"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-network",
"code": "in",
"display": "In-Network"
}
]
},
"unit": {
"coding": [
{
"system": "https://www.stedi.com/coverage-level-code",
"code": "IND",
"display": "Individual"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-unit",
"code": "individual",
"display": "Individual"
}
]
},
"benefit": [
{
"type": {
"coding": [
{
"system": "https://www.stedi.com/benefit-type-code",
"code": "B",
"display": "Co-Payment"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-type",
"code": "copay",
"display": "Copayment per service "
}
]
},
"allowedMoney": {
"value": 10, // $10 copay
"currency": "USD"
}
}
]
},

// COINSURANCE - Percentage patient pays after deductible is met (in-network)
{
"category": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/ex-benefitcategory",
"code": "30",
"display": "Health Benefit Plan Coverage"
},
{
"system": "https://x12.org/codes/service-type-codes",
"code": "30",
"display": "Health Benefit Plan Coverage"
}
]
},
"network": {
"coding": [
{
"system": "https://www.stedi.com/in-network-indicator",
"code": "Y",
"display": "Yes"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-network",
"code": "in",
"display": "In-Network"
}
]
},
"unit": {
"coding": [
{
"system": "https://www.stedi.com/coverage-level-code",
"code": "IND",
"display": "Individual"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-unit",
"code": "individual",
"display": "Individual"
}
]
},
"benefit": [
{
"type": {
"coding": [
{
"system": "https://www.stedi.com/benefit-type-code",
"code": "A",
"display": "Co-Insurance"
}
]
},
"allowedUnsignedInt": 10 // 10% coinsurance
}
]
},

// DEDUCTIBLE - Amount before insurance contributes (in-network)
{
"category": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/ex-benefitcategory",
"code": "30",
"display": "Health Benefit Plan Coverage"
},
{
"system": "https://x12.org/codes/service-type-codes",
"code": "30",
"display": "Health Benefit Plan Coverage"
}
]
},
"network": {
"coding": [
{
"system": "https://www.stedi.com/in-network-indicator",
"code": "Y",
"display": "Yes"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-network",
"code": "in",
"display": "In-Network"
}
]
},
"unit": {
"coding": [
{
"system": "https://www.stedi.com/coverage-level-code",
"code": "IND",
"display": "Individual"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-unit",
"code": "individual",
"display": "Individual"
}
]
},
"term": {
"coding": [
{
"system": "https://www.stedi.com/time-qualifier-code",
"code": "25", //This indicates that this is the contract's entire deductible
"display": "Contract"
}
]
},
"benefit": [
{
"type": {
"coding": [
{
"system": "https://www.stedi.com/benefit-type-code",
"code": "C",
"display": "Deductible"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-type",
"code": "deductible",
"display": "Deductible"
}
]
},
"allowedMoney": {
"value": 500, // $500 deductible
"currency": "USD"
}
}
]
},

// DEDUCTIBLE - Remaining deductible (in-network)
{
"category": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/ex-benefitcategory",
"code": "30",
"display": "Health Benefit Plan Coverage"
},
{
"system": "https://x12.org/codes/service-type-codes",
"code": "30",
"display": "Health Benefit Plan Coverage"
}
]
},
"network": {
"coding": [
{
"system": "https://www.stedi.com/in-network-indicator",
"code": "Y",
"display": "Yes"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-network",
"code": "in",
"display": "In-Network"
}
]
},
"unit": {
"coding": [
{
"system": "https://www.stedi.com/coverage-level-code",
"code": "IND",
"display": "Individual"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-unit",
"code": "individual",
"display": "Individual"
}
]
},
"term": {
"coding": [
{
"system": "https://www.stedi.com/time-qualifier-code",
"code": "29", //This indicates that this is the remaining deductible
"display": "Remaining"
}
]
},
"benefit": [
{
"type": {
"coding": [
{
"system": "https://www.stedi.com/benefit-type-code",
"code": "C",
"display": "Deductible"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-type",
"code": "deductible",
"display": "Deductible"
}
]
},
"allowedMoney": {
"value": 250, // $250 remaining deductible (in-network)
"currency": "USD"
}
}
]
},

// OUT-OF-POCKET (STOP LOSS) - the amount of money that the patient has to pay
// out of pocket before the insurance covers 100% (in-network)
{
"category": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/ex-benefitcategory",
"code": "30",
"display": "Health Benefit Plan Coverage"
},
{
"system": "https://x12.org/codes/service-type-codes",
"code": "30",
"display": "Health Benefit Plan Coverage"
}
]
},
"network": {
"coding": [
{
"system": "https://www.stedi.com/in-network-indicator",
"code": "Y",
"display": "Yes"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-network",
"code": "in",
"display": "In-Network"
}
]
},
"unit": {
"coding": [
{
"system": "https://www.stedi.com/coverage-level-code",
"code": "IND",
"display": "Individual"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-unit",
"code": "individual",
"display": "Individual"
}
]
},
"term": {
"coding": [
{
"system": "https://www.stedi.com/time-qualifier-code",
"code": "29",
"display": "Remaining"
}
]
},
"benefit": [
{
"type": {
"coding": [
{
"system": "https://www.stedi.com/benefit-type-code",
"code": "G",
"display": "Out of Pocket (Stop Loss)"
},
{
"system": "http://terminology.hl7.org/CodeSystem/benefit-type",
"code": "benefit",
"display": "Benefit"
}
]
},
"allowedMoney": {
"value": 7000,
"currency": "USD"
}
}
]
},
]
},
//You will usually get out of network benefits as well
]
}

Here are the STEDI specific codes that will be included in each of these fields:

Network Indicator Codes - Indicates whether a service is in-network or out-of-network (System: https://www.stedi.com/in-network-indicator)
CodeDisplay
YYes
NNo
UUnknown
WNot Applicable
Coverage Level Codes - Defines who is covered under the benefit (individual, family, employee, etc.) (System: https://www.stedi.com/coverage-level-code)
CodeDisplay
CHDChildren Only
DEPDependents Only
ECHEmployee and Children
EMPEmployee Only
ESPEmployee and Spouse
FAMFamily
INDIndividual
SPCSpouse and Children
SPOSpouse Only
Time Qualifier Codes - Specifies the time period for the benefit (calendar year, lifetime, remaining, etc.) (System: https://www.stedi.com/time-qualifier-code)
CodeDisplay
624 Hours
7Years
13Service Year
21Calendar Year
22Year to Date
23Contract
24Episode
25Visit
26Outlier
27Remaining
28Exceeded
29Not Exceeded
30Lifetime
31Lifetime Remaining
32Month
33Hour
34Week
35Day
36Admission
Benefit Type Codes - Defines the type of benefit (deductible, copay, coinsurance, coverage status, etc.) (System: https://www.stedi.com/benefit-type-code)
CodeDisplay
1Active Coverage
2Active - Full Risk Capitation
3Active - Services Capitated
4Active - Services Capitated to Primary Care Physician
5Active - Pending Investigation
6Inactive
7Inactive - Pending Eligibility Update
8Inactive - Pending Investigation
ACo-Insurance
BCo-Payment
CDeductible
CBCoverage Basis
DBenefit Description
EExclusions
FLimitations
GOut of Pocket (Stop Loss)
HUnlimited
INon-Covered
JCost Containment
KReserve
LPrimary Care Provider
MPre-existing Condition
MCManaged Care Coordinator
OServices Restricted to Following Provider
PNot Deemed a Medical Necessity
QBenefit Disclaimer
RSecond Surgical Opinion Required
SOther or Additional Payor
TPrior Year(s) History
UCard(s) Reported Lost/Stolen
VContact Following Entity for Eligibility or Benefit Information
WCannot Process
XOther Source of Data
YHealth Care Facility
NSpend Down

Different Subscriber and Dependent

If the subscriber and dependent are different, for example if you are checking benefits for a spouse or child who is covered under their parent's insurance, your Coverage resource will need to reference both the subscriber and dependent Patient resources. You will need to use this model for coverage eligibility checks that are not for the subscriber themselves.

How to find the raw eligibility check data

The eligibility check data is also stored in a DocumentReference resource with an identifier that has this system: http://stedi.com/eligibility-response.