Skip to main content

Webhooks

Webhooks notify your integration when data changes, so you can keep a local copy fresh without polling. Register an HTTPS endpoint with POST /webhooks, choosing which of the event types listed by GET /webhook_events it should receive.

Events describe what changed, not the new values. A delivery names the listings affected and expects you to re-read the detail through the relevant endpoint — price recommendations, reservations or flags. This keeps payloads small and stable, and means you never have to reconcile a webhook body against an API response.

Deliveries are batched. Events occurring within a five-minute window collapse into a single request whose data.listing_ids names every listing involved, so a nightly repricing run across a large portfolio arrives as a handful of requests rather than thousands. Each delivery only ever names listings you have access to.

Verify every delivery. Requests carry a Wh-Signature header of the form t=<unix timestamp>,v1=<hex>, where the hex is HMAC-SHA256(secret, "<t>.<raw request body>"). Recompute it with the subscription's secret and compare; reject the request if it does not match, or if t is older than your tolerance (five minutes is a reasonable choice) to prevent replay. The secret is returned only when the subscription is created and by POST /webhooks/\{id\}/rotate_secret — it cannot be read back afterwards.

Delivery is at-least-once, so de-duplicate. Retries reuse the same Wh-Event-Id header (also data-adjacent as the envelope id); treat a repeated id as already handled. Respond with any 2xx status as soon as you have durably accepted the request — do not do your processing before responding, since we time out after 15 seconds. Failed attempts are retried with backoff over roughly 20 minutes, and a subscription that keeps failing is disabled automatically; re-enable it with PUT /webhooks/{id} once your endpoint is healthy. Use GET /webhooks/{id}/deliveries to see what we actually sent and what your endpoint returned.