How to migrate to Stedi's redesigned JSON Real-Time Eligibility Check API

We've released a redesigned version of our JSON Real-Time Eligibility Check API endpoint. It returns the same benefits information as our legacy JSON real-time eligibility endpoint with an improved response shape.

The new shape is easier for developers and AI coding agents, like Claude Code and Codex, to parse. Each benefit type has its own schema, and benefits are grouped by health plan.

If you're building a new Stedi integration, start with the new endpoint.

If you're still on the legacy endpoint, this guide can help you migrate to the new endpoint. It covers what's changed and explains the new response shape. The guide also includes migration tips and a prompt for your coding agent.

Migration tips

Use Stedi's SDKs for TypeScript and Python

If you use TypeScript or Python, Stedi's TypeScript and Python SDKs include methods and runnable examples for the new endpoint:

The SDKs give you a reusable client, types, retries, and error handling. You only need to write the parts that are specific to your product.

Use a coding agent

The new endpoint is designed to work well with coding agents like Claude Code and Codex. Give your agent this prompt to kick off the migration process:

Migrate this codebase from Stedi's legacy JSON Real-Time Eligibility Check API endpoint to the redesigned endpoint, using the appropriate Stedi SDK or REST API:

- TypeScript: https://www.npmjs.com/package/@stedi/sdk
- Python: https://pypi.org/project/stedi/
- REST API:
  - API reference: https://www.stedi.com/docs/healthcare/api-reference/post-eligibility-check.mdx
  - OpenAPI spec: https://github.com/Stedi/openApi/blob/main/healthcare.json

Fetch the following migration guides and apply the appropriate changes:
- https://www.stedi.com/docs/healthcare/eligibility-response-shapes
- https://www.stedi.com/blog/migrate-to-the-redesigned-json-real-time-eligibility-check-api

Do not touch more files than necessary for the migration.

Request body changes

You provide the same information to run eligibility checks with either endpoint:

Legacy endpoint request
An example curl request using the legacy endpoint:

curl --request POST \
  --url https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/eligibility/v3 \
  --header 'Authorization: <api-key>' \
  --header 'Content-Type: application/json' \
  --data '{
    "tradingPartnerServiceId": "87726",
    "provider": {
      "organizationName": "Provider Name",
      "npi": "1999999984"
    },
    "subscriber": {
      "firstName": "John",
      "lastName": "Doe",
      "dateOfBirth": "19700101",
      "memberId": "UHC202649"
    },
    "encounter": {
      "serviceTypeCodes": ["30"]
    }
  }'

New endpoint request
The new endpoint groups related request fields into nested objects. It also replaces the separate serviceTypeCodes and procedureCode fields with a single services array.

A few field names were renamed to be clearer. For example, tradingPartnerServiceId is now payerId. The dateOfBirth format also changed. It uses YYYY-MM-DD instead of YYYYMMDD.

The same curl request using the new endpoint:

curl --request POST \
  --url https://healthcare.us.stedi.com/2026-06-01/eligibility-check \
  --header 'Authorization: <api-key>' \
  --header 'Content-Type: application/json' \
  --data '{
    "payerId": "87726",
    "provider": {
      "name": {
        "organization": "Provider Name"
      },
      "npi": "1999999984"
    },
    "subscriber": {
      "name": {
        "person": {
          "firstName": "John",
          "lastName": "Doe"
        }
      },
      "dateOfBirth": "1970-01-01",
      "memberId": "UHC202649"
    },
    "encounter": {
      "services": [
        {
          "system": "STC",
          "value": "30"
        }
      ]
    }
  }'

To get more details on individual request fields, see the related guide and API reference in our docs.

Response changes

Most providers run eligibility checks to answer two questions:

  • Does this patient have active insurance coverage?
  • If so, what do they need to pay out of pocket for this service or procedure? This includes co-payments, deductibles, and co-insurance.

