Productions
Create a production
Push a brief. Raylight writes a free pitch (script plus shot list) in the background; poll the production or receive production.pitch_ready on a webhook. externalId makes the call idempotent per key owner and workspace: repeating it with a key from the same owner, in the same workspace, answers 200 with the production the first call made and Idempotent-Replayed: true, and nothing new is created. origin is display only (the Productions pages and emails); Raylight never calls the provider.
POST
/v1/productionsAPI key with the productions scope.
Request body
application/json
| Field | Type | Description |
|---|---|---|
workspaceId | uuid | |
briefrequired | object | |
brief.intentrequired | string | |
brief.context | string | null | Default null |
brief.media | object[] | |
brief.media[].idrequired | string | |
brief.media[].kindrequired | enum | One of: image, video |
brief.media[].urlrequired | url | |
brief.media[].namerequired | string | |
brief.media[].description | string | null | Default null |
brief.code | object[] | |
brief.code[].pathrequired | string | |
brief.code[].sourcerequired | string | |
brief.code[].status | enum | null | One of: added, modified, removed, renamedDefault null |
brief.code[].additions | integer | Default 0 |
brief.code[].deletions | integer | Default 0 |
brief.code[].patch | string | null | Default null |
brief.code[].digest | string | null | Default null |
brief.code[].score | number | Default 0 |
brief.code[].sourceOmitted | boolean | |
brief.format | object | |
brief.format.template | enum | One of: changelog, launch, feature, digest, customDefault changelog |
brief.format.durationMs | integer | Default 10000 |
brief.format.aspect | enum | One of: 16:9, 4:3, 3:2, 21:9, 1:1, 9:16, 3:4, 2:3, 4:5Default 16:9 |
brief.format.sound | object | |
brief.format.sound.voiceover | boolean | Default true |
brief.format.sound.music | boolean | Default true |
brief.format.sound.sfx | boolean | Default true |
brief.brand | object | |
brief.brand.name | string | null | Default null |
brief.brand.logoUrl | url | null | Default null |
brief.brand.primaryColor | string | null | Default null |
brief.brand.backgroundColor | string | null | Default null |
brief.brand.fontFamily | string | null | Default null |
brief.brand.tone | string | null | Default null |
greenlightMode | enum | One of: manual, autoDefault manual |
externalId | string | |
origin | object | |
origin.providerrequired | string | |
origin.labelrequired | string | |
origin.url | url | null | Default null |
origin.ref | string | null | Default null |
origin.requestedBy | string | null | Default null |
Responses
200A repeat of an earlier create with the same
externalId: the existing production.201The new production, queued for a pitch.
400Invalid request.
401Missing, invalid or revoked key.
402The workspace owner's credits do not cover a video of the length asked for (code
credits). A pitch is free, but it is only written when the video it asks for could be paid for. Nothing was created.403The key lacks the scope, or the key's owner has view-only access to the workspace (code
forbidden).404Not found.
429Rate limited, or a monthly cap reached.
503Raylight can't write pitches right now (code
disabled). Nothing was created.200 response body
| Field | Type | Description |
|---|---|---|
productionrequired | object | |
production.idrequired | uuid | |
production.workspaceIdrequired | uuid | |
production.stagerequired | enum | One of: queued, writing_pitch, pitch_ready, greenlit, making, exporting, delivered, skipped, declined, cancelled, failed |
production.sourcerequired | object | |
production.source.kindrequired | enum | One of: app, api, mcp |
production.source.externalIdrequired | string | null | |
production.source.origin | object | null | Default null |
production.source.origin.providerrequired | string | |
production.source.origin.labelrequired | string | |
production.source.origin.url | url | null | Default null |
production.source.origin.ref | string | null | Default null |
production.source.origin.requestedBy | string | null | Default null |
production.briefrequired | object | |
production.brief.intentrequired | string | |
production.brief.context | string | null | Default null |
production.brief.media | object[] | |
production.brief.media[].idrequired | string | |
production.brief.media[].kindrequired | enum | One of: image, video |
production.brief.media[].urlrequired | url | |
production.brief.media[].namerequired | string | |
production.brief.media[].description | string | null | Default null |
production.brief.code | object[] | |
production.brief.code[].pathrequired | string | |
production.brief.code[].sourcerequired | string | |
production.brief.code[].status | enum | null | One of: added, modified, removed, renamedDefault null |
production.brief.code[].additions | integer | Default 0 |
production.brief.code[].deletions | integer | Default 0 |
production.brief.code[].patch | string | null | Default null |
production.brief.code[].digest | string | null | Default null |
production.brief.code[].score | number | Default 0 |
production.brief.code[].sourceOmitted | boolean | |
production.brief.format | object | |
production.brief.format.template | enum | One of: changelog, launch, feature, digest, customDefault changelog |
production.brief.format.durationMs | integer | Default 10000 |
production.brief.format.aspect | enum | One of: 16:9, 4:3, 3:2, 21:9, 1:1, 9:16, 3:4, 2:3, 4:5Default 16:9 |
production.brief.format.sound | object | |
production.brief.format.sound.voiceover | boolean | Default true |
production.brief.format.sound.music | boolean | Default true |
production.brief.format.sound.sfx | boolean | Default true |
production.brief.brand | object | |
production.brief.brand.name | string | null | Default null |
production.brief.brand.logoUrl | url | null | Default null |
production.brief.brand.primaryColor | string | null | Default null |
production.brief.brand.backgroundColor | string | null | Default null |
production.brief.brand.fontFamily | string | null | Default null |
production.brief.brand.tone | string | null | Default null |
production.pitchrequired | object | null | |
production.pitch.versionrequired | integer | |
production.pitch.verdict | enum | One of: video, skipDefault video |
production.pitch.verdictReason | string | null | Default null |
production.pitch.titlerequired | string | |
production.pitch.summaryrequired | string | |
production.pitch.shotsrequired | object[] | |
production.pitch.shots[].indexrequired | integer | |
production.pitch.shots[].titlerequired | string | |
production.pitch.shots[].durationMsrequired | integer | |
production.pitch.shots[].beat | string | null | Default null |
production.pitch.shots[].visualrequired | string | |
production.pitch.shots[].text | string | null | Default null |
production.pitch.shots[].voiceover | string | null | Default null |
production.pitch.shots[].mediaIds | string[] | |
production.pitch.shots[].codePaths | string[] | |
production.pitch.music | string | null | Default null |
production.pitch.estimatedCreditsrequired | integer | |
production.pitch.createdAtrequired | datetime | |
production.greenlightrequired | object | null | |
production.greenlight.moderequired | enum | One of: manual, auto |
production.greenlight.actorrequired | string | |
production.greenlight.actorName | string | null | |
production.greenlight.atrequired | datetime | |
production.greenlight.pitchVersionrequired | integer | |
production.greenlightModerequired | enum | One of: manual, auto |
production.deliveryrequired | object | null | |
production.delivery.shareUrlrequired | url | |
production.delivery.projectIdrequired | uuid | |
production.delivery.editUrlrequired | url | |
production.delivery.exportIdrequired | uuid | |
production.delivery.deliveredAtrequired | datetime | |
production.projectIdrequired | uuid | null | |
production.creditsChargedrequired | integer | |
production.errorrequired | string | null | Why the production failed, in words you can show a person. Never the render machine's own diagnostics. |
production.createdAtrequired | datetime | |
production.updatedAtrequired | datetime | |
production.terminal | boolean | True once the stage is one the production never leaves (delivered, skipped, declined, cancelled, failed, or a terminal stage added later). Stop polling when it is true; it is computed by the server, so it stays right for stages your client does not know yet. Absent from payloads stored before the field existed. |
production.pageUrl | url | The production's page in the Raylight app. Absent from payloads stored before the field existed. |
201 response body
| Field | Type | Description |
|---|---|---|
productionrequired | object | |
production.idrequired | uuid | |
production.workspaceIdrequired | uuid | |
production.stagerequired | enum | One of: queued, writing_pitch, pitch_ready, greenlit, making, exporting, delivered, skipped, declined, cancelled, failed |
production.sourcerequired | object | |
production.source.kindrequired | enum | One of: app, api, mcp |
production.source.externalIdrequired | string | null | |
production.source.origin | object | null | Default null |
production.source.origin.providerrequired | string | |
production.source.origin.labelrequired | string | |
production.source.origin.url | url | null | Default null |
production.source.origin.ref | string | null | Default null |
production.source.origin.requestedBy | string | null | Default null |
production.briefrequired | object | |
production.brief.intentrequired | string | |
production.brief.context | string | null | Default null |
production.brief.media | object[] | |
production.brief.media[].idrequired | string | |
production.brief.media[].kindrequired | enum | One of: image, video |
production.brief.media[].urlrequired | url | |
production.brief.media[].namerequired | string | |
production.brief.media[].description | string | null | Default null |
production.brief.code | object[] | |
production.brief.code[].pathrequired | string | |
production.brief.code[].sourcerequired | string | |
production.brief.code[].status | enum | null | One of: added, modified, removed, renamedDefault null |
production.brief.code[].additions | integer | Default 0 |
production.brief.code[].deletions | integer | Default 0 |
production.brief.code[].patch | string | null | Default null |
production.brief.code[].digest | string | null | Default null |
production.brief.code[].score | number | Default 0 |
production.brief.code[].sourceOmitted | boolean | |
production.brief.format | object | |
production.brief.format.template | enum | One of: changelog, launch, feature, digest, customDefault changelog |
production.brief.format.durationMs | integer | Default 10000 |
production.brief.format.aspect | enum | One of: 16:9, 4:3, 3:2, 21:9, 1:1, 9:16, 3:4, 2:3, 4:5Default 16:9 |
production.brief.format.sound | object | |
production.brief.format.sound.voiceover | boolean | Default true |
production.brief.format.sound.music | boolean | Default true |
production.brief.format.sound.sfx | boolean | Default true |
production.brief.brand | object | |
production.brief.brand.name | string | null | Default null |
production.brief.brand.logoUrl | url | null | Default null |
production.brief.brand.primaryColor | string | null | Default null |
production.brief.brand.backgroundColor | string | null | Default null |
production.brief.brand.fontFamily | string | null | Default null |
production.brief.brand.tone | string | null | Default null |
production.pitchrequired | object | null | |
production.pitch.versionrequired | integer | |
production.pitch.verdict | enum | One of: video, skipDefault video |
production.pitch.verdictReason | string | null | Default null |
production.pitch.titlerequired | string | |
production.pitch.summaryrequired | string | |
production.pitch.shotsrequired | object[] | |
production.pitch.shots[].indexrequired | integer | |
production.pitch.shots[].titlerequired | string | |
production.pitch.shots[].durationMsrequired | integer | |
production.pitch.shots[].beat | string | null | Default null |
production.pitch.shots[].visualrequired | string | |
production.pitch.shots[].text | string | null | Default null |
production.pitch.shots[].voiceover | string | null | Default null |
production.pitch.shots[].mediaIds | string[] | |
production.pitch.shots[].codePaths | string[] | |
production.pitch.music | string | null | Default null |
production.pitch.estimatedCreditsrequired | integer | |
production.pitch.createdAtrequired | datetime | |
production.greenlightrequired | object | null | |
production.greenlight.moderequired | enum | One of: manual, auto |
production.greenlight.actorrequired | string | |
production.greenlight.actorName | string | null | |
production.greenlight.atrequired | datetime | |
production.greenlight.pitchVersionrequired | integer | |
production.greenlightModerequired | enum | One of: manual, auto |
production.deliveryrequired | object | null | |
production.delivery.shareUrlrequired | url | |
production.delivery.projectIdrequired | uuid | |
production.delivery.editUrlrequired | url | |
production.delivery.exportIdrequired | uuid | |
production.delivery.deliveredAtrequired | datetime | |
production.projectIdrequired | uuid | null | |
production.creditsChargedrequired | integer | |
production.errorrequired | string | null | Why the production failed, in words you can show a person. Never the render machine's own diagnostics. |
production.createdAtrequired | datetime | |
production.updatedAtrequired | datetime | |
production.terminal | boolean | True once the stage is one the production never leaves (delivered, skipped, declined, cancelled, failed, or a terminal stage added later). Stop polling when it is true; it is computed by the server, so it stays right for stages your client does not know yet. Absent from payloads stored before the field existed. |
production.pageUrl | url | The production's page in the Raylight app. Absent from payloads stored before the field existed. |
Example
curl -X POST https://api.raylight.app/v1/productions \ -H "Authorization: Bearer $RAYLIGHT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "brief": { "intent": "Announce dark mode in the Acme dashboard to existing customers.", "context": "PR #412 adds a theme toggle to Settings. Charts, tables and the sidebar all pick up the dark palette. Ships to everyone on Thursday.", "media": [ { "id": "dashboard-dark", "kind": "image", "url": "https://cdn.acme.dev/press/dashboard-dark.png", "name": "Dashboard in dark mode", "description": "The analytics overview with the new dark theme." } ], "code": [ { "path": "src/components/settings/theme-toggle.tsx", "source": "export const ThemeToggle = () => { /* ... */ }" } ], "format": { "template": "feature", "durationMs": 10000, "aspect": "16:9", "sound": { "voiceover": true, "music": true, "sfx": true } }, "brand": { "name": "Acme", "primaryColor": "#6C5CE7", "tone": "confident, plain" } }, "greenlightMode": "manual", "externalId": "acme/web#412", "origin": { "provider": "github", "label": "acme/web #412", "url": "https://github.com/acme/web/pull/412", "ref": "feat/dark-mode", "requestedBy": "jane" }}'