How long can a Sume Format run take? The expires_at deadline

A Sume Format run is force-finalized as failed 90 minutes after it was created, or sooner if it goes silent. How to read expires_at and set your own timeout.

4 min readSume
All posts

A Sume Format run has a hard deadline: a run that is still not terminal is force-finalized as failed 90 minutes after created_at, or sooner when the run is older than 25 minutes and has been silent for 10. Every non-terminal receipt carries that deadline as expires_at.

The rules are from Runs and results, read 2026-09-29. The docs also say long-form video is 15 to 30 minutes of work, so the deadline is a ceiling, not an expected time.

Where do I read the deadline?

On the receipt from GET /v1/format-runs/{run_id} and on the smaller poll payload at status_url. It is null once the run is terminal. Set your own client timeout from expires_at rather than inventing a number.

That matters for job runners: if your worker gives up after ten minutes, the run keeps going and keeps spending. Give up only after expires_at has passed, or cancel the run explicitly with a key that carries formats:write.

From Runs and results, read 2026-09-29.
FieldWhat it tells you
expires_atThe deadline past which a non-terminal run is force-finalized as failed; null when terminal
queue.statewaiting while pickup is inside the normal window; runtime_unavailable once it has waited past it with nothing claiming it
queue.retry_after_secondsHow long to back off when queue.state is runtime_unavailable
queue.positionAlways null; Sume does not publish queue depth

How do I poll without wasting requests?

A fixed one-second poll wastes requests on a run that takes tens of minutes. Double the gap up to a minute. A 429 or 503 during the loop is transient: the run is still executing and still spending, so wait and poll again instead of treating it as failed. Stop on any status that is not queued or processing.

RUN_ID="arun_demo"
SLEEP=5
while :; do
  RUN=$(curl -sS "https://api.sume.com/v1/format-runs/$RUN_ID" \
    -H "Authorization: Bearer $SUME_API_KEY")
  STATUS=$(echo "$RUN" | jq -r '.data.status')
  case "$STATUS" in
    queued|processing) sleep "$SLEEP"; SLEEP=$(( SLEEP < 60 ? SLEEP * 2 : 60 )) ;;
    *) break ;;
  esac
done
echo "$RUN" | jq '{status: .data.status, error: .data.error}'

Why does my run stay queued?

Read queue. While queue.state is waiting, pickup is inside the normal window. Once it is runtime_unavailable, the run has waited past that window with nothing claiming it, and retry_after_seconds says how long to back off. The docs say a runtime_unavailable that lasts more than a few minutes is worth a support ticket with the request_id from the receipt.

What happens to spend if the run hits the deadline?

The run ends failed and artifacts[] still carries whatever was made. The docs say generation that finished before a cancel or a failure is billed, and a later step failing does not refund it; the run's usage reports the amount. For the cap side of the same question, see the spend cap post.

If you would rather not poll, register a communication.webhook_url on the create and take the one terminal webhook; see the lifecycle post.

Sources

Related posts

More in Formats

All Formats posts

Written by Sume