← All @molecule/* packages · App templates
@molecule/api-travel-amadeusProvider bond · travel · API (Node) · v1.0.1 · Apache-2.0
Amadeus travel trip-planning aggregator (flights + hotels + activities) provider for molecule.dev
npm install @molecule/api-travel-amadeusnpm · Source on GitHub · Implements @molecule/api-travel
@molecule/api-travel-amadeus is a provider bond on the API (Node) side: it implements the travel core interface (@molecule/api-travel) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setProvider } from '@molecule/api-travel'
import { provider } from '@molecule/api-travel-amadeus'
setProvider(provider)Works with: @molecule/api-secrets, @molecule/api-travel
Secrets: AMADEUS_CLIENT_ID, AMADEUS_CLIENT_SECRET
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.
Amadeus travel trip-planning provider for molecule.dev.
Implements the TravelProvider interface against the Amadeus
Self-Service flight, hotel and activities APIs. Defaults to the
test sandbox (https://test.api.amadeus.com); set
AMADEUS_USE_PRODUCTION=true to route to production.
Reuses the same AMADEUS_CLIENT_ID / AMADEUS_CLIENT_SECRET
credentials as @molecule/api-flights-amadeus and
@molecule/api-hotels-amadeus — Amadeus issues a single
client-credentials pair per account that grants access to all of
its Self-Service products.
Cars are intentionally returned as an empty array: Amadeus does not expose a public car-rental API as of v22.
Hotels require a check-out date: searchTripOptions prices hotels only
when returnDate is supplied — a one-way search (where includeHotels
defaults to true) resolves with hotels: [] rather than throwing. Hotel
pricing is also best-effort per batch: individual batch failures are
swallowed and partial hotel results returned, so a short/empty hotels
array is not necessarily an upstream outage.
import { setProvider } from '@molecule/api-travel'
import { provider } from '@molecule/api-travel-amadeus'
setProvider(provider)
provider
npm install @molecule/api-travel-amadeus @molecule/api-secrets @molecule/api-travel
AmadeusTravelConfigConfiguration options for the Amadeus travel trip-planning provider.
The bond reuses the SAME OAuth2 client-credentials flow as
@molecule/api-flights-amadeus and @molecule/api-hotels-amadeus:
a single AMADEUS_CLIENT_ID / AMADEUS_CLIENT_SECRET pair grants
access to flights, hotels, points-of-interest (used for activities)
and any other Self-Service product on the same account. There is no
cross-bond shared cache — each provider instance mints its own token
— but credentials are interchangeable.
interface AmadeusTravelConfig {
/**
* OAuth2 client ID, sent as the `client_id` form field when minting
* a fresh access token.
*
* If omitted, the provider falls back to the `AMADEUS_CLIENT_ID`
* environment variable. Requests fail with a sanitized error if
* neither is set.
*/
clientId?: string
/**
* OAuth2 client secret, sent as the `client_secret` form field when
* minting a fresh access token.
*
* If omitted, the provider falls back to the `AMADEUS_CLIENT_SECRET`
* environment variable. The secret is NEVER included in any error
* message — token-mint failures redact it before bubbling up.
*/
clientSecret?: string
/**
* When `true`, routes requests to the production endpoint
* (`https://api.amadeus.com`). When `false` or omitted, uses the
* Self-Service test sandbox (`https://test.api.amadeus.com`).
*/
useProduction?: boolean
/**
* Base URL override. Takes precedence over {@link useProduction}.
*/
baseUrl?: string
/**
* Request timeout in milliseconds for both the token-mint call and
* the data-API calls. Defaults to `15000`.
*/
timeout?: number
/**
* Number of seconds to subtract from the upstream `expires_in`
* value before treating a cached token as stale. Defaults to `30`.
*/
tokenSkewSeconds?: number
}
AmadeusTravelMissingCredentialsErrorError thrown by the Amadeus travel provider when no client credentials are configured.
Never includes any credential value in its message or properties.
AmadeusTravelTokenMintErrorError thrown by the Amadeus travel provider when the OAuth2
token-mint call fails. The client_secret NEVER appears in this
error's message or properties.
AmadeusTravelUpstreamErrorError thrown by the Amadeus travel provider for any non-OK upstream data-API response. Never includes the OAuth secret.
createProvider(config)Creates an Amadeus travel trip-planning provider.
function createProvider(config?: AmadeusTravelConfig): TravelProvider
config — Provider configuration. Credentials may be supplied here directly or via the AMADEUS_CLIENT_ID and AMADEUS_CLIENT_SECRET environment variables.Returns: A {@link TravelProvider} backed by Amadeus.
MISSING_CREDENTIALSStable error code emitted by the Amadeus travel provider when neither
clientId nor clientSecret (nor their env-var fallbacks) are
configured.
const MISSING_CREDENTIALS: 'MISSING_CREDENTIALS'
providerThe default provider implementation, lazily initialized on first use.
Reads AMADEUS_CLIENT_ID, AMADEUS_CLIENT_SECRET,
AMADEUS_USE_PRODUCTION, and AMADEUS_BASE_URL from environment
variables. Use {@link createProvider} directly if you need to supply
configuration programmatically.
const provider: TravelProvider
TOKEN_MINT_FAILEDStable error code emitted by the Amadeus travel provider when the OAuth2 token-mint call fails.
const TOKEN_MINT_FAILED: 'TOKEN_MINT_FAILED'
travelAmadeusSecretDefinitionsSecret definitions required by the Amadeus travel bond.
const travelAmadeusSecretDefinitions: SecretDefinition[]
UPSTREAM_ERRORStable error code emitted by the Amadeus travel provider for any non-OK upstream HTTP response (including HTTP 429).
const UPSTREAM_ERROR: 'UPSTREAM_ERROR'
Implements @molecule/api-travel interface.
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-travel'
import { provider } from '@molecule/api-travel-amadeus'
export function setupTravelAmadeus(): void {
setProvider(provider)
}
Peer dependencies:
@molecule/api-secrets ^1.0.1@molecule/api-travel ^1.0.1AMADEUS_CLIENT_ID (required) — Amadeus API key
AMADEUS_CLIENT_SECRET (required) — Amadeus API secret
@molecule/api-secrets@molecule/api-travelIntegration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual trip-planning / 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:
searchTripOptions with a real origin ->
destination, a departureDate weeks out, and returnDate for a round
trip — e.g. JFK -> PAR) returns REAL results rendered in the UI: each
opted-in vertical (includeFlights / includeHotels / includeCars /
includeActivities) shows populated flights / hotels / cars /
activities, each an actual offer — never an empty list, a stuck spinner,
or a placeholder row presented as a successful search.FlightOffer's first
segments[].departure.airport is the searched origin and its last
arrival.airport the destination, on the requested dates; each
HotelOffer is at the destination with checkInDate / checkOutDate
equal to the searched departure / return dates — not random routes,
cities, or dates.includeFlights,
includeHotels, includeCars, or includeActivities adds ONLY that
section, and a vertical not requested (or one the provider can't serve,
e.g. cars) comes back as an EMPTY array — rendered as "none", never as a
failed or blank search. maxResultsPerCategory actually caps how many
offers each section shows. Any separate activities / cars screen calls
searchActivities / searchCars and renders its own ActivityOffer[] /
CarOffer[].price.total shows its ISO 4217 price.currency
(formatted with it — never a hardcoded $) and is sane: a flight total
is the grand total for ALL travelers, a hotel total covers the whole
stay, a car total the whole rental — positive and the right order of
magnitude.departureDate, a returnDate before it, or a route with no
availability — shows a clear per-section "no results" / "invalid" state,
not a crash and not a blank list presented as a successful search.ActivityOffer.bookingUrl or
the app's own checkout) — verify the app RECORDS the SELECTED offer (its
priced total + itinerary), since opaque OfferIds are short-lived and
can't be replayed later.