Skip to main content
Preview: nothing is sent yet. This describes the Distribution API contract (version 1.0.0). No notification is delivered until the sandbox opens.
A webhook is a thin notification: it says what changed and names it, and you read the resource it names. Notifications follow Standard Webhooks, so a library for it in your language can verify them.

Register an endpoint

POST /webhooks (scope manage:webhooks) registers an endpoint, and your channel may have up to five:
  • url is a public HTTPS address on port 443. A private, reserved, loopback or link-local target is refused (url_not_allowed), and redirects are never followed.
  • events lists up to 20 event types or patterns (*, property.*, availability.updated), each covered by your key’s scopes.
  • The answer contains the endpoint’s signing secret (whsec_…), shown once: store it now.
POST /webhooks/{webhook_id}/test sends a signed ping and reports the outcome. GET /webhooks/{webhook_id}/deliveries lists the deliveries made to an endpoint, newest first, and GET /webhooks/{webhook_id}/deliveries/{delivery_id} every attempt of one; deliveries are kept for 35 days.

Verify the signature

Each notification is a POST with three headers: To verify it:
  1. Reject a timestamp more than 5 minutes away from your clock, so a captured notification cannot be replayed later.
  2. Compute the HMAC-SHA256 of id.timestamp.body over the raw body exactly as received, before any JSON parsing. The key is the secret’s base64 part after whsec_, decoded.
  3. Accept the notification if any v1, value matches, compared in constant time. While a secret is being rotated, two signatures are sent.

Apply a notification

The body is the event:
  • Delivery is at least once, in no particular order. Deduplicate on webhook-id.
  • Read the resource the event names, and apply it only when its version is higher than the one you hold.
  • An availability.updated event names a property and a range of nights (from, to exclusive) and carries no version: always re-read that range.
  • Answer with any 2xx within 10 seconds, and do the work afterwards.

Retries and suspension

A non-2xx answer or a timeout is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, then every 12 hours, each with ±20 % jitter, for 3 days. After that the endpoint becomes inactive with suspended_reason: failing, and your technical contact is e-mailed. A 410 Gone answer makes it inactive at once (gone). A redirect is never followed, and counts as not delivered. Nothing is delivered to an inactive endpoint. POST /webhooks/{webhook_id}/enable enables it again once a signed ping to it succeeds. Nothing is replayed: recover what it missed from GET /events (Synchronisation).

Rotate a secret

POST /webhooks/{webhook_id}/rotate-secret issues a new secret, shown once. The previous one keeps signing beside it for 24 hours (previous_secret_expires_at), so both signatures arrive and a verifier holding either secret accepts the notification; send "expire_immediately": true when the old secret has leaked. Deleting an endpoint cancels its pending deliveries and destroys its secrets.