REST APIPlain JSON over HTTPS under /v1, authenticated with a workspace API key. Lists page with limit and cursor — pass the nextCursor you were given to get the next page.Prefer a machine-readable spec? It's OpenAPI 3.1 at /v1/openapi.json.
BrandsA brand is a product world Snoobl shoots in. Projects live inside it.
GET
/v1/brands
scope: read
List brandsReturns the workspace's brands newest first. No credits are charged; the common trap is treating type as a fixed enum when it is just a label you chose.
parameters
limitqueryoptional
Page size, 1–100. Default 20.
afterqueryoptional
Cursor from a previous page's `nextCursor`.
curl
curl "https://snoobl.com/v1/brands" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
dataBrand[]
idstring
A resource id (UUID).
namestring
typestring
A free-form label, e.g. "Skincare · DTC".
notestring | null
filmCountinteger
How many projects the brand has.
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
hasMoreboolean
Whether another page follows.
nextCursorstring | null
Pass as `after` to fetch the next page.
totalCountinteger
200 response
{ "data": [ { "id": "0197d2c4-8a1e-7c3b-9f20-5b6e1a2c3d4e", "name": "Midnight Repair", "type": "Skincare · DTC", "note": null, "filmCount": 1, "createdAt": "2026-10-11T09:00:00Z", "updatedAt": "2026-10-11T09:08:00Z" } ], "hasMore": false, "nextCursor": null, "totalCount": 1 }
can fail with
400
401
403
429
POST
/v1/brands
scope: render
Create a brandCreates a brand, which is the product world Snoobl uses for projects. Free; the thing people get wrong is over-modeling type, because it is free text, not taxonomy.
request body
namestring
typestringoptional
A free-form label, e.g. "Skincare · DTC". Default "Brand".
curl
curl -X POST "https://snoobl.com/v1/brands" \ -H "Authorization: Bearer $SNOOBL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Midnight Repair","type":"Skincare · DTC"}'
returns
idstring
A resource id (UUID).
namestring
typestring
A free-form label, e.g. "Skincare · DTC".
notestring | null
filmCountinteger
How many projects the brand has.
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
201 response
{ "id": "0197d2c4-8a1e-7c3b-9f20-5b6e1a2c3d4e", "name": "Midnight Repair", "type": "Skincare · DTC", "note": null, "filmCount": 0, "createdAt": "2026-10-11T09:00:00Z", "updatedAt": "2026-10-11T09:00:00Z" }
can fail with
400
401
403
429
GET
/v1/brands/{id}
scope: read
Get a brandFetches one brand by id. No credits are charged; do not use this to infer current project or render state, because those live on projects and renders.
parameters
idpath
A resource id (UUID).
curl
curl "https://snoobl.com/v1/brands/$ID" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
idstring
A resource id (UUID).
namestring
typestring
A free-form label, e.g. "Skincare · DTC".
notestring | null
filmCountinteger
How many projects the brand has.
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
200 response
{ "id": "0197d2c4-8a1e-7c3b-9f20-5b6e1a2c3d4e", "name": "Midnight Repair", "type": "Skincare · DTC", "note": null, "filmCount": 1, "createdAt": "2026-10-11T09:00:00Z", "updatedAt": "2026-10-11T09:08:00Z" }
can fail with
400
401
403
404
429
ProjectsOne film effort inside a brand: a brief, storyboards, renders.
GET
/v1/projects
scope: read
List a brand's projectsReturns projects newest first for the workspace or brand filter your request uses. No credits are charged; people usually mistake a project for a finished video, but the actual files are on renders.
parameters
limitqueryoptional
Page size, 1–100. Default 20.
afterqueryoptional
Cursor from a previous page's `nextCursor`.
brandIdquery
The brand whose projects to list.
curl
curl "https://snoobl.com/v1/projects" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
dataProject[]
idstring
A resource id (UUID).
brandIdstring
A resource id (UUID).
titlestring
briefstring
What the film is about.
stagestring
storyboard | generate | done
versionsCountinteger
takesCountinteger
hasActiveRendersboolean
currentVersionIdstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
hasMoreboolean
Whether another page follows.
nextCursorstring | null
Pass as `after` to fetch the next page.
totalCountinteger
200 response
{ "data": [ { "id": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "brandId": "0197d2c4-8a1e-7c3b-9f20-5b6e1a2c3d4e", "title": "Night serum — launch film", "brief": "A moody 10-second launch film for the night serum. Glass bottle, dark marble, one slow push-in.", "stage": "done", "versionsCount": 1, "takesCount": 1, "hasActiveRenders": false, "currentVersionId": "0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d", "createdAt": "2026-10-11T09:02:00Z", "updatedAt": "2026-10-11T09:45:00Z" } ], "hasMore": false, "nextCursor": null, "totalCount": 1 }
can fail with
400
401
403
429
POST
/v1/projects
scope: render
Create a projectCreates one film project inside a brand. Free; keep the brief short, because dumping a campaign deck here usually makes the Director worse, not wiser.
request body
brandIdstring
A resource id (UUID).
briefstring
What the film is about.
titlestringoptional
Derived from the brief when left out.
curl
curl -X POST "https://snoobl.com/v1/projects" \ -H "Authorization: Bearer $SNOOBL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"brandId":"0197d2c4-8a1e-7c3b-9f20-5b6e1a2c3d4e","title":"Night serum — launch film","brief":"A moody 10-second launch film for the night serum. Glass bottle, dark marble, one slow push-in."}'
returns
idstring
A resource id (UUID).
brandIdstring
A resource id (UUID).
titlestring
briefstring
What the film is about.
stagestring
storyboard | generate | done
versionsCountinteger
takesCountinteger
hasActiveRendersboolean
currentVersionIdstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
201 response
{ "id": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "brandId": "0197d2c4-8a1e-7c3b-9f20-5b6e1a2c3d4e", "title": "Night serum — launch film", "brief": "A moody 10-second launch film for the night serum. Glass bottle, dark marble, one slow push-in.", "stage": "storyboard", "versionsCount": 0, "takesCount": 0, "hasActiveRenders": false, "currentVersionId": null, "createdAt": "2026-10-11T09:02:00Z", "updatedAt": "2026-10-11T09:02:00Z" }
can fail with
400
401
403
429
GET
/v1/projects/{id}
scope: read
Get a projectFetches one project by id, including the current storyboard version id when one exists. No credits are charged; the common miss is expecting signed video URLs here, but those are render fields.
parameters
idpath
A resource id (UUID).
curl
curl "https://snoobl.com/v1/projects/$ID" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
idstring
A resource id (UUID).
brandIdstring
A resource id (UUID).
titlestring
briefstring
What the film is about.
stagestring
storyboard | generate | done
versionsCountinteger
takesCountinteger
hasActiveRendersboolean
currentVersionIdstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
200 response
{ "id": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "brandId": "0197d2c4-8a1e-7c3b-9f20-5b6e1a2c3d4e", "title": "Night serum — launch film", "brief": "A moody 10-second launch film for the night serum. Glass bottle, dark marble, one slow push-in.", "stage": "done", "versionsCount": 1, "takesCount": 1, "hasActiveRenders": false, "currentVersionId": "0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d", "createdAt": "2026-10-11T09:02:00Z", "updatedAt": "2026-10-11T09:45:00Z" }
can fail with
400
401
403
404
429
StoryboardsThe Director's creative plan for a project. Generating one is free.
POST
/v1/projects/{id}/storyboard
scope: render
Generate a storyboardStarts a Director job to write or rewrite the project's storyboard. Free and async; the usual mistake is polling the POST response instead of GET /v1/projects/{id}/storyboard.
parameters
idpath
A resource id (UUID).
request body
guidestringoptional
An optional steer. A vibe beats a shot list.
creativityintegeroptional≥ 0, ≤ 100
0 = stick to the brief, 100 = surprise me.
webResearchbooleanoptional
Let the Director research the product online first.
curl
curl -X POST "https://snoobl.com/v1/projects/$ID/storyboard" \ -H "Authorization: Bearer $SNOOBL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"guide":"After-hours, glossy, minimal. Keep the bottle heroic.","creativity":42,"webResearch":false}'
returns
idstring
A resource id (UUID).
kindstring
statusstring
queued | in_progress | completed | failed
errorstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
202 response
{ "id": "0197d2c6-2a10-7b22-b1d3-6f7e8d9c0b1a", "kind": "storyboard", "status": "in_progress", "error": null, "createdAt": "2026-10-11T09:05:00Z", "updatedAt": "2026-10-11T09:05:20Z" }
can fail with
400
401
403
404
429
GET
/v1/projects/{id}/storyboard
scope: read
Get the current storyboardReturns the current storyboard version plus the newest storyboard job for a project. No credits are charged; version can be null before the first job completes, so handle that instead of crashing politely.
parameters
idpath
A resource id (UUID).
curl
curl "https://snoobl.com/v1/projects/$ID/storyboard" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
projectIdstring
A resource id (UUID).
versionStoryboardVersion | null
The current storyboard, or null before the first one lands.
jobJob | null
The newest storyboard job — poll it while it's running.
200 response
{ "projectId": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "version": { "id": "0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d", "version": 1, "conceptName": "After Hours", "styleId": "cinematic-macro", "creativity": 42, "prompt": "Create a moody 10-second cinematic launch film for Midnight Repair night serum. Feature a glass bottle on dark marble with a slow push-in, low-key reflections, and restrained premium skincare styling.", "beats": [ { "index": 1, "title": "Midnight surface", "description": "Dark marble catches a thin line of light as the glass serum bottle enters frame in silhouette.", "camera": "Macro slider move, low angle, slow push-in.", "onScreenText": null, "audioCue": "Soft sub-bass swell with glassy texture." }, { "index": 2, "title": "Glass and glow", "description": "The bottle label becomes readable as cool highlights travel across the edges and dropper cap.", "camera": "Controlled push-in, shallow depth of field.", "onScreenText": "Midnight Repair", "audioCue": "Minimal pulse, no voiceover." }, { "index": 3, "title": "After Hours", "description": "The bottle settles hero-center on dark marble with a final reflective glint.", "camera": "Hold steady on hero packshot.", "onScreenText": "Night serum", "audioCue": "Clean resolved tone." } ], "createdAt": "2026-10-11T09:07:00Z" }, "job": { "id": "0197d2c6-2a10-7b22-b1d3-6f7e8d9c0b1a", "kind": "storyboard", "status": "completed", "error": null, "createdAt": "2026-10-11T09:05:00Z", "updatedAt": "2026-10-11T09:07:00Z" } }
can fail with
400
401
403
404
429
RendersFilms. Starting one spends credits; a failed one refunds them automatically.
POST
/v1/renders
scope: render
Start a renderStarts rendering a storyboard into one or more video takes. This example costs 1 credit for a 10-second 720p standard render; the common mistake is expecting URLs immediately, but they stay null until completion.
request body
projectIdstring
A resource id (UUID).
versionIdstringoptional
Which storyboard version. Default: the current one.
aspectRatio"16:9" | "9:16" | "1:1"optional
Default: the project's setting.
durationSeconds5 | 10 | 15optional
Default: the project's setting, else 10.
resolution"480p" | "720p" | "1080p"optional
Default: the project's setting.
tier"standard" | "fast"optional
Fast is cheaper; same model. Default standard.
generateAudiobooleanoptional
videoCreativityintegeroptional≥ 0, ≤ 100
How freely each take embellishes the prompt (0 = verbatim).
countintegeroptional≥ 1, ≤ 4
How many takes to render. Default 1.
curl
curl -X POST "https://snoobl.com/v1/renders" \ -H "Authorization: Bearer $SNOOBL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"projectId":"0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b","versionId":"0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d","aspectRatio":"16:9","durationSeconds":10,"resolution":"720p","tier":"standard","generateAudio":true,"videoCreativity":30,"count":1}'
returns
dataRender[]
idstring
A resource id (UUID).
projectIdstring
A resource id (UUID).
versionIdstring
A resource id (UUID).
statusstring
queued | in_progress | completed | failed | nsfw
errorstring | null
aspectRatiostring
durationSecondsinteger
resolutionstring
tierstring
generateAudioboolean
watermarkedboolean
creditsCostnumber
What this render cost, in credits.
videoUrlstring | null
Signed playback URL, good for an hour. Null until completed.
downloadUrlstring | null
Signed download URL (attachment). Null until completed.
parentTakeIdstring | null
The render this one refines.
editPromptstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
creditsCostnumber
Total credits debited for this call.
202 response
{ "data": [ { "id": "0197d2c7-9c42-7e88-b6a1-2d3e4f5a6b7c", "projectId": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "versionId": "0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d", "status": "queued", "error": null, "aspectRatio": "16:9", "durationSeconds": 10, "resolution": "720p", "tier": "standard", "generateAudio": true, "watermarked": false, "creditsCost": 1, "videoUrl": null, "downloadUrl": null, "parentTakeId": null, "editPrompt": null, "createdAt": "2026-10-11T09:10:00Z", "updatedAt": "2026-10-11T09:10:00Z" } ], "creditsCost": 1 }
can fail with
400
401
402
403
409
429
GET
/v1/renders/{id}
scope: read
Get a renderFetches a render's status and signed playback/download URLs once it completes. No credits are charged; cache the file if you need it later, because signed URLs are temporary.
parameters
idpath
A resource id (UUID).
curl
curl "https://snoobl.com/v1/renders/$ID" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
idstring
A resource id (UUID).
projectIdstring
A resource id (UUID).
versionIdstring
A resource id (UUID).
statusstring
queued | in_progress | completed | failed | nsfw
errorstring | null
aspectRatiostring
durationSecondsinteger
resolutionstring
tierstring
generateAudioboolean
watermarkedboolean
creditsCostnumber
What this render cost, in credits.
videoUrlstring | null
Signed playback URL, good for an hour. Null until completed.
downloadUrlstring | null
Signed download URL (attachment). Null until completed.
parentTakeIdstring | null
The render this one refines.
editPromptstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
200 response
{ "id": "0197d2c7-9c42-7e88-b6a1-2d3e4f5a6b7c", "projectId": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "versionId": "0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d", "status": "completed", "error": null, "aspectRatio": "16:9", "durationSeconds": 10, "resolution": "720p", "tier": "standard", "generateAudio": true, "watermarked": false, "creditsCost": 1, "videoUrl": "https://cdn.snoobl.com/renders/0197d2c7-9c42-7e88-b6a1-2d3e4f5a6b7c.mp4?signature=play_eY3nT8vQm2", "downloadUrl": "https://cdn.snoobl.com/renders/0197d2c7-9c42-7e88-b6a1-2d3e4f5a6b7c.mp4?signature=download_R6pL0sK9wX", "parentTakeId": null, "editPrompt": null, "createdAt": "2026-10-11T09:10:00Z", "updatedAt": "2026-10-11T09:38:00Z" }
can fail with
400
401
403
404
429
POST
/v1/renders/{id}/refine
scope: render
Refine a renderCreates a new render that applies a small edit to a completed take. It costs one quarter of the original render, minimum 0.25 credits; the bad move is asking for five changes when you should start a fresh render.
parameters
idpath
A resource id (UUID).
request body
promptstring
The change, e.g. "make the bottle matte black".
rangeStartnumberoptional≥ 0
Edit only from this second…
rangeEndnumberoptional≥ 0
…to this second.
curl
curl -X POST "https://snoobl.com/v1/renders/$ID/refine" \ -H "Authorization: Bearer $SNOOBL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt":"Make the final highlight on the bottle slightly cooler and less bright.","rangeStart":7,"rangeEnd":10}'
returns
idstring
A resource id (UUID).
projectIdstring
A resource id (UUID).
versionIdstring
A resource id (UUID).
statusstring
queued | in_progress | completed | failed | nsfw
errorstring | null
aspectRatiostring
durationSecondsinteger
resolutionstring
tierstring
generateAudioboolean
watermarkedboolean
creditsCostnumber
What this render cost, in credits.
videoUrlstring | null
Signed playback URL, good for an hour. Null until completed.
downloadUrlstring | null
Signed download URL (attachment). Null until completed.
parentTakeIdstring | null
The render this one refines.
editPromptstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
202 response
{ "id": "0197d2c7-b8f1-7dd0-a5d6-7e8f9a0b1c2d", "projectId": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "versionId": "0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d", "status": "queued", "error": null, "aspectRatio": "16:9", "durationSeconds": 10, "resolution": "720p", "tier": "standard", "generateAudio": true, "watermarked": false, "creditsCost": 0.25, "videoUrl": null, "downloadUrl": null, "parentTakeId": "0197d2c7-9c42-7e88-b6a1-2d3e4f5a6b7c", "editPrompt": "Make the final highlight on the bottle slightly cooler and less bright.", "createdAt": "2026-10-11T09:42:00Z", "updatedAt": "2026-10-11T09:42:00Z" }
can fail with
400
401
402
403
404
409
429
POST
/v1/renders/{id}/retry
scope: render
Retry a failed renderRetries a failed render with the same settings and returns a new render. It debits credits again because the failed render was already refunded; do not use retry to tweak creative direction.
parameters
idpath
A resource id (UUID).
curl
curl -X POST "https://snoobl.com/v1/renders/$ID/retry" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
idstring
A resource id (UUID).
projectIdstring
A resource id (UUID).
versionIdstring
A resource id (UUID).
statusstring
queued | in_progress | completed | failed | nsfw
errorstring | null
aspectRatiostring
durationSecondsinteger
resolutionstring
tierstring
generateAudioboolean
watermarkedboolean
creditsCostnumber
What this render cost, in credits.
videoUrlstring | null
Signed playback URL, good for an hour. Null until completed.
downloadUrlstring | null
Signed download URL (attachment). Null until completed.
parentTakeIdstring | null
The render this one refines.
editPromptstring | null
createdAtstring
ISO 8601 timestamp.
updatedAtstring
ISO 8601 timestamp.
202 response
{ "id": "0197d2c7-c6a9-7d31-8b22-1f2e3d4c5b6a", "projectId": "0197d2c5-11f0-7a44-8e02-9c1d2e3f4a5b", "versionId": "0197d2c6-3b7a-7d15-a4c9-0e1f2a3b4c5d", "status": "queued", "error": null, "aspectRatio": "16:9", "durationSeconds": 10, "resolution": "720p", "tier": "standard", "generateAudio": true, "watermarked": false, "creditsCost": 1, "videoUrl": null, "downloadUrl": null, "parentTakeId": null, "editPrompt": null, "createdAt": "2026-10-11T09:44:00Z", "updatedAt": "2026-10-11T09:44:00Z" }
can fail with
400
401
402
403
404
409
429
CreditsThe workspace's balance and what each render option costs.
GET
/v1/credits
scope: read
Get the credit balanceReturns the workspace's shared credit balance. No credits are charged; remember this is workspace-level, not tied to a brand, project, or API key.
curl
curl "https://snoobl.com/v1/credits" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
balancenumber
Credits available.
balanceMicronumber
The same balance in micro-credits (×1,000,000), exact.
200 response
{ "balance": 23.75, "balanceMicro": 23750000 }
can fail with
401
403
429
GET
/v1/credit-costs
scope: read
List render pricesReturns render pricing for each resolution, tier, and duration combination. No credits are charged; check this table instead of hard-coding pricing into your app like it is 2009.
curl
curl "https://snoobl.com/v1/credit-costs" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
dataCreditCost[]
resolutionstring
tierstring
durationSecondsinteger
creditsnumber
200 response
{ "data": [ { "resolution": "480p", "tier": "fast", "durationSeconds": 5, "credits": 0.2 }, { "resolution": "480p", "tier": "fast", "durationSeconds": 10, "credits": 0.35 }, { "resolution": "480p", "tier": "fast", "durationSeconds": 15, "credits": 0.5 }, { "resolution": "480p", "tier": "standard", "durationSeconds": 5, "credits": 0.4 }, { "resolution": "480p", "tier": "standard", "durationSeconds": 10, "credits": 0.7 }, { "resolution": "480p", "tier": "standard", "durationSeconds": 15, "credits": 1 }, { "resolution": "720p", "tier": "fast", "durationSeconds": 5, "credits": 0.35 }, { "resolution": "720p", "tier": "fast", "durationSeconds": 10, "credits": 0.6 }, { "resolution": "720p", "tier": "fast", "durationSeconds": 15, "credits": 0.9 }, { "resolution": "720p", "tier": "standard", "durationSeconds": 5, "credits": 0.6 }, { "resolution": "720p", "tier": "standard", "durationSeconds": 10, "credits": 1 }, { "resolution": "720p", "tier": "standard", "durationSeconds": 15, "credits": 1.5 }, { "resolution": "1080p", "tier": "fast", "durationSeconds": 5, "credits": 0.75 }, { "resolution": "1080p", "tier": "fast", "durationSeconds": 10, "credits": 1.25 }, { "resolution": "1080p", "tier": "fast", "durationSeconds": 15, "credits": 1.9 }, { "resolution": "1080p", "tier": "standard", "durationSeconds": 5, "credits": 1.2 }, { "resolution": "1080p", "tier": "standard", "durationSeconds": 10, "credits": 2 }, { "resolution": "1080p", "tier": "standard", "durationSeconds": 15, "credits": 3 } ] }
can fail with
401
403
429
WebhooksSigned POSTs to your server when a render finishes or fails.
GET
/v1/webhooks
scope: manage
List webhook endpointsLists the workspace's webhook endpoints. No credits are charged; this requires manage scope, and the usual foot-gun is exposing the signing secret in logs.
curl
curl "https://snoobl.com/v1/webhooks" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
dataWebhook[]
idstring
A resource id (UUID).
urlstring
events"render.completed" | "render.failed"[]
enabledboolean
secretstring
The signing secret — verify X-Snoobl-Signature with it.
createdAtstring
ISO 8601 timestamp.
200 response
{ "data": [ { "id": "0197d2c8-0d53-7f19-8c7b-3e4f5a6b7c8d", "url": "https://example.com/hooks/snoobl", "events": [ "render.completed", "render.failed" ], "enabled": true, "secret": "whsec_mR7qV2nJ9sK4xP8aL0tY6uB3cD5eF1gH2iJ4kL5zQwR", "createdAt": "2026-10-11T09:12:00Z" } ] }
can fail with
401
403
429
POST
/v1/webhooks
scope: manage
Create a webhook endpointRegisters an HTTPS endpoint for signed render events and returns its signing secret. Free; verify X-Snoobl-Signature on every delivery, because accepting unsigned render.completed events is how you earn a long afternoon.
request body
urlstring
An https URL you control.
events"render.completed" | "render.failed"[]
curl
curl -X POST "https://snoobl.com/v1/webhooks" \ -H "Authorization: Bearer $SNOOBL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/hooks/snoobl","events":["render.completed","render.failed"]}'
returns
idstring
A resource id (UUID).
urlstring
events"render.completed" | "render.failed"[]
enabledboolean
secretstring
The signing secret — verify X-Snoobl-Signature with it.
createdAtstring
ISO 8601 timestamp.
201 response
{ "id": "0197d2c8-0d53-7f19-8c7b-3e4f5a6b7c8d", "url": "https://example.com/hooks/snoobl", "events": [ "render.completed", "render.failed" ], "enabled": true, "secret": "whsec_mR7qV2nJ9sK4xP8aL0tY6uB3cD5eF1gH2iJ4kL5zQwR", "createdAt": "2026-10-11T09:12:00Z" }
can fail with
400
401
403
429
DELETE
/v1/webhooks/{id}
scope: manage
Delete a webhook endpointDeletes a webhook endpoint and its delivery history. No credits are charged; after this, events are not replayed to that URL, so do not use it as a temporary pause button.
parameters
idpath
A resource id (UUID).
curl
curl -X DELETE "https://snoobl.com/v1/webhooks/$ID" \ -H "Authorization: Bearer $SNOOBL_API_KEY"
returns
deletedtrue
200 response
{ "deleted": true }
can fail with
400
401
403
404
429
Your films are yours. Commercial use included — no asterisk.
© 2026 Snoobl · hello@snoobl.com