Skip to main content
Webhooks send task and highlight changes to your server. An organization admin registers each destination once, then a task selects it by ID.

Step 1: Expose a Receiver

Your receiver must accept POST requests over public HTTPS. For local development, run it on port 3000 and expose it with ngrok:
Use a route such as https://example.ngrok-free.app/webhooks/narrative. Preserve the exact request body bytes; you will verify them in Step 4.

Step 2: Register the Endpoint

Open Webhooks, select Add endpoint, and choose the events to receive. Only organization owners and admins can view or manage endpoints. Copy both values after creating it:
  • Endpoint ID — pass this as webhook_id when creating a task.
  • Signing secret — store it in a secret manager. It is shown once.
Endpoints belong to the organization, not an individual task. Update the registered URL instead of sending a raw URL with every task.

Step 3: Create a Task

Use an endpoint ID from the same organization as the API key. See Create Task for the full request.

Events

One immutable event is created per logical change, not per video orientation or render. Delivery may occur more than once.

Step 4: Verify the Signature

Every delivery includes: The signed input is the event ID, timestamp, and exact raw request body, separated by periods:
Reject timestamps more than five minutes from your server clock. Verify before parsing JSON.
Pass both the current and previous signing secrets during a rotation. Remove the previous secret after the delivery retry window.
Never verify a re-serialized JSON body, and never compare signatures with == or ===. Use your language’s constant-time comparison function.

Delivery Semantics

Delivery is at least once. Narrative retries timeouts and non-2xx responses, so return 2xx only after you have accepted the event. Retries keep the same Narrative-Event-Id; store that ID and ignore duplicates. Do not rely on delivery order. Narrative attempts delivery up to eight times over roughly two minutes. Exhausted deliveries enter dead-letter storage and can be replayed operationally with the same event ID.