Sora jobs in flight at shutdown: reconcile, then resubmit to Sume

OpenAI's page gives the removal date but not in-flight jobs. Mark every unfinished Sora row, then resubmit its prompt to Sume with a key built from the old id.

5 min readSume
All posts

Treat every Sora row that never reached completed as lost, mark it, and resubmit its saved prompt to Sume once, using an Idempotency-Key built from the old Sora id so a re-run of your script cannot bill the same video twice. The deprecations page lists September 24, 2026 as the removal date for the Videos API and says nothing about what happens to jobs queued or running on that day, so do not assume any will finish.

I read OpenAI's deprecations page and video guide on 2026-10-08; neither describes in-flight handling or a grace period for downloads.

Classify the rows first

Before you spend anything, sort your table into the groups below. Only the first group needs new generation.

Row triage, facts from OpenAI's pages read 2026-10-08
Row state at shutdownWhat you knowAction
queued or in_progress, no file storedpage is silent on in-flight jobsresubmit the prompt to Sume
completed, file copied to your storagedownload URLs lived at most 1 hournothing to do
completed, only the Sora id storedthe id cannot be fetched after removalresubmit if the clip is still needed
failedno output was producedresubmit only if a person still wants it

The reconcile script

This reads a local SQLite table and resubmits each unfinished row. Keying on the old id means a crash halfway through is safe: the second run gets the first job back for rows already sent. Check your Sume balance first, since each submit reserves the list price times 1.25 from the workspace USD balance and answers 402 insufficient_credits when it is short.

import json, os, sqlite3, urllib.request

KEY = os.environ["SUME_API_KEY"]
db = sqlite3.connect("jobs.db")
db.execute("create table if not exists jobs (id text primary key, prompt text, status text, sume_id text)")

def submit(prompt, idem):
    req = urllib.request.Request(
        "https://api.sume.com/v1/videos", method="POST",
        data=json.dumps({"model": "sume/auto", "prompt": prompt}).encode(),
        headers={"Authorization": "Bearer " + KEY, "Content-Type": "application/json",
                 "Idempotency-Key": idem})
    return json.load(urllib.request.urlopen(req))["id"]

def main():
    rows = db.execute("select id, prompt from jobs "
                      "where status in ('queued', 'in_progress') and sume_id is null").fetchall()
    for old_id, prompt in rows:
        new_id = submit(prompt, "migrate-" + old_id)
        db.execute("update jobs set status = 'resubmitted', sume_id = ? where id = ?", (new_id, old_id))
        db.commit()
        print(old_id, "->", new_id)

main()

After the resubmit

The new clip will not be frame-identical to anything Sora would have produced, because you are on a different model. Tell whoever asked for it. If you also need to cap the spend, submit in waves and respect the plan queue; the Sume docs list concurrency, queue and accepted capacity per plan, from 1, 5 and 6 on Free to 20, 100 and 120 on Scale.

The shutdown runbook has the full six steps, and the post on what to store in place of Sora ids covers the column design.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume