Bowmark AIdocs

Flights

Search flights with one call and get back normalized, price-sorted results (the same physical flight appears once). Each result carries the site it came…

Search flights with one call and get back normalized, price-sorted results (the same physical flight appears once). Each result carries the site it came from (site) and every site it was found on (sites). Returns { flights, warnings }warnings names any site that was dropped from the fan-out, so a degraded search cannot read as a complete one.

Also known as: flight, airfare, airline, airlines, fly, plane ticket, air ticket, flight ticket, plane fare

Call it

bowmark.flights.search(query: FlightQuery, options?: CallOptions): Promise<FlightSearchResult>
bowmark.flights.getBookingOptions(flight: FlightResult, options?: CallOptions): Promise<BookingOptionsResult>
bowmark.flights.getFlightStatus(query: FlightStatusQuery, options?: CallOptions): Promise<FlightStatusResult>

Functions

FunctionWhat it does
searchSearches for flights matching the query and returns { flights, warnings }. flights are normalized FlightResults, price-sorted, deduped so the same physical flight appears once; each…
getBookingOptionsEvery seller on offer for ONE result — pass the whole row from search(), not its id.
getFlightStatusA flight's live status, checked directly with the airline that flies it.

Types

type FlightQuery = {
  from: string          // IATA ("SFO") — best for cross-provider matching
  to: string
  depart: string        // ISO date "2026-09-01"
  return?: string       // omit for one-way
  cabin?: "economy" | "premium" | "business" | "first"
  stops?: "any" | "nonstop" | "1"
}

// One normalized flight. Same shape no matter where it came from.
type FlightResult = {
  price: number | null      // price for this flight (matches this result's times/label)
  currency: string
  airlines: string[]
  stops: number             // 0 = nonstop
  date: string              // the departure DATE this result is for ("2026-09-01"),
                            // stamped from the query — lets a date-range sweep tell days apart
  depart: string            // OUTBOUND departure TIME of day, "7:00 AM". For a round
                            // trip this describes the outbound leg only; the return-leg
                            // times are not in this object.
  arrive: string            // OUTBOUND arrival time, "3:30 PM" ("+1" if next day)
  durationMinutes: number | null
  tripType: "round trip" | "one way"
  url: string               // link to view/book this flight on its site
  site: string              // the site this result comes from
  sites: string[]           // every site this same flight was found on. A site MISSING
                            // here had no matching flight — it does NOT tell you the
                            // site was reached. Read warnings for that
  sponsored: boolean        // true if this result is a promoted placement
  id: string                // opaque handle for getBookingOptions()
}

type FlightSearchResult = {
  flights: FlightResult[]   // deduped and price-sorted; the answer
  warnings: string[]        // always present, empty when every site answered.
                            // One line per site DROPPED from the fan-out — read
                            // it before treating the rows as the whole market.
                            // A site missing from a result's sites list merely had no
                            // matching flight; that is NOT the same fact.
}

type CallOptions = {
  timeoutMs?: number   // per-provider budget in ms, default 30000, clamped to 1000-55000.
                       // A provider slower than this is DROPPED from the results and
                       // NAMED in warnings — never silently absent
}

// What getBookingOptions returns, one per fare on offer for a single result.
type BookingOption = {
  provider: string          // who would sell you this fare ("Frontier", "Expedia")
  fareType: string          // that seller's own name for it ("Basic Fare")
  price: number | null      // this fare's price; null where the seller quoted none
  currency: string
  deepLink: string | null   // straight to this fare, when the site exposes one —
                            // frequently null, so fall back to the result's url
}

type BookingOptionsResult = {
  options: BookingOption[]  // cheapest first; unpriced fares last
  warnings: string[]        // always present. Names what this seller list does NOT
                            // contain — fields the site left unreported, and the
                            // OTHER sites the same flight was found on, whose
                            // sellers are not in here. Empty means nothing dropped.
}

// Give EITHER flightNumber OR both origin and destination, plus date and airline.
type FlightStatusQuery = {
  airline: string          // IATA carrier code, e.g. "AA" — routes to the airline
                            // that flies it; there is no default to guess
  date: string              // the flight's ORIGIN date, ISO "2026-08-04"
  flightNumber?: string     // "100", "2005", or "AA2005"
  origin?: string           // IATA code — with destination, returns every NONSTOP
  destination?: string      // that airline flies on the route that day
}

// One leg's status, at one end of the flight.
type FlightStatusAirport = {
  airportCode: string
  cityName: string | null
  gate: string | null        // null is UNKNOWN, not "no gate" — normal for a flight
                              // weeks out
  terminal: string | null
  state: string | null
  country: string | null
  baggageClaim: string | null   // arrival end only
  scheduledTime: string | null  // ISO 8601 WITH the airport's own UTC offset
  estimatedTime: string | null
  actualTime: string | null     // what happened, once it has; null before the event
  scheduledBoardingTime: string | null   // departure end only
  estimatedBoardingTime: string | null
}

