Professional Claims Submission (837P) | Medplum
On this page
This guide explains how to model FHIR resources and invoke the Stedi integration to submit professional (X12 837P) claims to payers.
Overview
The Stedi integration maps a Claim and related resources into Stedi's Professional Claims JSON API, submits the claim to the payer, and returns submission metadata.
This workflow is handled by the Stedi Professional Claims Bot. Please contact the Medplum team to get access to this bot.
info
This integration supports professional (837P) claims only. Institutional (837I) and dental claims are not supported yet.
Project secrets
Configure these secrets on the Medplum project that runs the bot:
| Secret | Type | Required | Description |
|---|---|---|---|
STEDI_CLAIM_API_KEY |
string | Yes | Stedi API key with permission to submit professional claims |
STEDI_CLAIM_TEST_MODE |
boolean | No | When true, sets Stedi usageIndicator to T (test). Default is P (production) |
note
Stedi's test claims workflow uses a production API key. It does not use Stedi test API keys (prefix test_) the same way eligibility sandbox checks do.
Resource model
The bot reads the Claim you submit and follows references to gather patient, billing provider, rendering/supervising practitioners, coverage, payer, and encounter data.
The claim links its providers directly:
Claim.providerreferences the billing provider — anOrganizationfor organization billing (the common case), or aPractitionerfor individual billing.Claim.careTeamreferences the practitioners who delivered care, disambiguated byrole.coding.code(systemhttp://terminology.hl7.org/CodeSystem/claimcareteamrole):primary→ the rendering provider (the practitioner who performed the service). Required.supervisor→ the supervising provider (e.g. an MD overseeing a coach or nurse practitioner). Optional.
This separates the billing relationship (Claim.provider) from the clinical relationship (Claim.careTeam), so the billing Organization does not need to match any PractitionerRole.organization your application uses for other purposes.
Billing as an organization vs. an individual
The 837P always requires a billing provider, taken from Claim.provider. You can bill either way:
- As an organization (most common for clinics): set
Claim.providerto anOrganizationwith an NPI, Tax ID (EIN), address, and phone. The claim is billed under the organization, and the rendering practitioner comes fromClaim.careTeam. - As an individual provider: set
Claim.providerto thePractitionerdirectly. The bot then bills under the practitioner, which means the practitioner must carry the billing data itself — NPI, a tax identifier ( EIN or SSN), an address, and a phone. When nocareTeammember is present, that same practitioner is also used as the rendering provider.
Example transaction Bundle (organization billing, Stedi test payer)
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:11111111-1111-4111-8111-111111111111",
"resource": {
"resourceType": "Patient",
"name": [{ "family": "Doe", "given": ["John"] }],
"birthDate": "1990-01-15",
"gender": "male",
"address": [{
"line": ["123 Main St"],
"city": "Boston",
"state": "MA",
"postalCode": "02118"
}]
},
"request": { "method": "POST", "url": "Patient" }
},
{
"fullUrl": "urn:uuid:22222222-2222-4222-8222-222222222222",
"resource": {
"resourceType": "Organization",
"name": "Example Family Practice",
"identifier": [
{ "system": "http://hl7.org/fhir/sid/us-npi", "value": "1999999984" },
{ "system": "http://hl7.org/fhir/sid/us-ein", "value": "12-3456789" }
],
"telecom": [{ "system": "phone", "value": "6175550100" }],
"address": [{
"line": ["500 Clinic Way"],
"city": "Boston",
"state": "MA",
"postalCode": "02118"
}]
},
"request": { "method": "POST", "url": "Organization" }
},
{
"fullUrl": "urn:uuid:33333333-3333-4333-8333-333333333333",
"resource": {
"resourceType": "Practitioner",
"name": [{ "family": "Smith", "given": ["Alice"], "prefix": ["Dr."] }],
"identifier": [{ "system": "http://hl7.org/fhir/sid/us-npi", "value": "1234567893" }],
"qualification": [{
"code": {
"coding": [
{
"system": "http://nucc.org/provider-taxonomy",
"code": "207Q00000X",
"display": "Family Medicine"
}
]
}
}]
},
"request": { "method": "POST", "url": "Practitioner" }
},
{
"fullUrl": "urn:uuid:44444444-4444-4444-8444-444444444444",
"resource": {
"resourceType": "Practitioner",
"name": [{ "family": "Jones", "given": ["Robert"], "prefix": ["Dr."] }],
"identifier": [{ "system": "http://hl7.org/fhir/sid/us-npi", "value": "1999999984" }],
"qualification": [{
"code": {
"coding": [
{
"system": "http://nucc.org/provider-taxonomy",
"code": "207R00000X",
"display": "Internal Medicine"
}
]
}
}]
},
"request": { "method": "POST", "url": "Practitioner" }
},
{
"fullUrl": "urn:uuid:55555555-5555-4555-8555-555555555555",
"resource": {
"resourceType": "Organization",
"name": "Stedi Test Payer",
"identifier": [{
"system": "https://www.stedi.com/healthcare/network",
"value": "STEDITEST"
}],
"type": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
"code": "ins",
"display": "Insurance Company"
}]
}]
},
"request": { "method": "POST", "url": "Organization" }
},
{
"fullUrl": "urn:uuid:66666666-6666-4666-8666-666666666666",
"resource": {
"resourceType": "Coverage",
"status": "active",
"subscriberId": "AMBETTER123",
"subscriber": {
"reference": "urn:uuid:11111111-1111-4111-8111-111111111111",
"display": "John Doe"
},
"beneficiary": {
"reference": "urn:uuid:11111111-1111-4111-8111-111111111111",
"display": "John Doe"
},
"relationship": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/subscriber-relationship",
"code": "self"
}]
},
"payor": [{
"reference": "urn:uuid:55555555-5555-4555-8555-555555555555",
"display": "Stedi Test Payer"
}]
},
"request": { "method": "POST", "url": "Coverage" }
},
{
"fullUrl": "urn:uuid:77777777-7777-4777-8777-777777777777",
"resource": {
"resourceType": "Encounter",
"status": "finished",
"class": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
"code": "AMB",
"display": "ambulatory"
},
"subject": {
"reference": "urn:uuid:11111111-1111-4111-8111-111111111111",
"display": "John Doe"
},
"period": { "start": "2026-04-01T15:00:00Z", "end": "2026-04-01T15:30:00Z" }
},
"request": { "method": "POST", "url": "Encounter" }
},
{
"fullUrl": "urn:uuid:88888888-8888-4888-8888-888888888888",
"resource": {
"resourceType": "Claim",
"status": "active",
"type": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/claim-type",
"code": "professional"
}]
},
"use": "claim",
"patient": {
"reference": "urn:uuid:11111111-1111-4111-8111-111111111111",
"display": "John Doe"
},
"created": "2026-04-01",
"provider": {
"reference": "urn:uuid:22222222-2222-4222-8222-222222222222",
"display": "Example Family Practice"
},
"careTeam": [{
"sequence": 1,
"provider": {
"reference": "urn:uuid:33333333-3333-4333-8333-333333333333",
"display": "Dr. Alice Smith"
},
"role": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/claimcareteamrole", "code": "primary" }]}
},
{
"sequence": 2,
"provider": {
"reference": "urn:uuid:44444444-4444-4444-8444-444444444444",
"display": "Dr. Robert Jones"
},
"role": { "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/claimcareteamrole", "code": "supervisor" }]}
}],
"priority": { "coding": [{ "code": "normal" }] },
"insurance": [{
"sequence": 1,
"focal": true,
"coverage": { "reference": "urn:uuid:66666666-6666-4666-8666-666666666666" }
}],
"diagnosis": [{
"sequence": 1,
"diagnosisCodeableConcept": {
"coding": [{
"system": "http://hl7.org/fhir/sid/icd-10-cm",
"code": "J06.9",
"display": "Acute upper respiratory infection, unspecified"
}]
}
}],
"item": [{
"sequence": 1,
"productOrService": {
"coding": [{
"system": "http://www.ama-assn.org/go/cpt",
"code": "99213",
"display": "Office/outpatient visit, established patient"
}]
},
"servicedDate": "2026-04-01",
"unitPrice": { "value": 180, "currency": "USD" },
"quantity": { "value": 1 },
"diagnosisSequence": [1],
"locationCodeableConcept": { "coding": [{ "code": "11" }] },
"encounter": [{ "reference": "urn:uuid:77777777-7777-4777-8777-777777777777" }]
}],
"total": { "value": 180, "currency": "USD" }
},
"request": { "method": "POST", "url": "Claim" }
}
]
}
FHIR resource requirements
Claim
| Field | Description | Required |
|---|---|---|
patient |
Reference to the patient on the claim | Yes |
provider |
Reference to the billing provider — an Organization (org billing) or Practitioner (individual billing). Contained references (#id) are supported |
Yes |
careTeam[] with role.coding.code = primary |
Reference to the renderingPractitioner. Falls back to the first careTeam member, then to provider when it is a Practitioner |
Yes |
careTeam[] with role.coding.code = supervisor |
Reference to the supervisingPractitioner |
No |
insurance[0].coverage |
Reference to Coverage |
Yes |
item[0].encounter[0] |
Reference to Encounter (used for default service date) |
Yes |
item[] |
Service lines | Yes (at least one) |
item[].productOrService.coding.code |
HCPCS/CPT procedure code | Yes |
item[].unitPrice or item[].net |
Line charge (used for line and total amounts) | Yes |
item[].quantity |
Units of service | No (defaults to 1) |
item[].diagnosisSequence |
Pointers into Claim.diagnosis (1-based) |
No (defaults to ['1']) |
Common rejections and troubleshooting
Most failures are caused by missing or malformed FHIR data. The bot validates some of these up front (failing fast with a clear message); others come back from Stedi or the payer as a 400 with an errors[] array.