Customer Callback Example API
Introduction
Coverage Discovery is asynchronous. When you submit a Coverage Discovery request, the final result is not returned inline with the original request. Instead, you can receive the result in one or both of these ways:
- Callback delivery to your whitelisted callback URL
- Polling
GET /rcm/eligibility/v1/coverage-discovery/{id}
Use this page only for callback and polling implementation details.
Use Developer Onboarding for whitelisting prerequisites and delivery-model planning.
Use Getting Started for first API calls and general headers.
Use Troubleshooting and Support for production issue triage.
Most customers reach this workflow through integrated Real-Time Eligibility. Direct Coverage Discovery submission is also supported, but it is typically an advanced pattern.
If your team is still building callback or polling support, ask about the temporary batch-file option described in onboarding. Optum can sometimes provide a secure batch file containing x12-271 responses produced from Real-Time Eligibility and/or Coverage Discovery as a proof-of-concept stop-gap.
This guide explains:
- what is posted back to your system
- how callback authentication works
- how to tie a callback back to the originating Real-Time Eligibility or Coverage Discovery request
- how to interpret the different
CoverageDiscoveryTaskresult shapes - how tenant and subtenant context should be handled in callback processing
- how polling fits alongside callbacks
How Integrated Real-Time Eligibility Feeds Coverage Discovery
For most customers, the callback payload exists because a prior Real-Time Eligibility request triggered Coverage Discovery automatically.
Operationally, that means your callback handler should expect many discovery task ids to originate from the real-time response link header rather than from a direct POST /coverage-discovery request.
Coverage Discovery Response Model
The payload posted to your callback endpoint uses the same CoverageDiscoveryTask model returned by:
GET /rcm/eligibility/v1/coverage-discovery/{id}
That means your implementation can use a single parser for:
- callback payloads
- polled discovery responses
The Main Fields You Should Read First
For most integrations, start with these fields:
id
The Coverage Discovery task id. This is the primary identifier for the discovery record.status
The overall task status. Typical values arepending,success, orfailure.correlationId
Echoes the original request correlation when one was supplied. This is the easiest way to tie the discovery result back to your originating workflow.name
The configured discovery task name assigned for your enrolled workflow.startDateTimeandendDateTime
Show when the discovery task started and when it completed.realTime
Optional. Present when callback consolidation is enabled and the abbreviated parent Real-Time Eligibility result is included with the discovery record.discoveryPaths
The path-by-path discovery results. This is where you determine what happened during discovery.
How The Parent RTE Transaction Relates To CD Child Transactions
Coverage Discovery does not replace the original Real-Time Eligibility transaction. It extends it.
In an integrated flow:
- the parent Real-Time Eligibility request is what originally triggered discovery
- the parent Real-Time Eligibility response may be included in the callback under
realTimewhen consolidated callback delivery is enabled - each executed Coverage Discovery path can produce its own child eligibility transaction under
discoveryPaths.successful[*].transactionordiscoveryPaths.unsuccessful[*].transaction
Think of the relationship this way:
realTime.transaction
The abbreviated parent Real-Time Eligibility result that triggered or accompanied discoverydiscoveryPaths.*[].transaction
The related transaction details for individual discovery results
What The realTime Object Is For
realTime Object Is ForThe realTime object is optional and exists only for customers enrolled in consolidated callback delivery.
What it does:
- carries related Real-Time Eligibility context alongside the discovery task
- lets you correlate the discovery result back to the original real-time response without having to do a separate transaction lookup
- preserves related real-time transaction details when included
What it does not do:
- it does not replace the path-level discovery results
- it is not guaranteed to be present for every customer or every callback
Most customers focus on identifiers, statuses, and the parts of the payload they need for operations and audit.
Understanding discoveryPaths
discoveryPathsThe discoveryPaths object groups path outcomes into four arrays:
successful
Discovery paths that returned a successful coverage result.unsuccessful
Discovery paths that completed without a successful coverage result.pending
Discovery paths that have not completed yet.skipped
Discovery paths that were not executed.
Each path entry may contain:
id
The discovery path record idname
The path name associated with that record.timestamp
When that path reached its current recorded statereason
Present on skipped paths to explain why they did not executetransaction
Present when transaction details are available and may include:idstatuschcPayerIdx12-271
How To Read Root name Versus Path name
name Versus Path nameThere are two different naming levels in the Coverage Discovery response:
- root
name
Identifies the configured discovery task assigned for your tenant or subtenant. This is the enrolled workflow definition. discoveryPaths.*[].name
Identifies the specific discovery path that actually ran for that record.
Examples:
- a task root
namemight beMedicaid + HMO - another task root
namemight beCommercial + HMO + RTCOB
Common Result Shapes
You should expect several valid shapes of the same model:
- Success with one or more successful paths
The rootstatusissuccess, anddiscoveryPaths.successfulcontains one or more entries. - Failure with only unsuccessful paths
The rootstatusisfailure, anddiscoveryPaths.unsuccessfulcontains one or more entries. - Failure with only skipped paths
The rootstatuscan still befailureeven when no downstream path executed because all configured paths were skipped. - Mixed path outcomes
A successful task may still include bothsuccessfulandunsuccessfulpath entries. - Consolidated callback with
realTime
The callback contains related real-time eligibility context underrealTime, in addition to the discovery path results.
UserealTimeto review the related eligibility context anddiscoveryPaths.*[].transactionto review individual discovery result records.
Your parser should not assume:
- only one successful path
- only one unsuccessful path
- that
realTimeis always present - that
skippedmeans the overall task failed - that every path entry contains a
transaction - that the root task
statusalone is enough for all business decisions
How Customers Tie Results Back To The Original Request
There are two main correlation methods, and many customers use both.
1. correlationId
correlationIdIf you send x-optum-correlation-id on the originating request, that value is the easiest way to tie later records back to your own transaction in:
- callback headers as
x-optum-correlation-id - callback body as
correlationId - transaction search
- discovery search
Recommended practice:
- generate a unique correlation ID in your application
- store it with your internal encounter or request record
- use it as the primary join key when a callback arrives later
- for integrated Real-Time Eligibility, also store the related real-time transaction id and any returned discovery task ids from the
linkheader
2. Discovery Resource Path From Headers
You can also tie requests together using the returned discovery resource path.
When starting from Real-Time Eligibility
If you are enrolled in integrated Coverage Discovery and a Real-Time Eligibility request triggers discovery, the Real-Time Eligibility response may include a link header with one or more related discovery task resource paths.
Example pattern:
link: </coverage-discovery/0716e3e8-87ee-11ee-b9d1-0242ac120002>; title="coverage discovery - Task 1"; rel="related"
Use that related resource path to:
- store the discovery task id immediately
- poll
GET /rcm/eligibility/v1/coverage-discovery/{id} - match a later callback payload whose body
idis the same discovery task id
When starting from direct Coverage Discovery POST
If you submit POST /rcm/eligibility/v1/coverage-discovery directly, the initial asynchronous response returns a location header for the created task resource when a single task is created.
Example pattern:
location: /coverage-discovery/09876z5y-43x2-1w09-v8u7-tr6543s210qp
Use the location header to:
- store the discovery task id
- poll for status
- match the later callback body
id
Recommended Correlation Strategy
The most reliable production pattern is:
- Generate and send your own
x-optum-correlation-id - Store the returned discovery resource path:
linkheader when discovery was triggered from Real-Time Eligibilitylocationheader when you submitted direct Coverage Discovery POST
- When a callback arrives, match on:
correlationId- discovery task
id - optional parent
realTime.transaction.idwhen consolidated callback delivery is enabled - child discovery transaction ids under
discoveryPaths.*[].transaction.idwhen you need to reconcile individual result records - optional
x-optum-subtenant-idwhen applicable
Data Tenancy And Subtenant Handling In Callbacks
The callback guide needs the same tenancy rules that apply everywhere else in the API.
Tenant Context
Enhanced Eligibility is a multi-tenant platform. Your tenant is assigned automatically through your Marketplace credentials and is echoed back in request processing and callback delivery as:
x-optum-tenant-id
For callback consumers, this means:
x-optum-tenant-ididentifies the tenant context under which the original request was processed- your callback service should validate that this header matches the tenant you expect for that integration
- clients should not invent or derive tenant ids; the value is controlled by Optum
In practice, this header is a data-isolation control as well as a troubleshooting aid.
Subtenant Context
Some customers operate under one tenant but need different configuration for downstream customers, facilities, or workflows. In those cases, Optum may assign one or more subtenant ids that are carried on requests and echoed back on callback delivery as:
x-optum-subtenant-id
Important callback rules:
- this header is only present when the originating request used a configured subtenant
- you should treat it as part of the routing and correlation context for that callback
- you should not assume it is always present
- you should not generate or infer subtenant values yourself
Think of the headers this way:
x-optum-tenant-ididentifies your organizationx-optum-subtenant-ididentifies the downstream customer, facility, or workflow context within your organization when one was configured
If your implementation serves multiple downstream customers or facilities, storing both values alongside the callback payload is the safest way to preserve data-tenancy context for auditing and support.
Callback Delivery Flow
End-to-End Sequence
- Your system submits either:
- a Real-Time Eligibility request that may trigger integrated Coverage Discovery
- or a direct Coverage Discovery request
- Enhanced Eligibility accepts the work.
- If callback delivery is configured, Enhanced Eligibility authenticates to your token endpoint.
- Enhanced Eligibility POSTs the completed
CoverageDiscoveryTaskpayload to your whitelisted callback URL. - Your system returns
204 No Contentafter successfully accepting and processing the payload.
If you are not using callbacks, or if you want a fallback validation path, you can poll the discovery resource directly.
Callback Authentication
Customers must expose a token endpoint that adheres to RFC 6749. This token endpoint must be whitelisted by Optum and is used to obtain a bearer token before callback delivery.
Token Request
Endpoint:
POST https://your-auth-server.com/token
Headers:
Authorization: Basic <base64(client_id:client_secret)>
Content-Type: application/x-www-form-urlencoded
Body:
grant_type=client_credentials
Token Response
The token endpoint must respond with 200 OK and a JSON body like:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": ""
}
The expires_in field is required because it tells the caller when to request a new token.
Callback Request Headers
Once a token is obtained, the callback request includes:
Authorization: Bearer <access_token>x-optum-tenant-id: <your-tenant-id>x-optum-correlation-id: <correlation-id>when the originating request included onex-optum-subtenant-id: <subtenant-id>when the originating transaction includedx-optum-subtenant-id
Subtenant echo behavior:
- if the originating transaction included
x-optum-subtenant-id, the callback request will include that samex-optum-subtenant-id - if the originating transaction did not include
x-optum-subtenant-id, the callback request will not include it
Validation guidance:
- validate the bearer token before accepting the payload
- validate
x-optum-tenant-idagainst the expected tenant for that callback endpoint - when your implementation uses subtenants, validate and store
x-optum-subtenant-idas part of the callback’s routing context
What Your Callback Endpoint Must Return
- Return
204 No Contentwhen the callback was accepted and processed successfully. - Return
401 Unauthorizedif the bearer token is invalid or expired. - Make the endpoint idempotent because retries may deliver the same payload more than once.
Polling Flow
Polling is supported whether or not you also use callbacks.
When Polling Is Useful
- you do not want to expose a callback endpoint
- you want a fallback when callbacks are temporarily unavailable
- you want to inspect the task record before or after callback delivery
How To Poll
- Capture the discovery task id from either:
- the Real-Time Eligibility response
linkheader - the direct Coverage Discovery response
locationheader
- the Real-Time Eligibility response
- Call:
GET /rcm/eligibility/v1/coverage-discovery/{id}
- Continue polling until the root
statusis no longerpending
Polling returns the same CoverageDiscoveryTask model that callback delivery uses, so your application logic can be shared between both retrieval methods.
If you do not have the task id immediately available, you can also search discovery records using the list endpoint and your original correlationId, then retrieve the matching task by id.
Callback Payload Interpretation Guide
Use this reading order when a callback arrives:
- Validate auth headers and tenant context
- Read root
id - Read root
correlationId - Read root
status - Check whether
realTimeis present and whether you need the related real-time eligibility context - Inspect
discoveryPaths.successful - Inspect
discoveryPaths.unsuccessful - Read each nested child
transaction.status - Inspect
discoveryPaths.pending - Inspect
discoveryPaths.skipped
For many customers, the most important business outcomes are:
- Was any alternate coverage found?
- If no coverage was found, which paths were attempted?
- Was the parent real-time result included?
- Which child path transactions should be retained for audit or support?
- Did any returned statuses require follow-up under your operational workflow?
Refer to the Coverage Discovery model here for the full schema and example responses.
Note: We recommend downloading the OpenAPI specification and viewing it in an OpenAPI editor for the best experience. Download the spec here.
Retries
Automated Retries
Our system automatically performs exponential‑backoff retries whenever either the token request or callback delivery fails. Operations are retried up to 5 times, with increasing delays to accommodate transient outages and reduce downstream load.
| Retry | Minutes |
|---|---|
| 1 | 5 |
| 2 | 30 |
| 3 | 120 (2 hours) |
| 4 | 300 (5 hours) |
| 5 | 480 (8 hours) |
This prevents temporary issues (network delays, downstream downtime, intermittent service failures) from causing lost callbacks.
Ensure your callback API is idempotent, as retries may deliver the same payload more than once.
Manual Retries
We also support manual callback redrives:
- Retry a single record using its
correlationId - Retry by time range for bulk recovery
- Full queue redrive for all persisted failed messages (retained up to 14 days)
These tools give operations teams full control over recovery during outages or deployment issues.
Callback Testing
Use your preferred HTTP client or API tool to test your token endpoint and callback endpoint. This guide is the source of truth for callback headers, OAuth requirements, and CoverageDiscoveryTask payload interpretation.
Recommended tooling:
- Postman: Import data into Postman
- Insomnia: Import and export data
- OpenAPI Generator: GitHub repository and documentation
Recommended validation flow:
- Confirm your OAuth2 token endpoint returns
200 OKfor a valid client-credentials request. - Send a valid callback request to your whitelisted callback URL and confirm your endpoint returns
204 No Content. - Send a callback request with an invalid bearer token and confirm your endpoint returns
401 Unauthorized. - Verify that your callback implementation logs the incoming tenant, correlation, and task identifiers needed for support and audit.
Example Callback Requests
Use the examples below as copy-paste starting points when testing your callback endpoint. These examples preserve the CoverageDiscoveryTask field names used by the API model.
Standard callback example
POST /your-callback-path HTTP/1.1
Authorization: Bearer <valid_access_token>
x-optum-tenant-id: <your-tenant-id>
x-optum-correlation-id: 91d76432-ac2b-4ae2-b031-f8a6615a2df4
Content-Type: application/json
{
"id": "cd1505db-3cdf-4361-b515-52f86cd52a4c",
"status": "success",
"tenantName": "Customer Name",
"traceId": "4c22f47b-1cca-7f48-373c-af7d887443b0",
"correlationId": "91d76432-ac2b-4ae2-b031-f8a6615a2df4",
"name": "serial discover task",
"type": "serial",
"startDateTime": "2024-07-22T16:17:08Z",
"endDateTime": "2024-07-22T16:17:09Z",
"realTime": {},
"discoveryPaths": {
"pending": [],
"skipped": [],
"successful": [
{
"id": "239da46d-4c63-4365-a440-9f316bb0a069",
"name": "Commercial",
"timestamp": "2024-07-22T16:17:08Z",
"transaction": {
"id": "611c1f2c-4b0a-49df-918b-5d40c8d41fc9",
"chcPayerId": "AETNA",
"status": "eligible",
"x12-271": "ISA*...*271~"
}
}
],
"unsuccessful": []
}
}
Consolidated callback example with realTime
realTimePOST /your-callback-path HTTP/1.1
Authorization: Bearer <valid_access_token>
x-optum-tenant-id: <your-tenant-id>
x-optum-correlation-id: 91d76432-ac2b-4ae2-b031-f8a6615a2df4
Content-Type: application/json
{
"id": "cd1505db-3cdf-4361-b515-52f86cd52a4c",
"status": "success",
"tenantName": "Customer Name",
"traceId": "4c22f47b-1cca-7f48-373c-af7d887443b0",
"correlationId": "91d76432-ac2b-4ae2-b031-f8a6615a2df4",
"name": "serial discover task",
"type": "serial",
"startDateTime": "2024-07-22T16:17:08Z",
"endDateTime": "2024-07-22T16:17:09Z",
"realTime": {
"id": "ccf9a2c8-2e36-4c93-b0ec-743859e569cc",
"name": "Real Time",
"timestamp": "2024-07-22T16:17:08Z",
"transaction": {
"id": "611c1f2c-4b0a-49df-918b-5d40c8d41fc9",
"chcPayerId": "AETNA",
"status": "patient_unknown",
"x12-271": "ISA*...*271~"
}
},
"discoveryPaths": {
"pending": [],
"skipped": [
{
"id": "",
"name": "Commercial",
"reason": "request does not meet path conditions",
"timestamp": "2024-07-22T17:05:59Z"
}
],
"successful": [
{
"id": "18f36e9e-458b-417d-8222-6c57fdecf935",
"name": "Medicare",
"timestamp": "2024-07-22T17:05:58Z",
"transaction": {
"id": "5d26c880-aa58-4e8d-9f5a-d20e1369145d",
"chcPayerId": "CMSHSP",
"status": "eligible",
"x12-271": "ISA*...*271~"
}
}
],
"unsuccessful": []
}
}
Invalid-token test example
POST /your-callback-path HTTP/1.1
Authorization: Bearer INVALID_BEARER_TOKEN
x-optum-tenant-id: <your-tenant-id>
x-optum-correlation-id: 91d76432-ac2b-4ae2-b031-f8a6615a2df4
Content-Type: application/json
{
"id": "cb27966f-f2fc-4c53-936f-b5f6d6278069",
"status": "failure",
"tenantName": "Customer Name",
"traceId": "4c22f47b-1cca-7f48-373c-af7d887443b0",
"correlationId": "91d76432-ac2b-4ae2-b031-f8a6615a2df4",
"name": "serial discover task",
"type": "serial",
"startDateTime": "2024-07-22T17:05:40Z",
"endDateTime": "2024-07-22T17:05:41Z",
"discoveryPaths": {
"pending": [],
"skipped": [],
"successful": [],
"unsuccessful": [
{
"id": "aa3711a8-a5c5-4ab9-8f3a-07a58706e1aa",
"name": "Medicare",
"timestamp": "2024-07-22T17:05:40Z",
"transaction": {
"id": "23ab8447-0779-40ce-8171-2771015d9e46",
"chcPayerId": "CMSHSP",
"status": "processing_error"
}
}
]
}
}
When testing callback payloads:
- use the payload shapes documented earlier in this guide
- preserve the
CoverageDiscoveryTaskfield names exactly as they appear in the API model - test both standard callback payloads and consolidated callback payloads when
realTimeis part of your enrolled workflow - test optional
x-optum-subtenant-idhandling only when your integration uses subtenants
Need help? See Troubleshooting and Support
Looking for the homepage? Return to Enhanced Eligibility Overview here.
Updated 15 days ago