Streaming search
Flight and hotel searches ask many suppliers and can take 30–40 seconds to return. You don't have to wait for the full response before showing results. While the search runs, the server writes partial results to JSON files on the logs site. Poll those files and show results as they arrive, then switch to the final response when it comes back.
This is the same flow our own B2B portal uses. It's optional: if you only need the final result, send the search and wait for the response.
How it works
Pick a short_ref
Generate a value that is unique to this search, such as a UUID or a hash of the search body. Use letters, digits,
-and_only. The logs files are named after it.Send the search
POST /flight/searchorPOST /hotel/searchwithshort_refin the body. Keep the request open: it returns the final, complete result.Poll the log files
While the request is open,
GETthe two log files below every 2 seconds. A404means the file isn't written yet, so keep polling. Show the newest file that returnsstatus: "success".Use the final response
When the search response arrives, stop polling and replace what you showed with its
data. Use itstracking_idfor the next step (price check, rooms, booking).
Log file URLs
The files are on your brand's logs URL (see Environments), not on the API base URL. They are plain GET requests with no auth headers.
| Search | Quick results | Fuller results |
|---|---|---|
| Flight | {logs_url}/flight_logs/{short_ref}-basic.json | {logs_url}/flight_logs/{short_ref}.json |
| Hotel | {logs_url}/hotel_logs/{short_ref}-basic.json | {logs_url}/hotel_logs/{short_ref}.json |
| Hotel rooms | | {logs_url}/hotel_logs/room_logs/{short_ref}.json |
The -basic file is written first, with the suppliers that answered quickly. The other file is rewritten as more suppliers answer. Each write replaces the whole file. Don't merge one poll's results into the last one; replace them.
Flight
Send the search with short_ref:
{
"journey_type": "OneWay",
"segment": [
{
"departure_airport_type": "AIRPORT",
"departure_airport": "DAC",
"arrival_airport_type": "AIRPORT",
"arrival_airport": "DXB",
"departure_date": "2026-12-15"
}
],
"travelers_adult": 1,
"travelers_child": 0,
"travelers_child_age": [],
"travelers_infants": 0,
"travelers_infants_age": [],
"preferred_carrier": [],
"non_stop_flight": "any",
"baggage_option": "any",
"booking_class": "Economy",
"supplier_uid": "all",
"language": "en",
"fare_type": ["brand"],
"short_ref": "7f3c9a2e-5b1d-4e8a-9c0f-2a6d8e4b1c37"
}
Each log file has the same shape as the search response, with fewer results:
{
"status": "success",
"search_duration": "5 seconds",
"tracking_id": "11179474330880180GR6UB",
"total_fight": 9,
"currency": "BDT",
"data": [ { "flight_key": "…", "supplier_uid": "…", "flight_group": [], "price": {} } ],
"filter_data": { }
}
In one test search, the -basic file appeared after about 4 seconds with 9 flights. The full file reached 917 flights, and the search response returned after 35 seconds.
Hotel
Send POST /hotel/search with short_ref and poll the hotel_logs files the same way. Each log has the search response's status, tracking_id, total_hotel, data and filter fields.
{
"location": "Dubai, United Arab Emirates",
"radius": "auto",
"checkIn": "2026-12-15",
"checkOut": "2026-12-16",
"occupancies": [{ "adult": "2" }],
"guest_nationality": "BD",
"hotel_star_level": "any",
"breakfast_option": "any",
"supplier_uid": "all",
"short_ref": "c41e8b07-93d2-4a6f-b5e1-0d7a2f9c3e48"
}
POST /hotel/rooms takes a short_ref too. While it runs, poll hotel_logs/room_logs/{short_ref}.json. Use a new short_ref for the rooms call, not the one from the hotel search.
Example
async function streamingSearch(path, body, logsUrl, logsDir, onPreview) {
const shortRef = crypto.randomUUID();
let finished = false;
const final = fetch(`${API_BASE}${path}`, {
method: "POST",
headers: { "Content-Type": "application/json", apikey: API_KEY, secretecode: SECRET_CODE },
body: JSON.stringify({ ...body, short_ref: shortRef }),
})
.then((r) => r.json())
.finally(() => { finished = true; });
(async () => {
for (let i = 0; i < 20 && !finished; i++) {
await new Promise((r) => setTimeout(r, 2000));
for (const file of [`${shortRef}.json`, `${shortRef}-basic.json`]) {
const res = await fetch(`${logsUrl}/${logsDir}/${file}`).catch(() => null);
const log = res?.ok ? await res.json().catch(() => null) : null;
if (log?.status === "success" && !finished) { onPreview(log); break; }
}
}
})();
return final; // the complete result, with tracking_id
}
// streamingSearch("/flight/search", flightBody, LOGS_URL, "flight_logs", render);
// streamingSearch("/hotel/search", hotelBody, LOGS_URL, "hotel_logs", render);
Run this on your server. The search call needs your keys, which must never reach a browser. Forward previews to your front end however you like, for example with server-sent events.