How long to poll a Format run: use expires_at, not your own timeout
A non-terminal Format run receipt carries expires_at, 90 minutes after created_at or earlier if the run goes silent. Set your poll ceiling from it and back off.

Poll a Format run until its status is terminal or until its expires_at, whichever comes first, and do not invent a timeout of your own. A non-terminal receipt carries expires_at: the deadline after which Sume force-finalizes the run as failed. It is 90 minutes from created_at, or earlier when the run is older than 25 minutes and has been silent for 10.
The rules for a correct loop
The Runs docs give three practices. Back off, because long-form video is 15 to 30 minutes of work and a poll each second gives nothing and uses read budget. Use expires_at as the ceiling. Read queue if the run stays queued.
- Start at 5 seconds and double the gap up to 60 seconds; the docs' own loop does exactly that.
- A
429or503during the loop is temporary. The run keeps executing and spending, so wait and poll again; do not mark it failed. - When the run is terminal,
expires_atisnull. - If
queue.stateisruntime_unavailable,retry_after_secondstells you how long to back off; if it lasts more than a few minutes, contact support with therequest_id.
Time arithmetic
With the 5-second start and the doubling rule, the waits are 5, 10, 20, 40, then 60 seconds each. The first five polls cover 5 + 10 + 20 + 40 + 60 = 135 seconds, and then you poll once a minute. A 90-minute run is 5,400 seconds, so after the first 135 seconds you would make about (5,400 - 135) / 60 = 87.75, so roughly 88 more reads. Reads have a separate budget that is forty times the write budget, so even a Free plan's 4,800 reads a minute is not near this.
| Phase | Waits | Reads |
|---|---|---|
| Ramp-up | 5, 10, 20, 40, 60 s | 5 reads in 135 s |
| Steady | 60 s each | about 88 reads in the remaining 5,265 s |
| Total | 90 minutes = 5,400 s | about 93 reads |
Better: poll the small endpoint, or take the webhook
status_url returns a small payload with status, next_action, cancelable and expires_at, and never the output. Use it for the loop, then read result_url once at the end. Or send communication.webhook_url and keep the poll as a backup for the day your endpoint is down. In TypeScript, subscribeFormatRun and waitForRun run this loop for you.
What the force-finalize looks like
When the deadline passes, Sume finalizes the run as failed. The artifacts the run already made stay on the receipt, and a failed run that left work can be continued with previous_run_id. So a timeout in your own code is a worse choice than waiting for Sume's: if you give up at 20 minutes, you may drop a run that would have finished at 25.
Use GET /v1/format-runs/{run_id}/events if you want to know whether a slow run is slow or stalled. It shows the phases preparing, running and finalizing, and the at of the last entry is the progress clock. If it has not moved for several minutes, the run is stalled, and Sume will finalize it at the bounds above. The endpoint is a phase timeline, not a log stream, and it will not show tool calls.
Sources
Related posts
More in Formats
- Format run media URLs never expire and anyone can open them
Media from a Sume Format run lives at durable media.sume.com URLs that anyone with the link can open. What that means for per-customer access and retention.
- Format run spend caps: $400 default, $500 maximum, and what null does
How Sume Format run spend caps work: the $400 platform default, a per-run generation_spend_cap_usd up to $500, null for $500, and 0 or above 500 as a 400.
- Format webhook: 10 s timeout, 10 attempts, about 3 h 5 min of retries
A slow Format webhook gets 10 tries. Without jitter, the last starts 11,010 s after the first; with 10 s timeouts the span is about 3 h 5 min. Code included.
- Restyle last year's holiday clip with the Sume restyle Format
Reuse a holiday video you own with a new look. The Sume restyle Format keeps motion and cuts and changes the style; it does not swap a person or product.
Written by Sume