SudoMock
GET

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.

GET/api/v1/jobs/{render_uuid}
no credits

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_uuidstringRequired

The job identifier returned from the 202 Accepted response of an async render, an async upload, or a video request.

Headers

x-api-keystring

Your SudoMock API key starting with sm_. Required unless using Bearer token authentication.

Authorizationstring

Alternative 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.

StatusTerminalMeaning
queuedNoAccepted and waiting for a worker.
dispatchedNoHanded to a worker, about to start.
runningNoActively being processed.
succeededYesFinished. result_url (render/video) or mockup_uuid (upload) is populated.
failedYesCould not complete. error explains why. No credits charged.
cancelledYesStopped before completion. No credits charged.

Poll until terminal

Keep polling while the status is queued, dispatched, or running. Stop as soon as it becomes succeeded, failed, or cancelled.

Response

In progress

200OK
Job 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

This is the most common integration mistake. A succeeded 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.
kindRead the result fromOther field
renderresult_urlmockup_uuid is null
videoresult_urlmockup_uuid is null
uploadmockup_uuidresult_url is a /library/mockups/{...} link
Succeeded render / video (result_url)
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}
Succeeded upload (mockup_uuid)
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.

Failed job
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_uuidstringRequired

The job identifier you polled.

kindstringRequired

One of "render", "video", or "upload". Determines which result field is populated.

statusstringRequired

Current state: queued, dispatched, running, succeeded, failed, or cancelled.

modelstring

The 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_urlstring

The 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_uuidstring

UUID of the created mockup. Populated on success for upload jobs; null for render and video jobs.

credits_chargedinteger

Credits deducted for this job. Only charged on success; failed and cancelled jobs charge 0.

paygobject

Present when the job was billed through pay-as-you-go. Contains credits, unit_price, and cost.

payg.creditsinteger

Number of credits billed via pay-as-you-go for this job.

payg.unit_pricenumber

Price per credit applied to this job, in USD.

payg.costnumber

Total pay-as-you-go cost for this job, in USD (credits x unit_price).

errorstring

Human-readable failure reason. Null unless the job failed.

created_atstring

ISO 8601 timestamp when the job was accepted.

updated_atstring

ISO 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.

Succeeded job billed via pay-as-you-go
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.898
14 },
15 "created_at": "2026-06-22T10:05:00Z",
16 "updated_at": "2026-06-22T10:05:48Z"
17}

List jobs

GET/api/v1/jobs
no credits

Retrieve 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

kindstring

Filter by job kind: "video", "render", or "upload". Omit to list every kind.

limitinteger= 20

How many jobs to return per page (1 to 50).

cursorstring

Opaque 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

200OK

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.

List of video jobs
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": null
36 }
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

A user with no matching jobs gets 200OK with an empty list and a null cursor, never a 404.
No matching jobs
1{
2 "jobs": [],
3 "next_cursor": null
4}

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_secondsinteger

Length of the clip in seconds. Null for non-video jobs.

audioboolean

Whether the clip includes an audio track. Null for non-video jobs.

mockup_namestring

Display name of the source mockup, for labelling a list row. Null when unavailable (for example, a raw-image video or an upload).

poster_urlstring

CDN 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

List jobs page by page
bash
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"
4
5# Next page: pass the next_cursor from the previous response
6curl "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

To read or poll a single job, use GET /api/v1/jobs/{render_uuid}. The list endpoint is for browsing your history; the per-job endpoint stays the source of truth for a job's live status.

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.

Poll a job to completion
javascript
1const BASE_URL = "https://api.sudomock.com/api/v1";
2const headers = { "x-api-key": "sm_your_api_key" };
3
4// 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();
11
12 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 }
19
20 await new Promise(r => setTimeout(r, delay));
21 delay = Math.min(delay * 1.5, 8000); // cap at 8s
22 }
23 throw new Error("Polling timed out");
24}

Prefer webhooks over tight polling

Register a webhook to be notified the instant a job finishes. Webhooks and this endpoint describe the same job; polling remains the source of truth if a delivery is missed.

Errors

401Unauthorized

Missing or invalid API key or Bearer token.

json
1{
2 "detail": "Not authenticated",
3 "success": false
4}
404Not Found

No job exists for that render_uuid, or it does not belong to your account.

json
1{
2 "detail": "Job not found",
3 "success": false
4}

SDKs cover jobs

The 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.
Jobs API Endpoint | SudoMock Docs