Crash-safe Sume submit: write the intent row and key first
If your process dies after a Sume submit but before storing the job id, a pre-written intent row and Idempotency-Key let the retry return the original job.

Store the intent and the idempotency key before you submit to Sume, then store the job id after. A crash between those two writes is then harmless: on restart you resend the same request with the same key and Sume returns the original job instead of billing a second one.
Why the order matters
The job id only exists after the response, so you cannot store it first. The key you can. The docs say a retried submit with the same Idempotency-Key returns the original job, and that you must not submit a new paid job for the same intent just because a local process timed out.
import asyncio, os, sqlite3, uuid
import httpx
async def main() -> None:
db = sqlite3.connect("jobs.db")
db.execute("create table if not exists jobs(key text primary key, job_id text)")
key = str(uuid.uuid4())
db.execute("insert into jobs(key) values (?)", (key,))
db.commit()
headers = {"x-api-key": os.environ["SUME_API_KEY"], "Idempotency-Key": key}
async with httpx.AsyncClient(base_url="https://api.sume.com", headers=headers) as c:
r = await c.post("/v1/image-1.0/generate",
json={"prompt": "matte black bottle", "mode": "async"})
r.raise_for_status()
job_id = r.json()["request_id"]
db.execute("update jobs set job_id=? where key=?", (job_id, key))
db.commit()
asyncio.run(main())On restart
Select rows with a key but no job id and resend each with its stored key. Reusing a key for the same payload is what the header is for; a different payload under the same key returns 409 idempotency_conflict, so store the payload or its hash with the row.
Related limit
A failed create releases its key, so a retry after a rejected request can proceed on the same key once you fix the request. Nothing is charged for a 4xx at create.
| Crash happens | State on restart | Recovery |
|---|---|---|
| Before the intent row | Nothing stored | Safe to start over |
| After row, before submit | Key, no job id | Submit with stored key |
| After submit, before job id saved | Key, no job id | Resubmit with stored key returns same job |
Sources
Related posts
More in Developers
- YouTube Analytics creatorContentType: split Shorts from long-form
The creatorContentType dimension separates SHORTS from VIDEO_ON_DEMAND in YouTube Analytics API reports. How to use it on clips you generated with Sume.
- YouTube captions.update costs 450 units: replace a caption track
captions.list costs 50, captions.update 450, captions.insert 400. Plan how many Sume-made caption files a 10,000-unit day can replace on your Shorts.
- YouTube Data API changes in 2026: a checklist for Shorts uploads
The 2026 YouTube Data API changes that touch Shorts uploads: own quota bucket, batchGetStats, 50 MB thumbnails, new view rule, and what to change.
- defaultLanguage vs defaultAudioLanguage on a dubbed AI Short
snippet.defaultLanguage is the language of title and description; defaultAudioLanguage is the spoken language. Set each on a dubbed or voiced Short.
Written by Sume