Subscribe to Events via Webhook
A webhook subscription forwards platform events to a URL you control. Use it to connect Bookable to Slack, a data warehouse, an access control system, or any downstream pipeline that needs to react in real time. See Event for the full envelope and the list of event names.
Create the Subscription
POST /event/webhook
{
"url": "https://hooks.example.com/bookable",
"event_name": "booking_created",
"owner_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}url and owner_id are required. Set event_name to the name of a single event to receive only that event. Set event_name: null to subscribe to every event the owner can see.
Response:
{
"data": {
"id": "55555555-6666-7777-8888-999999999999",
"url": "https://hooks.example.com/bookable",
"event_name": "booking_created",
"active": true,
"secret": "wh_sec_2f1d3a8b6c4e0f9a7d2b1c8e5f3a9b6d2c7e1f4a8b3d6c9e0f5a7b1d8e2c4f6",
"owner_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"created_by": "e992bfc1-0336-42c5-bd0a-4f4804a9fd24",
"created_at": "2026-05-15T10:00:00.000Z",
"updated_at": "2026-05-15T10:00:00.000Z"
},
"request_id": "c1d2e3f4-a5b6-7890-cdef-123456789012",
"count": 1
}WARNING
secret is returned once, in this response only. Read endpoints do not disclose it. Capture it now into the receiver's config. If the secret is lost, delete the subscription and create a new one.
What the Receiver Gets
Each delivery is an HTTP POST to the configured URL with the standard event envelope:
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event_name": "booking_created",
"timestamp": "2026-05-15T08:00:12Z",
"context": {
"booking": { "id": "f9955a9a-bb9e-450b-8e91-09a43f0e6cd6" },
"bookable": { "id": "c3d4e5f6-a7b8-9012-cdef-345678901234" },
"user": { "id": "e992bfc1-0336-42c5-bd0a-4f4804a9fd24" }
}
}Verifying the Signature
Every delivery includes an X-Samna-Signature header in the form:
X-Samna-Signature: t=1747299612,v1=3d9f1a2b4c5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1at is the Unix timestamp of the delivery. v1 is the HMAC SHA-256 hex digest of <timestamp>.<body> using the subscription secret as the key. Reject deliveries where t is more than 5 minutes from now to defend against replay.
Inspecting and Removing
GET /event/webhook lists every subscription the caller can see. GET /event/webhook/{id} returns one subscription without the secret. DELETE /event/webhook/{id} removes the subscription; deliveries stop on the next event.
One Subscription for Many Events
A single subscription with event_name: null receives every event for the owner. Filter on the receiver side by event_name in the envelope. This is the simplest setup when one downstream handles many types.
To route by destination, create one subscription per event_name value, each pointing at a different URL.