Sume Format run expires_at: 90 minutes, and how to set your timeout
A non-terminal Sume Format run carries an expires_at, 90 minutes from creation. Use it as your client timeout instead of inventing a number.

Use the receipt's expires_at as your timeout and stop guessing. While a Format run is not terminal, its receipt carries the deadline after which Sume force-finalizes the run as failed. The deadline is 90 minutes after created_at, or earlier when a run is older than 25 minutes and has been silent for 10 (Sume docs: Format runs, read 2026-10-06).
Once the run is terminal, expires_at is null. So the field is itself a signal: a non-null value means the run can still change.
Why not pick your own number
A client timeout of five minutes will abandon healthy runs, and one of three hours will wait on a run Sume has already ended. Neither has any reason behind it. A run you abandon is not cancelled; it keeps spending until it finishes or you cancel it, so a client-side timeout without a cancel is how money leaks.
Read the status payload at status_url. It is the small poll body and carries status, next_action, cancelable, expires_at and timestamps. It never carries output or artifacts, so it is cheap to read often.
A loop that respects the deadline
The loop below polls the status, stops on a terminal status and cancels the run if your own budget runs out first. Cancel returns cancel_effect canceled when it worked, and no_op when the run had already finished.
import os, time, requests
from datetime import datetime
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
run_id = os.environ["RUN_ID"]
base = "https://api.sume.com/v1/format-runs/" + run_id
my_budget = time.time() + 20 * 60
while True:
s = requests.get(base + "/status", headers=H, timeout=30).json()["data"]
print(s["status"], s.get("expires_at"))
if s.get("expires_at") is None:
break
if time.time() > my_budget:
c = requests.post(base + "/cancel", headers=H, timeout=30)
print("cancel", c.status_code)
break
time.sleep(15)What happens after the deadline
A run force-finalized at the deadline ends as failed, and a failed run still publishes any partial result it wrote. Read the receipt before you retry: a half-finished episode might be recoverable by continuing the run with previous_run_id rather than starting from scratch.
For a bulk queue, each child has its own deadline, so one slow item does not hold the others to its clock. It does hold the queue open, though, because completed means nothing is left to run.
| expires_at | Meaning | Action |
|---|---|---|
| A timestamp | Run is not terminal yet | Keep polling, or cancel |
| null | Run is terminal | Read the result |
| Past, status failed | Force-finalized | Read the error, maybe continue |
Plan for the long tail
Most episodes finish well before the deadline, so build your alerting around the ones that do not. Flag any run past half its window, and decide in advance whether a flagged run is cancelled, continued or left alone.
Billing and abandoned runs
Walking away from a run does not stop it. Until the run is terminal it can keep consuming within its spend cap, and the cap is the real ceiling on what an abandoned run can cost. That is one more reason to set generation_spend_cap_usd on every call, since a bounded run that you forgot about is a small mistake and an unbounded one is not.
If you cancel, read cancel_effect in the answer. A value of canceled means you stopped it. A value of no_op means it had already finished, and the receipt is ready to read.
Sources
Related posts
More in Formats
- Sume output schema limits: depth 10, 5,000 properties, 120,000 chars
How big can a Sume output_schema be? Depth 10, 5,000 properties and 120,000 characters, and a refusal before any spend. What to flatten and where it fails.
- Sume webhook payload is null: receipt over 1 MiB, fetch result_url
A Sume format.run.terminal webhook with payload null means the receipt was over 1 MiB. Read error.result_url and fetch the receipt instead of failing the run.
- Why did my Format run do that? Read the first message of its thread
A Format run's first thread message is the text the agent received: Format pointer, your instruction, unattended note and input file path. Read it first.
- Ready-made Formats for product video: the Sume Format catalog
Sume ships ready-made Formats for product and UGC-style video and images, each callable from your backend with one HTTP request at the reserved sume handle.
Written by Sume