Webhook endpoints
Register HTTPS URLs to receive signed events for every operational mutation. Secrets are generated server-side and shown exactly once — Stripe semantics.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /v1/webhook_endpoints | List |
| POST | /v1/webhook_endpoints | Create (returns the whsec_... secret once) |
| GET | /v1/webhook_endpoints/{id} | Retrieve (no secret) |
| PATCH | /v1/webhook_endpoints/{id} | Update (url, description, enabled, metadata) |
| DELETE | /v1/webhook_endpoints/{id} | Delete |
Create an endpoint
curl -s $API/v1/webhook_endpoints -H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: ops-hook" -H "Content-Type: application/json" \
-d '{"url":"https://ops.example.com/bookingflow/hooks",
"description":"Park ops automation"}'
The response includes "secret": "whsec_..." — store it now; it is never
shown again. URLs must be HTTPS.
Verifying signatures
Each delivery carries:
BookingFlow-Signature: t=1735689600,v1=<hex hmac>
The MAC is HMAC-SHA256 over "{t}.{rawBody}" with the endpoint secret:
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
// compare with timing-safe equality; reject t older than 5 minutes
Events delivered
booking.created, booking.updated, booking.confirmed, booking.cancelled,
customer.created, customer.updated, customer.deleted,
accommodation.created, accommodation.updated, pitch.created,
pitch.updated, meter_reading.created, invoice.created, rate.updated,
rates.bulk_updated, webhook_endpoint.*.
The payload is an event object; data.object is the resource at
event time and update events include previous_attributes. Delivery is
at-least-once; treat duplicate deliveries idempotently (e.g. key on
event.id). Delivery results are recorded on the event and visible via
GET /v1/events.