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.

4 min readSume
All posts

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.

What expires_at tells you, read 2026-10-06 against Sume docs
expires_atMeaningAction
A timestampRun is not terminal yetKeep polling, or cancel
nullRun is terminalRead the result
Past, status failedForce-finalizedRead 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

All Formats posts

Written by Sume