On September 24, 2026, OpenAI removed the Videos API and every Sora 2 model from its API. If your product called sora-2 or sora-2-pro, those requests no longer work, and OpenAI's deprecations page lists no recommended replacement. The shutdown means applications need a new video backend and a reviewed request flow.
This guide covers what shut down, how to pick a new model for each kind of work you ran on Sora, and what the migration looks like in code.
What exactly shut down
OpenAI notified developers on March 24, 2026. On September 24, 2026, it removed:
- the Videos API
sora-2andsora-2-pro- the dated snapshots
sora-2-2025-10-06,sora-2-2025-12-08andsora-2-pro-2025-10-06
OpenAI's API deprecations page confirms the date, affected aliases and absence of a recommended replacement. This guide concerns the developer API; account exports and consumer app availability are separate.
Pick the replacement by workload, not by leaderboard
No single video model is best at everything. So the useful question isn't "what's the best Sora alternative?" but "what was I actually using Sora for?"
| What you used Sora for | Where to start | Why |
|---|---|---|
| Turning a written scene into a clip with sound | Veo 3.1 Fast | Text to video, built around atmosphere, camera movement and sound |
| Animating an existing image (product shot, key visual, character) | Kling 3 Pro | Image to video (plus text to video): keeps a strong still frame and adds directed motion |
| Short atmospheric or looping clips from a description | Seedance 2.5 | Text to video, with subject, action and mood set in the prompt |
Two caveats. First, clip length, resolution and reference-image limits change often, so read each model's current input schema instead of trusting a blog table (including this one). Second, the only reliable test is your own prompt. Run the same shot on two or three models before you commit.
What migration looks like in code
Alternative platforms have their own request bodies and job lifecycle. Check both contracts before treating migration as a base-URL change. Plan to rewrite two things: how you build the request and how you wait for the result.
On Raywake every generation follows the same three steps, whatever the model:
- Quote: price the exact model and input. Nothing is charged.
- Generate: submit the same input with the
quote_idand anIdempotency-Key. - Job: read the status and output link (or wait inline with
?wait=true).
import os, time, uuid, requests
API = "https://api.raywake.com/v1"
H = {"Authorization": f"Bearer {os.environ['RAYWAKE_API_KEY']}"}
# Get the exact model ID and input schema from:
# GET /v1/models?category=text-to-video (or image-to-video)
model = "veo3.1/fast"
inp = {"prompt": "A jaguar slowly turns toward the camera in a lush jungle. Soft daylight, steady close camera."}
# 1. Price it first. Free.
payload = {"model": model, "input": inp}
response = requests.post(f"{API}/quotes", headers=H, json=payload, timeout=30)
response.raise_for_status()
quote = response.json()
print("Credits to reserve:", quote["credits"])
# 2. Start it. One idempotency key per intended job.
key = str(uuid.uuid4())
response = requests.post(f"{API}/generate", params={"wait": "true"},
headers={**H, "Idempotency-Key": key},
json={**payload, "quote_id": quote["quote_id"]}, timeout=200)
response.raise_for_status()
job = response.json()
# 3. Poll if it's still running (every 2-5 seconds).
TERMINAL = {"succeeded", "failed", "submission_unknown", "needs_review", "needs_reconciliation"}
for _ in range(120):
if job["status"] in TERMINAL:
break
time.sleep(5)
response = requests.get(f"{API}/jobs/{job['job_id']}", headers=H, timeout=30)
response.raise_for_status()
job = response.json()
else:
raise TimeoutError(f"Continue polling job {job['job_id']}; do not submit a replacement")
if job["status"] == "succeeded":
print(job["outputs"][0]["url"]) # signed for 7 days, download it
else:
print(job["status"], job.get("error")) # don't auto-resubmit
This example starts a paid generation when you run it with a funded key. Install requests, create a key with generate and jobs:read, and persist the payload, idempotency key and returned job ID in your application. If submission times out, reuse that saved key and body; restarting the script creates a new key.
Switching from Veo 3.1 Fast to Kling 3 Pro is a change of the model string and its input fields. The key, the balance and the flow stay the same.
Four things that bite during a migration
- Not every "done" is a success. Besides
succeededandfailed, a job can end assubmission_unknown,needs_revieworneeds_reconciliation. Credits stay held in those cases, so don't submit a replacement job automatically. - A timeout isn't a failure. Video jobs take time. If a request times out, retry with the same
Idempotency-Key, never a new one, so you don't pay twice. - Price before you run. Video is the expensive part of any creative pipeline. A quote gives you the credit amount to reserve before anything starts; usage-billed models settle within that upper bound, and a failed generation releases its reserved credits.
- Download what you keep. Generated media is stored for 30 days and signed links expire. Copy outputs to your own storage.
A migration checklist
- Inventory your stored outputs and make sure important clips are in storage you control.
- List every place your code calls the Videos API, including background jobs and retries.
- Group those calls by workload: text to video, image to video, short loops.
- Run the same 3–5 real prompts on two or three candidate models and compare output and cost.
- Rewrite request building and polling. Add idempotency keys to every submit.
- Move output storage off temporary links.
Build a small migration test
Use one prompt that represents your real workload, rather than a dramatic scene selected for a showcase. Keep the aspect ratio, intended clip length and evaluation criteria fixed. Record the input, model ID, quote, job status and final output together so a later catalog change can be traced.
For a product shot, review whether the object stays the same through the last frame. For a speaking scene, review audio and visual timing. For a background loop, check the join between the final and first frames. A clip that looks attractive but misses the requirement is still a failed migration test.
Changing models may mean changing supported settings or rewriting the prompt. Keep a model-specific input adapter behind your application's common job interface. That lets your product present the same progress and download behavior while each adapter builds a request that its selected model actually accepts.
For image-led workloads, follow our image-to-video walkthrough. For retries and credit settlement, see AI video API costs.
Try it
Available models run in the Raywake studio and through the API on one balance, so you can test a prompt by hand in the studio and then call the same model from code.
Try video in the studio Read the API quickstart