Skip to main content
For live updates without polling, subscribe to the submission’s channel — see the Realtime updates guide. Polling remains the reliable fallback and the way to reconcile state.

Status polling pattern

The typical polling flow looks like this:
1

Create submission

POST to create a submission and read the submissionId.
2

Poll status

GET the submission at regular intervals.
3

Check completion

When the submission is complete, partial, or failed, stop polling. queued and processing are both non-terminal — keep polling through them.
4

Retrieve results

Fetch each asset’s result and its issues or clustered topics.

Getting submission status

Use GET /api/submissions/{submission_id} — there is no /status suffix.
Response:
Per-asset failures are reported as flat fields — errorMessage, errorType, isRetryable, retryCount — not a nested error object. The terminal submission statuses are complete, partial, and failed. A queued status means every asset is accepted and waiting for a free review slot — it is non-terminal, so keep polling. Assets are admitted to review a few at a time, so don’t infer progress from the submission status alone: it reads processing as soon as the first asset starts and stays there until the last one settles. Read assets[].processingStatus to see which assets are still queued versus already compliant / in_review / failed. startedAt and completedAt report when work actually happened, so completedAt - startedAt is the real processing time. Both are per attempt: they sit at null while an asset waits in the queue, and a retry re-stamps startedAt and clears completedAt. completedAt is set for any terminal outcome, so on a failed asset it is the failure time rather than a success time. At the submission level, startedAt is the earliest asset start.

Polling strategy

Basic polling loop

Exponential backoff

For long-running submissions, start with short intervals and back off over time:

Retrieving results

Once an asset is done, fetch its result with GET /api/submissions/{submission_id}/assets/{asset_id}. The result includes the asset’s status, issueCount, and an issues array. For the flat enriched issue list call .../assets/{asset_id}/issues; for AI-clustered topics call .../assets/{asset_id}/topics.
Asset result shape:
Issue severity is one of CRITICAL | MAJOR | MINOR | INFO, and issue status is one of OPEN | ACKNOWLEDGED | AWAITING_HUMAN_INPUT | RESOLVED | DISMISSED. The clustered topics endpoint returns { "assetId", "topics", "orphanIssues", "metadata" }. Topics group two or more related issues; orphanIssues are unclustered singletons and are normal. The issues and topics endpoints return 404 if the asset has not finished processing yet.

Complete polling example

A full end-to-end example:

Polling recommendations

  • Start with a poll interval of a few seconds for fast feedback.
  • Back off over time to avoid hammering the API.
  • Use progressPercent to surface progress to your users.
  • Set a reasonable timeout to prevent infinite waits.
  • Prefer webhooks over tight polling for production volume.

Polling vs webhooks

For production systems with high volume, webhooks are recommended. See Webhook subscriptions.

Handling timeouts

If a submission does not finish within your timeout:
  1. Re-fetch the submission later — it may simply still be processing.
  2. Check the per-asset errorMessage, errorType, and isRetryable fields.
  3. Retry a failed, retryable asset with POST .../assets/{asset_id}/retry.
  4. Switch to webhooks for more reliable completion detection.