letsfg 2026.5.74 → 2026.5.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # LetsFG — Your AI agent just learned to book flights. (Node.js)
2
2
 
3
- **Server-side search engine. Real prices. One function call.** Search hundreds of airlines at raw airline prices — **$20–$50 cheaper** than Booking.com, Kayak, and other OTAs. Zero dependencies. Built for AI agents.
3
+ **Server-side search engine. Real prices. One function call.** Search every airline in the world and the major booking sites; the price shown is the total you pay. Zero dependencies. Built for AI agents.
4
4
 
5
5
  [![GitHub stars](https://img.shields.io/github/stars/LetsFG/LetsFG?style=social)](https://github.com/LetsFG/LetsFG)
6
6
  [![npm](https://img.shields.io/npm/v/letsfg)](https://www.npmjs.com/package/letsfg)
@@ -54,7 +54,7 @@ const flights = await bt.search('GDN', 'BER', '2026-03-03');
54
54
  const best = cheapestOffer(flights);
55
55
  console.log(offerSummary(best));
56
56
 
57
- // Book — no booking fee, no transaction fee — our margin is already in the price you saw; no unlock step. Starts the booking:
57
+ // Book — no booking fee, no transaction fee on top of the price you saw; no unlock step. Starts the booking:
58
58
  // the fare is HELD on your card and a LetsFG agent buys the ticket (4-11 min).
59
59
  const result = await bt.book(
60
60
  best.id,
@@ -87,7 +87,7 @@ console.log(status); // { state: 'completed', pnr: 'ABC123', charged_amount: 93,
87
87
  ### How booking works
88
88
 
89
89
  `bt.book()` posts to `POST /api/agent-book` and does exactly what the website
90
- checkout does: the fare plus LetsFG's markup is **held** on the connected card
90
+ checkout does: the price shown is **held** on the connected card
91
91
  (not taken), a LetsFG booking agent buys the ticket from the seller, and the
92
92
  hold is captured only once a real airline PNR exists. If the booking fails the
93
93
  hold is released and nothing is charged. Every offer can be booked this way —
@@ -182,6 +182,12 @@ MIT
182
182
 
183
183
  Your agent can book hotels as well as flights. Same card-backed token or API key, same connected payment method.
184
184
 
185
+ > **Update your SDK before booking hotels.** Hotel booking needs **letsfg 2026.5.101** or later (Python),
186
+ > **letsfg 2026.5.74** or later (JavaScript/TypeScript) or **letsfg-mcp 2026.5.77** or later. Earlier releases send
187
+ > the reservation-fee fields retired on 2026-09-11 (`expected_balance`, no `expected_cost`), and the API refuses
188
+ > every hotel booking they make. Update with `pip install -U letsfg`, `npm install letsfg@latest` or
189
+ > `npx -y letsfg-mcp@latest`. The hosted MCP at `https://letsfg.co/developers/api/mcp` needs no update.
190
+
185
191
  ```python
186
192
  from letsfg import LetsFG
187
193
  lfg = LetsFG()
@@ -232,9 +238,7 @@ released and nothing is charged.
232
238
  There is **no reservation fee, no deposit and no pay link**, and the guest owes the hotel nothing
233
239
  further. (Those belonged to the process retired on 2026-09-11.)
234
240
 
235
- `price` is the supplier's cost plus 6.4% (our margin and payment processing) for Revolut Pay or a
236
- card issued in the EEA, or 8.3% for a card issued outside the EEA — the search response's
237
- `markup_rate` says which. Nothing is added at booking. Prices are in the currency you search in:
241
+ `price` is what the guest pays. Nothing is added at booking. Prices are in the currency you search in:
238
242
  USD unless you ask for another.
239
243
 
240
244
  Cancelling a refundable rate before its `free_cancellation_until` costs nothing and refunds the
@@ -1618,15 +1618,23 @@ var LetsFG = class {
1618
1618
  currency: options.currency ?? "EUR",
1619
1619
  limit: options.limit ?? 50
1620
1620
  };
1621
- if (options.returnDate) body.return_date = options.returnDate;
1622
- if (options.cabinClass) body.cabin_class = options.cabinClass;
1623
- if (options.maxStopovers != null) body.max_stopovers = options.maxStopovers;
1624
- if (options.sort) body.sort = options.sort;
1625
1621
  if (options.departureTimeFrom) body.departure_time_from = options.departureTimeFrom;
1626
1622
  if (options.departureTimeTo) body.departure_time_to = options.departureTimeTo;
1627
1623
  if (this.usingPFS) {
1628
- return this.searchPFS(body);
1624
+ if (options.returnDate) body.return_date = options.returnDate;
1625
+ if (options.cabinClass) body.cabin = options.cabinClass;
1626
+ if (options.maxStopovers != null) body.max_stops = options.maxStopovers;
1627
+ if (options.sort) body.sort_by = options.sort;
1628
+ const result = await this.searchPFS(body);
1629
+ if (options.limit != null && Array.isArray(result.offers)) {
1630
+ result.offers = result.offers.slice(0, Math.max(0, options.limit));
1631
+ }
1632
+ return result;
1629
1633
  }
1634
+ if (options.returnDate) body.return_from = options.returnDate;
1635
+ if (options.cabinClass) body.cabin_class = options.cabinClass;
1636
+ if (options.maxStopovers != null) body.max_stopovers = options.maxStopovers;
1637
+ if (options.sort) body.sort = options.sort;
1630
1638
  return this.post("/developers/api/v1/flights/search", body);
1631
1639
  }
1632
1640
  /** PFS path: POST /api/search -> poll /api/results/<id> */
package/dist/cli.js CHANGED
@@ -374,15 +374,23 @@ var LetsFG = class {
374
374
  currency: options.currency ?? "EUR",
375
375
  limit: options.limit ?? 50
376
376
  };
377
- if (options.returnDate) body.return_date = options.returnDate;
378
- if (options.cabinClass) body.cabin_class = options.cabinClass;
379
- if (options.maxStopovers != null) body.max_stopovers = options.maxStopovers;
380
- if (options.sort) body.sort = options.sort;
381
377
  if (options.departureTimeFrom) body.departure_time_from = options.departureTimeFrom;
382
378
  if (options.departureTimeTo) body.departure_time_to = options.departureTimeTo;
383
379
  if (this.usingPFS) {
384
- return this.searchPFS(body);
380
+ if (options.returnDate) body.return_date = options.returnDate;
381
+ if (options.cabinClass) body.cabin = options.cabinClass;
382
+ if (options.maxStopovers != null) body.max_stops = options.maxStopovers;
383
+ if (options.sort) body.sort_by = options.sort;
384
+ const result = await this.searchPFS(body);
385
+ if (options.limit != null && Array.isArray(result.offers)) {
386
+ result.offers = result.offers.slice(0, Math.max(0, options.limit));
387
+ }
388
+ return result;
385
389
  }
390
+ if (options.returnDate) body.return_from = options.returnDate;
391
+ if (options.cabinClass) body.cabin_class = options.cabinClass;
392
+ if (options.maxStopovers != null) body.max_stopovers = options.maxStopovers;
393
+ if (options.sort) body.sort = options.sort;
386
394
  return this.post("/developers/api/v1/flights/search", body);
387
395
  }
388
396
  /** PFS path: POST /api/search -> poll /api/results/<id> */
package/dist/cli.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  LetsFG,
4
4
  LetsFGError,
5
5
  offerSummary
6
- } from "./chunk-GVKYPTY3.mjs";
6
+ } from "./chunk-6IWYHW62.mjs";
7
7
 
8
8
  // src/auth.ts
9
9
  import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync } from "fs";
package/dist/index.js CHANGED
@@ -1667,15 +1667,23 @@ var LetsFG = class {
1667
1667
  currency: options.currency ?? "EUR",
1668
1668
  limit: options.limit ?? 50
1669
1669
  };
1670
- if (options.returnDate) body.return_date = options.returnDate;
1671
- if (options.cabinClass) body.cabin_class = options.cabinClass;
1672
- if (options.maxStopovers != null) body.max_stopovers = options.maxStopovers;
1673
- if (options.sort) body.sort = options.sort;
1674
1670
  if (options.departureTimeFrom) body.departure_time_from = options.departureTimeFrom;
1675
1671
  if (options.departureTimeTo) body.departure_time_to = options.departureTimeTo;
1676
1672
  if (this.usingPFS) {
1677
- return this.searchPFS(body);
1673
+ if (options.returnDate) body.return_date = options.returnDate;
1674
+ if (options.cabinClass) body.cabin = options.cabinClass;
1675
+ if (options.maxStopovers != null) body.max_stops = options.maxStopovers;
1676
+ if (options.sort) body.sort_by = options.sort;
1677
+ const result = await this.searchPFS(body);
1678
+ if (options.limit != null && Array.isArray(result.offers)) {
1679
+ result.offers = result.offers.slice(0, Math.max(0, options.limit));
1680
+ }
1681
+ return result;
1678
1682
  }
1683
+ if (options.returnDate) body.return_from = options.returnDate;
1684
+ if (options.cabinClass) body.cabin_class = options.cabinClass;
1685
+ if (options.maxStopovers != null) body.max_stopovers = options.maxStopovers;
1686
+ if (options.sort) body.sort = options.sort;
1679
1687
  return this.post("/developers/api/v1/flights/search", body);
1680
1688
  }
1681
1689
  /** PFS path: POST /api/search -> poll /api/results/<id> */
package/dist/index.mjs CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  offerSummary,
24
24
  rankOffers,
25
25
  selectDiverseTop
26
- } from "./chunk-GVKYPTY3.mjs";
26
+ } from "./chunk-6IWYHW62.mjs";
27
27
  export {
28
28
  AuthenticationError,
29
29
  BoostedTravel,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "letsfg",
3
- "version": "2026.5.74",
4
- "description": "Flights and hotels for AI agents. Server-side engine covers hundreds of airlines; hotels are real bookable inventory with free cancellation and pay-later terms. Includes open-source ranking engine.",
3
+ "version": "2026.5.75",
4
+ "description": "Flights and hotels for AI agents. Server-side engine covers hundreds of airlines; hotels are real bookable inventory with pay-later terms, and every rate says whether it is refundable. Includes open-source ranking engine.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",