For background on how webhooks work and when to use them, see Webhooks. For complete API details, see the Webhooks API Reference.
Prerequisites
- An API token with Webhooks
readandwritepermissions - An HTTPS endpoint ready to receive POST requests
- Familiarity with job types and job states
What you’ll learn
- How to create a job webhook subscription with filters
- How to receive and verify webhook events
- How to list, inspect, and archive subscriptions
Creating a job webhook subscription
Use thePOST /webhooks endpoint to create a subscription. Set the type to webhook_subscription_jobs and provide your endpoint URL.
Decide which job events you want to receive. You can filter by job IDs, job types, job states, or any combination.
job_types: ["materialize-view"], states: ["completed"]job_ids: ["<job-id>"]states: ["failed"]job_ids, job_types, and statescurl -X POST https://api.narrative.io/webhooks \
-H "Authorization: Bearer $NIO_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "webhook_subscription_jobs",
"url": "https://your-app.example.com/webhooks/narrative",
"name": "completed_matviews",
"job_types": ["materialize-view"],
"states": ["completed", "failed"]
}'
The response includes a
secret field — a UUID used to verify that incoming requests are from Narrative. Store this value securely.{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"secret": "8b6dba8c-9a8b-4a3a-8469-9dc7a33c3e17",
"status": "active",
"companyId": 42,
"jobTypes": ["materialize-view"],
"jobStates": ["completed", "failed"],
"url": "https://your-app.example.com/webhooks/narrative",
"createdAt": "2025-04-29T16:12:45.123456",
"updatedAt": "2025-04-29T16:12:45.123456"
}
Receiving events
When a job matches your subscription’s filters, Narrative sends an HTTP POST to your URL with a JSON payload.Example event payload
2xx status code to acknowledge receipt.
Handling idempotency
Each event includes anidempotencyKey — a unique identifier for that specific delivery. If Narrative delivers the same event more than once (for example, due to a network retry), the idempotency key remains the same.
Use the idempotency key to detect duplicates:
- When you receive an event, check if you’ve already processed that
idempotencyKey - If yes, return
200 OKwithout processing again - If no, process the event and store the key
Managing subscriptions
List all subscriptions
active and archived subscriptions.
Get a specific subscription
Archive a subscription
Archiving stops event delivery but retains the subscription record.Best practices
| Practice | Why |
|---|---|
| Respond quickly | Return a 2xx response immediately, then process the event asynchronously. Slow responses may cause delivery timeouts. |
| Store the secret | Save the secret from the creation response. You cannot retrieve it later. |
| Implement idempotency | Use the idempotencyKey to deduplicate events in case of retries. |
| Use HTTPS | Webhook URLs must use HTTPS to protect payloads in transit. |
| Filter narrowly | Subscribe only to the job types and states you need. This reduces noise and processing overhead. |

