Skip to main content
Flight search in Travelbase is synchronous. A single POST /v1/air/search request returns all available offers immediately.

How it works

Travelbase uses a single‑request model: one call returns all live offers inline. Each offer in the response carries its own id — pass that directly to POST /v1/air/orders to confirm a booking.

Synchronous by design

One request, one response. Offers are returned inline — no polling loop, no separate offer‑fetch step required.

offer.id is your booking key

Every offer returned carries a unique id. Pass it directly to the orders endpoint — no intermediate lookup needed.

Offer expiry still applies

Each offer has an expires_at. Always check it before initiating a booking — expired offers cannot be booked.

Re‑search to refresh

If a user returns after an offer expires, run a new search. Never re‑present stale, cached offers.

Quickstart

1

Search for flights

Send a POST request with your origin, destination, date, and passenger details. The API responds immediately with a full list of bookable offers.
POST /v1/air/search
Content-Type: application/json
Authorization: Bearer <token>
{
    "slices": [
{
    "origin": "LOS",
    "destination": "LHR",
    "departure_date": "2025-09-14"
}
    ],
    "passengers": [
{ "type": "adult" }
    ],
    "cabin_class": "economy"
}
Response
{
    "data": {
    "slices": [...],
    "passengers": [...],
    "offers": [
{
    "id": "off_0000AEdFkLPQNPPHhwYUJk",
    "total_amount": "432.50",
    "total_currency": "USD",
    "expires_at": "2025-09-14T14:28:00Z",
    "owner": {
    "iata_code": "BA",
    "name": "British Airways"
},
    "slices": [...],
    "passenger_identity_documents_required": false
}
    ]
}
}
The offer.id returned in each offer object is your booking key. Store the ID of the offer your user selects — you’ll pass it directly to the orders endpoint.
2

Select an offer and book

Once the user picks an offer, pass its id to POST /v1/air/orders with passenger details and payment. No intermediate lookup is required.
POST /v1/air/orders
Content-Type: application/json
Authorization: Bearer <token>
{
    "selected_offers": ["off_0000AEdFkLPQNPPHhwYUJk"],
    "passengers": [
{
    "id": "pas_0001",
    "born_on": "1990-04-22",
    "email": "ada@example.com",
    "family_name": "Lovelace",
    "given_name": "Ada",
    "gender": "f",
    "phone_number": "+44 7700 900077",
    "title": "ms"
}
    ],
    "payments": [
{
    "type": "balance",
    "currency": "USD",
    "amount": "432.50"
}
    ]
}
A 201 Created response confirms the booking. The response body contains your order.id, booking reference, and full itinerary.
Always compare offer.expires_at to the current time before initiating payment. Booking an expired offer returns 422 offer_no_longer_available.

Request reference

POST /v1/air/search

FieldTypeRequiredDescription
slicesarrayOne or more route segments. Each requires origin, destination, and departure_date.
passengersarrayAt least one passenger with a type of adult, child, or infant_without_seat.
cabin_classstringPreferred cabin: economy, premium_economy, business, or first. Defaults to economy.
max_connectionsintegerMaximum connections per slice. Set to 0 for direct flights only.

Slice object

FieldTypeRequiredDescription
originstringIATA airport or city code for the departure point (e.g. LOS, LHR).
destinationstringIATA airport or city code for the arrival point.
departure_datestringISO 8601 date (YYYY-MM-DD). Covers all departures on this date.

Offer object

Every item in data.offers[] is a complete, bookable itinerary priced in real time.
PropertyDescription
idYour booking key. Pass this as selected_offers[0] when creating an order.
total_amountTotal price for all passengers as a decimal string.
total_currencyISO 4217 currency code (e.g. USD, NGN, GBP). Always display alongside total_amount.
expires_atISO 8601 datetime after which this offer can no longer be booked.
ownerAirline responsible for fulfilling the itinerary (iata_code, name).
slicesArray of slice objects — segments, stops, cabin, baggage allowance.
passenger_identity_documents_requiredWhether passport/ID numbers are required at the time of booking.

Best practices

Debounce search input

Avoid firing on every keystroke. Trigger search on form submission or after 400–600 ms of inactivity.

Respect offer expiry

Check offer.expires_at before showing the booking CTA. Prompt a re‑search if expiry is imminent.

Never cache stale offers

Don’t persist offers across sessions or page reloads. Run a fresh search each time the user begins a booking flow.

Sort client‑side

Offers are returned unordered. Sort by total_amount, duration, or stops in your UI — no extra API call needed.

Display currency correctly

Always render total_currency alongside total_amount. Offers from different airlines may be in different currencies.

Handle 422 gracefully

If booking returns offer_no_longer_available, redirect the user to a fresh search rather than surfacing a raw error.

Common mistakes

Travelbase’s search endpoint is synchronous. There is no offer_request_id to store or poll with. Offers are returned directly in data.offers[] on the initial response.Fix: Read offers from response.data.offers. Use each offer.id to proceed to booking.
There is no asynchronous pipeline. You do not need to call GET /v1/air/offers separately. All offers are included synchronously in the search response body.Fix: Remove any polling logic. A single POST /v1/air/search is the complete search flow.
Attempting to create an order with an expired offer returns 422 offer_no_longer_available, creating a dead‑end mid‑checkout.Fix: Compare offer.expires_at to Date.now() before showing the booking confirmation step. If expired, redirect to a new search.
Firing a new search on every component mount or route change wastes rate‑limit quota and introduces avoidable latency.Fix: Cache the search result in component or session state. Only re‑search when the user explicitly changes their query.
Displaying a price without its currency code is a compliance risk. Offers from different sources may return different currencies.Fix: Always render total_currency with total_amount. Format using Intl.NumberFormat with the user’s locale and the appropriate currency code.

Error reference

HTTP StatusCodeMeaning
400invalid_search_paramsMalformed request — check required fields, date formats, and IATA codes.
401unauthorizedMissing or invalid Authorization header.
422offer_no_longer_availableThe selected offer expired or sold out. Prompt the user to re‑search.
429rate_limit_exceededToo many requests — implement exponential backoff starting at 500 ms.
500internal_server_errorUpstream airline source error. Retry once, then contact support with the x-request-id header value.

API reference

POST /v1/air/search

Search for available flights. Returns a complete offers[] array synchronously.

GET /v1/air/offers/:id

Fetch full fare conditions, baggage rules, and seat availability for a single offer.

POST /v1/air/orders

Convert an offer into a confirmed booking using the offer.id from search.

Manage Orders

Handle post‑booking actions — cancellations, changes, and seat selection.

Next steps

Book an offer

Convert an offer into a confirmed booking with passenger details and payment.

Manage orders

Handle post‑booking flows — cancellations, amendments, and ancillary services.

Webhooks

Subscribe to real‑time events for order status, schedule changes, and more.