Skip to main content

Booking & Vouchers

Once allocation picks a hotel for each group, the booking worker reserves rooms with the provider, generates a voucher, and hands off to notifications.

Flow

For each allocation:
1. Idempotency check (caseUrn + waveUrn + groupId)
2. Try primary hotel with retries
- 5 attempts, exp backoff 2s → 32s
- Token refresh on 401, retry on 429 / 5xx
3. Fallback to next-ranked hotels (3 max, 1 attempt each)
4. On success:
- Decrement direct-contract inventory
- Generate voucher (HTML + text)
- Enqueue notification
5. On exhaustion:
- Create ManualReviewItem { category: BOOKING_FAILED, priority: HIGH }
- Transition case to MANUAL_REVIEW

Payment methods

Nexa supports two payment modes — per policy and per provider.

Corporate guarantee (default)

Used for airline-pays scenarios. The booking is placed with payment.method = GUARANTEE; the hotel holds the room but does not charge a card. Payment is settled via the airline's corporate account at check-out.

  • Pros: no PCI surface, simpler reconciliation.
  • Cons: some hotels refuse GUARANTEE and need a card; those are filtered out at allocation time.

Tokenized card

For airports where corporate guarantee is not accepted, Nexa integrates with a PSP (payment service provider) to tokenize a corporate card. Only the PSP token is stored — never a PAN.

Enable per policy:

"acceptedPayments": ["CARD"],
"cardToken": "tok_xxxxxxxxxxxx"

Voucher

A voucher is generated after CONFIRMED and contains everything a front desk needs to honor the stay:

  • Confirmation code
  • Hotel name, address, phone
  • Check-in / check-out dates and times
  • Rooms reserved
  • Passenger list (names as on the manifest, no sensitive IDs)
  • Total cost + currency
  • Payment instructions (corporate guarantee boilerplate or card reference)
  • Any SSR special instructions (accessibility, connecting rooms, early check-in)

Fetch HTML or text:

curl https://us-central1.api.nexastudio.io/booking/reservations/$RESERVATION_URN/voucher/html
curl https://us-central1.api.nexastudio.io/booking/reservations/$RESERVATION_URN/voucher/text

Vouchers are deterministic: re-rendering the same reservation produces byte-identical output, which makes the idempotency key safe to re-use.

Retry logic in detail

Attempt 1 → provider call
on 429 → exp backoff, retry
on 401 → refresh token, retry
on 5xx → exp backoff, retry
on 4xx (not 401/429) → stop, return failure
Attempt N (up to 5) → same
Exhausted →
Try fallback hotel (rank 2) with single attempt
Try fallback hotel (rank 3) with single attempt
Try fallback hotel (rank 4) with single attempt
All failed → Manual Review

Idempotency is the safety net: the same (caseUrn, waveUrn, groupId) can be retried safely — if the provider already confirmed, Nexa returns the existing reservation rather than double-booking.

Manual booking

An operator can book a hotel directly, bypassing the allocation wave, for edge cases (a passenger insists on a specific property that passes policy):

curl -X POST https://us-central1.api.nexastudio.io/booking/manual \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"caseUrn": "urn:nexa:case:xyz",
"groupId": "GRP-3",
"hotelUrn": "urn:nexa:hotel:abc",
"providerOfferId": "ASDFGHJKL...",
"reason": "passenger preference — contract-direct Ibis MAD"
}'

Manual bookings still flow through the provider adapter; they simply skip ranking. Audit records the manual override with the reason.

Cancellations

  • Amadeus Self-Service does not expose cancellations; those reservations have to be cancelled at the hotel or through Amadeus Enterprise.
  • Hotelbeds supports cancellations; Nexa exposes POST /booking/reservations/:urn/cancel for operators.
  • Direct contracts always cancel immediately and restore inventory.

On cancellation:

  • Reservation status → CANCELLED with reason.
  • Direct-contract inventory is restored.
  • Notifications send a cancellation email if the voucher was already delivered.
  • Audit records the cancelling actor.
Was this helpful?