Booking Detail (by ID)
GET /api/v1/bookings/{bookingId} returns a single booking, keyed directly on the booking id. It is
public — no authentication; anyone who has the booking id can read it, the same model as the
pay-booking guest page (/api/v1/pay-booking/{bookingId}). An unknown id returns 404 Not Found.
GET /api/v1/bookings/{bookingId}
Because it is public-by-id, the full booking (guest name, agent, pricing, cancellation) is visible to anyone holding the booking id — the same exposure trade-off as the pay-booking guest page.
Response is polymorphic — versioned by the booking itself
The response shape is not chosen by a request parameter. It's implied entirely by the booking's own
api_version column, which the caller does not see or control:
bookings.api_version | Meaning | Response shape |
|---|---|---|
non-null (e.g. 1) | Booking created through the new bard booking pipeline | NEW — GuestCartView |
null | Legacy booking, or a booking migrated from innsync | LEGACY — LegacyBooking |
New bookings created going forward always stamp api_version, so this split is a permanent, self-describing
property of each booking row — old bookings keep returning the legacy shape forever; there is no backfill or
cutover date to track.
How the client knows which shape it got
The response carries an X-Booking-Format header naming the shape, so the frontend branches on the header
rather than sniffing the body:
X-Booking-Format | Body shape |
|---|---|
current | GuestCartView |
legacy | LegacyBooking |
const res = await fetch(`/api/v1/bookings/${bookingId}`);
const booking = await res.json();
if (res.headers.get('X-Booking-Format') === 'legacy') renderLegacy(booking);
else renderCurrent(booking);
The header is derived from api_version server-side; both response bodies stay exactly as documented below
(the legacy body is unchanged, preserving its innsync fidelity).
Consumers that only handle bookings they created themselves (e.g. a client that only ever creates bookings through the new cart flow) will only ever see the NEW shape. A client that reads older bookings — migrated history, or bookings placed before this feature shipped — must be able to handle both.
NEW shape — GuestCartView
Used when api_version is non-null. This is the exact same shape the cart's guest/confirmation view
returns (bookedOn populated instead of null), so a booking-confirmation page can reuse the cart's
rendering components unchanged. Top-level fields:
| Field | Notes |
|---|---|
state | The booking's status (e.g. CONFIRMED) — not a constant |
currency | |
bookedOn | "Booked on" timestamp — set for a booking, null for a plain cart view |
guest | Lead guest: name, email, phone |
stays | The booked stays (listing, dates, guests, meals/VAS per stay) |
payment | Payment breakdown |
elicashEarned is part of GuestCartView but is never populated by BookingDetailAssembler for a
booking — it is always absent from this response, not just null.
See com.elivaas.common.dto.booking.GuestCartView for the full nested shape (Stay, Payment, etc.).
It's assembled by com.elivaas.dao.booking.read.BookingDetailAssembler, shared by both crs (agent +
guest booking-detail endpoints) and website, so the confirmation view is identical across surfaces.
LEGACY shape — LegacyBooking
Used when api_version is null. This is a REST/JSON mirror of innsync's GraphQL type Booking
(returned as-is, no envelope), so pre-existing website clients built against the old GraphQL response
keep working unchanged against this new REST endpoint. It carries far more detail than the new shape:
agent/referred-agent/guest-manager, cancellation plan and policy, per-payment records, meals/VAS line
items, rewards, one level of childBookings, split-payment and platform-fee breakdown, and more.
The assembler also replicates innsync's findByIdv3 derivations: showPrice defaults to true and is
false for a NON_BRANDED channel; couponDiscountApplied / promotionDiscountApplied /
paymentDiscountApplied are set from the presence of a coupon / promotion / bank-offer code; and user
and property fall back to booking_guest / the first booking_properties row when the primary
join is absent.
Because old clients depend on the exact wire shape, field and JSON-key names are transcribed verbatim from the original GraphQL schema rather than "cleaned up" — including known quirks:
walletAmountUsedis serialized under the capitalized JSON keyWalletAmountUsed.mealCost/mealCostAfterTaxand the*Percentagefields are floats, not theBigDecimaltype used by the other amount fields.- Dates and timestamps are plain strings;
bookingDateis date-only (yyyy-MM-dd), matching the original GraphQLDatescalar's wire format. childBookingsrecurses one level only — each child's ownchildBookingsis alwaysnull, so grandchildren are never fetched.
A few fields have no equivalent data source in bard today and are always null by design:
securityDeposit, additionalServices, originalNetPerNightAmountBeforeTax, and the singular reward
field (distinct from the rewards list, which is populated from bookings.rewards) — see
com.elivaas.dao.booking.read.LegacyBookingAssembler's class Javadoc for the authoritative list.
Errors
| Status | When |
|---|---|
404 Not Found | No booking exists for the given id |