Booking Architecture

1. System overview

Nuitee Connect Experiences is a unified API for tours and activities. Your system owns the UX, session state, and business logic. Connect owns inventory access, pricing responses, payment intent creation, booking confirmation, and cancel quotes.

The booking flow is stateful. Values created at booking-options and prebook must be carried forward correctly:

  • tourId, optionId, dateTime, participants
  • Slot price → prebook selection.price.amount
  • prebookId, transactionId, secretKey
  • bookingId after book

Lose or substitute these and checkout breaks. Treat checkout state as a first-class concern.

Build for async confirmation from day one: book often returns PENDING_CONFIRMATION before CONFIRMED.


2. Frontend responsibilities

The frontend drives UX but must not own secrets.

What the frontend owns:

  • Search, tour detail, date/participant selection, slot picker
  • Booking question forms and contact collection
  • Stripe SDK initialization and payment confirmation
  • Session-scoped checkout state (memory)
  • UX for price refresh (2015), confirming states, voucher display

What the frontend must not do:

  • Call Nuitee Connect directly from the browser with your API key
  • Persist mid-checkout secrets in localStorage across sessions
  • Call book before Stripe confirms

Session state model (example):

Frontend session (memory only, per tab):
{
  tourId: number,
  language: string,
  currency: string,
  optionId: number,
  dateTime: string,
  participants: [...],
  priceAmount: number,
  prebookId: string,
  transactionId: string,
  secretKey: string,
  bookingId: string
}

Flush after confirmation or tab close. Never reuse an expired prebook.


3. Backend responsibilities

Your backend is the only layer that should communicate with Nuitee Connect using your API key.

Core responsibilities:

  • Proxy Connect calls with X-API-Key injected server-side
  • Persist checkout / booking state across requests
  • Enforce flow integrity (no book without successful prebook + payment)
  • Handle retries and logging for ops
  • Receive partner webhooks (or poll) for confirmation / cancel / voucher

Minimal data model (illustrative):

experience_checkout_sessions (
  session_id     UUID PRIMARY KEY,
  user_id        UUID,
  tour_id        BIGINT,
  prebook_id     TEXT,
  transaction_id TEXT,
  price_amount   DECIMAL,
  currency       CHAR(3),
  status         TEXT,  -- OPTIONS | PREBOOKED | PAID | BOOKED | CONFIRMED | FAILED
  expires_at     TIMESTAMP,
  created_at     TIMESTAMP
)

experience_bookings (
  id             UUID PRIMARY KEY,
  session_id     UUID,
  user_id        UUID,
  booking_id     TEXT NOT NULL,  -- Connect booking id
  status         TEXT,
  total_charged  DECIMAL,
  currency       CHAR(3),
  voucher_json   JSONB,
  created_at     TIMESTAMP
)

Flow enforcement (example):

POST /api/experiences/prebook
  → validate selection + price from latest booking-options
  → call Connect prebooks
  → store prebookId / transactionId / secretKey

POST /api/experiences/book
  → validate Stripe payment confirmed
  → call Connect bookings
  → store bookingId + PENDING_CONFIRMATION
  → wait for webhook / poll → CONFIRMED

4. Payment handling

  1. Prebook creates the PaymentIntent (secretKey, transactionId)
  2. Client confirms Stripe
  3. Backend books with TRANSACTION_ID

Rules:

  • Never book without a successful payment confirmation
  • Use the transactionId from this prebook only
  • If book fails after capture, surface failure; do not show a confirmed voucher

5. Confirmation & webhooks

Prefer partner webhooks for:

  • experience.book.confirmed
  • experience.book.voucher.available
  • experience.book.cancelled
  • experience.book.failed

Poll GET /experiences/bookings/{bookingId} as a fallback. See Async Confirmation & Webhooks.


6. Cancel architecture

Guest cancel should be:

  1. cancel-preview → show quote
  2. cancel → may return CANCELLATION_REQUESTED
  3. Webhook / poll → CANCELLED

Do not assume refund settlement on the cancel HTTP response alone.


7. Failure modes to design for

FailureRecommended behavior
Booking-options empty / unavailable slotsAsk guest to pick another date
Prebook 2015Refresh options; require accept of new price
Prebook 2016Selection invalid; restart slot selection
Stripe failureStay on payment step; do not book
Book 502Show failure; support path; do not claim confirmed
Long PENDING_CONFIRMATIONKeep confirming UI; poll / webhook

Next



Did this page help you?