x402-flight-search

Flight offers, confirmed pricing, and pay-per-poll fare watching over the Amadeus API. One paid HTTP call, answer in the response body. Pay in USDC on Base or Solana — your client picks the rail.

git clone https://github.com/nirholas/x402-flight-search && cd x402-flight-search && npm install && npm run dev

Pricing

RoutePriceYou get back
GET /search$0.005Flight offers for a route and date — carriers, segments, cabin, total fare
GET /price/:offerId$0.003Confirmed priced offer, re-priced against the carrier
GET /check$0.002Cheapest-fare snapshot + delta vs the price you pass in
GET /healthfreeService status and which data source is live
GET /airportsfreeIATA codes the fixture data covers well
GET /.well-known/x402freeMachine-readable price sheet, both rails

A full "find and confirm" is $0.008. Watching a fare costs $0.002 per look, and nothing accrues between polls.

Two rails, one challenge

Every 402 lists both networks. A caller holding USDC on Base pays on Base; a caller holding USDC on Solana pays on Solana. Same route, same price, same artifact.

EVM

USDC on Base

base-sepolia by default, base for mainnet. EIP-3009 transfer authorization.

0x40252CFDF8B20Ed757D61ff157719F33Ec332402
SVM

USDC on Solana

solana mainnet by default, solana-devnet for testing. SPL transfer.

WwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwW

How a query flows

402quote in USDC on
Base and Solana
signclient picks a rail
and signs
retrysame request +
X-PAYMENT
200offers in body,
receipt in header

Quickstart

# 1. Run the service (works immediately — no keys needed)
cp .env.example .env
npm run dev                # http://localhost:4022

# 2. See the dual-rail 402 quote (no wallet needed)
curl -s "http://localhost:4022/search?origin=JFK&destination=LAX&date=2026-09-15" \
  | jq '.accepts[] | {network, payTo, maxAmountRequired}'

# 3. Pay for real on Base Sepolia (free test USDC: faucet.circle.com)
export PRIVATE_KEY=0x…
npm run client             # searches, confirms a price, runs a fare check

Live data vs fixtures

Amadeus is a keyed API, so the service is env-gated: set AMADEUS_CLIENT_ID and AMADEUS_CLIENT_SECRET (free sandbox keys, no card) and every route hits the real API. Without them you get deterministic fixtures instead, so the demo always runs. Every response carries a source field"amadeus" or "fixture" — so a caller is never guessing which it got. Never quote a fixture fare as a real price.