Batch eligibility checks
Batch eligibility checks are a great option as your volume grows. Stedi handles complexity like queuing and retries according to established best practices, so you don't have to build this logic yourself. We recommend using batch checks for bulk workflows that aren't time sensitive, including:
- Monthly or weekly coverage refreshes
- Upcoming appointments
- Sets of thousands or millions of checks that can run in the background
However, batch checks have a longer feedback cycle than real-time checks because you don't receive the payer's response immediately. That's why we strongly recommend starting with real-time checks when integrating with a new payer or working with eligibility checks for the first time. This approach allows you to ensure that your pipeline is working smoothly before you begin staging batch checks.
You can submit batch checks manually by uploading CSV files to the Stedi portal or programmatically through the API.
Transaction enrollment
Some payers require transaction enrollment before you can start sending them eligibility checks. The Payer Network specifies which payers require enrollment.
Manual submission
To upload a CSV file with batch eligibility checks, go to the Eligibility check batches page in the Stedi portal and click + New CSV batch.
CSV upload
You can download a template CSV file with all of the supported properties.
- Each row in the file corresponds to one batch eligibility check. You can submit up to 1,000 checks per CSV file.
- CSV batch checks support a subset of the properties available in the API. The available properties cover the vast majority of use cases. Contact Stedi support if you need to include additional properties.
Once you upload the CSV file, click Verify file so Stedi can validate the data in each eligibility check. You can fix any validation errors and re-upload the CSV file as many times as needed.
When the file is error-free, you'll be able to click Execute batch to send the eligibility checks to Stedi. Stedi processes the checks asynchronously, implementing best practices to avoid payer throttling.
Batch status
The batch status changes to In progress while Stedi is processing the batch. The status changes to Completed when Stedi has sent all checks in the batch to payers and received responses. A completed batch may contain both successful and failed eligibility checks.
You can retrieve the results of each check in the batch through the Stedi portal or API.
API submission
You can use Stedi's Batch Eligibility Check API to submit up to 10,000 eligibility checks in a single request. Stedi processes these eligibility checks asynchronously, implementing best practices to avoid payer throttling.
Headers - required
You must include the following headers in your API request:
Authorization: Generate an API key to use for authentication.Content-Type: Set toapplication/json.
curl --request POST \
--url https://manager.us.stedi.com/2024-04-01/eligibility-manager/batch-eligibility \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \Headers - situational
When sending eligibility checks to the Centers for Medicare & Medicaid Services (CMS), you may need to include the X-Forwarded-For header set to a comma-separated list of any upstream IP addresses. Visit CMS traceability requirements for details and examples.
Request data
The information you provide to the payer in an eligibility check can vary, depending on the circumstances. However, each batch eligibility check must include at least the following information:
| Information | Description |
|---|---|
tradingPartnerServiceId |
|
submitterTransactionIdentifier |
|
provider object, name and identifier |
|
subscriber and/or dependents objects |
|
encounter object, service dates |
|
encounter object, service or procedure codes |
|
Patient information
Batch checks should follow the same best practices as real-time eligibility checks when entering patient information. Visit Real-time eligibility checks for guidance on:
- Which patient identifiers to use for best results
- How to know if a patient qualifies as a dependent
- How to enter patient names for best results
MBI for CMS checks
A Medicare Beneficiary Identifier (MBI) is a unique, randomly-generated identifier assigned to individuals enrolled in Medicare. You must include the patient's MBI in every eligibility check to the Centers for Medicare and Medicaid Services (payer ID: CMS).
Some payers return the patient's MBI in one of the following properties of the standard eligibility response:
If the value in either of these properties matches the format specified in the Medicare Beneficiary Identifier documentation, the number is likely an MBI, and we recommend sending a follow-up eligibility check to CMS for additional benefits data. You're most likely to receive an MBI in eligibility check responses from commercial Medicare Advantage plans, but they can also be present in responses from Medicaid plans for dual-eligible patients.
When you don't know a patient's MBI, you can use Stedi's eligibility check APIs to perform an MBI lookup using their Social Security Number instead. Stedi returns a complete benefits response from CMS with the patient's MBI in the subscriber object for future reference. Visit Medicare Beneficiary Identifier (MBI) lookup for complete details.
Don't submit eligibility checks for Medicare Advantage plans to CMS (HETS) – you should submit them to the actual Medicare Advantage plan payer instead.
Conditional requirements
Note that objects marked as required are required for all requests, while others are conditionally required depending on the circumstances. When you include a conditionally required object, you must include all of its required properties.
For example, you must always include the provider object in your request, but you only need to include the dependents object when you need to request benefits information for a dependent on the subscriber's insurance plan.
Character restrictions
Only use the X12 Basic and Extended character sets in request data. Using characters outside these sets may cause validation and HTTP 400 errors.
Don't include the following characters in your request data: ~, *, : and ^. They are reserved for delimiters in the resulting X12 EDI transaction, and X12 doesn't support using escape sequences to represent delimiters or special characters. Stedi returns a 400 error if you include these restricted characters in your request.
Autocorrection for backticks
Stedi automatically replaces backticks (`), also known as backquotes or grave accents, with an apostrophe (') in subscriber and dependents first and last names. These corrections prevent errors when submitting your request. Stedi returns a message in the response's warnings array when it makes this replacement.
Sample request and response
The following example demonstrates how to submit a batch of eligibility checks in the items array, where each item represents an individual eligibility check. Stedi returns a batchId that you can use to retrieve the results of these checks later.
Visit Determine patient benefits for detailed explanations of how to determine the patient's active coverage, financial responsibility, whether referrals and authorizations are required, and more.
curl --request POST \
--url https://manager.us.stedi.com/2024-04-01/eligibility-manager/batch-eligibility \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '{
"items": [
{
"submitterTransactionIdentifier": "ABC123456789",
"tradingPartnerServiceId": "AHS",
"encounter": {
"serviceTypeCodes": [
"MH"
]
},
"provider": {
"organizationName": "ACME Health Services",
"npi": "1999999984"
},
"subscriber": {
"dateOfBirth": "19000101",
"firstName": "Jane",
"lastName": "Doe",
"memberId": "1234567890"
}
},
{
"submitterTransactionIdentifier": "DEF123456799",
"tradingPartnerServiceId": "AHS",
"encounter": {
"serviceTypeCodes": [
"78"
]
},
"provider": {
"organizationName": "ACME Health Services",
"npi": "1999999984"
},
"subscriber": {
"dateOfBirth": "19001021",
"firstName": "John",
"lastName": "Doe",
"memberId": "1234567892"
}
}
]
}'{
"batchId": "01928d19-df25-76c0-8d51-f5351260fa05",
"submittedAt": "2023-11-07T05:31:56Z"
}Concurrency limit
Asynchronous batch checks don’t count toward your Stedi account concurrency limit for real-time checks.
There are no limits on the number of batches you can run in parallel.
Automatic retries
Stedi retries checks that fail due to payer connectivity issues for up to 8 hours. Therefore, it can take up to 8 hours for all checks in a batch to return results.
Retrieve batch results
After you've submitted a batch of eligibility checks, you can review and retrieve the results through the Stedi portal or API.
Stedi portal
You can review the progress of batch eligibility checks submitted through API or CSV upload on the Eligibility check batches page.
Click the batch name to view its details, including the status of each check in the batch. You can also download the original CSV input, if the batch was submitted as a CSV file.
On the batch details page, you can click any eligibility check to review it in Eligibility Manager, including the full request and response payload. You'll also be able to edit the request details for failed eligibility checks and resubmit them to the payer.
Status endpoints
You can use the following endpoints to programmatically check the status of batch eligibility checks submitted through the API or CSV upload. These endpoints help you determine when to start polling for results.
Retrieve Batch Status
The Retrieve Batch Status endpoint returns a summary of the batch's processing status, including the number of completed checks, the error count, and the overall batch status. You can use it to determine when to start polling for the results of the eligibility checks within the batch. For example, you shouldn't start polling until the successCount is greater than zero. You can also stop polling when the inProgressCount reaches zero or when the batch status is COMPLETED or COMPLETED_WITH_ERRORS.
The following is an example response for a batch submitted through the API. The successCount matches the totalCount, indicating that all checks in the batch have been successfully processed and that the payer returned a response.
Note that successful processing doesn't necessarily mean that the patient has active coverage; it simply means that the payer returned a response for the check. You'll need to review the individual check results to determine the patient's coverage status.
{
"batchType": "ELIGIBILITY",
"createdAt": "2025-06-13T17:14:20.02Z",
"errorCount": 0,
"id": "01976a49-05f4-7421-bc33-aed86f1fccc6",
"inProgressCount": 0,
"name": "01976a49-05f4-7421-bc33-aed86f1fccc6",
"source": "API",
"status": "COMPLETED",
"successCount": 9000,
"totalCount": 9000,
"updatedAt": "2025-06-13T17:14:24.872Z",
"validatedCount": 0,
"validationFailedCount": 0
}Retrieve Batch Check Statuses
The Retrieve Batch Check Statuses endpoint retrieves the processing status of the eligibility checks in the specified batch. You can use it to determine whether specific eligibility checks within a batch have completed. You can also use the response to determine whether patients have active or inactive coverage without having to poll.
The following is an example response for two checks in a batch submitted through a CSV upload. You can tell because the results include the rowNumber, which indicates the row number for that eligibility check in the CSV file.
- The first check has an
eligibilitySearchStatusofactive, indicating that the payer returned at least one active eligibility and benefit type. This means that the patient has active coverage for at least some services. it'sstateisCOMPLETED, indicating that the check was successfully processed and that the payer returned a response. - The second check has an
eligibilitySearchStatusoffailed, indicating that Stedi didn't receive benefits information from the payer. ItsstateisCOMPLETED_WITH_ERRORS, which typically indicates that Stedi couldn't get a response from the payer after retrying. Failures like this are often due to payer connectivity issues.
Each check's additionalInfo.eligibility object includes the submitterTransactionIdentifier you assigned when you submitted the batch. This identifier is also present in the polling results, allowing you to correlate the status of each check with the original request and the results from the polling endpoint.
{
"items": [
{
"additionalInfo": {
"eligibility": {
"eligibilitySearchId": "01932c61-2d4f-7d22-85fa-c7db2e13e771",
"submitterTransactionIdentifier": "ABC123456789",
"eligibilitySearchStatus": "active",
"payerId": "BCBS",
"subscriberFirstName": "John",
"subscriberLastName": "Doe",
"subscriberMemberId": "123456789"
}
},
"batchId": "01932c61-2d4f-7d22-85fa-c7db2e13e771",
"createdAt": "2025-03-31T14:25:30Z",
"requestId": "req-01a2b3c4-d5e6-7f89-0123-456789abcdef",
"rowNumber": 3,
"state": "COMPLETED",
"updatedAt": "2025-03-31T14:26:45Z"
},
{
"additionalInfo": {
"eligibility": {
"eligibilitySearchId": "01932c61-2d4f-7d22-85fa-c7db2e13e772",
"submitterTransactionIdentifier": "GHJ987654321",
"eligibilitySearchStatus": "failed",
"payerId": "AETNA",
"subscriberFirstName": "Jane",
"subscriberLastName": "Smith",
"subscriberMemberId": "987654321"
}
},
"batchId": "01932c61-2d4f-7d22-85fa-c7db2e13e771",
"createdAt": "2025-03-31T14:25:30Z",
"requestId": "req-02a2b3c4-d5e6-7f89-0123-456789abcdef",
"rowNumber": 2,
"state": "COMPLETED_WITH_ERRORS",
"updatedAt": "2025-03-31T14:27:15Z"
}
],
"nextPageToken": "945ff6de213d3ef481d028065d4c12fb996a166a3a90ef98564318decfae50ce4b36d74b7e9d9bafa6e1d169"
}Polling endpoint
You can use the Poll Batch Eligibility Checks endpoint to retrieve the results from batch checks submitted through both the API and CSV upload.
You should track completed checks to determine when to stop polling.
Polling strategy
We recommend using the Retrieve Batch Status endpoint to monitor the progress of large batches and determine when to start polling for results.
- Don't start polling until the
successCountis greater than zero. You may also want to wait until all checks are complete and then poll once, depending on your use case. - You can stop polling when the
inProgressCountreaches zero or when the batchstatusisCOMPLETEDorCOMPLETED_WITH_ERRORS.
While batches are in progress, a single polling attempt may not retrieve responses for all checks within the batch. Most batches complete in 15 to 30 minutes. However, Stedi retries checks that fail due to payer connectivity issues for up to 8 hours, so it can take up to 8 hours for all checks in a batch to return results.
After your initial poll, use exponential backoff with jitter. Start at 2 minutes and approximately double the wait between polls, up to 8 hours. For example, you might use something similar to the following formula (all values in seconds):
wait_time = (0 if attempt == 0 else min(120 * 2**(attempt - 1), 8*60*60)) + random(0, 30)In this formula:
- Immediate first poll: if
attempt == 0then wait time is0. - Start at 2 minutes: On attempt ==
1, base wait is 120 seconds (2 minutes). - Exponential backoff: Doubles each time: 2, 4, 8, 16, ... minutes.
- Cap at 8 hours: min(..., 86060) ensures it never exceeds 480 minutes.
- Jitter: Adds a random delay between 0 and 30 seconds.
Filter polling results
You can filter the polling results using the following query parameters:
batchId: Retrieve results for a specific batch of eligibility checks. You can find this value in the synchronous response from the Batch Eligibility Check endpoint.startDateTime: Retrieve results for checks submitted after a specific date and time (in ISO 8601 format).
The following example example retrieves the results for batch checks submitted after 2025-12-31T00:00:00Z:
curl --request GET \
--url https://manager.us.stedi.com/2024-04-01/eligibility-manager/polling/batch-eligibility?startDateTime=2025-12-31T00:00:00Z \
--header 'Authorization: <api-key>'Track completed checks
The polling endpoint only returns checks that have been fully processed. These are checks that:
- Returned benefits information indicating either active or inactive coverage. These checks have a final
stateofCOMPLETEDand aneligibilitySearchStatusofactiveorinactive. - Returned an error response from the payer that doesn't indicate payer connectivity issues. For example, if the payer returns an error indicating that the member ID is invalid, Stedi considers this a completed check and returns it in the batch results with the associated
AAAerror of72(Invalid/Missing Subscriber/Insured ID). These checks have a finalstateofCOMPLETEDand aneligibilitySearchStatusoffailed. - Returned
AAAerrors42or80for Stedi's entire retry period. TheseAAAerrors indicate payer connectivity issues, and Stedi retries checks that fail due to payer connectivity issues for up to 8 hours. After 8 hours, Stedi returns it in the batch results with the associatedAAAerror. These checks have a finalstateofCOMPLETED_WITH_ERRORSand aneligibilitySearchStatusoffailed. - Stedi couldn't process due to validation errors in the request data. These checks have a final
stateofVALIDATION_FAILEDand aneligibilitySearchStatusoffailed.
Checks that Stedi hasn't yet finished processing aren't included in the polling results. For example, the polling endpoint won't return results for checks that are eligible for automatic retries.
You'll need to track the status of pending checks to determine when to stop polling. You can do this with either of the status endpoints:
- Retrieve Batch Status: Returns summary information about the batch, including the
inProgressCount, which indicates how many checks are still pending. You can stop polling when this count reaches zero or when the batchstatusisCOMPLETEDorCOMPLETED_WITH_ERRORS. - Retrieve Batch Check Statuses: Returns status information for all checks in the batch, including those that are still pending. The information for each check includes the
submitterTransactionIdentifieryou assigned when you submitted the batch. This identifier is also present in the polling results, allowing you to correlate the status of each check with the results from the polling endpoint.
Costs
The costs for running a batch eligibility check – manually or using the API – are the same as running the equivalent number of real-time eligibility checks.
For example, if you run a batch with 500 checks, it will cost the same as running 500 real-time eligibility checks.
Minimize waste
We recommend the following to optimize batch eligibility checks:
- Periodically purge or archive records for inactive patients. It's a waste to perform eligibility checks on patients who have died or who haven't scheduled an encounter for several years.
- Remove or deactivate patients that are no longer eligible. The payer indicates ineligibility by setting
benefitsInformation.code = “6”(Inactive) in the response.
Monitor for potential coverage loss
When you receive the results of your batch eligibility checks, look for patients who have coverage that may be at risk.
Check for benefitsInformation.code = “5”, which stands for Active - Pending investigation, or a response containing a benefitsDateInformation.premiumPaidToDateEnd before the current date. Some payers may still show active coverage while the subscriber is behind on premium payments.
You may want to conduct additional checks on these patients because they have an elevated risk of losing coverage soon.
CMS traceability requirements
Starting November 8, 2025, the Centers for Medicare & Medicaid Services (CMS) requires submitters to include the entire chain of network hops for every eligibility request sent to CMS's eligibility system, HETS.
Specifically, requests must include a standard X-Forwarded-For HTTP header containing the network IP addresses from the point of origin through receipt by the HETS system. CMS expects X-Forwarded-For to list each IP, comma-separated, starting with the originating system and continuing through every intermediary.
To comply with this requirement:
- You must collect all IP addresses for upstream requests and pass them in the standard
X-Forwarded-Forheader when calling Stedi's API. If you are yourself an intermediary – for example, an RCM, EHR, or PMS system – you'll need to coordinate with your providers and any third-party organizations to ensure they include the Network IP details as part of theX-Forwarded-Forheader. This enables CMS to receive a complete list of all IPs, including the original initiator of the request (typically, the provider). - Stedi records the IP address you use when you call our API, as well as all the IP addresses listed in the
X-Forwarded-Forheader. We include these IP addresses in the list submitted to CMS.
You only need to include the X-Forwarded-For header in eligibility requests when there are upstream IP addresses.
The following examples illustrate when and how to include the header:
| Scenario | X-Forwarded-For required? | Result |
|---|---|---|
A provider (IP 2.2.2.2) connects directly to Stedi without intermediaries. | No. | CMS ultimately receives X-Forwarded-For: 2.2.2.2 |
A provider (IP 2.2.2.2) routes through an RCM platform's transactional system (IP 3.3.3.3) that calls Stedi's API using a separate integration backend (IP 4.4.4.4). | Yes. The RCM platform sets X-Forwarded-For: 2.2.2.2, 3.3.3.3. Stedi records the IP address of the API caller (4.4.4.4 ) and sends it to CMS. | CMS ultimately receives X-Forwarded-For: 2.2.2.2, 3.3.3.3, 4.4.4.4. |
A provider network (IP 2.2.2.2) passes through an office firewall (IP 4.4.4.4) and then an RCM platform (IP 3.3.3.3), which calls Stedi's API. | Yes. The RCM platform sets X-Forwarded-For: 2.2.2.2, 4.4.4.4. Stedi records the IP address of the API caller (3.3.3.3) and sends it to CMS. | CMS ultimately receives X-Forwarded-For: 2.2.2.2, 4.4.4.4, 3.3.3.3. |