WebhooksEvent types

Event types

There are 9 of them. You subscribe per endpoint, by passing event_types when you register it.

Subscribe narrowly. An endpoint listing every type receives every type, and most integrations genuinely need two or three.

Bookings

TypeFires whenRepeats?
booking.createdA booking row now exists. It is not yet paid for or confirmed.Fires at most once per booking.
booking.payment_authorizedFunds are authorized against the customer. The booking is still not confirmed.Fires at most once per booking.
booking.confirmedThe booking is confirmed and the customer can travel on it.Fires at most once per booking.
booking.cancelledThe booking was cancelled — by the customer, by you, or by us.Fires at most once per booking.
booking.expiredThe booking lapsed without being confirmed in time.Fires at most once per booking.
booking.completedThe rental or trip finished.Fires at most once per booking.
booking.supplier_confirmedA supplier-fulfilled booking got a reservation back from the supplier.Fires at most once per booking.
booking.supplier_failedThe supplier reservation attempt did not succeed.Fires at most once per booking.

Test

TypeFires whenRepeats?
pingA test event, sent only when you ask for one via POST /v1/webhooks/{id}/test.Fires at most once per booking.

The payload

For every type except ping, data is the booking resource — the same object GET /v1/bookings/{id} returns, at the moment the event fired. There is no separate webhook-only schema to learn, and no partial “just the changed fields” diff.

Every event type carries that same shape. What distinguishes them is type, not the body.

booking.supplier_confirmed and booking.supplier_failedAvis checkout-bridge (partner-p2b Task 3): a partner-booked Avis rental is created `pending_supplier` (see v1/rentals.ts) and only becomes `confirmed` once the supplier auto-reserve task (live-search/ reserve-task.ts) actually gets a reservation code back. These two events are how a partner learns that outcome without polling forever — emitted from runAvisReserveTask itself, not from the booking-create route (the route only knows 'pending', never the eventual supplier answer).

Unrecognised types are dropped, not rejected

If you register with a type we do not know, we do not reject the registration. The unknown type is silently dropped from event_types and the rest is saved.

This is deliberate — it means a type added to our vocabulary is subscribable before every deploy has caught up — but it has a sharp edge for you: a typo in a type name fails silently. booking.confirm is not an error, it is a subscription to nothing.

Read the response back after registering and check event_types contains what you sent:

curl -sS "https://{your-base-url}/v1/webhooks/42" \
  -H "Authorization: Bearer $TOKEN" | jq .event_types

GET /v1/events is stricter, and does reject an unknown value in types with 400 invalid_types. The two surfaces genuinely differ here.

“Repeats?” and why it matters

The third column is about distinct events, not about delivery. Read it as: can this event legitimately fire more than once for one booking?

  • Fires at most once per booking — a second booking.confirmed for the same booking is not generated. If you see one, it is a redelivery of the same event, and id will be identical.

The rule for your handler is the same whatever the column says: deduplicate on id. That is always correct and needs no knowledge of this column.