Jobs
Track the status of any asynchronous job by its render_uuid. One endpoint covers render, video, and upload jobs, with the result, credits charged, and pay-as-you-go cost.
/api/v1/jobs/{render_uuid}When you submit work asynchronously (see Async Rendering) or request a video, you receive a render_uuid. Use this endpoint to read that job's current state, and once it succeeds, to retrieve the result. Polling a job is free.
Request
Path Parameters
render_uuidstringRequiredThe job identifier returned from the 202 Accepted response of an async render, an async upload, or a video request.
Headers
x-api-keystringYour SudoMock API key starting with sm_. Required unless using Bearer token authentication.
AuthorizationstringAlternative to x-api-key. Use Bearer <JWT> with a JWT from your dashboard login.
Status State Machine
Every job moves forward through a fixed set of states. The first three are in-progress; the last three are terminal. Once a job reaches a terminal state it never changes again.
| Status | Terminal | Meaning |
|---|---|---|
| queued | No | Accepted and waiting for a worker. |
| dispatched | No | Handed to a worker, about to start. |
| running | No | Actively being processed. |
| succeeded | Yes | Finished. result_url (render/video) or mockup_uuid (upload) is populated. |
| failed | Yes | Could not complete. error explains why. No credits charged. |
| cancelled | Yes | Stopped before completion. No credits charged. |
Poll until terminal
queued, dispatched, or running. Stop as soon as it becomes succeeded, failed, or cancelled.Response
In progress
1{2 "render_uuid": "9d4e2b51-0c7a-4f8e-bb1c-2a6f9e3d8c10",3 "kind": "render",4 "status": "running",5 "model": null,6 "result_url": null,7 "mockup_uuid": null,8 "error": null,9 "credits_charged": null,10 "payg": null,11 "created_at": "2026-06-22T10:00:00Z",12 "updated_at": "2026-06-22T10:00:03Z"13}
result_url vs mockup_uuid
The result lives in a different field per kind
render or video job exposes the output in result_url and leaves mockup_uuid null. A succeeded upload job puts the new mockup's UUID in mockup_uuid, while result_url holds a /library/mockups/{mockup_uuid} deep-link to that mockup. Branch on kind before reading the result.| kind | Read the result from | Other field |
|---|---|---|
| render | result_url | mockup_uuid is null |
| video | result_url | mockup_uuid is null |
| upload | mockup_uuid | result_url is a /library/mockups/{...} link |
1{2 "render_uuid": "9d4e2b51-0c7a-4f8e-bb1c-2a6f9e3d8c10",3 "kind": "render",4 "status": "succeeded",5 "model": null,6 "result_url": "https://cdn.sudomock.com/renders/9d4e2b51.webp",7 "mockup_uuid": null,8 "error": null,9 "credits_charged": 1,10 "payg": null,11 "created_at": "2026-06-22T10:00:00Z",12 "updated_at": "2026-06-22T10:00:06Z"13}
1{2 "render_uuid": "1f0a8c23-7b44-4e90-9c2d-55ab1e7f0d33",3 "kind": "upload",4 "status": "succeeded",5 "model": null,6 "result_url": "/library/mockups/c315f78f-d2c7-4541-b240-a9372842de94",7 "mockup_uuid": "c315f78f-d2c7-4541-b240-a9372842de94",8 "error": null,9 "credits_charged": 0,10 "payg": null,11 "created_at": "2026-06-22T10:01:00Z",12 "updated_at": "2026-06-22T10:01:12Z"13}
Failed
A failed job stays at 200OK at the HTTP level (the lookup succeeded), with status set to failed and a human-readable error. Failed jobs are not charged.
1{2 "render_uuid": "9d4e2b51-0c7a-4f8e-bb1c-2a6f9e3d8c10",3 "kind": "render",4 "status": "failed",5 "model": null,6 "result_url": null,7 "mockup_uuid": null,8 "error": "Image source for 'Front Design' returned HTTP 404.",9 "credits_charged": 0,10 "payg": null,11 "created_at": "2026-06-22T10:00:00Z",12 "updated_at": "2026-06-22T10:00:04Z"13}
Response Fields
render_uuidstringRequiredThe job identifier you polled.
kindstringRequiredOne of "render", "video", or "upload". Determines which result field is populated.
statusstringRequiredCurrent state: queued, dispatched, running, succeeded, failed, or cancelled.
modelstringThe identifier of the model the job ran at (for example, veo-3.1-fast) for video jobs. Null for render and upload jobs, and while a video job is still in progress.
result_urlstringThe output to fetch. For render and video jobs, a CDN URL of the rendered file. For upload jobs, a /library/mockups/{mockup_uuid} deep-link to the created mockup. Null while in progress.
mockup_uuidstringUUID of the created mockup. Populated on success for upload jobs; null for render and video jobs.
credits_chargedintegerCredits deducted for this job. Only charged on success; failed and cancelled jobs charge 0.
paygobjectPresent when the job was billed through pay-as-you-go. Contains credits, unit_price, and cost.
payg.creditsintegerNumber of credits billed via pay-as-you-go for this job.
payg.unit_pricenumberPrice per credit applied to this job, in USD.
payg.costnumberTotal pay-as-you-go cost for this job, in USD (credits x unit_price).
errorstringHuman-readable failure reason. Null unless the job failed.
created_atstringISO 8601 timestamp when the job was accepted.
updated_atstringISO 8601 timestamp of the latest state change.
Pay-as-you-go cost
When a job is billed through pay-as-you-go, the response includes a payg object so you can reconcile spend per job without a separate billing call.
1{2 "render_uuid": "9d4e2b51-0c7a-4f8e-bb1c-2a6f9e3d8c10",3 "kind": "video",4 "status": "succeeded",5 "model": "veo-3.1-fast",6 "result_url": "https://cdn.sudomock.com/videos/9d4e2b51.mp4",7 "mockup_uuid": null,8 "error": null,9 "credits_charged": 949,10 "payg": {11 "credits": 949,12 "unit_price": 0.002,13 "cost": 1.89814 },15 "created_at": "2026-06-22T10:05:00Z",16 "updated_at": "2026-06-22T10:05:48Z"17}
List jobs
/api/v1/jobsRetrieve your async jobs as a list, newest first. The list is owner-scoped (you only ever see your own jobs) and paginated. Each item carries the same fields as a single-job lookup, so you can render a history view without polling each job one by one. Listing is free.
Query Parameters
kindstringFilter by job kind: "video", "render", or "upload". Omit to list every kind.
limitinteger= 20How many jobs to return per page (1 to 50).
cursorstringOpaque keyset cursor from a previous response's next_cursor. Omit on the first page. This is a keyset token, not a numeric offset, so do not build or parse it yourself.
Response
The response is an envelope with a jobs array ordered by created_at descending, plus a next_cursor. Each job item mirrors the single-job response fields and adds four video display fields (duration_seconds, audio, mockup_name, poster_url), populated for video jobs and null otherwise, so you can build a gallery without a second call.
1{2 "jobs": [3 {4 "render_uuid": "9d4e2b51-0c7a-4f8e-bb1c-2a6f9e3d8c10",5 "kind": "video",6 "status": "succeeded",7 "model": "veo-3.1-fast",8 "result_url": "https://cdn.sudomock.com/videos/9d4e2b51.mp4",9 "mockup_uuid": null,10 "error": null,11 "credits_charged": 949,12 "payg": null,13 "created_at": "2026-06-22T10:05:48Z",14 "updated_at": "2026-06-22T10:06:31Z",15 "duration_seconds": 4,16 "audio": false,17 "mockup_name": "Jacket Back",18 "poster_url": "https://cdn.sudomock.com/videos/9d4e2b51_poster.webp"19 },20 {21 "render_uuid": "1f0a8c23-7b44-4e90-9c2d-55ab1e7f0d33",22 "kind": "video",23 "status": "running",24 "model": "veo-3.1-fast",25 "result_url": null,26 "mockup_uuid": null,27 "error": null,28 "credits_charged": null,29 "payg": null,30 "created_at": "2026-06-22T10:04:10Z",31 "updated_at": "2026-06-22T10:04:13Z",32 "duration_seconds": 4,33 "audio": false,34 "mockup_name": "Tote Front",35 "poster_url": null36 }37 ],38 "next_cursor": "MjAyNi0wNi0yMlQxMDowNDoxMFp8MWYwYThjMjMtN2I0NC00ZTkwLTljMmQtNTVhYjFlN2YwZDMz"39}
Keyset pagination
Pages are walked with a keyset cursor. Make the first request without cursor, then pass the next_cursor from each response back as the cursor of the next request. When next_cursor comes back null, you have reached the last page. Treat the cursor as opaque: it encodes the keyset position, not a row number, so it stays stable even as new jobs are created at the top of the list.
Empty result
1{2 "jobs": [],3 "next_cursor": null4}
Item Fields
Every item carries the same fields as a single-job lookup (render_uuid, kind, status, model, result_url, mockup_uuid, error, credits_charged, payg, created_at, updated_at). List items add the four video display fields below; they are null for non-video jobs.
duration_secondsintegerLength of the clip in seconds. Null for non-video jobs.
audiobooleanWhether the clip includes an audio track. Null for non-video jobs.
mockup_namestringDisplay name of the source mockup, for labelling a list row. Null when unavailable (for example, a raw-image video or an upload).
poster_urlstringCDN URL of a still frame to use as a thumbnail. Populated on success for video jobs; null while in progress and for non-video jobs.
Listing example
1# First page (most recent first)2curl "https://api.sudomock.com/api/v1/jobs?kind=video&limit=20" \3 -H "x-api-key: sm_your_api_key"45# Next page: pass the next_cursor from the previous response6curl "https://api.sudomock.com/api/v1/jobs?kind=video&limit=20&cursor=MjAyNi0wNi0yMlQxMDowNDoxMFp8MWYwYThjMjMtN2I0NC00ZTkwLTljMmQtNTVhYjFlN2YwZDMz" \7 -H "x-api-key: sm_your_api_key"
One job vs many
Polling & backoff
Poll on an interval with a capped backoff. Start around 1.5s, grow the gap, and cap it (for example at 8s) so a long job does not waste requests. Always stop at a terminal status.
1const BASE_URL = "https://api.sudomock.com/api/v1";2const headers = { "x-api-key": "sm_your_api_key" };34// Poll a job with capped exponential backoff.5async function pollJob(renderUuid, { maxMs = 120000 } = {}) {6 const deadline = Date.now() + maxMs;7 let delay = 1500;8 while (Date.now() < deadline) {9 const res = await fetch(`${BASE_URL}/jobs/${renderUuid}`, { headers });10 const job = await res.json();1112 if (job.status === "succeeded") {13 // result_url for render/video, mockup_uuid for upload.14 return job.kind === "upload" ? job.mockup_uuid : job.result_url;15 }16 if (job.status === "failed" || job.status === "cancelled") {17 throw new Error(`Job ${job.status}: ${job.error ?? "unknown"}`);18 }1920 await new Promise(r => setTimeout(r, delay));21 delay = Math.min(delay * 1.5, 8000); // cap at 8s22 }23 throw new Error("Polling timed out");24}
Prefer webhooks over tight polling
Errors
Missing or invalid API key or Bearer token.
1{2 "detail": "Not authenticated",3 "success": false4}
No job exists for that render_uuid, or it does not belong to your account.
1{2 "detail": "Job not found",3 "success": false4}
SDKs cover jobs
sudomock npm (npmjs.com/package/sudomock) and sudomock PyPI (pypi.org/project/sudomock) packages cover renders, async, video, jobs, and webhooks, including a helper that polls a job to completion for you.