Skip to main content

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}
note

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_versionMeaningResponse shape
non-null (e.g. 1)Booking created through the new bard booking pipelineNEWGuestCartView
nullLegacy booking, or a booking migrated from innsyncLEGACYLegacyBooking

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-FormatBody shape
currentGuestCartView
legacyLegacyBooking
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:

FieldNotes
stateThe booking's status (e.g. CONFIRMED) — not a constant
currency
bookedOn"Booked on" timestamp — set for a booking, null for a plain cart view
guestLead guest: name, email, phone
staysThe booked stays (listing, dates, guests, meals/VAS per stay)
paymentPayment 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:

  • walletAmountUsed is serialized under the capitalized JSON key WalletAmountUsed.
  • mealCost / mealCostAfterTax and the *Percentage fields are floats, not the BigDecimal type used by the other amount fields.
  • Dates and timestamps are plain strings; bookingDate is date-only (yyyy-MM-dd), matching the original GraphQL Date scalar's wire format.
  • childBookings recurses one level only — each child's own childBookings is always null, 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

StatusWhen
404 Not FoundNo booking exists for the given id