Concepts
Jobs
Every create call starts a job that moves from queued to running and ends as succeeded or failed. A create call waits up to 60 seconds for it by default, and any request can wait up to 300 seconds or poll the job until it's done.
The job object is the same everywhere: in create responses, from GET /v1/jobs/{id} and in webhooks.
The job object#
API responses wrap the job in { "job": ... }, and webhooks send the job object on its own.
| Field | Description |
|---|---|
idstring |
|
opstring | The endpoint that created the job. slideshowcaptionsshortsffmpeg |
statusstring | Where the job is. See Statuses. queuedrunningsucceededfailed |
stagestring or null | What a running short is doing. Always planningvoiceimagesrendering |
created_atstring | When the job was created, in ISO 8601 UTC. |
finished_atstring or null | When the job succeeded or failed. |
outputsobject | The finished files as URLs, keyed by name, such as |
resultobject or null | Shorts only: |
duration_snumber or null | Length of the main video in seconds. |
errorobject or null |
|
usageobject | What the job used. See Usage. |
poll_urlstring | The job's |
Statuses#
The HTTP status of every job response follows the job's status, so you can branch on either.
| status | HTTP | Meaning |
|---|---|---|
| queued | 202 | Accepted and waiting for a worker, or waiting for its automatic retry. |
| running | 202 | Rendering now. Shorts also report a stage. |
| succeeded | 200 | Done. outputs holds the files. |
| failed | 422 or 500 | Stopped for good. 422 means the inputs were the problem and 500 means we were. See Errors. |
A 202 also carries a Location header with the job's poll_url and Retry-After: 5. A failed job comes back as an error with the job next to it, in { "error": ..., "job": ... }.
{
"job": {
"id": "job_x5wepdaqkop4tepq05xp",
"op": "shorts",
"status": "queued",
"stage": null,
"created_at": "2026-10-26T01:15:26.166Z",
"finished_at": null,
"outputs": {},
"result": null,
"duration_s": null,
"error": null,
"usage": {
"output_seconds": 0,
"audio_seconds": 0,
"tts_characters": 0,
"images": 0
},
"poll_url": "https://api.reelsdk.com/v1/jobs/job_x5wepdaqkop4tepq05xp"
}
}Get a job#
GET /v1/jobs/{id} returns the job with the same status codes as the create call. It answers at once unless you ask it to wait, and an id that doesn't exist or belongs to another key returns 404 NOT_FOUND with unknown job.
curl -sS "https://api.reelsdk.com/v1/jobs/job_x5wepdaqkop4tepq05xp" \
-H "Authorization: Bearer $REELSDK_KEY"Waiting#
Any create call or GET /v1/jobs/{id} can hold the connection open until the job finishes. The response comes back the moment the job ends, so a long wait never slows down a fast job.
| Send | Effect |
|---|---|
?wait=N | Wait up to N seconds, from 0 to 300. Anything else returns 400 with wait must be 0..300 seconds. |
Prefer: wait=N | The same wait, sent as a header. Values above 300 count as 300. |
Prefer: respond-async | Return at once, like ?wait=0. |
| None of these | Create calls wait up to 60 seconds. GET /v1/jobs/{id} returns at once. |
When you send both, ?wait wins.
Polling#
When a job is still running after the wait, poll it. The simplest loop holds each GET open for up to 60 seconds, so a 100 second short needs only two or three calls. Plain polling works too: wait Retry-After seconds between calls. The curl loop uses jq to read the status.
JOB_ID="job_x5wepdaqkop4tepq05xp"
# We poll until the job leaves queued and running
while :; do
body=$(curl -sS "https://api.reelsdk.com/v1/jobs/$JOB_ID?wait=60" \
-H "Authorization: Bearer $REELSDK_KEY")
state=$(printf '%s' "$body" | jq -r ".job.status")
[ "$state" = queued ] || [ "$state" = running ] || break
done
printf '%s' "$body" | jq ".error // .job.outputs"- Stop as soon as the status is
succeededorfailed, which is also when the HTTP status stops being202. - Treat
queuedandrunningthe same, since a job can go back toqueuedfor its automatic retry. - If a create call fails with a network error, look the job up instead of sending the request again. A second
POSTstarts a second job.
Automatic retries#
When a job fails on our side, we put it back to queued and run it once more, 1 second later, or 10 seconds later when no worker was free. A short picks up from its last finished step. You only see a 500 after that retry also failed, except for TIMEOUT, which isn't retried.
Failures caused by the inputs, such as a URL that returns 404, fail at once with 422 and are never retried.
Usage#
usage reports what the job consumed. Values are 0 while the job runs.
| Field | Meaning |
|---|---|
| output_seconds | Length of the rendered video. For ffmpeg, the total length of every audio and video output. |
| audio_seconds | Seconds of audio we transcribed for captions. For shorts, the length of the voiceover. |
| tts_characters | Characters of text we turned into speech for a voiceover or a short. |
| images | Scene images drawn for a short. |
The files in outputs are deleted 7 days after the job finishes, so copy what you want to keep.
Last updated 26 October 2026