Skip to main content
Instead of polling, you can subscribe to a submission’s realtime channel and receive status events as they happen. Processing runs one review per asset, and every event for a submission — per-asset progress and the overall outcome — is published to a single channel: submission:{submissionId}. Realtime uses Ably. You never hold an Ably key: you request a short-lived, subscribe-only token from the API and hand it to the Ably client.
Realtime is a convenience layer on top of the REST API, not a replacement for it. Events are best-effort and are not replayed to late or reconnecting subscribers, so treat GET /api/submissions/{submission_id} as the source of truth and use it to reconcile state. See Reliability.

What you need

1

The channel id

POST /api/submissions returns ablyChannel (e.g. submission:550e8400-...). It is always submission:{submissionId}.
2

A subscription token

Call the token endpoint below to get an Ably token scoped to that one channel.
3

An Ably client

Use an Ably SDK, pointing its auth at the token endpoint so it can refresh automatically.

Get a subscription token

POST /api/submissions/{submission_id}/realtime-token Returns an Ably token request granting subscribe only on submission:{submissionId} — nothing else. The submission must belong to your API key’s workspace.
The response is an Ably token request — relay it verbatim to the Ably client:
A 404 is returned if the submission does not exist in your workspace. A 503 is returned if realtime is not enabled for the deployment — fall back to polling. See Create realtime token for the full endpoint reference.

Connect and subscribe

Point the Ably client’s authCallback at the token endpoint. The SDK calls it on connect and again whenever the token nears expiry, so refresh is automatic.

Status events

Status updates arrive as the workflow_update event. Each message payload has the same envelope:
Realtime payload keys are snake_case (asset_id, asset_count), unlike the REST API, which is camelCase. Read fields off the event payload, not off the REST schema.
The status field tells you what happened: COMPLETED, PARTIAL, and FAILED are terminal — after one of them, no further status events fire (unless you retry a failed asset, which re-activates processing on the same channel). The per-asset status on ASSET_COMPLETED is the asset’s compliance result: compliant (no issues) or in_review (issues found).

Preview events

Alongside status, the channel also emits asset_preview_ready when an asset’s rendered preview becomes available:
This is best-effort and only useful if you display asset previews — otherwise ignore it. Subscribe to it explicitly (channel.subscribe('asset_preview_ready', ...)) or subscribe without an event name to receive every event on the channel.

Reliability

Events are delivered best-effort and are not replayed. The subscribe-only token grants no message history, so an event published before you connect (or while you were disconnected) is missed.
  • Reconcile with the REST API. After connecting, and on reconnect, call GET /api/submissions/{submission_id} to get the authoritative current state. A submission that reached a terminal state before you subscribed will not re-emit — read it from the status endpoint.
  • Tokens are short-lived. The default lifetime is one hour. Using an authCallback (above) lets the Ably SDK refresh transparently; a token cannot be reused after it expires.
  • One channel per submission. All per-asset workflows publish to the same submission:{submissionId} channel, so a single subscription covers the whole submission.

See also