Full flight booking flow
What you’ll build: a complete booking — search for flights, confirm a price, take the money decision, place the booking, and confirm (or issue) the ticket. This is the money path, so it leans on three Kitionz safety guarantees you’ll see throughout: idempotency (a retry never double-books), the signed quoteToken (Kitionz never books above the price you quoted), and safe retries (a slow supplier never looks like a failed booking).
Note: New to flight APIs or unsure about a word like
quoteTokenorofferId? The Glossary defines every term in plain English — keep it open in a second tab.
The same endpoints can be used for less than this. If you only want to show fares, stop after Search. If you only manage existing bookings, start at Step 4. This recipe is the full transaction.
Before you start
On the Live API you need two things:
-
Your Live key, sent as
Authorization: Bearer <keyId>:<secret>on every request, from an IP on its allow-list, with your organisation’s KYC approved. -
On every write (
/book,/ticket,/cancel…): anIdempotency-Key: <uuid>header — a new UUID for each write, saved with your order before you call; send the same value again only when you resend the same request after a timeout — +Content-Type: application/json. You’re auto-pinned to an API version, so you don’t sendKitionz-Version.
Step 1 — Search
What: find bookable offers for a route + date + passenger mix.
When: the start of every booking. Next: pick one offer and send its offerId to the fare quote.
Send origin, destination and departureDate; every other field is optional (adults defaults
to 1). A real request and its recorded answer: Search.
No tripType sent, so the answer holds every trip leaving that day: one-way fares and fixed
round-trip packages, each with its own tripType. "tripType": "ROUND_TRIP" returns round trips
only, and "tripType": "ONE_WAY" one-way offers only (data.meta.filtersApplied counts the round
trips it left out).
There are two meta objects. data.meta describes the search (trip kinds, how many suppliers
answered, filtersApplied). The outer meta, beside requestId, carries diagnostics when the
answer is empty or an input looks wrong (see “What can go wrong” below).
Critical: a round trip is ONE offer. It comes only from suppliers that sell round trips as one two-leg fare: a single offer with
legs: [OUTBOUND, RETURN], oneprice.totalAmount, oneofferId. Never staple two one-way offers yourself.
Critical: every offer says which trip it is —
tripType,departureDateand, for a round trip,returnDate. A round trip’s price covers both ways: say so on your screen. The fare quote and the booking take them from the offer: you need not send them.
Critical: search prices are indicative. They can move. Never charge your customer off a search price — re-price in the next step.
Required: search with the passengers you will book. An offer is quoted and booked only for the
adults,childrenandinfantsit was searched with; another party is refused at the fare quote with400 PASSENGER_COUNTS_CHANGED, and at the booking with409 QUOTE_TOKEN_PAX_MISMATCH. Kitionz accepts an offer’sofferIduntil itsexpiresAt(about 15 minutes). That is not a price or seat guarantee.
Required — international trips: read the offer’s
isInternationalandrequiredPassengerFieldsbefore you show a passenger form.isInternationalistruewhen a flight crosses a border (or when Kitionz cannot tell); then every passenger needsdateOfBirth,passportNumber,passportExpiryDateandnationality, and the passport must be valid at least 6 months after the last flight. Collect them before you take payment (Step 3 has the details).
Show what the seller did not state
Kitionz never makes up a value. A value the seller did not state is null, and a refund or change
policy is NOT_GIVEN. A 0 the seller did state stays 0. Live sellers leave many values
unstated, and so does Kitionz Test Air (it is built to look like them), so build every screen for
them:
Baggage rows use paxType ADT, CHD and INF (for ADULT, CHILD, INFANT): match them to
passengers with that table.
Important: a leg with a stop has one segment per flight. Some suppliers give the wait at a stop but not the clock times there, so a segment’s
departureTimeorarrivalTimecan benullat that stop. The wait is in the leg’slayovers(layovers[k]is the stop aftersegments[k]); a booking carries it assegments[].layoverAfterMinutes. Show “Time not stated”, and never work out a time or a duration from anull. A leg’s first departure and last arrival always have a time. If the supplier’s own times at a stop contradict each other, Kitionz shows them as not stated as well; when it has no wait for that stop, the leg has nolayoversand the booking’slayoverAfterMinutesisnull.
More ways to call search
The fields of this call and a real answer are on its page: Search.
Note — What can go wrong here?
- Empty
offerswith no error → readdiagnosticsin the outermeta(besiderequestId, notdata.meta). It names why:NO_RESULTS_FOR_QUERY(your suppliers had nothing for that route and date),FILTERS_REMOVED_ALL_OFFERS(your filters removed every offer),UNKNOWN_AIRPORT(an airport code Kitionz does not know — check it), or a supplier not yet approved for Live. See Go live.- Your filters removed every offer →
data.meta.filtersAppliedhas one{ field, removed }entry per filter you sent. Few suppliers state a fare brand or a refund policy, sofareBrandsIncludeorrefundableOnlycan remove everything.FORBIDDEN(403) → a code insupplierCodesis not switched on for your account. Switch it on under Suppliers, or leavesupplierCodesout.VALIDATION_ERROR→ a field name/format is off, or the search asks for something Kitionz does not offer (three or moreslices, or a way back to other airports). Readerror.details.invalidFields: it names the field.
Step 2 — Fare quote (confirm the price, get a token)
What: re-price the chosen offer against the live supplier and get a signed
quoteToken. Why it matters: for about 15 minutes, the token binds this price, offer and
passengers, and Kitionz will not book above that price. It does not hold the seat. Send the
offerId: the passengers and the trip are the offer’s. adults, children, infants,
departureDate, tripType and returnDate are optional; if you send one it must be the offer’s or
the number you searched with (another trip → 400 OFFER_TRIP_MISMATCH, another party →
400 PASSENGER_COUNTS_CHANGED). Next: pass the token to Book.
Send { "offerId": "floffer_…" }. A real request and its recorded answer:
Fare quote.
Note — per-passenger prices:
price.passengerFareshas one row per passenger type (passengerType,count).totalis the price of all passengers of that type together andperPersonis one passenger’s, to the paisa: two adults on{ "passengerType": "ADULT", "count": 2, "perPerson": 5324, "total": 10648 }cost ₹5,324 each. When every row states a total, the rows add up tototalAmount. Chargeprice.totalAmount, never a sum ofperPerson. The booking carries the samepriceblock.
Required: book the passengers you searched with. The
quoteTokenbinds the offer, the passengers and the trip; Book counts the passengers from itspassengerslist (another party →409 QUOTE_TOKEN_PAX_MISMATCH: search again with them). There is no supplier field to send: theofferIdalready names the supplier.
Critical: the price can change here. Always show the customer
price.totalAmountfrom this response, never the search price.priceChangedistruewhen it differs from the offer’s total at search (searchTotalAmount); Kitionz compares the two for every supplier. With an infant, readprice.infantFare.statusfirst: if the infant price was given at only one of the two steps, the difference is the infant fare, not a fare change. IfpriceChangedistrue, tell the customer the price moved and book only if they accept. ThequoteTokencarries this price. At booking, Kitionz checks again: if the price went up or the seats are gone, nothing is booked (FARE_HIGHER_THAN_QUOTED/INSUFFICIENT_SEATS) and you quote again. If the price moved down, some sellers book at the lower price and some refuse any change with409 SUPPLIER_FARE_CHANGED_AT_BOOK(nothing booked: quote again) — never rely on either. Seats can also go at the seller itself: then Book answers201with aFAILEDbooking andfailure.codeSUPPLIER_BOOK_FAILED. The token is valid untilquoteTokenExpiresAt(about 15 minutes).
Required — offer & quote lifetimes: two short-lived clocks run here.
- Search offer, until its
expiresAt(about 15 min): after that, quoting or booking itsofferIdreturnsOFFER_EXPIRED→ re-search. A successful fare quote extends it.- quoteToken ~15 min: the signed token expires (
quoteTokenExpiresAt). Booking after that returnsQUOTE_TOKEN_EXPIRED→ re-quote.- If the live fare rose above the quote at book time you get
FARE_HIGHER_THAN_QUOTED— re-quote and show the new price; never auto-charge the difference.
Quote variants
The fields of this call and a real answer are on its page: Fare quote.
Note — What can go wrong here?
OFFER_EXPIRED→ the offer’sexpiresAtpassed. Re-run search, quote a freshofferId.PASSENGER_COUNTS_CHANGED→ you sent otheradults/children/infantsthan the search.error.details.searchedPartyandsentPartyshow both. Search again with the passengers you will book.priceChanged: trueon a 200 → the price moved since search. It is not an error: the NEWquoteToken+ price are in the body — show the customer the new price before booking with it.KYC_NOT_APPROVED(Live key only) → your org’s KYC isn’t approved yet.
Step 3 — Book
What: place the booking. Why the token: Book requires the quoteToken and takes
the price from it. There is no amount field, so a price can’t be made up, changed or
replayed. Why idempotency: Kitionz reserves the booking before it asks the supplier to book,
and keys it on your Idempotency-Key, so a network retry returns the same booking instead of
charging twice.
Send offerId, quoteToken, passengers and your own externalReference, with a new
Idempotency-Key header saved with your order before you call. A real request and its recorded
answer: Book.
The HTTP status is 201. Decide by data.status and data.nextAction.
Required — passengers:
passengerTypeis"ADULT"(12 or older),"CHILD"(2–11) or"INFANT"(under 2), by the passenger’s age on the date of the last flight (on a round trip, the return flight). Search with that count: an infant who turns 2 before the return flight travels as aCHILD. A passenger whose age does not fit the type is refused before any seller is called with422 PASSENGER_FIELD_REQUIREDonpassengers.N.dateOfBirth— for example “Passenger 2: This infant will be 2 or older on the return flight on 2026-12-20. Search again with this passenger as a child.” Fix it with a new search, not by changing Book: the passengers are bound to the search and the quote. No passenger may be born after the departure date.passengersmust hold exactly the passengers you searched with; if you also sendadults,childrenorinfants, they must match it. At most 9 adults and children in one booking.- Infants sit on an adult’s lap: every
INFANTneedsguardianPassengerIndex, the position inpassengers(0 = the first) of thatADULT. One infant per adult.- Names: send
firstNameandlastNamefor everyone. A traveller with one name: send it as both.- Titles:
Mr,MrsorMsfor adults;Master(boy) orMiss(girl) for children and infants. Kitionz setsgenderfrom the title; with any other title (Dr,Prof), sendgender(MALEorFEMALE).- Date of birth: a
CHILDorINFANTalways needsdateOfBirth. A domesticADULTsent without one is sent to the seller with 1 January of (this year − 20), because some sellers refuse a booking without a date of birth. The booking never shows that date as the passenger’s: it answersdateOfBirth: nullwithdateOfBirthDefaulted: true(falsefor everyone else).
Required — international trips: collect what the offer needs before you take payment. On an offer whose
isInternationalistrue, every passenger needsdateOfBirth,passportNumber,passportExpiryDateandnationality. The passport must be valid at least 6 months after the last flight. Send countries as two-letter codes (IN, notIndian). LeavepassportIssuingCountryout unless the passport was issued by another country thannationality: Kitionz sends the nationality. A missing field answers422 PASSENGER_FIELD_REQUIRED, a passport that expires too soon422 PASSPORT_EXPIRY_TOO_SOON; both list every passenger and field inerror.details.invalidFields, and nothing is sent to the seller.
Note — who the seller contacts: the seller receives your organisation’s registered email and mobile as the booking contact (your Kitionz account details), not
booker.email;booker.phoneis sent only when your organisation has no mobile on record. E-tickets, schedule changes and cancellations from the seller or the airline come to you: pass them on to your traveller.bookeris your record of who made the booking; some sellers receivebooker.nameas the contact name. Phone numbers: an Indian mobile, 10 digits,+91optional.
Required — other fields:
- Send only the fields in the reference. Any other field is
400 VALIDATION_ERROR. Seats, meals, extra baggage, payment details, corporate or tour codes and frequent-flyer numbers cannot be sent at booking: no supplier receives them.bookingModeis"INSTANT"(the default: book now) or"HOLD".- Idempotency is the
Idempotency-KeyHEADER (required on/book) — there’s no body field for it. Make a new UUID for each booking, persist it, and send the same value only when you resend the same request.externalReferenceis your own order number (up to 120 characters). Kitionz stores it and returns it on the booking. Send it on every booking: if you lose Book’s answer,GET /v1/flights/bookings?externalReference=ORDER-1001finds the booking. Kitionz does not check it for uniqueness.- Test is lenient: Kitionz Test Air accepts any title, phone or country. Live sellers refuse what they cannot take (below), so follow these rules in Test too.
- Names, booker details and passport fields are plain text: no control characters (tab, line feed and carriage return are allowed) and no half of an emoji. Kitionz refuses such a value with
400 VALIDATION_ERRORbefore anything is booked. A value pasted from a document can hide one — ask the customer to retype the fielderror.details.invalidFieldsnames.
Critical: reuse the SAME idempotency value on retries. A new key = a new booking. If your
/bookrequest times out, send the identical request again with the same key: you get the first booking back, or409while it is still running. The booking is reserved before Kitionz asks the supplier to book, so a retry with the same key can never book twice. Book answers201when a booking was recorded, even one the supplier refused, except a refusal you can act on (402,409, a400 BOOK_…code): that comes as the error, and nothing was booked. Decide bydata.statusand do whatdata.nextActionsays, not by the HTTP code — and never bypnr(aHELDbooking already has a PNR and is not ticketed).
Which id to keep
Key your orders on id, never on the PNR (two airlines can issue the same PNR). Kitionz does not
return e-ticket numbers or the ticket document: get them from the seller named in the booking’s
seller.name.
Book variants — confirm now vs hold-then-ticket
The fields of this call and a real answer are on its page: Book.
Note — What can go wrong here?
QUOTE_TOKEN_EXPIRED→ the token’s ~15 min passed. Re-quote, show the (possibly new) price, book with the fresh token.QUOTE_TOKEN_ALREADY_USED→ this token already made a booking:error.details.existingBookingIdandexistingBookingStatusname it. Read that booking. Quote again and book with a new key only if it isFAILED.IDEMPOTENCY_KEY_REQUIRED→ the header is missing. AddIdempotency-Key: <uuid>(and persist the uuid on your order row).SUPPLIER_INSUFFICIENT_BALANCE(402) → your balance with this seller is too low. Nothing was booked. If the seller refused at the booking call, aFAILEDbooking is left inGET /v1/flights/bookingswith the seller inseller.name; if it refused when Kitionz checked the price again, no booking is left. Top up with the seller, then quote and book again with a new Idempotency-Key.SUPPLIER_FARE_CHANGED_AT_BOOK,FARE_HIGHER_THAN_QUOTED,INSUFFICIENT_SEATS(409) → the fare or seats changed just before booking. Nothing was booked. Quote again and show the new price.400 BOOK_CONTACT_EMAIL_REQUIRED,BOOK_CONTACT_PHONE_UNSUPPORTED,BOOK_PASSENGER_TITLE_UNSUPPORTED,BOOK_PASSENGER_COUNTRY_UNSUPPORTED→ this seller cannot take one detail as sent. Nothing was booked. Fix it and book again with a new Idempotency-Key.CAPABILITY_NOT_SUPPORTED,HOLD_NOT_SUPPORTED_FOR_THIS_OFFER(422, Book withbookingMode: "HOLD") → this offer cannot be held. Book withbookingMode: "INSTANT".PASSENGER_FIELD_REQUIRED,PASSPORT_EXPIRY_TOO_SOON(422) → a passenger misses what the offer needs.error.details.invalidFieldslists each one.
Step 4 — Check the result
Critical — when to take the money. Take your customer’s payment just before
/book(a quote lasts 15 minutes). Then act on the booking:
CONFIRMEDorHELD→ keep the payment.FAILED, or any other4xxfrom/book→ refund it: nothing was booked.RESERVEDorPENDING_CONFIRMATION(nextAction.code: WAIT), a5xx, no answer,409 BOOKING_IN_PROGRESSor409 IDEMPOTENT_REQUEST_IN_PROGRESS(the first request may still book) or409 QUOTE_TOKEN_ALREADY_USED(a booking from this quote exists, inerror.details.existingBookingId) → keep it: the booking may exist. Do not refund and do not book again: send the same request again with the same key, or read the booking, until it readsCONFIRMEDorFAILED. Most settle within 10 minutes; still pending after 20 minutes, contact Kitionz support.Kitionz takes no money for a booking: you pay the seller from your own account with that seller.
What: resolve the real outcome. Every booking carries nextAction (never null): a code, a
plain description, and the call to make (method, path) when there is one. Decide by status
and nextAction.code — never by pnr:
A booking is FAILED only when the supplier clearly refused it (sold out, fare gone) or the
request never reached the supplier. When the supplier’s answer is unclear — a timeout, an answer
Kitionz cannot read, or the supplier accepted but Kitionz could not save its answer — the booking
is PENDING_CONFIRMATION, never FAILED, and Kitionz checks it with the supplier. Do not book
that trip again while it is PENDING_CONFIRMATION.
RESERVED reads like PENDING_CONFIRMATION (WAIT). A FAILED booking can have empty
passengers and segments; its origin, destination, departureDate, policy and
baggage say what was tried. Every status and its next action is in the
Flights reference. Never book again while a booking is RESERVED or
PENDING_CONFIRMATION.
Critical — Kitionz does not watch confirmed bookings for airline changes yet.
SCHEDULE_CHANGEDis not produced today. On a confirmed booking,CANCELLED_BY_SUPPLIERappears only after a call that asks the seller, such asPOST /v1/flights/bookings/{id}/refresh, and the seller reports the booking cancelled; itsnextAction.codeisCONTACT_SUPPLIER. No webhook is sent for either. Sellers and airlines send changes to the booking contact — your organisation’s registered email and mobile. To catch changes, watch each booked flight with Flight Status (POST /v1/flight-status/monitors) and refresh the booking the day before departure.
Note — request bookings expire. A
PENDING_FULFILMENTrequest carries its deadline innextAction.deadlineAt: the earlier of 72 hours (by default) after it was booked and the first flight’s departure. After it, Kitionz may cancel the request at any time: it becomesCANCELLED, and/fulfilthen answers409 BOOKING_NOT_PENDING. Book on the seller’s site (seller.website) straight away — the fare there can go much sooner — with the same flights, date and passengers, then send the airline PNR. Kitionz records the quoted total; it does not see what you paid on the seller’s site.
Read it with Get a booking: its recorded answer is
a booking Kitionz is still confirming (PENDING_CONFIRMATION, nextAction.code WAIT). A booking
the supplier refused is FAILED, with failure.code (for example SUPPLIER_BOOK_FAILED) and
nextAction.code SEARCH_AGAIN: nothing was booked and nothing charged.
The wording of description and failure.message can change. Branch on the codes.
The two failure modes — handle them differently
Critical: Never show the customer an error when a request times out. A real, billable booking may exist behind a timeout or a
PENDING_CONFIRMATION.
- No answer, a timeout or any
5xxfrom/book: you have no booking id yet. Send the identical request again with the SAMEIdempotency-Key: you get the first booking back, or409 BOOKING_IN_PROGRESS/IDEMPOTENT_REQUEST_IN_PROGRESSwhile it is still running (wait a few seconds and send it again), or409 QUOTE_TOKEN_ALREADY_USEDnaming the booking inerror.details.existingBookingId— read that booking. Never use a new key. 500 BOOKING_OUTCOME_UNKNOWN: the supplier may have booked, but Kitionz could not record its answer.error.details.bookingIdnames the booking when there is one — read it. Do not book that trip again; contact Kitionz support with therequest_id.PENDING_CONFIRMATION(you got a response): the booking may exist. With asupplierReferencethe supplier accepted it and Kitionz checks for the PNR; without one, Kitionz settles it with the supplier. ReadGET /v1/flights/bookings/{id}everynextAction.pollAfterSeconds; most settle within 10 minutes. No webhook is sent for this change.- Still pending after 20 minutes: contact Kitionz support with the booking id and
request_id. Keep the customer’s payment and do not book again.
Need a fresh pull from the supplier (not the stored booking)? Use
POST /v1/flights/bookings/{id}/refresh — it asks the supplier directly and updates the
stored booking. Use it only now and then, for example when your customer asks; for routine
waiting, the plain GET is enough, because Kitionz already checks the supplier for you.
Read variants — read once, or wait for a pending booking
The fields of this call and a real answer are on its page: Get a booking.
Note — What can go wrong here?
- Status stuck in
PENDING_CONFIRMATIONpast 20 minutes → contact Kitionz support with the booking id andrequest_id; keep the customer’s payment and do not book again.- 404 on the booking id → you’re reading with a different key/org than the one that booked, or the id is mistyped (
bkg_…).
Step 5 — Ticket (only if HELD)
Only Kitionz Test Air supports holds today; with your Live suppliers a booking never comes back HELD.
A HELD booking must be ticketed before a supplier-imposed deadline.
If Step 4 shows HELD, issue the ticket:
send POST /v1/flights/bookings/{id}/ticket with a new Idempotency-Key
(Ticket a hold).
A CONFIRMED booking needs no ticketing call — skip this step. Asking again for a booking that is
already CONFIRMED answers 200 with the booking and does not ask the supplier again. A 202 means the
supplier accepted the request and has not finished: read the booking until it is CONFIRMED.
Note — What can go wrong here?
nextAction.deadlineAtpassed → the seller may have released the seats, and Kitionz does not change the status. Ask the seller; if released, start a fresh search → quote → book.BOOKING_NOT_TICKETABLE(409) → the booking is notHELD(for exampleFAILEDorCANCELLED). Read it; nothing to ticket.TICKETING_REFUSED(422) → the supplier refused to ticket. The booking staysHELD: try again beforenextAction.deadlineAt, or contact the seller named inseller.name.
Cancel and refund in Live
Only Kitionz Test Air cancels and refunds confirmed bookings through the API today. On a Live
booking, /cancel answers 422 CANCEL_WITH_SUPPLIER. A PENDING_FULFILMENT request can be withdrawn
with /cancel on every supplier. With a Live booking:
- Cancel with the seller named in the booking’s
seller.name, by phone or email. The seller applies the fare’s penalty and refunds you to your account with them, on their timeline. Kitionz is not told and does not track the refund. - The Kitionz booking stays
CONFIRMED: record the cancellation in your own system. If you later call/refreshand the seller reports the cancellation, the booking readsCANCELLED_BY_SUPPLIER— for a cancellation you asked for, that does not mean the airline cancelled. - The offer’s
capabilities.cancellationsays how cancelling works:REALTIME—/cancelcancels through Kitionz (only Kitionz Test Air today);OFFLINE— the seller cancels by phone or email;NONE— Kitionz has no cancellation path for this seller: ask the seller.
Before you go Live
Follow Going Live on the Flights overview: it lists every step, in order. Your integration is ready for Live when:
- One new
Idempotency-Keyper write (booking, cancel…), persisted on your side for safe retries. - Your screens handle “not stated” (
null,NOT_GIVEN): Live sellers leave many values unstated. Test Air does the same, so a screen that works in Test should hold. - Your passenger form follows the Live rules (titles, Indian mobile, two-letter countries, passports on international trips): Test Air accepts anything.
- Handle
PENDING_CONFIRMATIONby reading the booking until it settles (nextAction.code: WAIT) — this is the difference between a clean integration and lost bookings.
When things go wrong
Every 4xx/5xx has the same envelope, so you can handle errors generically: error.type,
error.code, error.message, error.doc_url and error.request_id (see the
Introduction).
Give the request_id to support when you need help. Follow doc_url for help with the error: in
Test it opens the public Error codes page; in Live, the error’s own page on the
kitionz.com console (sign in first). The common booking-path codes and what to
do about each:
FARE_QUOTE_UNUSABLE (422). Kitionz checks every fare quote, and the fare again just before
booking. A fare that fails is not quoted or booked, and no money moves. error.supplierError.failureClass
says why: TOTAL_NOT_POSITIVE (the total is ₹0 or less, or not a number), CURRENCY_NOT_INR,
TOTAL_ABOVE_CEILING (far above any real fare), PRICED_FOR_ANOTHER_PARTY (priced for a different
number of passengers: search again with the passengers you will book), PASSENGER_NOT_PRICED (an adult
or child has no price), LINES_DO_NOT_ADD_UP (the per-passenger prices do not add up to the total). A
missing infant price is never this error: the quote comes back with
price.infantFare.status: NOT_GIVEN.
FARE_RECHECK_FAILED (409). Kitionz could not confirm this fare as quoted just before booking.
Nothing was booked or charged. The reason is in error.supplierError.failureClass. What to do:
- Call
/fare-quoteagain. If it succeeds, book with the newquoteToken. SUPPLIER_UNAVAILABLE: the supplier is failing right now, so Kitionz did not ask it. Wait about 30 seconds before you try again.INFANT_PRICE_WITHDRAWN: you were quoted an infant price and the supplier gives none now. The new quote showsinfantFare.status: NOT_GIVEN, and itstotalAmountcovers adults and children only, so add your own infant charge before you book.INFANT_PRICE_APPEARED: your quote saidNOT_GIVENand the supplier now gives an infant price. The new quote showsPRICEDwith the infant insidetotalAmount, so remove your own infant charge before you book.- If
/fare-quotekeeps failing, search again or choose another offer.
See the full Error codes reference for every code, its meaning, and the fix.