The eligibility response's benefits answer those questions. Both endpoints return the same benefits information. The biggest change is that each benefit type now has its own schema. The new endpoint also groups benefits by plan.

This section gives you the highlights. For more information, see response shapes in our docs.

Benefits grouped by plan

Legacy endpoint
The legacy endpoint returns every benefit in a single, flat benefitsInformation array with no plan grouping. When a patient has more than one plan, entries for every plan appear in the array. Only planCoverage tells you which plan each entry belongs to.

"benefitsInformation": [
  {
    "code": "C",                       // Deductible
    "coverageLevelCode": "IND",        // Individual coverage
    "serviceTypeCodes": ["30"],        // Health Benefit Plan Coverage
    "timeQualifierCode": "23",         // Calendar year
    "benefitAmount": "1000",           // $1,000 per year deductible
    "planCoverage": "OPEN ACCESS PLUS" // Medical plan
  },
  {
    "code": "C",                 // Deductible
    "coverageLevelCode": "IND",  // Individual coverage
    "serviceTypeCodes": ["35"],  // Dental care
    "timeQualifierCode": "23",   // Calendar year
    "benefitAmount": "50",       // $50 per year deductible
    "planCoverage": "PPO DENTAL" // Dental plan
  }
]

New endpoint
The new endpoint returns benefits in a nested plans array, which groups benefits under their associated health plan. A response can contain multiple plans.

For example, a patient with medical and dental coverage through the same payer receives a separate plans object for each plan. Each plan's name is in plans[].name.

"plans": [
  {
    "name": "Open Access Plus",
    "benefits": {
      "deductible": [
        {
          "amount": "1000",
          "coverageLevel": "INDIVIDUAL",
          "service": {
            "system": "STC",
            "value": "30",
            "definition": "Health Benefit Plan Coverage"
          },
          "timePeriod": "CALENDAR_YEAR"
        }
      ]
    }
  },
  {
    "name": "PPO Dental",
    "benefits": {
      "deductible": [
        {
          "amount": "50",
          "coverageLevel": "INDIVIDUAL",
          "service": {
            "system": "STC",
            "value": "35",
            "definition": "Dental Care"
          },
          "timePeriod": "CALENDAR_YEAR"
        }
      ]
    }
  }
]

Different schema for different benefit types

Legacy endpoint
In the legacy endpoint's benefitsInformation array, every benefit entry reuses the same object schema. As a result, the schema can't tell you which fields are expected from a payer for each entry type.

Each benefitsInformation entry includes a code that tells you what the rest of the entry means.

For example, an entry with a code of C is a deductible. The entry's benefitAmount field includes a dollar amount for the deductible. The schema lists benefitAmount as optional. But payers should always return a benefitAmount for deductible entries.

{
  "benefitsInformation": [
    {
      "code": "C",             // Deductible
      "benefitAmount": "1000", // $1,000 deductible
      ...
    },
    ...
  ]
}

An entry with a code of A indicates co-insurance. The entry's benefitPercent field includes a percent for the co-insurance. The schema lists benefitPercent as optional, but payers should always return a benefitPercent for co-insurance entries. The benefitAmount field is also listed as optional, but payers shouldn't return benefitAmount for co-insurance entries.

{
  "benefitsInformation": [
    {
      "code": "A",           // Co-insurance
      "benefitPercent": "0", // 0% co-insurance
      ...
    },
    ...
  ]
}

New endpoint
In plans responses, benefit types use a named key instead of a code field. For example, objects in the statuses array tell you whether the patient has insurance coverage and which services it applies to. Every other kind of benefit is its own named array, such as coPayment or deductible.

Each benefit type also has its own object schema. That schema matches what's expected in the payer response. For example, deductible objects require an amount. coInsurance objects have no amount field. They require a percent instead.

{
  "plans": [
    {
      "benefits": {
        "deductible": [
          {
            "amount": "1000", // $1,000 deductible
            ...
          }
        ],
        "coInsurance": [
          {
            "percent": "0", // 0% co-insurance
            ...
          }
        ],
        ...
      }
    },
    ...
  ]
}

