# A production event, delivered to your endpoint

> Raylight POSTs one event per delivery to each subscribed endpoint. Verify `Raylight-Signature` against the raw body before parsing (`t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, two `v1` entries while a rolled secret is live, 5 minute tolerance). Dedupe on `Raylight-Event-Id`. `data.production` is the production as the API returns it, except that every code file in the brief has `source` and `patch` emptied and carries `sourceOmitted: true`; read the production over the API for the full files. A redelivered event has its own `id` and `redeliveryOf` naming the original. New event types and enum values are added without a version bump; acknowledge types you do not know with a 2xx.

### POST your endpoint URL

**A production event, delivered to your endpoint**

Raylight POSTs one event per delivery to each subscribed endpoint. Verify `Raylight-Signature` against the raw body before parsing (`t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">`, two `v1` entries while a rolled secret is live, 5 minute tolerance). Dedupe on `Raylight-Event-Id`. `data.production` is the production as the API returns it, except that every code file in the brief has `source` and `patch` emptied and carries `sourceOmitted: true`; read the production over the API for the full files. A redelivered event has its own `id` and `redeliveryOf` naming the original. New event types and enum values are added without a version bump; acknowledge types you do not know with a 2xx.

Auth: Raylight signs the request with your endpoint's secret in `Raylight-Signature`. Verify it before trusting the body.

Headers:

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `raylight-signature` | header | string | yes | t=<unix seconds>,v1=<hex HMAC-SHA256>[,v1=...] |
| `raylight-event-id` | header | string | yes | Stable across retries; dedupe on it. |
| `raylight-event-type` | header | string | yes | The payload's `type`. |

Payload (application/json):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | uuid | yes |  |
| `type` | enum | yes | One of: `production.pitch_ready`, `production.skipped`, `production.greenlit`, `production.progress`, `production.delivered`, `production.failed`, `production.declined`, `production.cancelled`, `ping`. |
| `createdAt` | datetime | yes |  |
| `workspaceId` | uuid | yes |  |
| `redeliveryOf` | uuid | no |  |
| `data` | object | yes |  |
| `data.production` | object | no |  |
| `data.production.id` | uuid | yes |  |
| `data.production.workspaceId` | uuid | yes |  |
| `data.production.stage` | enum | yes | One of: `queued`, `writing_pitch`, `pitch_ready`, `greenlit`, `making`, `exporting`, `delivered`, `skipped`, `declined`, `cancelled`, `failed`. |
| `data.production.source` | object | yes |  |
| `data.production.source.kind` | enum | yes | One of: `app`, `api`, `mcp`. |
| `data.production.source.externalId` | string \| null | yes |  |
| `data.production.source.origin` | object \| null | no | Default `null`. |
| `data.production.source.origin.provider` | string | yes |  |
| `data.production.source.origin.label` | string | yes |  |
| `data.production.source.origin.url` | url \| null | no | Default `null`. |
| `data.production.source.origin.ref` | string \| null | no | Default `null`. |
| `data.production.source.origin.requestedBy` | string \| null | no | Default `null`. |
| `data.production.brief` | object | yes |  |
| `data.production.brief.intent` | string | yes |  |
| `data.production.brief.context` | string \| null | no | Default `null`. |
| `data.production.brief.media` | object[] | no |  |
| `data.production.brief.media[].id` | string | yes |  |
| `data.production.brief.media[].kind` | enum | yes | One of: `image`, `video`. |
| `data.production.brief.media[].url` | url | yes |  |
| `data.production.brief.media[].name` | string | yes |  |
| `data.production.brief.media[].description` | string \| null | no | Default `null`. |
| `data.production.brief.code` | object[] | no |  |
| `data.production.brief.code[].path` | string | yes |  |
| `data.production.brief.code[].source` | string | yes |  |
| `data.production.brief.code[].status` | enum \| null | no | One of: `added`, `modified`, `removed`, `renamed`. Default `null`. |
| `data.production.brief.code[].additions` | integer | no | Default `0`. |
| `data.production.brief.code[].deletions` | integer | no | Default `0`. |
| `data.production.brief.code[].patch` | string \| null | no | Default `null`. |
| `data.production.brief.code[].digest` | string \| null | no | Default `null`. |
| `data.production.brief.code[].score` | number | no | Default `0`. |
| `data.production.brief.code[].sourceOmitted` | boolean | no |  |
| `data.production.brief.format` | object | no |  |
| `data.production.brief.format.template` | enum | no | One of: `changelog`, `launch`, `feature`, `digest`, `custom`. Default `changelog`. |
| `data.production.brief.format.durationMs` | integer | no | Default `10000`. |
| `data.production.brief.format.aspect` | enum | no | One of: `16:9`, `4:3`, `3:2`, `21:9`, `1:1`, `9:16`, `3:4`, `2:3`, `4:5`. Default `16:9`. |
| `data.production.brief.format.sound` | object | no |  |
| `data.production.brief.brand` | object | no |  |
| `data.production.brief.brand.name` | string \| null | no | Default `null`. |
| `data.production.brief.brand.logoUrl` | url \| null | no | Default `null`. |
| `data.production.brief.brand.primaryColor` | string \| null | no | Default `null`. |
| `data.production.brief.brand.backgroundColor` | string \| null | no | Default `null`. |
| `data.production.brief.brand.fontFamily` | string \| null | no | Default `null`. |
| `data.production.brief.brand.tone` | string \| null | no | Default `null`. |
| `data.production.pitch` | object \| null | yes |  |
| `data.production.pitch.version` | integer | yes |  |
| `data.production.pitch.verdict` | enum | no | One of: `video`, `skip`. Default `video`. |
| `data.production.pitch.verdictReason` | string \| null | no | Default `null`. |
| `data.production.pitch.title` | string | yes |  |
| `data.production.pitch.summary` | string | yes |  |
| `data.production.pitch.shots` | object[] | yes |  |
| `data.production.pitch.shots[].index` | integer | yes |  |
| `data.production.pitch.shots[].title` | string | yes |  |
| `data.production.pitch.shots[].durationMs` | integer | yes |  |
| `data.production.pitch.shots[].beat` | string \| null | no | Default `null`. |
| `data.production.pitch.shots[].visual` | string | yes |  |
| `data.production.pitch.shots[].text` | string \| null | no | Default `null`. |
| `data.production.pitch.shots[].voiceover` | string \| null | no | Default `null`. |
| `data.production.pitch.shots[].mediaIds` | string[] | no |  |
| `data.production.pitch.shots[].codePaths` | string[] | no |  |
| `data.production.pitch.music` | string \| null | no | Default `null`. |
| `data.production.pitch.estimatedCredits` | integer | yes |  |
| `data.production.pitch.createdAt` | datetime | yes |  |
| `data.production.greenlight` | object \| null | yes |  |
| `data.production.greenlight.mode` | enum | yes | One of: `manual`, `auto`. |
| `data.production.greenlight.actor` | string | yes |  |
| `data.production.greenlight.actorName` | string \| null | no |  |
| `data.production.greenlight.at` | datetime | yes |  |
| `data.production.greenlight.pitchVersion` | integer | yes |  |
| `data.production.greenlightMode` | enum | yes | One of: `manual`, `auto`. |
| `data.production.delivery` | object \| null | yes |  |
| `data.production.delivery.shareUrl` | url | yes |  |
| `data.production.delivery.projectId` | uuid | yes |  |
| `data.production.delivery.editUrl` | url | yes |  |
| `data.production.delivery.exportId` | uuid | yes |  |
| `data.production.delivery.deliveredAt` | datetime | yes |  |
| `data.production.projectId` | uuid \| null | yes |  |
| `data.production.creditsCharged` | integer | yes |  |
| `data.production.error` | string \| null | yes |  |
| `data.production.createdAt` | datetime | yes |  |
| `data.production.updatedAt` | datetime | yes |  |
| `data.production.terminal` | boolean | no |  |
| `data.production.pageUrl` | url | no |  |
| `data.pitchMarkdown` | string \| null | no |  |
| `data.status` | string \| null | no |  |
| `data.links` | object | no |  |
| `data.links.page` | url | yes |  |
| `data.links.greenlight` | url \| null | yes |  |
| `data.links.comment` | url \| null | yes |  |
| `data.links.decline` | url \| null | yes |  |
| `data.links.share` | url \| null | yes |  |
| `data.links.edit` | url \| null | yes |  |
| `data.endpointId` | uuid | no |  |
| `data.message` | string | no |  |

Your answer:

| Status | Meaning |
| --- | --- |
| 200 | Any 2xx acknowledges the delivery. Anything else is retried at 30s, 2m, 10m, 1h and 6h. |

Example (production.pitch_ready):

```json
{
  "id": "c1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
  "type": "production.pitch_ready",
  "createdAt": "2026-10-17T18:04:12.000Z",
  "workspaceId": "0b9d8c7a-6e5f-4d3c-ab1a-09f8e7d6c5b4",
  "data": {
    "production": {
      "id": "6f1c2b7e-3d4a-4c8e-9a2b-1f0e5d6c7b8a",
      "workspaceId": "0b9d8c7a-6e5f-4d3c-ab1a-09f8e7d6c5b4",
      "stage": "pitch_ready",
      "source": {
        "kind": "api",
        "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"
        }
      },
      "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": "",
            "status": "modified",
            "additions": 48,
            "deletions": 9,
            "patch": null,
            "sourceOmitted": true,
            "digest": "ThemeToggle: a pill switch with sun and moon icons, label \"Appearance\", brand purple when on.",
            "score": 0.91
          }
        ],
        "format": {
          "template": "feature",
          "durationMs": 10000,
          "aspect": "16:9",
          "sound": { "voiceover": true, "music": true, "sfx": true }
        },
        "brand": {
          "name": "Acme",
          "logoUrl": null,
          "primaryColor": "#6C5CE7",
          "backgroundColor": null,
          "fontFamily": null,
          "tone": "confident, plain"
        }
      },
      "pitch": {
        "version": 1,
        "verdict": "video",
        "verdictReason": null,
        "title": "Dark mode, finally",
        "summary": "A 10 second feature spot: the toggle flips, the dashboard follows, and an end card says it ships Thursday.",
        "shots": [
          {
            "index": 0,
            "title": "The flip",
            "durationMs": 3000,
            "beat": "The theme toggle flips and the whole settings page goes dark.",
            "visual": "The ThemeToggle component rebuilt as layers at hero scale, centred, a slow push-in. On the flip the background sweeps from white to the brand dark.",
            "text": "Dark mode",
            "voiceover": "Dark mode is here.",
            "mediaIds": [],
            "codePaths": ["src/components/settings/theme-toggle.tsx"]
          },
          {
            "index": 1,
            "title": "The dashboard",
            "durationMs": 4500,
            "beat": "The analytics overview in dark, tilted, drifting left.",
            "visual": "dashboard-dark on a device frame, 12 degree tilt, a lateral drift with a soft depth of field.",
            "text": "Every chart. Every table.",
            "voiceover": "Charts, tables and the sidebar all follow.",
            "mediaIds": ["dashboard-dark"],
            "codePaths": []
          },
          {
            "index": 2,
            "title": "Sign-off",
            "durationMs": 2500,
            "beat": "The Acme logo on the dark background with the ship date.",
            "visual": "Logo centred on the brand dark, the date types on underneath, a short hold before the cut.",
            "text": "Thursday, for everyone",
            "voiceover": "Turn it on in Settings, Thursday.",
            "mediaIds": [],
            "codePaths": []
          }
        ],
        "music": "Low, steady, electronic. No drop.",
        "estimatedCredits": 600,
        "createdAt": "2026-10-17T18:04:11.000Z"
      },
      "greenlight": null,
      "greenlightMode": "manual",
      "delivery": null,
      "projectId": null,
      "creditsCharged": 0,
      "error": null,
      "createdAt": "2026-10-17T18:02:40.000Z",
      "updatedAt": "2026-10-17T18:04:11.000Z",
      "terminal": false,
      "pageUrl": "https://www.raylight.app/api/productions/6f1c2b7e-3d4a-4c8e-9a2b-1f0e5d6c7b8a"
    },
    "pitchMarkdown": "## Dark mode, finally\n\nA 10 second feature spot ...",
    "status": null,
    "links": {
      "page": "https://www.raylight.app/api/productions/6f1c2b7e-3d4a-4c8e-9a2b-1f0e5d6c7b8a",
      "greenlight": "https://www.raylight.app/go/v1.eyJqIjoiNmYxYzJiN2UiLCJ2IjoxfQ.q8Zt3VbY1mK0?action=greenlight",
      "comment": "https://www.raylight.app/go/v1.eyJqIjoiNmYxYzJiN2UiLCJ2IjoxfQ.q8Zt3VbY1mK0?action=comment",
      "decline": "https://www.raylight.app/go/v1.eyJqIjoiNmYxYzJiN2UiLCJ2IjoxfQ.q8Zt3VbY1mK0?action=decline",
      "share": null,
      "edit": null
    }
  }
}
```

## More

- Previous: [Redeliver an event](https://www.raylight.app/docs/reference/post-v1-webhooks-id-deliveries-deliveryid-redeliver.md)
- Next: [Read a signed greenlight link](https://www.raylight.app/docs/reference/get-production-links-token.md)
- All docs: https://www.raylight.app/llms.txt
- Everything in one file: https://www.raylight.app/llms-full.txt
- OpenAPI: https://api.raylight.app/v1/openapi.json
