{"openapi":"3.1.0","info":{"title":"LetsFG API","summary":"Agent-native travel search and booking — flights, hotels, transfers, activities. 400+ airlines via GDS/NDC + 140 local airline connectors. Multi-provider wholesale pricing, zero bias, $20-50 cheaper than OTAs.","description":"## What is LetsFG?\n\nAn API that lets AI agents search and book travel directly with airlines, hotels, and ground transport providers via NDC and GDS — the same systems suppliers themselves use. No OTA markup, no browser, no scraping. Pure API, designed for machines.\n\n**Plus 140 local airline connectors** that run on your machine (Ryanair, Wizz Air, EasyJet, Southwest, AirAsia, Norwegian, and 134 more) — completely **FREE**, no API key needed. Install with `pip install letsfg` and search immediately with `letsfg search-local`.\n\n## Why use LetsFG?\n\n- **Zero price bias** — travel websites (booking.com, Google Flights, Kayak) inflate prices based on demand, traffic, cookies, and repeat searches. We don't.\n- **Same exact services, just cheaper** — same airlines, same hotels, same schedules, $20-50 less\n- **Free search** — search as much as you want, no cost, no limits\n- **400+ airlines** — BA, AA, United, Delta, Lufthansa, easyJet, Ryanair, Emirates...\n- **140 local airline connectors** — FREE, no API key, run on your machine via Playwright + httpx\n- **300,000+ hotels** — wholesale net rates from multiple suppliers, cheaper than Booking.com\n- **Ground transfers** — private cars, taxis, shared shuttles, airport express\n- **300,000+ activities** — tours, museum tickets, day trips via wholesale suppliers\n- **Agent-native** — no browser, no CAPTCHA, just one fast API call\n- **Faster** — one API call vs loading slow travel websites in a browser\n- **Real bookings** — get actual airline PNR codes and hotel confirmations\n\n## Two Ways to Search Flights\n\n### Local Only (FREE, no API key)\n```bash\npip install letsfg\nletsfg search-local GDN BCN 2026-06-15\n```\nRuns 140 airline connectors locally. Completely free, unlimited.\n\n### With API Key (recommended — much better coverage)\nRegister for a free API key to also query enterprise GDS/NDC sources (Amadeus, Duffel, Sabre, Travelport) which add 400+ full-service airlines. Both local connectors AND cloud sources run simultaneously — results merged and deduplicated.\n\n## How it works (5 API calls)\n\n```\n1. POST /api/v1/agents/register      → Get API key (once)\n2. POST /api/v1/agents/setup-payment  → Attach card (once)\n3. POST /api/v1/flights/search        → Search flights (FREE)\n   POST /api/v1/hotels/search         → Search hotels (FREE)\n   POST /api/v1/transfers/search      → Search transfers (FREE)\n   POST /api/v1/activities/search     → Search activities (FREE)\n4. POST /api/v1/bookings/unlock       → Unlock offer ($1)\n5. POST /api/v1/bookings/book         → Book flight (FREE after unlock)\n```\n\n### Hotel booking workflow\n\n```\n1. POST /api/v1/hotels/search         → Get hotels with rate_key + rate_type\n2. POST /api/v1/bookings/unlock       → Unlock rate ($1) — pass booking_type='hotel' + rate_key\n3. POST /api/v1/hotels/book           → Book room (holder + paxes + unlocked rate_key)\n4. GET  /api/v1/hotels/voucher/{ref}  → Get guest voucher for check-in\n5. POST /api/v1/hotels/cancel         → Cancel or simulate cancellation\n```\n\n## Pricing\n\n| Action | Cost |\n|--------|------|\n| Search (flights, hotels, transfers, activities) | **Free** |\n| Unlock offer for booking | **$1.00** |\n| Book a flight | **Free** after unlock |\n| Book a hotel | **Free** after unlock |\n\n## Authentication\n\nAll endpoints (except register) require `X-API-Key` header.\nGet your key: `POST /api/v1/agents/register`\n\n## Important: passenger_ids\n\nFlight search results include `passenger_ids`. You **must** include these in the booking request — they map your passengers to the airline's offer.","version":"0.4.0"},"servers":[{"url":"https://api.letsfg.co","description":"Production"},{"url":"http://localhost:8080","description":"Local development"}],"paths":{"/api/v1/agents/register":{"post":{"tags":["agents"],"summary":"Register Agent","description":"Register a new agent — this is always the first step.\n\nNo authentication required. Send your agent name and email.\nReturns an `api_key` — use it as `X-API-Key` header in ALL subsequent requests.\n\n**Example request:**\n```json\n{\"agent_name\": \"my-travel-agent\", \"email\": \"agent@example.com\"}\n```\n\n**After registration:**\n1. Save your `api_key` — it's your permanent credential\n2. Next step: POST /api/v1/agents/setup-payment to attach a payment card\n3. Then you can search (free), unlock ($1), and book (free after unlock)","operationId":"register_agent_api_v1_agents_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/agents/link-github":{"post":{"tags":["agents"],"summary":"Link Github","description":"Link your GitHub account and verify you've starred LetsFG/LetsFG.\n\nStar the repo first: https://github.com/LetsFG/LetsFG\nThen call this with your GitHub username. Once verified, you get\n**free unlimited access forever** — unlock, book, checkout, everything.\n\n**Example request:**\n```json\n{\"github_username\": \"myusername\"}\n```\n\nThis is the recommended way to unlock access (replaces payment setup).","operationId":"link_github_api_v1_agents_link_github_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_link_github_api_v1_agents_link_github_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/agents/setup-payment":{"post":{"tags":["agents"],"summary":"Setup Payment","description":"Set up a payment method for an agent.\n\nAttach a payment method so the agent can unlock offers and book flights.\nAll future charges are automatic — no browser popups, no redirects.\n\n**Recommended (simplest):** Send a Stripe token.\n```json\n{\"token\": \"tok_visa\"}\n```\n\n**Alternative:** Send a Stripe PaymentMethod ID (from Stripe.js).\n```json\n{\"payment_method_id\": \"pm_xxx\"}\n```\n\n**Alternative:** Send raw card details (requires PCI-compliant Stripe account).\n```json\n{\"card_number\": \"4242424242424242\", \"exp_month\": 12, \"exp_year\": 2027, \"cvc\": \"123\"}\n```\n\nAfter setup, the ticket price + Stripe processing fees are charged automatically\nwhen you book a Duffel flight (GDS/NDC airlines). Kiwi flights are free.","operationId":"setup_payment_api_v1_agents_setup_payment_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AgentSetupPaymentRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/agents/confirm-payment":{"post":{"tags":["agents"],"summary":"Confirm Payment","description":"Confirm that a SetupIntent was completed (after Stripe.js flow).\nUpdates the agent's payment status.","operationId":"confirm_payment_api_v1_agents_confirm_payment_post","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"setup_intent_id","in":"query","required":true,"schema":{"type":"string","title":"Setup Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/agents/me":{"get":{"tags":["agents"],"summary":"Get Agent Profile","description":"Get the current agent's profile, usage stats, and payment status.","operationId":"get_agent_profile_api_v1_agents_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/agents/payment-success":{"get":{"tags":["agents"],"summary":"Payment Success","description":"Stripe Checkout redirect after successful card setup.\n\nAutomatically marks the agent's payment as ready by fetching the\nnewly-attached card from Stripe.","operationId":"payment_success_api_v1_agents_payment_success_get","parameters":[{"name":"agent_id","in":"query","required":false,"schema":{"type":"string","default":"","title":"Agent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/agents/payment-cancelled":{"get":{"tags":["agents"],"summary":"Payment Cancelled","description":"Stripe Checkout redirect when user cancels.","operationId":"payment_cancelled_api_v1_agents_payment_cancelled_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/agents/recover":{"post":{"tags":["agents"],"summary":"Request Recovery","description":"Request a recovery code to reset your API key.\n\nA 6-digit code will be sent to your email. Use POST /api/v1/agents/recover/verify\nwith the code to get a new API key.\n\n**Example request:**\n```json\n{\"email\": \"your-email@example.com\"}\n```\n\nThe code expires in 15 minutes.","operationId":"request_recovery_api_v1_agents_recover_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_request_recovery_api_v1_agents_recover_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/agents/recover/verify":{"post":{"tags":["agents"],"summary":"Verify Recovery","description":"Verify recovery code and get a new API key.\n\n**Example request:**\n```json\n{\"email\": \"your-email@example.com\", \"code\": \"123456\"}\n```\n\nOn success, returns a new API key. The old key is invalidated.","operationId":"verify_recovery_api_v1_agents_recover_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_verify_recovery_api_v1_agents_recover_verify_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/flights/search":{"post":{"tags":["flights"],"summary":"Search Flights","description":"Search for flights — completely FREE, no limits.\n\nReturns real-time offers from 400+ airlines via multiple providers (NDC + GDS).\nPrices are $20-50 cheaper than booking.com/Kayak because we connect directly.\n\n**IMPORTANT:** The response includes `passenger_ids` — you MUST pass these back when booking.\n\n**Example request:**\n```json\n{\"origin\": \"LON\", \"destination\": \"BCN\", \"date_from\": \"2026-04-01\", \"adults\": 1}\n```\n\n**Example response (abbreviated):**\n```json\n{\n  \"passenger_ids\": [\"pas_xxx\"],\n  \"offers\": [{\"id\": \"off_xxx\", \"price\": 78.47, \"airlines\": [\"BA\"]}]\n}\n```","operationId":"search_flights_api_v1_flights_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/flights/locations/{query}":{"get":{"tags":["flights"],"summary":"Resolve Location","description":"Resolve a city or airport name to IATA codes.\n\nUse this when the user says a city name instead of an IATA code.\nFor example, resolve \"London\" to get LON, LHR, LGW, STN, LTN, LCY.\n\n**Example:** GET /api/v1/flights/locations/london","operationId":"resolve_location_api_v1_flights_locations__query__get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"query","in":"path","required":true,"schema":{"type":"string","title":"Query"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/flights/providers":{"get":{"tags":["flights"],"summary":"List Providers","description":"List active flight data providers.","operationId":"list_providers_api_v1_flights_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/hotels/search":{"post":{"tags":["hotels"],"summary":"Search Hotels","description":"Search for hotels and accommodations — multi-provider.\n\nQueries multiple wholesale suppliers in parallel, merges results,\nand returns the cheapest options.\n\n**Example request:**\n```json\n{\n  \"location\": \"PAR\",\n  \"checkin\": \"2026-06-01\",\n  \"checkout\": \"2026-06-05\",\n  \"adults\": 2,\n  \"rooms\": 1\n}\n```","operationId":"search_hotels_api_v1_hotels_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/hotels/checkrate":{"post":{"tags":["hotels"],"summary":"Check Rate","description":"Confirm hotel rate pricing before booking.\n\n**When to use:**\n- REQUIRED when the room's `rate_type` is \"RECHECK\"\n- Optional for \"BOOKABLE\" rates (to get latest price + rate comments)\n\n**Best practice:** Send ONE rate key per request.\n\nReturns confirmed pricing, rate comments, cancellation policies,\nand an updated rate_key to use for booking.\n\n**Example request:**\n```json\n{\n  \"rate_keys\": [\"20260615|20260616|W|102|14915|DBT.EJ|NRF-...\"]\n}\n```","operationId":"check_rate_api_v1_hotels_checkrate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelCheckRateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelCheckRateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/hotels/book":{"post":{"tags":["hotels"],"summary":"Book Hotel","description":"Book a hotel room — creates a real hotel reservation. FREE after unlock.\n\n**Prerequisites:**\n1. Search hotels (POST /hotels/search) → get rate_key + rate_type\n2. Unlock the rate (POST /bookings/unlock with booking_type=\"hotel\") → $1\n3. Use the rate_key from the unlock response here\n\nThe $1 unlock fee is the only charge. Booking itself is free.\n\n**Do NOT** repeat the availability search between steps.\n\n**Children MUST include age in paxes.**\n\nBooking confirmation timeout is 65 seconds. Please be patient.\n\n**Example request:**\n```json\n{\n  \"holder_name\": \"John\",\n  \"holder_surname\": \"Doe\",\n  \"rooms\": [{\n    \"rate_key\": \"20260615|...\",\n    \"paxes\": [\n      {\"room_id\": 1, \"type\": \"AD\", \"name\": \"John\", \"surname\": \"Doe\"},\n      {\"room_id\": 1, \"type\": \"AD\", \"name\": \"Jane\", \"surname\": \"Doe\"}\n    ]\n  }],\n  \"client_reference\": \"MY-REF-001\"\n}\n```","operationId":"book_hotel_api_v1_hotels_book_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelBookingRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelBookingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/hotels/booking/{reference}":{"get":{"tags":["hotels"],"summary":"Get Booking","description":"Get hotel booking details by reference.\n\nReturns full booking information including hotel, rooms, paxes, and payment.","operationId":"get_booking_api_v1_hotels_booking__reference__get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelBookingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/hotels/cancel":{"post":{"tags":["hotels"],"summary":"Cancel Booking","description":"Cancel a hotel booking or simulate cancellation to check fees.\n\n**Simulation mode** (`simulate: true`): Returns cancellation fees\nwithout actually cancelling. Use this first to show the guest\nwhat they'll be charged.\n\n**Real cancellation** (`simulate: false`): Actually cancels the booking.\nThe hotel IS notified. Cancellation fees apply per the rate's policy.\n\n⚠️ Non-refundable (NRF) rates carry full cancellation charges.\n\n**Example request:**\n```json\n{\n  \"reference\": \"123-456789\",\n  \"simulate\": true\n}\n```","operationId":"cancel_booking_api_v1_hotels_cancel_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelCancelRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelCancelResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/hotels/voucher/{reference}":{"get":{"tags":["hotels"],"summary":"Get Voucher","description":"Generate a booking voucher — mandatory document for hotel check-in.\n\nReturns all certification-required information:\n- **Hotel info**: name, category, address, destination, phone\n- **Passenger info**: holder name, pax per room, child ages\n- **Booking info**: reference, dates, room type, board type, rate comments\n- **Payment info**: \"Payable through [Supplier]...\" notice\n\nThe guest presents this voucher at the hotel. It is mandatory\nto provide this for all confirmed bookings.","operationId":"get_voucher_api_v1_hotels_voucher__reference__get","security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}],"parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string","title":"Reference"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelVoucher"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transfers/search":{"post":{"tags":["transfers"],"summary":"Search Transfers","description":"Search for ground transport / transfers between locations — multi-provider.\n\nQueries Amadeus and Hotelbeds in parallel for private cars, shared shuttles,\ntaxis, hourly rentals, airport express, and airport buses.\n\n**Pickup/dropoff** can be specified as IATA airport codes or lat/lng coordinates.\n\n**Example request:**\n```json\n{\n  \"start_iata\": \"CDG\",\n  \"end_iata\": \"ORY\",\n  \"start_datetime\": \"2026-05-15T14:00:00\",\n  \"passengers\": 2,\n  \"transfer_type\": \"PRIVATE\"\n}\n```","operationId":"search_transfers_api_v1_transfers_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferSearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferSearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/activities/search":{"post":{"tags":["activities"],"summary":"Search Activities","description":"Search for tours, activities, and experiences — multi-provider.\n\nQueries Amadeus (300K+ activities) and Hotelbeds wholesale in parallel.\nReturns things to do: tours, museum tickets, day trips, excursions,\nfood tours, shows, and more.\n\n**Requires either a location code or latitude/longitude.**\n\n**Example request:**\n```json\n{\n  \"location\": \"BCN\",\n  \"latitude\": 41.3851,\n  \"longitude\": 2.1734,\n  \"radius\": 5\n}\n```","operationId":"search_activities_api_v1_activities_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitySearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitySearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/bookings/verify-checkout":{"post":{"tags":["bookings"],"summary":"Verify Checkout","description":"Verify a checkout token is valid for automated checkout.\n\nThe checkout_token is returned by the unlock endpoint after $1 payment.\nOpen-source SDK connectors call this to confirm the token before driving\nthe airline checkout flow.\n\nReturns valid=true if the token is correctly signed, matches the offer_id,\nbelongs to the calling agent, and hasn't expired (30min TTL).","operationId":"verify_checkout_api_v1_bookings_verify_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/bookings/unlock":{"post":{"tags":["bookings"],"summary":"Unlock Offer","description":"Unlock an offer for booking — FREE with GitHub star.\n\nWorks for **both flights and hotels**. Search is always free;\nunlock is free too once you've starred the repo and linked your GitHub.\n\n**For flights** (`booking_type: \"flight\"`):\n1. Confirms the latest price with the airline (FREE)\n2. Reserves the offer for 30 minutes\n→ Then proceed to POST /bookings/book\n\n**For hotels** (`booking_type: \"hotel\"`):\n1. Confirms the latest price via CheckRate (FREE)\n2. Returns an updated rate_key (use THIS for booking)\n→ Then proceed to POST /hotels/book with the updated rate_key\n\n**Flight example:**\n```json\n{\"booking_type\": \"flight\", \"offer_id\": \"off_xxx_from_search\"}\n```\n\n**Hotel example:**\n```json\n{\"booking_type\": \"hotel\", \"rate_key\": \"20260615|20260616|W|102|14915|DBT.EJ|NRF-...\"}\n```","operationId":"unlock_offer_api_v1_bookings_unlock_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnlockRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnlockResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/bookings/book":{"post":{"tags":["bookings"],"summary":"Book Flight","description":"Book a flight — creates a real airline reservation.\n\n**Prerequisites:**\n1. Star the repo and link GitHub (POST /agents/link-github)\n2. Unlock the offer first (POST /bookings/unlock)\n3. For Duffel flights: set up a payment method (POST /agents/setup-payment)\n\nFor **Duffel flights** (duf_/ama_ prefix): You are charged the ticket price\n+ Stripe processing fees.  If the booking fails, you are refunded automatically.\nFor **Kiwi flights** (kiw_ prefix): Free — Kiwi handles airline payment directly.\n\n⚠️ **CRITICAL — USE REAL PASSENGER DETAILS:**\n- The **email** you provide receives the e-ticket and booking confirmation.\n- The **name** must match the passenger's passport/ID exactly.\n- If you use a fake email, the passenger will NEVER receive their ticket.\n- This CANNOT be fixed after booking. The airline sends directly to the email provided.\n- Always ask your end-user for their real name, DOB, and email before booking.\n\n**Example request:**\n```json\n{\n  \"offer_id\": \"off_xxx\",\n  \"booking_type\": \"flight\",\n  \"passengers\": [{\n    \"id\": \"pas_xxx_from_search\",\n    \"given_name\": \"John\",\n    \"family_name\": \"Doe\",\n    \"born_on\": \"1990-01-15\",\n    \"gender\": \"m\",\n    \"title\": \"mr\",\n    \"email\": \"john.doe@gmail.com\",\n    \"phone_number\": \"+447123456789\"\n  }],\n  \"contact_email\": \"john.doe@gmail.com\"\n}\n```\n\n**Example response:**\n```json\n{\n  \"status\": \"confirmed\",\n  \"booking_reference\": \"ABC123\",\n  \"flight_price\": 349.00,\n  \"service_fee\": 0,\n  \"total_charged\": 359.43,\n  \"currency\": \"EUR\"\n}\n```\n\nThe `booking_reference` is the real airline PNR code.\nThe e-ticket is sent to the passenger email provided.","operationId":"book_flight_api_v1_bookings_book_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingConfirmation"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/bookings/start-checkout":{"post":{"tags":["bookings"],"summary":"Start Checkout","description":"Start automated checkout on behalf of the agent — drives Playwright to\nthe airline payment page, NEVER submits payment.\n\nRequires a valid checkout_token from the unlock endpoint ($1 paid).\n\nSupported airlines: Ryanair, Wizz Air, EasyJet.\nOther airlines return booking_url for manual completion.\n\nThe checkout runs server-side using headless Playwright. Returns a\nscreenshot of the payment page and a booking_url for manual completion.","operationId":"start_checkout_api_v1_bookings_start_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartCheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutProgressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]},{"APIKeyQuery":[]}]}},"/api/v1/analytics/dashboard":{"get":{"tags":["analytics"],"summary":"Analytics Dashboard","description":"Get analytics dashboard — admin only.\n\nShows total requests, top agents, popular routes, latency percentiles,\nstatus code breakdown, and hourly traffic.\n\nRequires `admin_key` query parameter matching `ANALYTICS_ADMIN_KEY` env var.","operationId":"analytics_dashboard_api_v1_analytics_dashboard_get","parameters":[{"name":"admin_key","in":"query","required":true,"schema":{"type":"string","description":"Admin key for analytics access","title":"Admin Key"},"description":"Admin key for analytics access"},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"description":"Time window in hours","default":24,"title":"Hours"},"description":"Time window in hours"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/agents/{agent_id}":{"get":{"tags":["analytics"],"summary":"Agent Analytics","description":"Get analytics for a specific agent — admin only.","operationId":"agent_analytics_api_v1_analytics_agents__agent_id__get","parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string","title":"Agent Id"}},{"name":"admin_key","in":"query","required":true,"schema":{"type":"string","description":"Admin key for analytics access","title":"Admin Key"},"description":"Admin key for analytics access"},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":24,"title":"Hours"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/live":{"get":{"tags":["analytics"],"summary":"Live Stats","description":"Live stats snapshot — admin only.\nQuick overview of current traffic.","operationId":"live_stats_api_v1_analytics_live_get","parameters":[{"name":"admin_key","in":"query","required":true,"schema":{"type":"string","description":"Admin key for analytics access","title":"Admin Key"},"description":"Admin key for analytics access"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/clients":{"get":{"tags":["analytics"],"summary":"Client Breakdown","description":"Usage breakdown by client type — admin only.\n\nShows how many requests come from CLI, Python SDK, JS SDK, MCP, Messenger, etc.\nBoth for the recent time window and all-time.","operationId":"client_breakdown_api_v1_analytics_clients_get","parameters":[{"name":"admin_key","in":"query","required":true,"schema":{"type":"string","description":"Admin key for analytics access","title":"Admin Key"},"description":"Admin key for analytics access"},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"description":"Time window in hours","default":24,"title":"Hours"},"description":"Time window in hours"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/connectors/health":{"get":{"tags":["analytics"],"summary":"Connector Health","description":"Connector health / down detector — admin only.\n\nShows each connector's success/failure rate, total offers returned,\nand status (healthy / degraded / down).\n\nData comes from two sources:\n- **cloud**: Our backend providers (Duffel, Amadeus, etc.)\n- **local**: User-reported outcomes from local SDK/CLI searches\n\nUse `source` param to filter: 'cloud', 'local', or 'all' (default).","operationId":"connector_health_api_v1_analytics_connectors_health_get","parameters":[{"name":"admin_key","in":"query","required":true,"schema":{"type":"string","description":"Admin key for analytics access","title":"Admin Key"},"description":"Admin key for analytics access"},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Filter: 'cloud', 'local', or 'all'","default":"all","title":"Source"},"description":"Filter: 'cloud', 'local', or 'all'"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/telemetry/connector-results":{"post":{"tags":["analytics"],"summary":"Ingest Connector Telemetry","description":"Receive connector health telemetry from local SDK/CLI users.\n\nCalled fire-and-forget by the local search engine after each search.\n**Requires a valid API key** — prevents anonymous data poisoning.\n\nRate limit: handled by the global rate limiter (60/min).","operationId":"ingest_connector_telemetry_api_v1_analytics_telemetry_connector_results_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"x-client-type","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Client-Type"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelemetryPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/protocols/":{"get":{"tags":["protocols"],"summary":"List all Agent Interaction Protocols","description":"Returns summaries of all available carrier protocols. Use the carrier code to fetch the full protocol definition.","operationId":"list_protocols_api_v1_protocols__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProtocolListResponse"}}}}}}},"/api/v1/protocols/{carrier}":{"get":{"tags":["protocols"],"summary":"Get full protocol for a carrier","description":"Returns the complete Agent Interaction Protocol for the specified carrier. Includes API endpoints, parameter schemas, booking flows, and data mapping. Use the IATA code (e.g. 'FR' for Ryanair) or the filename slug (e.g. 'ryanair').","operationId":"get_protocol_api_v1_protocols__carrier__get","parameters":[{"name":"carrier","in":"path","required":true,"schema":{"type":"string","title":"Carrier"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp":{"get":{"summary":"Mcp Get","description":"MCP Streamable HTTP — GET for server-initiated messages.\n\nReturns 405 since we don't support server-initiated SSE streams yet.\nAgents should use POST for all requests.","operationId":"mcp_get_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Mcp Post","description":"MCP Streamable HTTP transport.\n\nAccepts JSON-RPC 2.0 messages. Supports single requests and batch arrays.","operationId":"mcp_post_mcp_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp/sse":{"get":{"summary":"Mcp Sse","description":"Legacy MCP SSE transport — client connects here to open a session.\nReturns an SSE stream. First event is 'endpoint' with the POST URL.","operationId":"mcp_sse_mcp_sse_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp/messages":{"post":{"summary":"Mcp Messages","description":"Legacy MCP SSE transport — client POSTs JSON-RPC messages here.\nResponses are pushed through the SSE stream for the session.","operationId":"mcp_messages_mcp_messages_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"tags":["system"],"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"ActivityOffer":{"properties":{"id":{"type":"string","title":"Id","description":"Activity offer ID"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description","default":""},"price":{"type":"number","title":"Price"},"currency":{"type":"string","title":"Currency","default":"EUR"},"price_formatted":{"type":"string","title":"Price Formatted","default":""},"rating":{"anyOf":[{"type":"number","maximum":5.0,"minimum":0.0},{"type":"null"}],"title":"Rating","description":"User rating 0-5"},"review_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Review Count"},"image_url":{"type":"string","title":"Image Url","default":""},"booking_url":{"type":"string","title":"Booking Url","description":"Deep link to book the activity","default":""},"duration":{"type":"string","title":"Duration","description":"Duration (e.g., '3 hours', 'Full day')","default":""},"categories":{"items":{"type":"string"},"type":"array","title":"Categories"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"fetched_at":{"type":"string","format":"date-time","title":"Fetched At"}},"type":"object","required":["id","name","price"],"title":"ActivityOffer","description":"A single tour/activity/experience offer."},"ActivitySearchRequest":{"properties":{"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"City name or IATA code (e.g., 'Barcelona', 'BCN')"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude","description":"Latitude of search center"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude","description":"Longitude of search center"},"radius":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Radius","description":"Search radius in km","default":20},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","default":"EUR"},"sort":{"type":"string","title":"Sort","description":"Sort by: price, rating","default":"price"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","default":20}},"type":"object","title":"ActivitySearchRequest","description":"Parameters for a tours & activities search."},"ActivitySearchResponse":{"properties":{"search_id":{"type":"string","title":"Search Id","default":""},"location":{"type":"string","title":"Location","default":""},"offers":{"items":{"$ref":"#/components/schemas/ActivityOffer"},"type":"array","title":"Offers","default":[]},"total_results":{"type":"integer","title":"Total Results","default":0},"search_params":{"type":"object","title":"Search Params"}},"type":"object","title":"ActivitySearchResponse","description":"Full response from an activities search."},"AgentRegistrationRequest":{"properties":{"agent_name":{"type":"string","maxLength":100,"minLength":2,"title":"Agent Name","description":"Human-readable agent name"},"email":{"type":"string","title":"Email","description":"Contact email for billing and notifications (optional for auto-registration)","default":""},"owner_name":{"type":"string","title":"Owner Name","description":"Name of the person/org owning this agent","default":""},"description":{"type":"string","title":"Description","description":"What this agent does","default":""}},"type":"object","required":["agent_name"],"title":"AgentRegistrationRequest","description":"Request to register a new agent."},"AgentSetupPaymentRequest":{"properties":{"payment_method_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Method Id","description":"Stripe PaymentMethod ID (pm_xxx)"},"token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token","description":"Stripe token (tok_visa, tok_mastercard, etc.)"},"card_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Card Number","description":"Card number (headless setup)"},"exp_month":{"anyOf":[{"type":"integer","maximum":12.0,"minimum":1.0},{"type":"null"}],"title":"Exp Month"},"exp_year":{"anyOf":[{"type":"integer","maximum":2040.0,"minimum":2026.0},{"type":"null"}],"title":"Exp Year"},"cvc":{"anyOf":[{"type":"string","maxLength":4,"minLength":3},{"type":"null"}],"title":"Cvc"}},"type":"object","title":"AgentSetupPaymentRequest","description":"Request to set up payment for an agent."},"AirlineSummary":{"properties":{"airline_code":{"type":"string","title":"Airline Code"},"airline_name":{"type":"string","title":"Airline Name","default":""},"cheapest_price":{"type":"number","title":"Cheapest Price"},"currency":{"type":"string","title":"Currency","default":"EUR"},"offer_count":{"type":"integer","title":"Offer Count"},"cheapest_offer_id":{"type":"string","title":"Cheapest Offer Id","default":""},"sample_route":{"type":"string","title":"Sample Route","description":"e.g. KRK→WAW→BER","default":""}},"type":"object","required":["airline_code","cheapest_price","offer_count"],"title":"AirlineSummary","description":"Cheapest offer summary for one airline."},"Body_link_github_api_v1_agents_link_github_post":{"properties":{"github_username":{"type":"string","title":"Github Username","default":""}},"type":"object","title":"Body_link_github_api_v1_agents_link_github_post"},"Body_request_recovery_api_v1_agents_recover_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_request_recovery_api_v1_agents_recover_post"},"Body_verify_recovery_api_v1_agents_recover_verify_post":{"properties":{"email":{"type":"string","title":"Email"},"code":{"type":"string","title":"Code"}},"type":"object","required":["email","code"],"title":"Body_verify_recovery_api_v1_agents_recover_verify_post"},"BookingConfirmation":{"properties":{"booking_id":{"type":"string","title":"Booking Id"},"status":{"$ref":"#/components/schemas/BookingStatus","default":"pending"},"booking_type":{"$ref":"#/components/schemas/BookingType"},"offer_id":{"type":"string","title":"Offer Id"},"flight_price":{"type":"number","title":"Flight Price","default":0.0},"service_fee":{"type":"number","title":"Service Fee","default":0.0},"service_fee_percentage":{"type":"number","title":"Service Fee Percentage","default":0},"total_charged":{"type":"number","title":"Total Charged","default":0.0},"currency":{"type":"string","title":"Currency","default":"EUR"},"order_id":{"type":"string","title":"Order Id","default":""},"booking_reference":{"type":"string","title":"Booking Reference","default":""},"unlock_payment_id":{"type":"string","title":"Unlock Payment Id","default":""},"fee_payment_id":{"type":"string","title":"Fee Payment Id","default":""},"created_at":{"type":"string","format":"date-time","title":"Created At"},"details":{"type":"object","title":"Details"}},"type":"object","required":["booking_id","booking_type","offer_id"],"title":"BookingConfirmation","description":"Booking result — includes our service fee breakdown."},"BookingRequest":{"properties":{"offer_id":{"type":"string","title":"Offer Id","description":"The offer ID (must be unlocked first)"},"booking_type":{"$ref":"#/components/schemas/BookingType"},"passengers":{"items":{"$ref":"#/components/schemas/Passenger"},"type":"array","minItems":1,"title":"Passengers","description":"At least one passenger required — use REAL details!"},"contact_email":{"type":"string","title":"Contact Email","description":"REAL contact email — airline sends booking confirmation and e-ticket here"},"contact_phone":{"type":"string","title":"Contact Phone","default":""},"notes":{"type":"string","title":"Notes","default":""}},"type":"object","required":["offer_id","booking_type","passengers","contact_email"],"title":"BookingRequest","description":"Request to book an unlocked flight or hotel offer."},"BookingStatus":{"type":"string","enum":["pending","confirmed","failed","cancelled"],"title":"BookingStatus"},"BookingType":{"type":"string","enum":["flight","hotel"],"title":"BookingType"},"CheckedRate":{"properties":{"rate_key":{"type":"string","title":"Rate Key","description":"Updated rate key — use THIS for booking, not the original"},"rate_type":{"type":"string","title":"Rate Type","default":"BOOKABLE"},"net":{"type":"number","title":"Net","default":0.0},"selling_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Selling Rate"},"currency":{"type":"string","title":"Currency","default":"EUR"},"board_code":{"type":"string","title":"Board Code","default":""},"board_name":{"type":"string","title":"Board Name","default":""},"room_code":{"type":"string","title":"Room Code","default":""},"room_name":{"type":"string","title":"Room Name","default":""},"adults":{"type":"integer","title":"Adults","default":0},"children":{"type":"integer","title":"Children","default":0},"packaging":{"type":"boolean","title":"Packaging","default":false},"rate_comments":{"type":"string","title":"Rate Comments","default":""},"cancellation_policies":{"items":{"type":"object"},"type":"array","title":"Cancellation Policies"},"promotions":{"items":{"type":"object"},"type":"array","title":"Promotions"},"hotel_mandatory":{"type":"boolean","title":"Hotel Mandatory","default":false}},"type":"object","required":["rate_key"],"title":"CheckedRate","description":"A rate confirmed via CheckRate — ready for booking."},"CheckoutProgressResponse":{"properties":{"status":{"type":"string","title":"Status"},"step":{"type":"string","title":"Step","default":""},"step_index":{"type":"integer","title":"Step Index","default":0},"airline":{"type":"string","title":"Airline","default":""},"source":{"type":"string","title":"Source","default":""},"offer_id":{"type":"string","title":"Offer Id","default":""},"total_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Price"},"currency":{"type":"string","title":"Currency","default":""},"booking_url":{"type":"string","title":"Booking Url","default":""},"screenshot_b64":{"type":"string","title":"Screenshot B64","default":""},"message":{"type":"string","title":"Message","default":""},"can_complete_manually":{"type":"boolean","title":"Can Complete Manually","default":false},"elapsed_seconds":{"type":"number","title":"Elapsed Seconds","default":0},"details":{"type":"object","title":"Details","default":{}}},"type":"object","required":["status"],"title":"CheckoutProgressResponse"},"ConnectorResult":{"properties":{"connector":{"type":"string","maxLength":64,"minLength":2,"pattern":"^[a-z0-9_]+$","title":"Connector","description":"Connector source name, e.g. 'ryanair_direct'"},"ok":{"type":"boolean","title":"Ok","description":"Whether the connector returned offers"},"offers":{"type":"integer","maximum":10000.0,"minimum":0.0,"title":"Offers","description":"Number of offers returned","default":0},"latency_ms":{"type":"number","maximum":300000.0,"minimum":0.0,"title":"Latency Ms","description":"Search latency in milliseconds","default":0}},"type":"object","required":["connector","ok"],"title":"ConnectorResult"},"FlightOffer":{"properties":{"id":{"type":"string","title":"Id","description":"Unique offer ID"},"price":{"type":"number","title":"Price"},"currency":{"type":"string","title":"Currency","default":"EUR"},"price_formatted":{"type":"string","title":"Price Formatted","default":""},"outbound":{"$ref":"#/components/schemas/FlightRoute"},"inbound":{"anyOf":[{"$ref":"#/components/schemas/FlightRoute"},{"type":"null"}]},"airlines":{"items":{"type":"string"},"type":"array","title":"Airlines","description":"All airlines in itinerary"},"owner_airline":{"type":"string","title":"Owner Airline","description":"Validating carrier","default":""},"bags_price":{"type":"object","title":"Bags Price","description":"Baggage pricing"},"availability_seats":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Availability Seats"},"conditions":{"additionalProperties":{"type":"string"},"type":"object","title":"Conditions","description":"Refund/change policies"},"source":{"type":"string","title":"Source","description":"Provider source tag (e.g. 'duffel', 'amadeus', 'kiwi', 'travelpayouts')","default":""},"source_tier":{"type":"string","title":"Source Tier","description":"Data source cost tier: 'free' = cached/aggregated data (Travelpayouts), 'low' = affordable API (Kiwi Tequila), 'paid' = GDS/NDC providers (Duffel, Amadeus), 'protocol' = LCC direct via Agent Interaction Protocol (Ryanair, Wizzair)","default":"paid"},"is_locked":{"type":"boolean","title":"Is Locked","description":"Whether booking details require unlock","default":false},"fetched_at":{"type":"string","format":"date-time","title":"Fetched At"},"booking_url":{"type":"string","title":"Booking Url","description":"Only available after unlock","default":""},"price_normalized":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price Normalized","description":"Price converted to the search currency for sorting"}},"type":"object","required":["id","price","outbound"],"title":"FlightOffer","description":"A single flight offer with full itinerary, pricing, and booking details."},"FlightRoute":{"properties":{"segments":{"items":{"$ref":"#/components/schemas/FlightSegment"},"type":"array","title":"Segments","default":[]},"total_duration_seconds":{"type":"integer","title":"Total Duration Seconds","default":0},"stopovers":{"type":"integer","title":"Stopovers","default":0}},"type":"object","title":"FlightRoute","description":"One direction (outbound or return) composed of segments."},"FlightSearchRequest":{"properties":{"origin":{"type":"string","maxLength":4,"minLength":2,"title":"Origin","description":"IATA code of departure airport/city (e.g. 'PRG', 'LON')"},"destination":{"type":"string","maxLength":4,"minLength":2,"title":"Destination","description":"IATA code of arrival airport/city (e.g. 'BCN', 'NYC')"},"date_from":{"type":"string","format":"date","title":"Date From","description":"Departure date"},"date_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date To","description":"Latest departure date"},"return_from":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Return From","description":"Return date (omit for one-way)"},"return_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Return To","description":"Latest return date"},"adults":{"type":"integer","maximum":9.0,"minimum":1.0,"title":"Adults","default":1},"children":{"type":"integer","maximum":9.0,"minimum":0.0,"title":"Children","default":0},"infants":{"type":"integer","maximum":9.0,"minimum":0.0,"title":"Infants","default":0},"cabin_class":{"anyOf":[{"type":"string","pattern":"^[MWCF]$"},{"type":"null"}],"title":"Cabin Class","description":"M (economy), W (premium economy), C (business), F (first)"},"max_stopovers":{"type":"integer","maximum":4.0,"minimum":0.0,"title":"Max Stopovers","description":"Max connections per direction","default":2},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","default":"EUR"},"locale":{"type":"string","title":"Locale","description":"Language for city/airport names","default":"en"},"limit":{"type":"integer","maximum":200.0,"minimum":1.0,"title":"Limit","description":"Max results to return","default":50},"sort":{"type":"string","title":"Sort","description":"Sort by: price, duration, best_per_airline","default":"price"}},"type":"object","required":["origin","destination","date_from"],"title":"FlightSearchRequest","description":"Parameters for a flight search — FREE for agents."},"FlightSearchResponse":{"properties":{"search_id":{"type":"string","title":"Search Id","default":""},"offer_request_id":{"type":"string","title":"Offer Request Id","description":"Offer request ID (for booking flow)","default":""},"passenger_ids":{"items":{"type":"string"},"type":"array","title":"Passenger Ids","description":"Passenger IDs from the offer request — REQUIRED for booking. Map these 1:1 to your passengers when calling POST /bookings/book."},"origin":{"type":"string","title":"Origin"},"destination":{"type":"string","title":"Destination"},"currency":{"type":"string","title":"Currency","default":"EUR"},"offers":{"items":{"$ref":"#/components/schemas/FlightOffer"},"type":"array","title":"Offers","default":[]},"total_results":{"type":"integer","title":"Total Results","default":0},"airlines_summary":{"items":{"$ref":"#/components/schemas/AirlineSummary"},"type":"array","title":"Airlines Summary","description":"Cheapest offer per airline — quick overview of all options."},"search_params":{"type":"object","title":"Search Params"},"source_tiers":{"additionalProperties":{"type":"string"},"type":"object","title":"Source Tiers","description":"Breakdown of which source tiers were used in this search. Keys are tier names, values describe the data source. Example: {'paid': 'Duffel (NDC), Amadeus (GDS)', 'low': 'Kiwi Tequila', 'free': 'Travelpayouts'}"},"pricing_note":{"type":"string","title":"Pricing Note","description":"Pricing transparency for agents","default":"Search is free. Booking is free. No hidden fees."}},"type":"object","required":["origin","destination"],"title":"FlightSearchResponse","description":"Full response from a flight search — always FREE."},"FlightSegment":{"properties":{"airline":{"type":"string","title":"Airline","description":"Operating carrier IATA code"},"airline_name":{"type":"string","title":"Airline Name","default":""},"flight_no":{"type":"string","title":"Flight No","default":""},"origin":{"type":"string","title":"Origin","description":"Departure IATA"},"destination":{"type":"string","title":"Destination","description":"Arrival IATA"},"origin_city":{"type":"string","title":"Origin City","default":""},"destination_city":{"type":"string","title":"Destination City","default":""},"departure":{"type":"string","format":"date-time","title":"Departure"},"arrival":{"type":"string","format":"date-time","title":"Arrival"},"duration_seconds":{"type":"integer","title":"Duration Seconds","default":0},"cabin_class":{"type":"string","title":"Cabin Class","default":"economy"},"aircraft":{"type":"string","title":"Aircraft","default":""}},"type":"object","required":["airline","origin","destination","departure","arrival"],"title":"FlightSegment","description":"A single flight leg (e.g., PRG→FRA)."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HotelBookingHotel":{"properties":{"code":{"type":"integer","title":"Code","default":0},"name":{"type":"string","title":"Name","default":""},"category_code":{"type":"string","title":"Category Code","default":""},"destination_code":{"type":"string","title":"Destination Code","default":""},"destination_name":{"type":"string","title":"Destination Name","default":""},"zone_name":{"type":"string","title":"Zone Name","default":""},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"address":{"type":"string","title":"Address","default":""},"phone":{"type":"string","title":"Phone","default":""},"supplier_name":{"type":"string","title":"Supplier Name","default":""},"vat_number":{"type":"string","title":"Vat Number","default":""}},"type":"object","title":"HotelBookingHotel","description":"Hotel info from a booking confirmation."},"HotelBookingRequest":{"properties":{"holder_name":{"type":"string","title":"Holder Name","description":"Lead guest first name"},"holder_surname":{"type":"string","title":"Holder Surname","description":"Lead guest last name"},"rooms":{"items":{"$ref":"#/components/schemas/HotelBookingRoom"},"type":"array","minItems":1,"title":"Rooms","description":"Room(s) with rate key and guest details"},"client_reference":{"type":"string","maxLength":20,"title":"Client Reference","description":"Your internal booking reference (optional, max 20 chars)","default":""},"remark":{"type":"string","title":"Remark","description":"Special requests / notes for the hotel","default":""},"tolerance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tolerance","description":"Price tolerance percentage (e.g. 2.0 = accept up to 2% price increase)"}},"type":"object","required":["holder_name","holder_surname","rooms"],"title":"HotelBookingRequest","description":"Book a hotel room.\n\nWorkflow: search → checkrate (if RECHECK) → book.\nBooking timeout is 60+ seconds — please be patient."},"HotelBookingResponse":{"properties":{"reference":{"type":"string","title":"Reference","description":"Hotel booking reference","default":""},"client_reference":{"type":"string","title":"Client Reference","default":""},"status":{"$ref":"#/components/schemas/HotelBookingStatus","default":"PENDING"},"hotel":{"anyOf":[{"$ref":"#/components/schemas/HotelBookingHotel"},{"type":"null"}]},"checkin":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Checkin"},"checkout":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Checkout"},"total_net":{"type":"number","title":"Total Net","default":0.0},"total_selling":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Selling"},"currency":{"type":"string","title":"Currency","default":"EUR"},"holder_name":{"type":"string","title":"Holder Name","default":""},"holder_surname":{"type":"string","title":"Holder Surname","default":""},"remark":{"type":"string","title":"Remark","default":""},"rooms":{"items":{"type":"object"},"type":"array","title":"Rooms","description":"Booked room details"},"creation_date":{"type":"string","title":"Creation Date","default":""},"message":{"type":"string","title":"Message","default":""},"supplier_name":{"type":"string","title":"Supplier Name","default":""},"vat_number":{"type":"string","title":"Vat Number","default":""}},"type":"object","title":"HotelBookingResponse","description":"Confirmation of a hotel booking."},"HotelBookingRoom":{"properties":{"rate_key":{"type":"string","title":"Rate Key","description":"Rate key from CheckRate or availability (if BOOKABLE)"},"paxes":{"items":{"$ref":"#/components/schemas/HotelPax"},"type":"array","minItems":1,"title":"Paxes","description":"At least one pax per room. Children MUST include age."}},"type":"object","required":["rate_key","paxes"],"title":"HotelBookingRoom","description":"A room selection for booking."},"HotelBookingStatus":{"type":"string","enum":["CONFIRMED","CANCELLED","FAILED","PENDING"],"title":"HotelBookingStatus"},"HotelCancelRequest":{"properties":{"reference":{"type":"string","title":"Reference","description":"Hotel booking reference"},"simulate":{"type":"boolean","title":"Simulate","description":"True = just check cancellation fees without cancelling","default":false}},"type":"object","required":["reference"],"title":"HotelCancelRequest","description":"Cancel or simulate cancellation of a hotel booking."},"HotelCancelResponse":{"properties":{"reference":{"type":"string","title":"Reference","default":""},"status":{"$ref":"#/components/schemas/HotelBookingStatus","default":"CANCELLED"},"cancellation_amount":{"type":"number","title":"Cancellation Amount","default":0.0},"currency":{"type":"string","title":"Currency","default":"EUR"},"hotel_name":{"type":"string","title":"Hotel Name","default":""},"message":{"type":"string","title":"Message","default":""}},"type":"object","title":"HotelCancelResponse","description":"Cancellation result."},"HotelCheckRateRequest":{"properties":{"rate_keys":{"items":{"type":"string"},"type":"array","maxItems":10,"minItems":1,"title":"Rate Keys","description":"Rate key(s) from availability search. Best practice: one key per request. Max 10."}},"type":"object","required":["rate_keys"],"title":"HotelCheckRateRequest","description":"Request to confirm price for selected hotel room(s) before booking.\n\nUse this when the rate's `rate_type` is \"RECHECK\", or to get\nlatest pricing + rate comments before booking.\nBest practice: send ONE rateKey per request (not multiple)."},"HotelCheckRateResponse":{"properties":{"hotel_code":{"type":"integer","title":"Hotel Code","default":0},"hotel_name":{"type":"string","title":"Hotel Name","default":""},"category_code":{"type":"string","title":"Category Code","default":""},"destination_code":{"type":"string","title":"Destination Code","default":""},"checked_rates":{"items":{"$ref":"#/components/schemas/CheckedRate"},"type":"array","title":"Checked Rates","default":[]},"currency":{"type":"string","title":"Currency","default":"EUR"},"message":{"type":"string","title":"Message","default":""}},"type":"object","title":"HotelCheckRateResponse","description":"Response from CheckRate — confirmed pricing."},"HotelOffer":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"address":{"type":"string","title":"Address","default":""},"city":{"type":"string","title":"City","default":""},"stars":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Stars"},"rating":{"anyOf":[{"type":"number","maximum":10.0,"minimum":0.0},{"type":"null"}],"title":"Rating","description":"Guest rating 0-10"},"review_count":{"type":"integer","title":"Review Count","default":0},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"photos":{"items":{"$ref":"#/components/schemas/HotelPhoto"},"type":"array","title":"Photos"},"cheapest_room":{"anyOf":[{"$ref":"#/components/schemas/HotelRoom"},{"type":"null"}]},"rooms":{"items":{"$ref":"#/components/schemas/HotelRoom"},"type":"array","title":"Rooms"},"booking_url":{"type":"string","title":"Booking Url","default":""},"amenities":{"items":{"type":"string"},"type":"array","title":"Amenities"},"fetched_at":{"type":"string","format":"date-time","title":"Fetched At"}},"type":"object","required":["id","name"],"title":"HotelOffer","description":"A single hotel/property with its cheapest offer."},"HotelPax":{"properties":{"room_id":{"type":"integer","title":"Room Id","description":"Room number (1-based)","default":1},"type":{"type":"string","title":"Type","description":"AD = adult, CH = child","default":"AD"},"name":{"type":"string","title":"Name","description":"First name (must match ID)"},"surname":{"type":"string","title":"Surname","description":"Last name (must match ID)"},"age":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Age","description":"Required for children"}},"type":"object","required":["name","surname"],"title":"HotelPax","description":"A guest/passenger for a hotel booking."},"HotelPhoto":{"properties":{"url":{"type":"string","title":"Url"},"thumbnail":{"type":"string","title":"Thumbnail","default":""}},"type":"object","required":["url"],"title":"HotelPhoto"},"HotelRoom":{"properties":{"room_id":{"type":"string","title":"Room Id"},"name":{"type":"string","title":"Name"},"price":{"type":"number","title":"Price"},"currency":{"type":"string","title":"Currency","default":"EUR"},"price_per_night":{"type":"number","title":"Price Per Night","default":0.0},"cancellation_policy":{"type":"string","title":"Cancellation Policy","default":""},"breakfast_included":{"type":"boolean","title":"Breakfast Included","default":false},"max_occupancy":{"type":"integer","title":"Max Occupancy","default":2},"rate_key":{"type":"string","title":"Rate Key","description":"Opaque rate key — pass to CheckRate/Book. Do NOT parse.","default":""},"rate_type":{"type":"string","title":"Rate Type","description":"BOOKABLE = can book directly. RECHECK = must call /checkrate first.","default":"BOOKABLE"},"board_code":{"type":"string","title":"Board Code","description":"Board type code (RO, BB, HB, FB, AI)","default":""},"board_name":{"type":"string","title":"Board Name","default":""},"packaging":{"type":"boolean","title":"Packaging","description":"True = opaque rate, must combine with other services","default":false},"rate_comments_id":{"type":"string","title":"Rate Comments Id","default":""},"rate_comments":{"type":"string","title":"Rate Comments","default":""},"promotions":{"items":{"type":"object"},"type":"array","title":"Promotions"},"cancellation_policies":{"items":{"type":"object"},"type":"array","title":"Cancellation Policies","description":"Raw cancellation policies [{amount, from}]"}},"type":"object","required":["room_id","name","price"],"title":"HotelRoom","description":"A bookable room type."},"HotelSearchRequest":{"properties":{"location":{"type":"string","title":"Location","description":"City name or IATA code (e.g. 'Barcelona', 'BCN')"},"checkin":{"type":"string","format":"date","title":"Checkin","description":"Check-in date"},"checkout":{"type":"string","format":"date","title":"Checkout","description":"Check-out date"},"adults":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Adults","default":2},"children":{"type":"integer","maximum":6.0,"minimum":0.0,"title":"Children","default":0},"rooms":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Rooms","default":1},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","default":"EUR"},"min_stars":{"anyOf":[{"type":"integer","maximum":5.0,"minimum":1.0},{"type":"null"}],"title":"Min Stars"},"max_price":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Price","description":"Max price per night"},"sort":{"type":"string","title":"Sort","description":"Sort by: price, rating, distance","default":"price"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","default":20},"locale":{"type":"string","title":"Locale","default":"en"}},"type":"object","required":["location","checkin","checkout"],"title":"HotelSearchRequest","description":"Parameters for a hotel/accommodation search."},"HotelSearchResponse":{"properties":{"search_id":{"type":"string","title":"Search Id","default":""},"location":{"type":"string","title":"Location"},"checkin":{"type":"string","format":"date","title":"Checkin"},"checkout":{"type":"string","format":"date","title":"Checkout"},"currency":{"type":"string","title":"Currency","default":"EUR"},"offers":{"items":{"$ref":"#/components/schemas/HotelOffer"},"type":"array","title":"Offers","default":[]},"total_results":{"type":"integer","title":"Total Results","default":0},"search_params":{"type":"object","title":"Search Params"}},"type":"object","required":["location","checkin","checkout"],"title":"HotelSearchResponse","description":"Full response from a hotel search."},"HotelVoucher":{"properties":{"hotel_name":{"type":"string","title":"Hotel Name"},"hotel_category":{"type":"string","title":"Hotel Category","default":""},"hotel_address":{"type":"string","title":"Hotel Address","default":""},"hotel_destination":{"type":"string","title":"Hotel Destination","default":""},"hotel_phone":{"type":"string","title":"Hotel Phone","default":""},"holder_name":{"type":"string","title":"Holder Name"},"holder_surname":{"type":"string","title":"Holder Surname"},"rooms_pax":{"items":{"type":"object"},"type":"array","title":"Rooms Pax","description":"[{room_number, room_type, paxes: [{name, surname, type, age}]}]"},"booking_reference":{"type":"string","title":"Booking Reference"},"agency_reference":{"type":"string","title":"Agency Reference","default":""},"checkin":{"type":"string","format":"date","title":"Checkin"},"checkout":{"type":"string","format":"date","title":"Checkout"},"room_type":{"type":"string","title":"Room Type","default":""},"board_type":{"type":"string","title":"Board Type","default":""},"rate_comments":{"type":"string","title":"Rate Comments","default":""},"payment_notice":{"type":"string","title":"Payment Notice","description":"Payable through [Supplier], acting as agent for the service operating company, details of which can be provided upon request. VAT: [number] Reference: [booking_ref]","default":""},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["hotel_name","holder_name","holder_surname","booking_reference","checkin","checkout"],"title":"HotelVoucher","description":"Booking voucher — contains all required guest check-in information.\n\nContains all required info:\n- Hotel info (name, category, address, destination, phone)\n- Passenger info (holder, pax per room, child ages)\n- Booking info (reference, dates, room type, board, rate comments)\n- Payment info (payable through supplier)"},"Passenger":{"properties":{"id":{"type":"string","title":"Id","description":"Passenger ID from search response (pas_xxx)"},"given_name":{"type":"string","title":"Given Name","description":"First name (MUST match passport/ID exactly)"},"family_name":{"type":"string","title":"Family Name","description":"Last name (MUST match passport/ID exactly)"},"born_on":{"type":"string","title":"Born On","description":"YYYY-MM-DD (must be accurate)"},"gender":{"type":"string","title":"Gender","description":"m or f","default":"m"},"title":{"type":"string","title":"Title","description":"mr, ms, mrs, miss","default":"mr"},"email":{"type":"string","title":"Email","description":"REAL passenger email — airline sends e-ticket here. Do NOT use placeholder emails!","default":""},"phone_number":{"type":"string","title":"Phone Number","default":""},"identity_documents":{"items":{"type":"object"},"type":"array","title":"Identity Documents","description":"[{'unique_identifier': 'passport_number', 'expires_on': 'YYYY-MM-DD', 'issuing_country_code': 'US', 'type': 'passport'}]"}},"type":"object","required":["id","given_name","family_name","born_on"],"title":"Passenger","description":"Passenger details for booking. Names MUST match passport/ID exactly."},"ProtocolListResponse":{"properties":{"protocols":{"items":{"$ref":"#/components/schemas/ProtocolSummary"},"type":"array","title":"Protocols","default":[]},"total":{"type":"integer","title":"Total","default":0},"description":{"type":"string","title":"Description","default":"Agent Interaction Protocols document how AI agents can interact with airlines that lack traditional API/GDS connectivity. Each protocol describes API endpoints, booking flows, and data mapping."}},"type":"object","title":"ProtocolListResponse","description":"All available Agent Interaction Protocols."},"ProtocolSummary":{"properties":{"carrier_code":{"type":"string","title":"Carrier Code","description":"IATA airline code (e.g. 'FR')"},"carrier_name":{"type":"string","title":"Carrier Name","description":"Airline name"},"carrier_type":{"type":"string","title":"Carrier Type","description":"e.g. 'ultra_low_cost_carrier'","default":""},"protocol_version":{"type":"string","title":"Protocol Version","default":"1.0.0"},"confidence":{"type":"string","title":"Confidence","description":"high / medium / low — how reliable the protocol data is","default":""},"last_verified":{"type":"string","title":"Last Verified","description":"ISO date when this protocol was last verified","default":""},"endpoints_count":{"type":"integer","title":"Endpoints Count","description":"Number of documented API endpoints","default":0},"has_booking_flow":{"type":"boolean","title":"Has Booking Flow","description":"Whether a browser booking flow is documented","default":false}},"type":"object","required":["carrier_code","carrier_name"],"title":"ProtocolSummary","description":"Short summary of an available protocol."},"StartCheckoutRequest":{"properties":{"offer_id":{"type":"string","title":"Offer Id"},"checkout_token":{"type":"string","title":"Checkout Token"},"passengers":{"items":{"type":"object"},"type":"array","title":"Passengers","default":[]},"booking_url":{"type":"string","title":"Booking Url","default":""}},"type":"object","required":["offer_id","checkout_token"],"title":"StartCheckoutRequest"},"TelemetryPayload":{"properties":{"route":{"type":"string","maxLength":16,"pattern":"^[A-Z]{3}-[A-Z]{3}$|^$","title":"Route","description":"Route searched, e.g. 'LHR-JFK'","default":""},"sdk_version":{"type":"string","maxLength":32,"title":"Sdk Version","default":""},"client_type":{"type":"string","maxLength":32,"title":"Client Type","default":""},"results":{"items":{"$ref":"#/components/schemas/ConnectorResult"},"type":"array","maxItems":250,"minItems":1,"title":"Results","description":"Connector outcomes"}},"type":"object","required":["results"],"title":"TelemetryPayload"},"TransferOffer":{"properties":{"id":{"type":"string","title":"Id","description":"Transfer offer ID"},"transfer_type":{"type":"string","title":"Transfer Type","description":"PRIVATE, SHARED, TAXI, HOURLY, etc.","default":""},"price":{"type":"number","title":"Price"},"currency":{"type":"string","title":"Currency","default":"EUR"},"price_formatted":{"type":"string","title":"Price Formatted","default":""},"vehicle":{"$ref":"#/components/schemas/TransferVehicle"},"provider_name":{"type":"string","title":"Provider Name","default":""},"provider_logo":{"type":"string","title":"Provider Logo","default":""},"start_location":{"type":"string","title":"Start Location","default":""},"end_location":{"type":"string","title":"End Location","default":""},"duration_minutes":{"type":"integer","title":"Duration Minutes","default":0},"cancellation_policy":{"type":"string","title":"Cancellation Policy","default":""},"fetched_at":{"type":"string","format":"date-time","title":"Fetched At"}},"type":"object","required":["id","price"],"title":"TransferOffer","description":"A single transfer/ground-transport offer."},"TransferSearchRequest":{"properties":{"start_iata":{"anyOf":[{"type":"string","maxLength":4,"minLength":3},{"type":"null"}],"title":"Start Iata","description":"IATA airport code for pickup (e.g., 'BCN', 'CDG')"},"start_latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Start Latitude"},"start_longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Start Longitude"},"start_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Address","description":"Pickup address (if not using IATA)"},"end_iata":{"anyOf":[{"type":"string","maxLength":4,"minLength":3},{"type":"null"}],"title":"End Iata","description":"IATA airport code for dropoff (airport-to-airport transfers)"},"end_latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"End Latitude"},"end_longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"End Longitude"},"end_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Address","description":"Dropoff address"},"end_city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End City","description":"Dropoff city name"},"transfer_type":{"type":"string","title":"Transfer Type","description":"PRIVATE, SHARED, TAXI, HOURLY, AIRPORT_EXPRESS, AIRPORT_BUS","default":"PRIVATE"},"start_datetime":{"type":"string","format":"date-time","title":"Start Datetime","description":"Pickup date and time (ISO 8601)"},"passengers":{"type":"integer","maximum":15.0,"minimum":1.0,"title":"Passengers","default":2},"currency":{"type":"string","maxLength":3,"minLength":3,"title":"Currency","default":"EUR"},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","default":20}},"type":"object","required":["start_datetime"],"title":"TransferSearchRequest","description":"Parameters for a transfer/ground-transport search."},"TransferSearchResponse":{"properties":{"search_id":{"type":"string","title":"Search Id","default":""},"offers":{"items":{"$ref":"#/components/schemas/TransferOffer"},"type":"array","title":"Offers","default":[]},"total_results":{"type":"integer","title":"Total Results","default":0},"search_params":{"type":"object","title":"Search Params"}},"type":"object","title":"TransferSearchResponse","description":"Full response from a transfer search."},"TransferVehicle":{"properties":{"type":{"type":"string","title":"Type","description":"Vehicle type code (e.g., 'SD' = sedan, 'VN' = van)","default":""},"description":{"type":"string","title":"Description","default":""},"max_passengers":{"type":"integer","title":"Max Passengers","default":0},"image_url":{"type":"string","title":"Image Url","default":""}},"type":"object","title":"TransferVehicle","description":"Vehicle details for a transfer offer."},"UnlockRequest":{"properties":{"booking_type":{"type":"string","title":"Booking Type","description":"'flight' or 'hotel'","default":"flight"},"offer_id":{"type":"string","title":"Offer Id","description":"Offer ID — required for flights","default":""},"rate_key":{"type":"string","title":"Rate Key","description":"Rate key — required for hotels","default":""},"search_id":{"type":"string","title":"Search Id","description":"Search ID for tracking","default":""}},"type":"object","title":"UnlockRequest","description":"Request to unlock an offer for booking.\n\nFor flights: provide `offer_id` (from search response).\nFor hotels: provide `rate_key` (from search or checkrate response)."},"UnlockResponse":{"properties":{"offer_id":{"type":"string","title":"Offer Id","default":""},"booking_type":{"type":"string","title":"Booking Type","default":"flight"},"unlock_status":{"$ref":"#/components/schemas/UnlockStatus"},"payment_charged":{"type":"boolean","title":"Payment Charged","default":false},"payment_amount_cents":{"type":"integer","title":"Payment Amount Cents","default":0},"payment_currency":{"type":"string","title":"Payment Currency","default":"usd"},"payment_intent_id":{"type":"string","title":"Payment Intent Id","default":""},"confirmed_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confirmed Price"},"confirmed_currency":{"type":"string","title":"Confirmed Currency","default":""},"offer_expires_at":{"type":"string","title":"Offer Expires At","default":""},"checkout_token":{"type":"string","title":"Checkout Token","default":""},"rate_key":{"type":"string","title":"Rate Key","default":""},"rate_comments":{"type":"string","title":"Rate Comments","default":""},"cancellation_policies":{"items":{"type":"object"},"type":"array","title":"Cancellation Policies"},"message":{"type":"string","title":"Message","default":""}},"type":"object","required":["unlock_status"],"title":"UnlockResponse","description":"Response from unlocking an offer for booking."},"UnlockStatus":{"type":"string","enum":["locked","unlocked","payment_failed"],"title":"UnlockStatus"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyCheckoutRequest":{"properties":{"checkout_token":{"type":"string","title":"Checkout Token"},"offer_id":{"type":"string","title":"Offer Id"}},"type":"object","required":["checkout_token","offer_id"],"title":"VerifyCheckoutRequest"},"VerifyCheckoutResponse":{"properties":{"valid":{"type":"boolean","title":"Valid"},"message":{"type":"string","title":"Message","default":""},"offer_id":{"type":"string","title":"Offer Id","default":""},"agent_id":{"type":"string","title":"Agent Id","default":""}},"type":"object","required":["valid"],"title":"VerifyCheckoutResponse"}},"securitySchemes":{"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"},"APIKeyQuery":{"type":"apiKey","in":"query","name":"api_key"}}},"tags":[{"name":"agents","description":"Agent registration and payment setup. Register once to get an API key, then attach a payment card for booking."},{"name":"flights","description":"Flight search and location resolution. Searching is **FREE** — no limits. Returns real-time prices from 400+ airlines via GDS/NDC providers, plus 140 local airline connectors (Ryanair, Wizz Air, EasyJet, Southwest, AirAsia, Norwegian, and more). Local connectors work without an API key via `search-local`."},{"name":"bookings","description":"Unlock offers ($1) and book travel (free after unlock). Works for flights AND hotels. Unlock confirms the latest price and reserves for 30 minutes. Flight booking creates a real airline reservation with a PNR code. Hotel booking creates a real hotel reservation. ⚠️ Use REAL passenger/guest details."},{"name":"hotels","description":"Hotel search, booking, cancellation & vouchers — 300,000+ properties via multiple wholesale suppliers. Full booking workflow: search → checkrate (if RECHECK) → book → voucher. Multiple providers queried in parallel for search. Cancellation simulation available to check fees before committing."},{"name":"transfers","description":"Ground transport search — private cars, shared shuttles, taxis, airport express. Airport-to-city, airport-to-airport, and point-to-point transfers."},{"name":"activities","description":"Tours & activities search — 300,000+ things to do worldwide via wholesale suppliers. Museum tickets, day trips, excursions, food tours, shows, and more."},{"name":"protocols","description":"Agent Interaction Protocols (AIP) — machine-readable definitions for how AI agents can interact with LCC airlines (Ryanair, Wizzair, etc.) that lack GDS/API connectivity. Each protocol documents API endpoints, booking flows, and data mapping."}]}