← All @molecule/* packages · App templates
@molecule/api-flightsCore interface · flights · API (Node) · v1.0.1 · Apache-2.0
Flight search + offer pricing core interface for molecule.dev
npm install @molecule/api-flights@molecule/api-flights is the flights core interface on the API (Node) side: the API your app calls, with no vendor inside.
Choose the implementation by bonding one of its 1 provider: @molecule/api-flights-amadeus.
import { setProvider, searchFlights, priceOffer } from '@molecule/api-flights'
import { provider as amadeus } from '@molecule/api-flights-amadeus'
setProvider(amadeus)
const offers = await searchFlights({
origin: 'JFK',
destination: 'LHR',
departureDate: '2026-07-15',
adults: 1,
})
const priced = await priceOffer(offers[0].id)Providers (1): @molecule/api-flights-amadeus
Works with: @molecule/api-bond, @molecule/api-i18n
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Provider-agnostic flights interface for molecule.dev.
Defines the {@link FlightsProvider} interface for flight search +
pricing. Bond packages (Amadeus, Duffel, Sabre, etc.) implement this
interface. Application code uses the convenience functions
(searchFlights, getOffer, priceOffer) which delegate to the bonded
provider.
import { setProvider, searchFlights, priceOffer } from '@molecule/api-flights'
import { provider as amadeus } from '@molecule/api-flights-amadeus'
setProvider(amadeus)
const offers = await searchFlights({
origin: 'JFK',
destination: 'LHR',
departureDate: '2026-07-15',
adults: 1,
})
const priced = await priceOffer(offers[0].id)
core
npm install @molecule/api-flights @molecule/api-bond @molecule/api-i18n
FlightOfferNormalized flight offer returned by {@link FlightsProvider.searchFlights}.
interface FlightOffer {
/**
* Provider-specific opaque offer identifier.
*/
id: OfferId
/**
* Total grand-total price for ALL passengers in {@link currency}.
*/
price: number
/**
* Currency the {@link price} is expressed in (e.g. `'USD'`).
*/
currency: CurrencyCode
/**
* Flight segments, in chronological order. For round-trip itineraries
* outbound segments precede return segments. For multi-city the order
* matches the requested itinerary.
*/
segments: Segment[]
/**
* Total elapsed time across all segments (including layovers).
*/
duration: IsoDuration
}
FlightOfferDetailDetailed flight offer returned by {@link FlightsProvider.getOffer}.
Extends {@link FlightOffer} with a per-passenger price breakdown and an
optional source-data envelope. Providers that do not naturally support a
"fetch single offer" call MAY return the same offer they previously
returned from searchFlights here (without a fresh upstream round-trip).
interface FlightOfferDetail extends FlightOffer {
/**
* Per-passenger price breakdown rows. `null` when the upstream does not
* supply the breakdown.
*/
travelerPricings?: TravelerPricing[] | null
}
FlightsProviderFlights provider interface.
All flight providers (Amadeus, Duffel, Sabre, etc.) implement this interface. The interface is deliberately minimal so providers with very different upstream APIs can satisfy it identically. Providers that lack a "fetch single offer" call typically implement {@link getOffer} by round-tripping through their pricing endpoint and returning the priced offer.
interface FlightsProvider {
/**
* Searches for flight offers matching the supplied itinerary.
*
* @param options - Search parameters (origin, destination, dates,
* passenger counts, cabin, etc.).
* @returns Array of normalized flight offers.
*/
searchFlights(options: SearchFlightsOptions): Promise<FlightOffer[]>
/**
* Retrieves a previously-searched offer in detail.
*
* @param offerId - Opaque offer identifier returned by
* {@link searchFlights}.
* @returns The offer with per-passenger price breakdown when available.
*/
getOffer(offerId: OfferId): Promise<FlightOfferDetail>
/**
* Confirms the up-to-the-minute price for a previously-searched offer.
*
* @param offerId - Opaque offer identifier returned by
* {@link searchFlights}.
* @returns Authoritative price snapshot.
*/
priceOffer(offerId: OfferId): Promise<PricingResult>
}
PricingResultResult returned by {@link FlightsProvider.priceOffer}.
The price and currency reflect the upstream's authoritative price as
of the moment of the call — providers MAY return a different price than
the original {@link FlightOffer.price} if availability or fare rules
have shifted between search and pricing.
interface PricingResult {
/**
* Original opaque offer identifier the call was made for.
*/
offerId: OfferId
/**
* Authoritative grand-total price as of the moment of pricing.
*/
price: number
/**
* Currency the {@link price} is expressed in.
*/
currency: CurrencyCode
/**
* Per-passenger price breakdown rows. `null` when the upstream does not
* supply the breakdown.
*/
travelerPricings?: TravelerPricing[] | null
/**
* Timestamp the pricing snapshot was observed/published.
*/
pricedAt: Date
}
SearchFlightsOptionsOptions accepted by {@link FlightsProvider.searchFlights}.
interface SearchFlightsOptions {
/**
* Origin IATA airport / city code (e.g. `'JFK'`, `'NYC'`).
*/
origin: AirportCode
/**
* Destination IATA airport / city code.
*/
destination: AirportCode
/**
* Outbound departure date (ISO 8601 calendar date, e.g. `'2026-07-15'`).
*/
departureDate: IsoDate
/**
* Return date for round-trip searches. Omit for one-way.
*/
returnDate?: IsoDate
/**
* Adult passenger count (>=12 years). Defaults to `1` when omitted.
*/
adults?: number
/**
* Child passenger count (2-11 years). Defaults to `0` when omitted.
*/
children?: number
/**
* Infant passenger count (<2 years, lap or seated). Defaults to `0`
* when omitted.
*/
infants?: number
/**
* Cabin class to search for. Defaults to `'economy'` when omitted.
*/
cabin?: CabinClass
/**
* Maximum number of offers to return. Implementations MAY clamp this
* to whatever upper bound their upstream API enforces.
*/
maxResults?: number
}
SegmentOne leg of a {@link FlightOffer} — a single take-off / landing pair on a single operated flight.
interface Segment {
/**
* Departure airport / instant.
*/
departure: SegmentEndpoint
/**
* Arrival airport / instant.
*/
arrival: SegmentEndpoint
/**
* Marketing carrier IATA code (e.g. `'AA'`, `'BA'`).
*/
carrier: CarrierCode
/**
* Marketing flight number (e.g. `'100'`, `'1234'`).
*
* String rather than number to preserve any leading zeros and to
* accommodate alphanumeric carriers (e.g. EasyJet's `'EZY'` prefix).
*/
flightNumber: string
/**
* IATA aircraft code (e.g. `'77W'`, `'320'`). `null` when the upstream
* does not supply aircraft data for this segment.
*/
aircraft?: string | null
/**
* Block / total time the segment is in the air. `null` when the upstream
* does not supply per-segment duration.
*/
duration?: IsoDuration | null
}
SegmentEndpointDeparture or arrival point on a {@link Segment}.
interface SegmentEndpoint {
/**
* IATA airport code (e.g. `'JFK'`).
*/
airport: AirportCode
/**
* Local-time instant including timezone offset.
*/
at: IsoDateTime
/**
* Terminal designator (e.g. `'4'`, `'2A'`). `null` when not supplied.
*/
terminal?: string | null
}
TravelerPricingPer-passenger price row inside {@link FlightOfferDetail.travelerPricings}.
interface TravelerPricing {
/**
* Provider-specific traveler id (typically a 1-indexed string).
*/
travelerId: string
/**
* Adult, child, or infant. The infant variant is split between
* lap-infants (`'held-infant'`) and seated infants (`'seated-infant'`)
* because they are priced differently by most carriers.
*/
travelerType: 'adult' | 'child' | 'held-infant' | 'seated-infant'
/**
* Total price for this traveler in the offer's currency.
*/
price: number
/**
* Cabin class booked for this traveler. `null` when mixed across
* segments or not supplied.
*/
cabin?: CabinClass | null
}
AirportCodeIATA airport or city code (e.g. 'JFK', 'LAX', 'PAR').
Kept as a plain string alias rather than a string-literal union so
providers can support whatever set of airports / metropolitan codes their
upstream exposes.
type AirportCode = string
CabinClassCabin class enumeration.
Providers map each value onto whatever upstream code they require
(e.g. Amadeus uses 'ECONOMY' | 'PREMIUM_ECONOMY' | 'BUSINESS' | 'FIRST').
type CabinClass = 'economy' | 'premium-economy' | 'business' | 'first'
CarrierCodeIATA two-character airline / marketing carrier code (e.g. 'AA',
'BA', 'AF').
type CarrierCode = string
CurrencyCodeISO 4217 three-letter currency code (e.g. 'USD', 'EUR', 'JPY').
Conventionally upper-case to match {@link FlightOffer.currency} and the vast majority of upstream travel APIs.
type CurrencyCode = string
IsoDateISO 8601 calendar date (e.g. '2026-07-15'). Time-of-day MUST NOT be
included; this is a date for searching availability, not a timestamp.
type IsoDate = string
IsoDateTimeISO 8601 instant including timezone offset
(e.g. '2026-07-15T08:30:00+02:00').
Providers SHOULD preserve the upstream offset where available; consumers
that want a Date can new Date(value) it.
type IsoDateTime = string
IsoDurationISO 8601 duration string (e.g. 'PT2H30M', 'PT11H45M').
Plain string for the same reason as {@link IsoDate} — providers differ on whether they expose seconds-precision, fractional minutes, etc.
type IsoDuration = string
OfferIdProvider-specific offer identifier.
Opaque token returned by {@link FlightsProvider.searchFlights} that can be passed back to {@link FlightsProvider.getOffer} or {@link FlightsProvider.priceOffer}. Identifier scheme is provider-defined and MUST NOT be parsed by consumers.
type OfferId = string
getOffer(offerId)Retrieves a previously-searched offer in detail.
function getOffer(offerId: string): Promise<FlightOfferDetail>
offerId — Opaque offer identifier returned by searchFlights.Returns: The offer with per-passenger price breakdown when available.
getProvider()Retrieves the bonded flights provider, throwing if none is configured.
function getProvider(): FlightsProvider
Returns: The bonded flights provider.
hasProvider()Checks whether a flights provider is currently bonded.
function hasProvider(): boolean
Returns: true if a flights provider is bonded.
priceOffer(offerId)Confirms the up-to-the-minute price for a previously-searched offer.
function priceOffer(offerId: string): Promise<PricingResult>
offerId — Opaque offer identifier returned by searchFlights.Returns: Authoritative price snapshot.
searchFlights(options)Searches for flight offers matching the supplied itinerary.
function searchFlights(options: SearchFlightsOptions): Promise<FlightOffer[]>
options — Search parameters (origin, destination, dates, passenger counts, cabin, etc.).Returns: Array of normalized flight offers.
setProvider(provider)Registers a flights provider as the active singleton. Called by bond
packages (e.g. @molecule/api-flights-amadeus) during application
startup.
function setProvider(provider: FlightsProvider): void
provider — The flights provider implementation to bond.| Provider | Package |
|---|---|
| Amadeus | @molecule/api-flights-amadeus |
Peer dependencies:
@molecule/api-bond ^1.0.1@molecule/api-i18n ^1.0.1@molecule/api-bond
@molecule/api-i18n
Offer ids are opaque, provider-scoped, and short-lived. Never parse
them and never persist them as durable references — a stale id fails
getOffer/priceOffer; re-run the search instead of replaying old ids.
Re-price before you commit. PricingResult.price is the
authoritative total at pricing time and MAY differ from the search-time
FlightOffer.price — call priceOffer() right before the checkout/
summary step and display the re-priced figure.
This contract is search + pricing only — there is no booking method.
Don't invent a bookFlight(); booking needs vendor-specific work outside
this interface.
Server-side only; cache searches. Flight-search APIs are slow, rate-limited, and often billed per call — cache results per (origin, destination, dates, passengers) for a short TTL and never fire a search per keystroke.
Airports/cities are IATA codes ('JFK', 'NYC'), dates are ISO calendar
dates ('2026-07-15'), and prices carry an explicit ISO 4217 currency —
format with it, never a hardcoded $.
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual search / results screens, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
searchFlights offers rendered in the results list — each
showing an origin, a destination, departure/arrival times, and a price. No
empty list, null, or placeholder row is presented as a successful search.segment.departure.airport
and last segment.arrival.airport are the searched cities and the
departure.at falls on the requested date — not random routes or dates.currency (ISO 4217, formatted with it — never a
hardcoded $) and is sane (positive, right order of magnitude). If a
checkout/summary step re-prices via priceOffer/getOffer, the displayed
total is the re-priced figure, not the stale search-time price.bookFlight). If
the app adds a book/hold step it goes OUT-OF-BAND to the vendor — verify
the app records the SELECTED offer (its priced total + itinerary), since
opaque OfferIds are short-lived and can't be replayed later.