← All @molecule/* packages · App templates
@molecule/api-hotels-amadeusProvider bond · hotels · API (Node) · v1.0.1 · Apache-2.0
Amadeus self-service Hotel Search API provider bond.
npm install @molecule/api-hotels-amadeusnpm · Source on GitHub · Implements @molecule/api-hotels
@molecule/api-hotels-amadeus is a provider bond on the API (Node) side: it implements the hotels core interface (@molecule/api-hotels) 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-hotels'
import { provider } from '@molecule/api-hotels-amadeus'
setProvider(provider)Works with: @molecule/api-hotels, @molecule/api-secrets
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 hotels provider for molecule.dev.
Implements the HotelsProvider interface against the Amadeus
Self-Service hotels APIs. Provides hotel search (city or geo),
priced offer lookup (/v3/shopping/hotel-offers), and a booking
stub that explicitly surfaces "use the hosted checkout flow"
(Amadeus's direct hotel-booking endpoint requires PCI-compliant
card capture and is not safely callable from a generic bond).
Authentication uses Amadeus's OAuth2 client-credentials flow, with
the same AMADEUS_CLIENT_ID / AMADEUS_CLIENT_SECRET env vars
shared with @molecule/api-flights-amadeus. The bond mints and
caches tokens per-provider-instance.
The OAuth secret NEVER appears in error messages. URLs do not carry
authentication in the query string — the bearer token is sent via
the Authorization header — so URL-redaction is unnecessary.
import { setProvider } from '@molecule/api-hotels'
import { provider } from '@molecule/api-hotels-amadeus'
setProvider(provider)
provider
npm install @molecule/api-hotels-amadeus @molecule/api-hotels @molecule/api-secrets
AmadeusHotelsConfigConfiguration options for the Amadeus hotels provider.
Amadeus exposes a single OAuth2 client-credentials flow that is shared
across all of its product APIs (flights, hotels, points-of-interest,
etc.). The same AMADEUS_CLIENT_ID / AMADEUS_CLIENT_SECRET env vars
therefore drive both @molecule/api-flights-amadeus and
@molecule/api-hotels-amadeus. Token caching is per-provider-instance
— there is no cross-bond shared cache, but the OAuth pattern is
identical so credentials work interchangeably.
Amadeus exposes a free Self-Service "test" environment at
https://test.api.amadeus.com (sandbox data, generous rate limits) and a
paid production environment at https://api.amadeus.com. This bond
defaults to the TEST host — identical to @molecule/api-flights-amadeus
— so flights + hotels wired with one key pair hit the same host and a
token minted on one is accepted by the other. Set {@link useProduction}
(or the AMADEUS_USE_PRODUCTION=true env var, which both bonds honor) to
switch; a single env setting flips both together.
interface AmadeusHotelsConfig {
/**
* 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 error
* messages — 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`). Falls back
* to the `AMADEUS_USE_PRODUCTION=true` env var, which
* `@molecule/api-flights-amadeus` reads too — so one env setting flips
* both bonds to production together.
*/
useProduction?: boolean
/**
* Base URL override. Takes precedence over {@link useProduction}. When
* neither is set, defaults to the Self-Service test sandbox
* (`'https://test.api.amadeus.com'`). Pass `'https://api.amadeus.com'`
* for production, or any proxy URL for self-hosted setups.
*/
baseUrl?: string
/**
* Request timeout in milliseconds for both the token-mint call and the
* data-API calls. Defaults to `10000`.
*/
timeout?: number
/**
* Number of seconds to subtract from the upstream `expires_in` value
* before treating a cached token as stale. Defaults to `30`. Lower
* values reduce wasted token mints; higher values reduce the chance
* of using a token that expires mid-request.
*/
tokenSkewSeconds?: number
}
createProvider(config)Creates an Amadeus hotels provider.
function createProvider(config?: AmadeusHotelsConfig): HotelsProvider
config — Provider configuration. Credentials may be supplied here directly or via the AMADEUS_CLIENT_ID and AMADEUS_CLIENT_SECRET environment variables. Defaults to the Self-Service TEST host; set useProduction (or AMADEUS_USE_PRODUCTION) to route to production.Returns: A {@link HotelsProvider} backed by Amadeus.
sanitizeErrorMessage(message)Returns a sanitized copy of an error message body. Currently a no-op passthrough for the common "errors[].detail" shape — exposed for symmetry with the flights bond and to keep the redaction surface documented in one place.
function sanitizeErrorMessage(message: string): string
message — A free-form upstream error message.Returns: The same message, with any future-redacted patterns scrubbed.
BOOKING_NOT_SUPPORTEDError code raised when {@link HotelsProvider.bookHotel} is called. Amadeus's hotel-booking endpoint requires PCI-compliant card capture and is not safely callable from a generic backend bond — callers should use Amadeus's hosted checkout / "price the offer" flow instead.
const BOOKING_NOT_SUPPORTED: 'BOOKING_NOT_SUPPORTED'
hotelsAmadeusSecretDefinitionsSecret definitions required by the Amadeus hotels bond.
const hotelsAmadeusSecretDefinitions: SecretDefinition[]
MISSING_CREDENTIALSError code raised when a hotels-provider call is attempted with no
AMADEUS_CLIENT_ID and/or AMADEUS_CLIENT_SECRET configured (neither
via the config object nor via environment variables). Surfaced via
Error.cause so callers can distinguish it from upstream errors.
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 — the same set @molecule/api-flights-amadeus reads, so a
single AMADEUS_USE_PRODUCTION=true flips BOTH bonds to production
together. Defaults to the Self-Service TEST host. Use
{@link createProvider} directly if you need to supply configuration
programmatically.
const provider: HotelsProvider
TOKEN_MINT_FAILEDError code raised when the OAuth2 token-mint call fails (e.g. invalid
credentials, network error, non-2xx status). The error message NEVER
includes the raw client_secret.
const TOKEN_MINT_FAILED: 'TOKEN_MINT_FAILED'
UPSTREAM_ERRORError code raised when an Amadeus hotels data API call fails (e.g. a
non-2xx HTTP status, a structured errors[] body, etc.).
const UPSTREAM_ERROR: 'UPSTREAM_ERROR'
Implements @molecule/api-hotels interface.
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-hotels'
import { provider } from '@molecule/api-hotels-amadeus'
export function setupHotelsAmadeus(): void {
setProvider(provider)
}
Peer dependencies:
@molecule/api-hotels ^1.0.1@molecule/api-secrets ^1.0.1AMADEUS_CLIENT_ID (required) — Amadeus API key
AMADEUS_CLIENT_SECRET (required) — Amadeus API secret
@molecule/api-hotels
@molecule/api-secrets
Defaults to the TEST sandbox host (test.api.amadeus.com) — identical
to @molecule/api-flights-amadeus. Amadeus issues Self-Service TEST keys
first (production needs approval), and a token is host-specific, so the
safe default is TEST. Set AMADEUS_USE_PRODUCTION=true (or
useProduction/baseUrl on createProvider()) to route to production.
Because BOTH the flights and hotels bonds read the same
AMADEUS_USE_PRODUCTION env var, one setting flips them together — so a
travel app wiring flights + hotels with one key pair never has one bond
401ing on the wrong host.
bookHotel() ALWAYS throws (see the core's remarks) — implement checkout
on the vendor's hosted flow; search and priced offers are fully supported.
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
searchHotels with a cityCode or location) returns REAL
HotelSearchResults rendered in the UI — each with a name, its city /
address, and a fromPrice for the stay — never an empty list, a stuck
spinner, or placeholder cards. Results match the query: the right city, and
the dates / occupancy you entered are reflected in the prices shown.rating, amenities) actually
narrows / reorders the rendered list — e.g. a price sort puts the lowest
HotelPrice.total first; a 4–5 star filter drops lower-rated properties.checkOutDate not strictly after checkInDate) shows a visible "no
availability" empty state — never a crash, a blank screen, or fabricated
results.HotelOffer.price.total equals nights × nightly rate + any fees, in its
ISO 4217 HotelPrice.currency (no bare "123" with no symbol or code).getHotelOffers and shows its real rooms / rates (roomDescription +
price); selecting one records the chosen offerId in the app. Booking
itself goes out-of-band to the vendor (or bookHotel throws
BOOKING_NOT_SUPPORTED → a redirect) — verify the app's RECORDED
selection, not a fake in-app confirmation.