| name | hotel-search |
| description | Search and book real hotel rooms through LetsFG. Returns only bookable, free-cancellation, pay-later rates from live supplier inventory, with the price the guest actually pays. Use when the user asks to "find a hotel", "book a hotel", "find a room", "where should I stay in X", "hotels near Y", "cancel my hotel", or any accommodation query. Do NOT use for flights (use the flight-search skill), car rentals, or activities. |
| metadata | {"author":"LetsFG - github.com/LetsFG","version":"1.0.0"} |
Hotel Search and Booking
Real, bookable hotel inventory through LetsFG. Search is free; booking charges 5% of the
price to the card on file and hands you a pay link for the balance.
Read this before your first call
The same card authorises flights and hotels. The PFS Bearer token (card-backed, from
connecting the MCP server — the consent step saves a card at https://letsfg.co/connect) is
accepted by the hotel endpoints, and so is a Developer API key (X-API-Key). Use whichever
you already hold. If you hold neither, do not register a billing account on someone's behalf
and do not fall back to scraping a hotel site — say so plainly to whoever asked.
A card on file is required for search, not just booking. A hotel search opens a real
session at the supplier and booking blocks a real rate, so every hotel endpoint returns
402 without a payment method. This is deliberate: better to refuse up front than to let you
reach the point of commitment and discover you cannot pay.
Only free-cancellation, pay-later rates are sold. Those are the rates where the guest's
balance can safely be settled with the supplier after booking, which is what makes the
5%-now/rest-later model work at all. You will see fewer results than a metasearch shows.
Every one of them can actually be booked.
How the money works
| Step | Who is charged | Amount |
|---|
| Search | nobody | free |
| Book | the agent's card, immediately | 5% of the price, non-refundable |
| Balance | the guest pays the supplier directly, via pay_link | the rest, by balance_due_by |
balance_due_by is the supplier's own auto-cancellation date, not a date LetsFG invents.
Miss it and the room is released.
price in the search response is what the guest pays. There is no wholesale figure in the
response to quote by mistake.
Workflow
from letsfg import LetsFG
lfg = LetsFG(api_key="trav_...")
city = lfg.hotel_destinations("Warsaw")[0]
stays = lfg.search_hotels(
city_id=city["Id"], city_name=city["Name"],
check_in="2026-11-10", check_out="2026-11-12", adults=2,
)
hotel = stays["hotels"][0]
offer = hotel["offers"][0]
booking = lfg.book_hotel_and_wait(
session_id=stays["session_id"],
hotel_code=hotel["hotel_code"],
combination_id_v2=offer["combination_id_v2"],
expected_price=offer["price"],
expected_balance=offer["balance_to_supplier"],
city_id=city["Id"], city_name=city["Name"],
check_in="2026-11-10", check_out="2026-11-12",
guests=[{"title": "Mr", "first_name": "Jan", "last_name": "Kowalski"}],
email="guest@example.com", phone="512345678",
)
print(booking["confirmation"], booking["pay_link"], booking["balance_due_by"])
lfg.cancel_hotel(booking["confirmation"])
MCP tools, in call order: resolve_hotel_city → search_hotels → book_hotel →
get_hotel_booking → cancel_hotel_booking.
Critical rules
- Never call
book_hotel twice for the same rate. It is not idempotent: two calls book
the room twice and charge two reservation fees. If a call times out, poll the job.
- Booking is asynchronous.
book_hotel returns a booking_job_id, not a booking. Poll
get_hotel_booking every ~20s until status is succeeded or failed. This is what
makes it impossible to charge a card and then lose the confirmation to a timeout.
- Send
expected_price and expected_balance back verbatim from the search response.
The booking is refused if the supplier's price has moved, so a guest is never charged a
price they did not agree to.
- Use the guest's real email. The voucher and the pay link go there; a typo loses the
booking. It is validated before anything is charged.
- Tell the guest the fee is non-refundable before you book. Cancelling returns the
balance obligation, never the 5%.
- A cancellation timeout is not a failure. It drives a browser at the supplier and takes
over a minute. Re-check before retrying.
Error handling
| Status | Meaning | What to do |
|---|
401 | Credential invalid, expired or revoked | Reconnect at https://letsfg.co/connect, or check the API key |
402 | No payment method on file | Attach a card; required for search too |
409 | The chosen rate is gone | Search again and pick another |
504 | Supplier did not answer in time | If booking, poll the job — do NOT re-book |
job failed | Card declined, or no rate left | Read error; nothing was charged |
Links