type FlightStatusLeg = {
  flightNumber: string
  airlineCode: string
  flightStatus: string | null      // the airline's own wording, verbatim
  flightStatusKey: string | null   // a stable key behind the wording — branch on
                                    // this, not the display string
  flightStatusColor: string | null   // the airline's own severity colour, where
                                      // it publishes one (GREEN, ORANGE, RED, ...)
  canceled: boolean
  diverted: boolean
  inFlight: boolean
  landed: boolean
  departure: FlightStatusAirport
  arrival: FlightStatusAirport
  equipment: {
    tailNumber: string | null
    equipmentCode: string | null
    iataName: string | null
    displayName: string | null    // e.g. "Airbus A321neo"
  }
  disruptionMessage: string | null   // the airline's own passenger-facing prose
  codeShare: boolean
  operatedBy: string | null
  marketingCarrier: string | null
  wifiAvailable: boolean | null
  powerPortAvailable: boolean | null
}

type FlightStatusResult = {
  date: string                  // echoed back, "YYYY-MM-DD"
  flightNumber: string | null   // null in route mode
  origin: string | null
  destination: string | null
  flights: FlightStatusLeg[]    // EMPTY IS AN ANSWER: no such flight that day
  warnings: string[]            // always present, same contract as every other
                                 // function on this capability
}

Examples

// One call returns every matching flight, normalized and price-sorted.
// Destructure BOTH halves — `warnings` is how you learn the fan-out was thin.
const { flights, warnings } = await bowmark.flights.search({
  from: "YVR", to: "SFO", depart: "2026-09-01", return: "2026-09-08",
});
// Read them first: a dropped site means "cheapest" is only the cheapest of what
// answered, and the real floor may be on the site that didn't.
for (const w of warnings) log(w);
const cheapest = flights.filter(f => f.price).sort((a, b) => a.price - b.price)[0];
log(`$${cheapest.price} ${cheapest.airlines[0]} — from ${cheapest.site}`);
return {
  cheapest,
  sitesChecked: [...new Set(flights.flatMap(f => f.sites))],   // which sites RETURNED FLIGHTS
  incomplete: warnings.length > 0,                             // ...and whether any never answered
  warnings,
  totalFlights: flights.length,
};
// Flexible dates: sweep a DATE RANGE, keep the cheapest nonstop per day, sort.
// search() takes ONE date, so compose — fan the range out in parallel, and each
// result carries `date` so you can tell the days apart. A tighter per-site budget
// keeps five parallel searches inside one tool call.
const range = ["2026-09-01", "2026-09-02", "2026-09-03", "2026-09-04", "2026-09-05"];
const perDay = await Promise.all(
  range.map(async (depart) => {
    // A tighter per-site budget keeps five parallel searches inside one tool call.
    const { flights, warnings } = await bowmark.flights.search(
      { from: "YVR", to: "SFO", depart, stops: "nonstop" },
      { timeoutMs: 20000 },
    );
    const priced = flights.filter(f => f.price != null);
    const cheapest = priced.sort((a, b) => a.price - b.price)[0];
    // Keep `depart` and `warnings` on EVERY day, including one that produced no
    // flight. A day whose whole fan-out dropped also has no `cheapest`, so
    // returning null here would discard the warnings from exactly the day that
    // most needed them — and the sweep would show a silent hole in the range.
    return { date: depart, cheapest: cheapest ?? null, warnings };
  }),
);
// Log warnings for the WHOLE range first, unfiltered — before anything is dropped.
for (const d of perDay) for (const w of d.warnings) log(`${d.date}: ${w}`);
// Then rank only the days that actually returned a flight.
const ranked = perDay.filter(d => d.cheapest)
  .map(d => ({ date: d.date, price: d.cheapest.price, airline: d.cheapest.airlines[0], site: d.cheapest.site, warnings: d.warnings }))
  .sort((a, b) => a.price - b.price);
// A day whose fan-out was thin is not comparable to a day whose wasn't.
const unpriced = perDay.filter(d => !d.cheapest).map(d => d.date);
if (unpriced.length) log(`no flight returned for: ${unpriced.join(", ")}`);
log(`cheapest day in range: ${ranked[0]?.date ?? "none"} at $${ranked[0]?.price ?? "?"}`);
return { ranked, unpriced };

Providers behind it

Provider
google_flightsGoogle Flights
kayakKayak
momondoMomondo
cheapflightsCheapflights
aaAmerican Airlines