Which Sume Format run receipt fields to store in your database
Store id, format, status, created_at, finished_at, model, usage.debited_usd_micros, output and artifacts. Fetch the rest, because URLs and expires_at change.

Keep the run id, the Format identity, status, the three timestamps, model, the cost in usage.debited_usd_micros, and the output and artifacts you show to users. Do not store the poll URLs or expires_at as facts, because those describe the live run.
A receipt is large, and most of it is useful only while the run is in flight.
Columns worth having
Field names are from the Runs and results page (read 2026-10-03).
| Field | Store? | Why |
|---|---|---|
| id | Yes | Primary key; webhooks carry it as request_id |
| format.id, format.slug, format.version | Yes | Which Format version produced the output |
| status | Yes | completed, failed, canceled or skipped once terminal |
| created_at, started_at, finished_at | Yes | Latency and ordering |
| model | Yes | The orchestrator id that actually ran |
| usage.debited_usd_micros | Yes | The real cost of the run |
| output, output_error, artifacts | Yes | What the user gets; copy media you must keep |
| status_url, result_url, events_url, cancel_url | No | Derivable from id |
| expires_at, next_action, cancelable | No | Only true while the run is live |
Two traps
usage is null when spend could not be read, which is different from zero, so store null as null. Older receipts also leave the wallet fields null. See the cost helper for totalling.
Media URLs on media.sume.com are durable but public to anyone holding the URL. If you show them to your own customers, copy the file or proxy it.
import json, sqlite3
db = sqlite3.connect("runs.db")
db.execute("create table if not exists runs(id text primary key,"
" fmt text, status text, model text, micros integer, body text)")
def save(run):
u = run.get("usage") or {}
db.execute("insert or replace into runs values(?,?,?,?,?,?)",
(run["id"], run["format"]["slug"], run["status"],
run.get("model"), u.get("debited_usd_micros"),
json.dumps({"output": run.get("output"),
"artifacts": run.get("artifacts")})))
db.commit()
save({"id": "run_1", "format": {"slug": "teaser"}, "status": "completed",
"model": "gpt-6-sol", "usage": None, "output": {}, "artifacts": []})Keep the raw receipt too
If storage is cheap, keep the terminal receipt as JSON next to the columns. Fields are added over time, and a raw copy lets you backfill without calling the API for runs that may have aged out.
Sources
Related posts
More in Formats
- Shorts ad copy: 40-character headline, 90-character description
Google recommends 40-character headlines and 90-character descriptions for the Shorts ad CTA card. Draft copy in bulk with Sume and check lengths before upload.
- 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.
- What is a Sume Format? Turn an agent thread into one API call
A Sume Format is a saved video recipe your backend calls by handle and slug. One POST runs it in a fresh sandbox and returns media plus optional typed JSON.
- How to embed AI video generation in your product with Sume Formats
To embed AI video generation, your server holds one Sume API key and runs a Format per customer, with a derived Idempotency-Key, spend cap, and webhook.
Written by Sume