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
| Type | Fires when | Repeats? |
|---|---|---|
booking.created | A booking row now exists. It is not yet paid for or confirmed. | Fires at most once per booking. |
booking.payment_authorized | Funds are authorized against the customer. The booking is still not confirmed. | Fires at most once per booking. |
booking.confirmed | The booking is confirmed and the customer can travel on it. | Fires at most once per booking. |
booking.cancelled | The booking was cancelled — by the customer, by you, or by us. | Fires at most once per booking. |
booking.expired | The booking lapsed without being confirmed in time. | Fires at most once per booking. |
booking.completed | The rental or trip finished. | Fires at most once per booking. |
booking.supplier_confirmed | A supplier-fulfilled booking got a reservation back from the supplier. | Fires at most once per booking. |
booking.supplier_failed | The supplier reservation attempt did not succeed. | Fires at most once per booking. |
Test
| Type | Fires when | Repeats? |
|---|---|---|
ping | A 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_failed — Avis 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_typesGET /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.confirmedfor the same booking is not generated. If you see one, it is a redelivery of the same event, andidwill 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.