Handle a price change between search and booking
Re-quote an expired fare, renew a checkout session's selection hold, and get the traveler to accept a higher price before you book.
A fare you locked during search can move, or stop being available, before you
book it. This recipe covers both cases where that can happen: booking
directly from a fare you locked with fares/build, and booking through a
guest checkout session. {vertical} below is
one of flights, stays, cars, or trains.
Before you start
- You already locked a fare —
POST /v1/{vertical}/fares/build— and have
itsfareId. See the vertical guides:
flights, stays,
cars, trains. - Every request is signed with consumer HMAC, plus a
traveler bearer token — or, mid guest checkout, the session's guest
session token. - Two different clocks apply to a locked fare. The fare itself is
bookable for 30 minutes from the moment you locked it; after that, booking
with it fails and you need one of the recovery calls below. Separately,
travel.tech keeps a record of how you built that fare for 24 hours, so a
re-quote (step 2) can still succeed well after the 30-minute booking
window has closed — it does not extend the 30 minutes itself, it lets you
get a fresh, bookable fare after it has passed. - A guest checkout session's own hold (
selectionHoldExpiresAt) tracks the
same 30-minute fare lock, scoped to the session instead of to you
directly.
Steps
1. Try to book, and notice when the fare has moved on
Call the booking-create endpoint for your vertical with the locked fareId
— create a flight booking or
create a booking for stays, cars, and trains.
If the fare's 30-minute hold has already elapsed, this fails instead of
creating the booking — see Edge cases for the exact status
codes. Recover with step 2 (direct fare) or step 3 (checkout session)
depending on how you built the fare.
2. Re-quote a fare you locked directly
If you built the fare outside a checkout session — a signed-in traveler
booking straight from search — call POST /v1/{vertical}/fares/{fareId}/requote with the same fareId and a
fresh Idempotency-Key header:
re-quote a locked flight fare,
stay fare,
car fare,
train fare.
travel.tech re-locks the same offer — the same flight segments and fare
family, the same stay rate, the same car offer, or the same train fare — and
returns it under a new fareId, together with previousTotal,
newTotal, and priceChanged. previousTotal is what you locked
originally, not what you last saw, so it reflects the full move even after
more than one re-quote.
Replaying the same Idempotency-Key for the same fare returns the original
re-quote result instead of locking a second time; a different key starts a
new one. This endpoint does not accept a guest session token — a guest
checkout session renews through step 3 instead.
Continue to step 4 with the new fareId.
3. Renew a checkout session's selection hold
If the fare belongs to a guest checkout session, renew the session's hold
rather than calling requote directly, so the session's own
price-acceptance bookkeeping (below) stays accurate:
renew the current checkout session's selection hold.
This re-locks the same held selection, extends
selectionHoldExpiresAt, and reports the same previousTotal / newTotal /
priceChanged shape as a direct re-quote. It works under either credential
the session accepts: the guest session token, or — after the magic-link
exchange — the traveler's own bearer token plus consumer HMAC.
When the renewal raises the total, the session records it as
pendingRepriceAcceptance on GET /v1/checkout/sessions/current, and nothing can be confirmed until the
traveler accepts (step 4). A renewal that leaves the total unchanged or
lower never sets pendingRepriceAcceptance; one that moves the total back
down to the original baseline (or below) clears it.
4. Show the traveler the new total, and get acceptance before a higher price
priceChanged: false— the total is unchanged; continue to step 5.newTotallower thanpreviousTotal— nothing requires explicit
acceptance for a price decrease; continue to step 5.newTotalhigher thanpreviousTotal— show the traveler both
totals (not just the new one) before you go any further. Never book or
confirm a higher total the traveler has not seen and agreed to.
For a direct re-quote (step 2), your own UI is where that consent happens —
there is no separate accept-price call on this path; book with the new
fareId once the traveler agrees (step 5).
For a checkout session (step 3), record the traveler's agreement with
accept the renewed, higher total,
sending back exactly the newTotal value from pendingRepriceAcceptance —
not a value you computed yourself. This clears
pendingRepriceAcceptance and is required before the session's booking can
be confirmed (see Edge cases). The Idempotency-Key header is required;
replaying it after the acceptance was recorded returns 200 again as long
as newTotal is still current.
5. Book or confirm with the re-locked fare
- Direct re-quote: create the booking — create a flight
booking or create a
booking — using the re-quote's newfareId. - Checkout session: the renewed fare is already the session's
lockedSelectionId; confirm the session's existing booking with confirm
a booking. If the session already has a
bookingIdcreated on the fare the renewal replaced, that booking is
superseded (see Edge cases) — create a new one with the renewal's
renewedFareIdfirst.
Verify it worked
- The booking-create or confirm response's total matches the
newTotalyou
showed the traveler. - For a checkout session,
GET /v1/checkout/sessions/currentshowspendingRepriceAcceptance: nulland
status: bookedwithbookingIdset to the booking you confirmed.
Edge cases
Price moved up. priceChanged: true with newTotal greater than
previousTotal. Get the traveler's acceptance before booking or confirming
(step 4) — for a checkout session, confirm rejects with 409 PRICE_ACCEPTANCE_REQUIRED until you do.
Price moved down. priceChanged: true with newTotal less than
previousTotal. Nothing blocks booking immediately; a lower total needs no
explicit acceptance step.
Fare no longer available at any price. The provider cannot re-lock the
same offer — a direct re-quote returns 410 OFFER_EXPIRED with
recoveryAction: CHANGE_SELECTION; a checkout-session renewal returns the
same 410 OFFER_EXPIRED. Nothing is held. Send the traveler back to
results.
Hold expired past the point of recovery. A direct re-quote on a fareId
travel.tech has no lock record for (never locked by you, locked by a
different account, or more than 24 hours past the original lock) returns
404 — treat it the same as an unknown fare and send the traveler back to
search.
accept-price called with a stale amount. If a later renewal changed
pendingRepriceAcceptance.newTotal again — or nothing is pending — the
call returns 409 PRICE_ACCEPTANCE_STALE. Re-read the session and show the
traveler the current total before asking again.
Confirming a checkout-session booking the renewal has superseded. A
selection-hold renewal never reprices a booking that already exists; the
booking already created for the session is superseded instead, and
confirming it returns 409 BOOKING_FARE_SUPERSEDED with nothing charged.
Create a new booking on the renewal's renewedFareId and confirm that one.
When more than one of these conditions applies on the same confirm call,
travel.tech reports SELECTION_HOLD_EXPIRED first, then
BOOKING_FARE_SUPERSEDED, then PRICE_ACCEPTANCE_REQUIRED.
Related guides
Updated 8 days ago