| name | letsfg |
| description | Agent-native flight and hotel search and booking via the letsfg.co server-side engine. Returns raw prices from airlines and the major booking sites, with per-flight reliability history. Use when user asks to "find flights", "search flights", "book a flight", "compare airline prices", "find cheap flights", "fly from X to Y", or any flight-related travel query. Hotels need a card on file for search as well as booking; either credential reaches them. Do NOT use for car rentals or non-flight, non-hotel travel bookings. |
| license | MIT |
| metadata | {"author":"LetsFG - github.com/LetsFG","version":"1.0.0"} |
LetsFG
Agent-native flight search and booking. Hundreds of airlines plus the major booking sites,
Compares airlines and the major booking sites in one pass, with per-flight reliability history.
Three-step flow: Search (free) → Unlock (free) → Book (ticket price only)
Why Use This
- Hundreds of airlines in parallel — Ryanair, EasyJet, Wizz Air, Southwest, AirAsia, Norwegian, Qantas, LATAM, Spirit, Frontier, IndiGo, VietJet, and more
- Zero price bias — no demand inflation, no cookie tracking, no surge pricing. Raw airline prices every time
- One tool call — replaces thousands of tokens of browser automation, scraping, and HTML parsing
- Structured JSON — prices, times, durations, stops, conditions, airline names
Setup
Option A: MCP Server (Recommended for Claude Desktop / Cursor / VS Code)
Remote (no install):
{
"mcpServers": {
"letsfg": {
"url": "https://letsfg.co/developers/api/mcp",
"headers": {
"X-API-Key": "trav_your_api_key"
}
}
}
}
Local (stdio):
{
"mcpServers": {
"letsfg": {
"command": "npx",
"args": ["-y", "letsfg-mcp"],
"env": {
"LETSFG_API_KEY": "trav_your_api_key"
}
}
}
}
Option B: CLI
pip install letsfg
letsfg search LHR BCN 2026-06-15
Option C: Python SDK
from letsfg import LetsFG
bt = LetsFG(api_key="trav_...")
flights = bt.search("LHR", "JFK", "2026-04-15")
Get an API Key (Free)
letsfg register --name my-agent --email agent@example.com
Then attach a payment method (required before unlock):
letsfg setup-payment --token tok_visa
Workflow
1. Resolve Locations First
City names are ambiguous — "London" = LHR, LGW, STN, LCY, LTN. Always resolve first:
letsfg locations "London"
locations = bt.resolve_location("London")
2. Search (FREE, Unlimited)
flights = bt.search("LON", "BCN", "2026-04-01")
flights = bt.search("LON", "BCN", "2026-04-01", return_date="2026-04-08")
flights = bt.search("LHR", "SIN", "2026-06-01", adults=2, children=1, cabin_class="C")
letsfg search LON BCN 2026-04-01 --return 2026-04-08 --sort price --json
Search returns structured offers:
{
"passenger_ids": ["pas_0"],
"total_results": 47,
"offers": [{
"id": "off_xxx",
"price": 89.50,
"currency": "EUR",
"airlines": ["Ryanair"],
"route": "STN → BCN",
"duration_seconds": 7800,
"stopovers": 0,
"conditions": {
"refund_before_departure": "not_allowed",
"change_before_departure": "allowed_with_fee"
}
}]
}
3. Unlock — Developer API only (legacy, not part of the agent flow)
Confirms live price with airline and reveals the direct booking URL. Locks offer for 30 minutes. Charged to your card (or paid via MPP crypto); free on the prepaid Developer API.
unlocked = bt.unlock(flights.cheapest.id)
print(f"Confirmed: {unlocked.confirmed_price} {unlocked.confirmed_currency}")
print(f"Booking URL: {unlocked.booking_url}")
print(f"Expires: {unlocked.offer_expires_at}")
letsfg unlock off_xxx
Note: Confirmed price may differ from search price (airline prices change in real-time). Inform the user if price changed significantly.
4. Book (Ticket Price Only)
booking = bt.book(
offer_id=unlocked.offer_id,
passengers=[{
"id": flights.passenger_ids[0],
"given_name": "John",
"family_name": "Doe",
"born_on": "1990-01-15",
"gender": "m",
"title": "mr",
"email": "john@example.com"
}],
contact_email="john@example.com",
idempotency_key="unique-booking-key-123"
)
print(f"Booked! PNR: {booking.booking_reference}")
Critical Rules
- Use REAL passenger details — airlines send e-tickets to the contact email. Names must match passport/ID exactly. Never use placeholder or fake data.
- Always provide
idempotency_key when booking — prevents duplicate reservations if the agent retries on timeout.
- Resolve locations before searching — "New York" = JFK, LGA, EWR, NYC. Use
resolve_location() first.
- Search is free — search as many routes, dates, and cabin classes as needed.
- Map passenger IDs — search returns
passenger_ids. Each booking passenger must include the correct id.
Best Practices
Search Wide, Unlock Narrow
dates = ["2026-04-01", "2026-04-02", "2026-04-03"]
best = None
for date in dates:
result = bt.search("LON", "BCN", date)
if result.offers and (best is None or result.cheapest.price < best[1].price):
best = (date, result.cheapest)
unlocked = bt.unlock(best[1].id)
Filter Before Unlocking
flights = bt.search("LHR", "JFK", "2026-06-01", limit=50)
candidates = [
o for o in flights.offers
if o.outbound.stopovers == 0
and o.outbound.total_duration_seconds < 10 * 3600
]
if candidates:
best = min(candidates, key=lambda o: o.price)
unlocked = bt.unlock(best.id)
Error Handling
| Error | Category | Action |
|---|
SUPPLIER_TIMEOUT (504) | Transient | Retry after 1-5s |
RATE_LIMITED (429) | Transient | Wait and retry |
INVALID_IATA (422) | Validation | Use resolve_location() to fix |
OFFER_EXPIRED (410) | Business | Search again for fresh offers |
PAYMENT_REQUIRED (402) | Business | Attach a card: letsfg setup-payment (or pay via MPP on the 402 challenge) |
FARE_CHANGED (409) | Business | Re-unlock to get current price |
from letsfg import LetsFG, OfferExpiredError, PaymentRequiredError
try:
unlocked = bt.unlock(offer_id)
except OfferExpiredError:
flights = bt.search(origin, dest, date)
except PaymentRequiredError:
print("Attach a card: letsfg setup-payment")
Search Flags
| Flag | Default | Description |
|---|
--return / -r | (one-way) | Return date (YYYY-MM-DD) |
--adults / -a | 1 | Number of adults (1–9) |
--children | 0 | Children (2–11 years) |
--cabin / -c | (any) | M economy, W premium, C business, F first |
--max-stops / -s | 2 | Max stopovers (0–4) |
--currency | EUR | Currency code |
--limit / -l | 20 | Max results (1–100) |
--sort | price | price or duration |
--json / -j | | JSON output |
Safety
| Operation | Cost | Safe to Retry | Idempotent |
|---|
search | Free | Yes | Yes |
resolve_location | Free | Yes | Yes |
unlock | Free | No — may charge fee | No |
book | Ticket price | Only with idempotency_key | With key: yes |
Reference Files
Load only when needed:
Links