Invalid response data

Stedi builds both the new and legacy JSON eligibility responses from the same underlying X12 271 eligibility response we receive from the payer. The response shapes differ in how they handle data that doesn't conform to the X12 spec.

Legacy endpoint
If a payer returns an invalid X12 response, legacy responses pass that data through as is in the benefitsInformation entry.

For example, the response could include an entry for a co-payment that contains an invalid benefitPercent and is missing benefitAmount.

"benefitsInformation": [
  {
    "code": "B",                // Co-payment
    "benefitPercent": "0.2"     // Invalid X12 for a co-payment entry
                                // benefitAmount is missing
  }
]

New endpoint
The new endpoint validates benefit entries in the response against their types. Invalid entries appear in benefits.invalidEntries instead of the standard array. For example:

{
  "plans": [
    {
      "benefits": {
        "invalidEntries": {
          "coPayment": [
            {
              "percent": "0.2",
              ...
              "invalidReasons": [
                {
                  "code": "MISSING_AMOUNT",
                  "description": "Co-payment requires an amount value, but none was provided."
                },
                {
                  "code": "UNEXPECTED_PERCENT",
                  "description": "Co-payment has an unexpected percent value."
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

Parsing benefits for services or procedures

Providers commonly want every benefit for a specific STC or procedure code – coverage status, deductibles, co-insurance. Both endpoints name the service each benefit applies to, but they name it differently, so your filter changes.

Legacy endpoint
You can parse legacy benefitsInformation responses with TypeScript code like this:

const STC = "30";

// One entry can list several STCs, so check the whole array.
const benefits = response.benefitsInformation.filter((benefit) =>
  benefit.serviceTypeCodes?.includes(STC),
);

New endpoint
Using the new plans responses, you'd update that code to the following:

const STC = "30";

// Check the system too. A procedure code can have the same value as an STC.
const forStc = (benefit) =>
  benefit.service?.system === "STC" && benefit.service.value === STC;

const benefits = (response.plans ?? []).flatMap((plan) => {
  // invalidEntries is an object of arrays. Pull it out first.
  const { invalidEntries, ...standard } = plan.benefits ?? {};
  return [
    ...Object.values(standard).flat(),
    // Include invalid entries to match the legacy endpoint's behavior.
    ...Object.values(invalidEntries ?? {}).flat(),
  ].filter(forStc);
});

FAQs

Are you deprecating the legacy endpoint?

No. We're continuing to support the legacy endpoint, and there's no deadline for migration. Your existing integrations will keep working.

Does the new JSON Real-Time Eligibility Check API endpoint support test mode?

Yes. You can use the new endpoint to run pre-defined mock eligibility checks in test mode with a test API key.

Mock eligibility checks are available on all Stedi accounts, including free sandbox accounts.

Does the new response shape contain different benefits information?

No. Stedi builds both JSON response shapes from the same underlying X12 271 eligibility response.

The responses only differ in how they organize that information, what they name each property, and how they handle data that doesn't conform to the spec.

What endpoints use the new response shape?

Only the redesigned JSON Real-Time Eligibility Check API endpoint returns the new plans response shape.

Other eligibility-related endpoints use the benefitsInformation response shape.

Do the Stedi SDKs support the legacy eligibility endpoint?

No. Stedi's TypeScript and Python SDKs only support the new JSON Real-Time Eligibility Check API endpoint.

Availability and pricing

The redesigned JSON Real-Time Eligibility Check API endpoint is available on all Stedi accounts.

Production eligibility checks are priced per transaction. For pricing, see our Pricing page.

Previous5 ways MSOs can grow RCM with Stedi

Get started with Stedi

Start free with a sandbox account. Upgrade to production when you’re ready. There are no monthly minimums or setup fees. You only pay for the transactions you use. See our pricing.

Sign up free