Polling
Poll GET /eligibility-result until the task reaches a terminal status. The response you are polling is the result.
GET /eligibility-result/{task_id}Use GET /eligibility-result/{task_id} to retrieve task progress and results.
It reports the task's current state while the check runs, and returns the
parsed result once the check is done, so the poll and the read are the same
request and an integration needs only two endpoints.
If your existing code uses task-status, see
the comparison at the bottom of this page.
When to stop
Stop when status is one of three values:
status | Meaning |
|---|---|
PROCESS_COMPLETE | Finished. The body you are holding is the result. |
CANCELLED | Stopped before finishing. |
FAILED | The task failed. Inspect eligibility_result for details. |
Anything else means the task is still running. Today those values are
IN_QUEUE, NAVIGATING_WEBSITE and EXTRACTING_DATA.
Most of the wait is spent in NAVIGATING_WEBSITE
A task enters this state as soon as the check starts and stays there for the whole exchange with the payer. Expect it on almost every poll, and do not read a long stretch of it as a stall.
EXTRACTING_DATA is not a stage every task passes through
It appears once there is a payer page to parse. A check that ends before that, because the login
was rejected or the payer was never reached, goes straight from NAVIGATING_WEBSITE to a terminal
status. Stop on the terminal statuses above, never on having seen a particular in-flight one.
Test for the terminal three, not against the in-flight ones
Write ["PROCESS_COMPLETE", "CANCELLED", "FAILED"].includes(status), not
status !== "IN_QUEUE" && …. The set of in-flight statuses can grow; the
terminal set has been stable. With an allowlist, a status you have never seen
makes your client keep waiting, which is correct, instead of making it read a
result that is not there.
CHECKING_ELIGIBILITY shows why this matters in both directions. It is defined
in the status enum and appears in older integration notes, but it is never
emitted. Do not build a state machine that waits for it.
PROCESS_COMPLETE does not mean eligible
It means the task is over. The member may not have been found, the portal credentials may have
been rejected, or the policy may have lapsed. The answer is eligibility_result.status plus
eligibility_result.data_dump.data.is_eligible; see Results.
Response
Prop
Type
Sample not captured yet
eligibility-result/processing will be filled in once the sample capture pass has run against a completed production task.Sample not captured yet
eligibility-result/eligible will be filled in once the sample capture pass has run against a completed production task.While the task is in flight, eligibility_result is absent. Once it appears,
the task is done or nearly so, and its data_dump is the full result.
Interim results
Partway through a check the payer's response and any accompanying documents
are available, but parsing is not finished. At that point this endpoint starts
returning an interim_results block.
Prop
Type
Sample not captured yet
eligibility-result/processing-interim at interim_results will be filled in once the sample capture pass has run against a completed production task.Use it to show the user the portal screenshot while the parse finishes. It is not a substitute for the result: the parsed coverage, copay and network data only exist once the task is complete.
interim_results is null on a task that has not reached that stage, and it
is absent entirely on search-all tasks.
interim_results is only on this endpoint
task-status never returns it, so an integration polling that endpoint has to call this one as
well to show anything before the check finishes.
Search all
A search-all task carries a different envelope: no eligibility_result, an
aggregated_results array instead.
Prop
Type
Each entry in aggregated_results is one payer's answer:
Prop
Type
Sample not captured yet
eligibility-result/search-all-processing will be filled in once the sample capture pass has run against a completed production task.Sample not captured yet
eligibility-result/search-all-complete will be filled in once the sample capture pass has run against a completed production task.Stop when search_all_status is SEARCH_ALL_COMPLETE, or when the top-level
status is CANCELLED or FAILED. Then pick the winning payer as described
in Results.
total_tpas_checked counts answers, not attempts
It is the length of aggregated_results: the payers that have responded so far. It is not the
number of payers queried, and it does not tell you how many are still outstanding. Use
search_all_status to decide when to stop.
How completion is decided
A search-all is reported complete when any of the following holds:
- 17 payers have responded. This threshold is fixed and is lower than the number of payers queried for most organisations.
- Every payer that has responded found the member.
- A single aggregator has responded and the check that dispatched it has finished or returned an error.
Otherwise the check is still processing.
Completion does not guarantee a response from every payer
Because the threshold is fixed at 17, a search-all can be reported complete while other payers are
still working. Treat aggregated_results as the record of which payers actually responded, and
handle the returned results as potentially incomplete. If a specific payer matters to your
workflow, check it directly with a single-payer task rather than relying on search-all.
Recommended loop
- Poll every 5 seconds. Faster does not make the payer portal answer sooner.
- Set a polling timeout of 5 minutes for a single payer, 10 minutes for search-all. Both are recommended starting points, not guarantees; confirm them before you build a hard timeout.
- On a 5xx, retry the poll rather than recreating the task. Creating a second task runs a second real check at the payer.
- A task id stays valid after your timeout. Surface it as "still checking", keep the id, and poll again later.
Polling at this interval is inexpensive, and polling eligibility-result costs
no more than polling task-status.
Why not task-status
GET /task-status/{task_id} is supported and documented in
Endpoints. It returns a subset of what
eligibility-result returns, which is why these docs poll the latter.
eligibility-result (poll this) | task-status | |
|---|---|---|
| Parsed result | eligibility_result.data_dump | eligibility_result.data, the same object |
interim_results | returned | never returned |
| Document and screenshot links | re-signed on every read | returned as stored, and may have expired |
| Terminal status | PROCESS_COMPLETE | COMPLETE |
| In-flight status | the specific lifecycle state | reported as PROCESSING |
| Search-all completion | reported at 17 responses | requires 22 responses |
| Search-all payer list | omits responses missing an internal key | includes them |
Three differences drive the recommendation:
interim_results is available only here. Anything you display before the
check finishes comes from this endpoint.
Document links are re-signed on every read. task-status returns links as
they were stored, so on an older task they may already have expired.
Search-all completion is reported reliably. task-status requires 22
responses before it reports a search-all complete, and around 19 payers are
queried, so its search_all_status can remain SEARCH_ALL_PROCESSING
indefinitely. eligibility-result uses a threshold of 17, which is reached.
The two completion thresholds are under review
17 and 22 are two different values for the same quantity, and neither matches the number of payers
actually queried. Both are documented here as current behaviour. Until they are reconciled, read
aggregated_results for the record of which payers responded rather than inferring it from either
threshold.
task-status does offer a smaller status vocabulary: four values instead of
seven. If you would rather branch on PROCESSING versus not, it is available.
Do not mix the two endpoints in one client: the same finished task is
COMPLETE on one and PROCESS_COMPLETE on the other.