A guest booked one of your properties
Delivered when a guest completes and pays for a booking on a property you are synced to. This is the arrival-management and reconciliation payload.
It carries the guest’s name and nothing else about them. There is no email address and no phone number: the guest booked on Maat, and Maat carries the pre-arrival conversation on its own channels. If you need to reach a guest, reach the property.
amount_paid is what the guest actually paid, with the currency they were charged
in — always together, always one object. The split between Maat and the property
is not part of this payload.
Verifying a delivery
Every delivery carries:
| Header | What it is |
|---|---|
X-Signature | HMAC-SHA256(secret, "v1:" + timestamp + ":" + raw_body), hex. |
X-Signature-Timestamp | Unix seconds. Covered BY the signature — reject anything > 5m old. |
X-Signature-Previous | The same body under your PREVIOUS secret. Rotation windows only. |
Verify over the raw request body, before any JSON parsing. Re-serialised JSON does not round-trip byte-identically, and a re-serialised body will fail every time. Compare in constant time.
X-Signature-Previous is present only while a rotation overlap is open. Accept a
delivery if EITHER signature matches, and treat its absence as normal — it means
no rotation is in flight, not that something is wrong.
Retries and idempotency
event_id is stable across our retries, so use it as your idempotency key. We
back off on failure and give up after several attempts; a delivery we abandon is
surfaced to our operators rather than silently dropped. We never follow a redirect
— if your endpoint moves, register the new URL.
occurred_at is when the booking was confirmed, not when we sent it. Order two
deliveries by that, never by arrival: retries reorder.
Delivered in the sandbox today. On a production workspace this contract is not
enabled yet — see PUT /v1/webhooks/endpoint.
Authorizations
A short-lived partner token, obtained by exchanging your API key at
POST /token. Send it as Authorization: Bearer <access_token>.
Tokens live for fifteen minutes by default and never for more than an hour. Mint one per batch of work, not one per request.
The token carries the workspace and the environment its key was issued for. You cannot change either by asking: the exchange ignores everything in the request body for exactly that reason.
Never send it as a cookie or in a query string, and never store it — store the API key, mint tokens from it.
Body
Response
Return any 2xx to acknowledge. Anything else is retried with exponential
backoff; event_id is stable across retries.