Events & Filtering
Every message carries the same envelope shape; the event field (and, for updates, reason) tells you what
happened, and the same value is also set as the SNS message attribute eventType so you can filter at the
subscription level.
Event types
booking.created
A new booking has been persisted. Emitted from the booking-creation flow after the row is committed, on both
the online/Staah path and the Livbnb path. reason is null.
booking.updated
An existing booking changed. Always carries a reason:
reason | Meaning |
|---|---|
payment_collected | An online balance collection was applied — paidAmount / outstandingAmount / paymentStatus moved. |
settled | A finance-approved offline payment settled the booking (paid/outstanding/status recomputed). |
modified | (reserved) a future booking edit (VAS/meal/date changes). Not emitted yet. |
Only emitted when the booking row actually changed (e.g. a duplicate/no-op collection does not emit).
booking.cancelled
The booking was cancelled (bookingStatus → CANCELLED, loyalty reversed, cart released). reason is null.
The snapshot reflects the cancelled state.
Envelope
Every event body is:
{
"id": "9f1c8e2a-6b3d-4e7a-9c10-2f5b8a1d4e33",
"event": "booking.updated",
"occurredAt": "2026-07-23T09:14:05.482Z",
"bookingId": "GWVFXCDFFO",
"reason": "payment_collected",
"data": { /* full booking snapshot — see Payloads */ }
}
| Field | Type | Notes |
|---|---|---|
id | string (UUID) | Unique per emitted event. Use as your idempotency key. |
event | string | booking.created | booking.updated | booking.cancelled |
occurredAt | string (ISO-8601, UTC) | When the event was published (post-commit). |
bookingId | string | The booking id (equals the booking code). |
reason | string | null | Set only on booking.updated. |
data | object | null | The rich snapshot. null only if the booking couldn't be read at publish time. |
Message attribute & filter policies
Each SNS message sets a single String message attribute:
eventType = "booking.created" | "booking.updated" | "booking.cancelled"
Subscribe with an SNS filter policy (scope MessageAttributes) to receive only the types you care about.
The subscription API builds this for you when you pass eventTypes; the resulting
policy is:
{ "eventType": ["booking.created", "booking.cancelled"] }
A subscription with no filter policy receives all booking events.
The reason on booking.updated is not a message attribute — it lives in the body. If you need to filter
updates by reason, subscribe to booking.updated and branch on reason in your consumer.