| name | letsfg |
| description | LetsFG — Agent-native flight and hotel search and booking API. Hundreds of airlines plus the major booking sites (Google Flights, Skyscanner, Kiwi, Kayak, Momondo), with per-flight reliability history and instant booking. Plus real bookable hotel rates — free cancellation and pay-later: hold the room with a small upfront charge, then settle the balance by link up to the hotel's own deadline. letsfg.co |
SKILL.md — LetsFG Capabilities
MPP: a card-free enrolment lane for agents holding a Tempo wallet is
offered only when the 402 from POST /api/agent-access/request carries an
mpp object. It costs $0.01 once, as verification only. Search stays free
and booking costs the price on the offer. Earlier revisions of this page
described an MPP charge at unlock time; that never shipped. See
https://letsfg.co/for-agents.
⚠️ Agents: do not create a Developer API account
Do NOT call /developers/api/v1/agents/register or
/developers/api/v1/agents/setup-payment, and do NOT run
letsfg register or letsfg setup-payment. Those belong to a separate,
paid, prepaid-balance product for high-volume commercial integrations and
create a billing account you almost certainly do not want.
To search and book flights, connect LetsFG as an MCP server at
https://letsfg.co/developers/api/mcp and approve it — the consent step saves
a card at https://letsfg.co/connect (nothing charged). Then search and book.
See https://letsfg.co/for-agents.
Machine-readable skill manifest for AI agents and documentation indexers.
Identity
- Name: LetsFG
- Type: API + SDK + MCP Server + CLI
- Purpose: Agent-native flight and hotel search and booking
- Compatible agents: OpenClaw, Perplexity Computer, Claude Desktop, Cursor, Windsurf, and any MCP-compatible client
- API Base URL:
https://letsfg.co/developers/api/v1
- MCP Endpoint:
https://letsfg.co/developers/api/mcp (Streamable HTTP)
- Packages: PyPI
letsfg · npm letsfg · npm letsfg-mcp
- License: MIT
Access Modes
| Mode | Best for | Speed | Cost |
|---|
| MCP / SDK / CLI (PFS card-backed token) | Almost every agent. Search + booking | 8–10 s to first results | Free auth, free search, booking at the price on the offer |
Developer API (https://letsfg.co/developers) | Business / commercial / high-volume | 2–5 s (discover) · 8–10 s to first results (full search) | Prepaid credits; direct booking URLs, no per-booking fee |
Skills
search_flights
Search hundreds of airlines AND the major booking sites (Google Flights, Skyscanner, Kiwi, Kayak, Momondo) in one call. Returns real-time prices plus per-flight reliability history.
- Cost: FREE (unlimited)
- Input: origin (IATA), destination (IATA), date_from, optional: date_to, return_from, return_to, adults, children, infants, cabin_class (M/W/C/F), max_stopovers, currency, sort, limit
- Output: List of flight offers with price, airlines, times, segments, conditions, passenger_ids
- Note: On PFS (Bearer token), call
book_flight directly — no unlock step — then poll get_flight_booking. On the Developer API, offers must be unlocked before booking.
- Rate limit (PFS): 10 searches per 10 min, 30 per hour, 100 per day, per card. Polling results never counts.
resolve_hotel_city
Resolve a place name to the supplier city id that hotel search needs.
- Cost: FREE (a card must still be on file)
- Endpoint:
POST /api/v1/hotels/destinations
- Input: text (place name, e.g. "Warsaw")
- Output: Matches, best first. Use
Id as city_id and Name as city_name.
search_hotels
Search real, bookable hotel inventory.
- Cost: FREE, but a payment method on file is REQUIRED — for search, not just booking. A hotel
search opens a real session at the supplier, so it returns HTTP 402 without a card.
- Auth: Either a Developer API key (
X-API-Key) or the PFS card-backed token from the connect flow. The same card authorises flights and hotels.
- Endpoint:
POST /api/v1/hotels/search
- Input: city_id, city_name, check_in, check_out, adults, children, child_ages, nationality, limit
- Output: hotels[] each with offers[] carrying
price (what the guest pays),
reservation_fee_now (the 5%), balance_to_supplier, balance_due_by,
free_cancellation_until, combination_id_v2
- Note: Only free-cancellation, pay-later rates are sold, so the result set is smaller than a
metasearch and every rate returned can actually be booked. Keep
session_id and the chosen
offer's combination_id_v2 — booking needs both.
search_transfers
Search ground transfers — private cars, taxis, shared shuttles, airport express.
- Cost: FREE
- Input: origin, destination, date, passengers
- Output: Transfer options with prices and vehicle types
search_activities
Search activities — tours, museum tickets, day trips via direct APIs and aggregators.
- Cost: FREE
- Input: location, date_from, date_to
- Output: Activity options with prices, descriptions, availability
resolve_location
Resolve city names to IATA airport/city codes.
- Cost: FREE
- Input: query (city name, e.g. "London")
- Output: List of matching IATA codes (e.g. LON, LHR, LGW, STN, LTN, LCY)
unlock_flight_offer
Confirm live price with airline and reveal the direct booking URL. Reserves the offer for 30 minutes.
- Developer API only. There is no unlock step on a PFS Bearer token: call
/api/agent-book instead. Legacy path — not part of the agent flow.
- Endpoint:
POST /api/v1/bookings/unlock
- Input: offer_id from search results (only required parameter)
- Output: confirmed_price, confirmed_currency, booking_url, offer_expires_at
- Prerequisite: A payment method on file (
setup_payment) on the Developer API account.
- HTTP 402: No card on file. With MPP support, response carries a
WWW-Authenticate: Payment challenge — pay via Tempo USDC.e and retry. Otherwise add a card via setup_payment.
- HTTP 410: Offer expired — airline sold the seats, search again (OfferExpiredError)
- Note: confirmed_price may differ from search price (airline prices change in real-time). After unlock, you have 30 minutes to complete the booking. If the window expires, search again (free) and unlock again.
- Python:
unlocked = bt.unlock(offer_id) → returns UnlockResult
- CLI:
letsfg unlock off_xxx
- JS/TS:
const unlocked = await bt.unlock(offerId)
book_flight
Book an offer.
- PFS (Bearer token):
POST /api/agent-book. No unlock step — search, then book directly.
Works for every offer in the results, whichever seller it came from. Exactly what the website
checkout does: the fare plus LetsFG's markup is held on the connected card (not taken), a
LetsFG booking agent buys the ticket from the seller, and the hold is captured only once a real
airline PNR exists. If the booking fails the hold is released and nothing is charged.
- Input:
search_id + offer_id exactly as search returned them (offers expire ~15 min),
contact_email, and ONE passenger per call: given_name, family_name, born_on, gender (m/f),
nationality (ISO-2), phone_number + phone_country, address_line1, address_city,
address_postal, address_country; passport_number/country/expiry optional.
- Output (seconds):
{"state": "booking_in_progress", "booking_ref": "eyJ...", "held": {"amount": 93, "currency": "EUR", "card": "visa ending 5709"}, "charged": 0}.
The booking itself takes 4–11 minutes — poll get_flight_booking.
- Nothing charged on:
{"error": "missing_details", "missing_fields": [...]} (ask, call again),
payment_method_required and payment_declined (both carry add_card_url: https://letsfg.co/connect).
- Never call it twice for the same trip while one is in progress — that places a second hold.
- CLI:
letsfg book ws_off_xxx --search-id ws_xxx --passenger '{...}' --email you@example.com
- Python:
bt.book(offer_id=..., passengers=[{...}], contact_email=..., search_id=...)
- Developer API: Requires
unlock first. Creates a real airline reservation with PNR code, and
charges the ticket price to the card on the Developer API account before booking.
- Prerequisite: Payment method must be attached via
setup_payment first.
- Input: offer_id, passengers (id, given_name, family_name, born_on, gender, title, email, phone_number), contact_email
- Output: booking_reference (airline PNR), status, flight_price, currency
- Payment flow: the card is charged the ticket price → LetsFG books via the airline → you get the PNR. If the airline booking fails, you are automatically refunded.
- CRITICAL (both paths): Use real passenger names (must match passport/ID) and real email (airline sends e-ticket there).
get_flight_booking
Where a booking started by book_flight has got to (PFS). POST /api/agent-book/status {"booking_ref": "eyJ..."}.
- Cost: FREE. Poll every 20–30 s.
- States:
booking_in_progress (the agent is at the seller's checkout — keep waiting) →
completed (pnr, charged_amount, currency — booked) | failed (failure_reason; the hold was
released, nothing charged) | needs_attention (a human at LetsFG is checking it — do NOT book again;
the traveller will be emailed). updated_at_ms says when it last moved.
- Only
completed with a PNR means booked.
book_hotel
Start a hotel booking. Returns a job, NOT a booking.
- Cost: 5% of the price charged immediately to the card on file as a NON-REFUNDABLE
reservation fee. The balance is paid directly to the supplier through the returned
pay_link.
- Endpoint:
POST /api/v1/hotels/book
- Input: session_id, hotel_code, combination_id_v2, expected_price, expected_balance, city_id,
city_name, check_in, check_out, adults, guests[{title, first_name, last_name}], email, phone
- Output: booking_job_id, status "in_progress", poll URL
- Asynchronous: a real booking takes minutes — the rate is re-blocked at the supplier, the card
charged, the room committed. Poll
get_hotel_booking until status is succeeded or failed.
This is what makes it impossible to charge a card and then lose the confirmation to a timeout.
- CRITICAL: send
expected_price and expected_balance back exactly as search returned them,
or the booking is refused as a price mismatch — a guest is never charged a price they did not
agree to.
- CRITICAL: NOT idempotent. Calling this twice for the same rate books the room twice and
charges two reservation fees. If a call times out, poll the job; do not re-book.
- Note: the fee is charged BEFORE the room is committed, so a declined card costs nothing —
no reservation exists and nothing is charged.
get_hotel_booking
Collect the result of a booking started with book_hotel.
- Cost: FREE
- Endpoint:
GET /api/v1/hotels/booking/{booking_job_id}
- Output: status, and on success confirmation, reservation_fee_charged, pay_link, balance_due,
balance_due_by, terms (including the full cancellation ladder)
- Note:
balance_due_by is the supplier's own auto-cancellation date, not advisory. Miss it and
the room is released.
cancel_hotel_booking
Release a hotel reservation.
- Cost: Free until
balance_due_by; after that the hotel's own ladder applies and can reach
100%. The 5% reservation fee is NOT refunded.
- Endpoint:
POST /api/v1/hotels/cancel
- Input: confirmation
- Output: confirmation, charge
- Note: drives a browser at the supplier and takes over a minute. If it times out, do NOT
assume it failed — re-check before retrying.
register
Register a new AI agent.
- Cost: FREE
- Input: agent_name, email
- Output: api_key (permanent credential)
setup_payment
Developer API only. Attach a payment card to a prepaid Developer API account. Agents on the
PFS lane do not call this — their card is saved at https://letsfg.co/connect during the MCP
connect step.
- Cost: FREE (attaching the card is free; you are charged the ticket price when you book)
- Input: token or payment_method_id or card details
- Output: Payment status confirmation
- Note: Once per Developer API account. The card stays on file for future bookings.
get_agent_profile
Get current agent's profile, usage stats, and payment status.
- Cost: FREE
- Output: Agent details, search count, booking count, payment status
Authentication
PFS (recommended — almost every agent): a card-backed Bearer token. Nothing
is charged to connect: the card is saved in a 0.00 Revolut setup at
https://letsfg.co/connect (any card, or Revolut Pay / Google Pay; no Revolut
account needed; card details never touch LetsFG). Search, flight booking and
hotels all work with it.
Authorization: Bearer eyJ...
Get a token — the one way in:
- Add LetsFG as a remote MCP server:
https://letsfg.co/developers/api/mcp.
- Approve the connection. The OAuth consent step opens
https://letsfg.co/connect, where the person adds a card or pays 0.00 with
Revolut Pay / Google Pay.
- The OAuth token you receive is card-backed. Over the MCP it is carried for
you; over raw HTTP send it as
Authorization: Bearer <token>.
POST /api/agent-access/request answers 402 with these steps as JSON
(add_card_url, how). The Stripe enrolment lanes (setup_url, setup_intent,
card_token) were retired on 2026-09-02 and every token they issued was revoked
(401 TOKEN_REVOKED; /api/agent-access/verify answers 410 for a Stripe
credential) — reconnect at letsfg.co/connect. letsfg auth (npm or PyPI) now
drives that connect flow from the terminal and stores the token; the CLI and
SDKs otherwise read it from LETSFG_BEARER_TOKEN. One card = one account; quotas are per card. Full flow: