How to integrate with Stedi's clearinghouse APIs
A product team picks Stedi as its clearinghouse. The first task is to send one eligibility check, one claim and read back one remittance. Stedi publishes its full developer documentation, an API reference and OpenAPI specs on GitHub. The steps below follow those documents, endpoint by endpoint.
Account and API keys
New accounts start as free sandbox accounts that can only use test mode, per Stedi's account setup page. An upgrade to a paid production account adds multi-factor authentication and a Business Associate Agreement.
Every request carries an API key in the Authorization header. The authentication section documents two key types, test and production. You create a key in the portal under API keys and pick the mode. Stedi shows the key once. Keys do not expire, so you revoke a key by deleting it.
Authorization: <api-key>
The older form Authorization: Key <api-key> still works for backwards compatibility. Each API has its own host and a dated version in the path, for example healthcare.us.stedi.com/2026-06-01 or claims.us.stedi.com/2025-03-07.
Test mode and production
Test keys return realistic responses and send nothing to payers. The test mode page lists what test mode does not support: transaction enrollment, insurance discovery, coordination of benefits checks and 276/277 claim status. For eligibility, you send one of the predefined mock requests and get a mock 271 back. Stedi warns that some payers, CMS among them, prohibit test checks with fake patients against production systems.
Test claims need a production account. The test claim workflows page describes two paths. A test claim to any payer runs Stedi's edits and returns a test 277CA. A test claim to the Stedi Test Payer also returns a test 835. That second path requires an 835 enrollment with the Stedi Test Payer, and you must complete it in production.
Eligibility (270/271)
The current JSON endpoint is Real-Time Eligibility Check JSON. Stedi translates the JSON to an X12 270 and returns the payer's answer as JSON and raw X12.
POST https://healthcare.us.stedi.com/2026-06-01/eligibility-check
{
"payerId": "61101",
"provider": { "npi": "1999999984" },
"subscriber": {
"memberId": "HUMANA123",
"dateOfBirth": "1975-05-05",
"name": { "person": { "firstName": "Jane", "lastName": "Doe" } }
},
"encounter": { "services": [{ "system": "STC", "value": "30" }] }
}
The eligibility guide sets the rules. Payer IDs keep their leading zeros. Stedi recommends one service type code per request and defaults to code 30 when you send none. If you omit the provider name, Stedi fills it from the NPPES record for the NPI. Payers can take up to 60 seconds, and Stedi holds the request open for up to 120 seconds while it retries the payer. For checks sent to CMS, you must pass the chain of upstream IP addresses in X-Forwarded-For.
Claims (837P)
Stedi offers three professional claim endpoints. Create Professional Claim JSON uses a JSON shape that follows the CMS-1500 form. The legacy 837P JSON endpoint follows the X12 loops, and a raw X12 endpoint takes the 837P text. The claims guide states that the CMS-1500 endpoint does not support secondary or tertiary claims. Those go through the legacy endpoint.
POST https://claims.us.stedi.com/2025-03-07/professional-claim-submissions
Idempotency-Key: 0e1f9a8d-6c5b-4a3f-9d2e-7b8c1a0f4e6d
The body holds purpose, payer, insured, an optional patient, encounter, serviceLines, authorization, submitter and billing. Set billing.patientControlNumber to a unique value of 17 characters or fewer. Some payers cut longer values in the 277CA and 835. Set serviceLines[].lineItemControlNumber so you can match payments per line.
The endpoint returns HTTP 201 whether Stedi's edits pass or fail. Check for an errors array. If it is present, Stedi stored the claim as rejected and did not send it.
Send an Idempotency-Key on every claim. Per the idempotency section, a retry with the same key within 24 hours does not create a second claim. The same key with a different body returns 422. A retry while the first request still runs returns 409 with a Retry-After header.
Claim status (276/277)
Real-Time Claim Status JSON is POST https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/claimstatus/v2. The base request needs tradingPartnerServiceId, the billing provider, the subscriber and a service date range. The claim status guide recommends a range of plus or minus 7 days around the service date, no more than 30 days wide, with no future dates. It also recommends a first check at least 2 to 3 days after submission, then at 21 days and 1 month if no 835 arrives. Test keys do not work on this endpoint.
Finding 277CAs and 835s
Payer responses arrive later. You discover them by event destinations or by polling, then fetch them by ID. The claim responses guide describes both.
Event destinations are Stedi's webhooks. You can create up to 16 per account. Subscribe to transaction.processed. Events are thin: they carry IDs and no claim data. Each delivery has webhook-id, webhook-timestamp and webhook-signature headers that follow the Standard Webhooks scheme. Per the delivery page, only a 2xx counts as delivered. Stedi does not follow redirects. It retries for up to 48 hours, then disables the destination.
To poll, call Poll Transactions at GET https://core.us.stedi.com/2023-08-01/polling/transactions with startDateTime once, then follow pageToken. The page size defaults to 100 and goes up to 500. Filter for direction INBOUND and transaction set 277 or 835. Stedi recommends that each polling window start one day before the last transaction you processed, so you must remove duplicates.
With the transaction ID, call 835 ERA Report at GET https://healthcare.us.stedi.com/2024-04-01/change/medicalnetwork/reports/v2/{transactionId}/835. The 277CA report uses the same path ending in /277. Match the 835 to your claim on claimPaymentInfo.patientControlNumber, case-insensitive. Treat two ERAs with the same check or EFT trace number as duplicates.
Payer IDs and enrollment
Search Payers at GET https://payers.us.stedi.com/2024-04-01/payers/search takes a name, ID or alias and filters such as eligibilityCheck=SUPPORTED. Each payer record has a transactionSupport object. Each transaction type is supported, enrollment required or not supported.
The transaction enrollment page states that 835 ERAs always need enrollment. ERA enrollment is exclusive to one clearinghouse, so a switch to Stedi stops ERAs at the old one. You create a provider with POST https://enrollments.us.stedi.com/2024-09-01/providers, then one enrollment per transaction type with POST /enrollments. An enrollment moves through DRAFT, STEDI_ACTION_REQUIRED, PROVISIONING and LIVE. It can stop at PROVIDER_ACTION_REQUIRED or end as REJECTED. Stedi states that most enrollments finish within 24 to 48 hours and that some payers take up to 30 days.
Limits
The limits section sets 100 requests per second across the claims endpoints and the enrollment endpoints. Real-time eligibility and claim status share a default pool of 50 concurrent requests. Claim submission endpoints share a pool of 100. Past either limit, Stedi returns 429 with TOO_MANY_REQUESTS.
Splice Health offers a free 30 minute consult to review a Stedi integration plan before you build it.
