Skip to main content

LetsFG — Your AI agent just learned to book flights.

Server-side engine. Real prices. One function call. Search hundreds of airlines at raw airline prices — $20–$50 cheaper than Booking.com, Kayak, and other OTAs.

GitHub stars PyPI

Two ways to use LetsFG

CLI / SDK (PFS Bearer token) Developer API
Search cost Free (card-backed token from letsfg.co/connect, nothing charged) Prepaid credits
Booking POST /api/agent-book — fare held on your card, a LetsFG agent buys the ticket, captured only on a real PNR. Every offer. POST /flights/book — the same hold-then-capture flow, no unlock step, no booking or transaction fee
Speed 8–10 s to first results; longer on a split 2–5 s (discover) · 8–10 s to first results (full)
Setup pip install letsfg, then connect at letsfg.co/developers/api/mcp letsfg.co/developers

Building a product, or need hotels? Use the Developer API — look-to-book search (200 free after every booking, then $0.01), booking through POST /flights/book, no booking fee and no transaction fee.

Install

pip install letsfg

Connect a card once at letsfg.co/connect (nothing charged — see Authentication), then search is free and booking runs on that card:

export LETSFG_BEARER_TOKEN=eyJ...     # the card-backed token from the connect flow
letsfg search LHR BCN 2026-06-15

Search is free and the price you saw is the price charged. There is no unlock step, no booking fee and no transaction fee on any path — our margin is already included in every offer price. The Developer API works the same way: no booking fee and no transaction fee, with the margin already inside the offer price. Its unlock step and 1% (min $3) fee were retired on 2026-09-08.

Authentication

Connect LetsFG as an MCP server at https://letsfg.co/developers/api/mcp and approve the connection — in Claude, ChatGPT, Cursor, Windsurf, or Claude Code (claude mcp add --transport http letsfg https://letsfg.co/developers/api/mcp). The consent step opens letsfg.co/connect, where you add a card (any card, or Revolut Pay / Google Pay) in a 0.00 Revolut setup. Nothing is charged, no Revolut account is needed, and the card details go to Revolut, never to LetsFG. The token you get back is card-backed: it searches and it books. One card = one account; quotas are per card (10 searches per 10 min, 30 per hour, 100 per day — polling never counts).

The SDK reads the token from LETSFG_BEARER_TOKEN or ~/.letsfg/config.json.

Or skip the MCP client entirely and run letsfg auth, which does the same connect flow from the terminal: it registers itself as an OAuth client (PKCE + loopback redirect), opens the card screen for a person to approve, and writes the token to ~/.letsfg/config.json. Add --no-browser to print the URL instead of opening one. The access token lasts about an hour and refreshes itself from a stored 30-day refresh token — call ensure_bearer_token() in a long-lived process and it renews silently.

letsfg auth                # opens a browser
letsfg auth --no-browser   # prints the URL to open yourself

Retired 2026-09-02: the Stripe enrolment lanes (setup_url, setup_session_id, payment_method_id, card_token) and every token they issued (401 TOKEN_REVOKED). verify_payment_method() now raises and says so. There is no endpoint that mints a token from card details — a person must approve once in a browser, so never ask a user for a card number.

from letsfg import LetsFG

# Reads LETSFG_BEARER_TOKEN (or ~/.letsfg/config.json)
bt = LetsFG()

Prefer the paid Developer API instead? Register there and pass an api_keysearch()/book() dispatch automatically based on which credential is set:

# Register (one-time, no auth needed) — Developer API only, most agents don't need this
creds = LetsFG.register("my-agent", "agent@example.com")
bt = LetsFG(api_key=creds["api_key"])  # or set LETSFG_API_KEY env var

# Connect a Revolut payment method (nothing is charged to connect)
# POST /agents/connect-payment returns a one-time link; open it in a browser.
# setup_payment() below calls the RETIRED Stripe route and now answers 410 Gone.

Payments moved to Revolut on 2026-09-08. setup_payment() and the hosted-checkout lane were retired with Stripe and answer 410 Gone naming the replacement: POST /agents/connect-payment, then open the returned connect_url once in a browser.

Verify Your Credentials

# Check that auth + payment are working
profile = bt.me()
print(f"Agent: {profile['agent_name']}")
print(f"Payment: {profile.get('payment_status', 'not set up')}")
print(f"Searches: {profile.get('search_count', 0)}")

Auth Failure Recovery

from letsfg.connectors.auth import BearerTokenError
from letsfg import LetsFG

try:
    bt = LetsFG()
    flights = bt.search("LHR", "JFK", "2026-04-15")
except BearerTokenError:
    print("Token missing or revoked — reconnect at https://letsfg.co/connect through the MCP")

Quick Start (Python)

from letsfg import LetsFG

bt = LetsFG()  # reads LETSFG_BEARER_TOKEN

# Search flights — FREE
flights = bt.search("GDN", "BER", "2026-03-03")
print(f"{flights.total_results} offers, cheapest: {flights.cheapest.summary()}")

# Book — no booking fee, no transaction fee — our margin is already in the price you saw; no unlock step. Starts the booking:
# the fare is HELD on your card and a LetsFG agent buys the ticket (4-11 min).
result = bt.book(
    offer_id=flights.cheapest.id,
    passengers=[{
        "given_name": "John",
        "family_name": "Doe",
        "born_on": "1990-01-15",
        "gender": "m",
        "nationality": "GB",
        "phone_number": "+447700900123",
        "phone_country": "GB",
        "address_line1": "1 Analytical Way",
        "address_city": "London",
        "address_postal": "N1 9GU",
        "address_country": "GB",
    }],
    contact_email="john@example.com",
    search_id=flights.search_id,
)
booking_ref = result["booking_ref"]

# Poll until it lands (every 20-30 s): completed | failed | needs_attention
import time, requests
from letsfg.connectors.auth import get_bearer_token
while True:
    status = requests.post(
        "https://letsfg.co/api/agent-book/status",
        json={"booking_ref": booking_ref},
        headers={"Authorization": f"Bearer {get_bearer_token()}"},
    ).json()
    if status["state"] != "booking_in_progress":
        break
    time.sleep(25)
print(status)  # {"state": "completed", "pnr": "ABC123", "charged_amount": 93, "currency": "EUR"}

How booking works

book() posts to POST /api/agent-book and does 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. Every offer can be booked this way — no unlock step, no booking-link fallback, no separate LetsFG fee.

The call returns within seconds with a booking_ref; the booking itself takes 4–11 minutes. Poll POST /api/agent-book/status with {"booking_ref": ...} every 20–30 s (the SDK has no helper for this yet):

state Meaning
booking_in_progress the agent is at the seller's checkout — keep waiting
completed booked — pnr, charged_amount, currency are in the answer
failed not booked — the hold was released, nothing charged; see failure_reason
needs_attention a human at LetsFG is checking it — do not book again

One traveller per call, with the details an airline checkout asks for: name, date of birth, gender, nationality, email, phone with its country, residence address (passport optional). A missing detail returns missing_details with missing_fields and charges nothing. Never start a second booking for the same trip while one is in progress — that would place a second hold.

Multi-Passenger Search

Searching with multiple passengers works on both paths. Booking more than one passenger in a single call is Developer API only — the free PFS book() books one passenger per call.

# 2 adults + 1 child, round-trip, premium economy
flights = bt.search(
    "LHR", "JFK", "2026-06-01",
    return_date="2026-06-15",
    adults=2,
    children=1,
    cabin_class="W",  # W=premium, M=economy, C=business, F=first
    sort="price",
)

# passenger_ids will be ["pas_0", "pas_1", "pas_2"]
print(f"Passenger IDs: {flights.passenger_ids}")

# Developer API: book with details for EACH passenger. No unlock step.
booking = bt.book(
    offer_id=flights.cheapest.id,
    search_id=flights.search_id,
    passengers=[
        {"id": "pas_0", "given_name": "John", "family_name": "Doe", "born_on": "1990-01-15", "gender": "m", "title": "mr"},
        {"id": "pas_1", "given_name": "Jane", "family_name": "Doe", "born_on": "1992-03-20", "gender": "f", "title": "ms"},
        {"id": "pas_2", "given_name": "Tom", "family_name": "Doe", "born_on": "2018-05-10", "gender": "m", "title": "mr"},
    ],
    contact_email="john@example.com",
)

Resolve Locations

Always resolve city names to IATA codes before searching:

locations = bt.resolve_location("New York")
# [{"iata_code": "JFK", "name": "John F. Kennedy", "type": "airport", "city": "New York"}, ...]

# Use in search
flights = bt.search(locations[0]["iata_code"], "LAX", "2026-04-15")

Working with Search Results

flights = bt.search("LON", "BCN", "2026-04-01", return_date="2026-04-08", limit=50)

# Iterate all offers
for offer in flights.offers:
    print(f"{offer.owner_airline}: {offer.currency} {offer.price}")
    print(f"  Route: {offer.outbound.route_str}")
    print(f"  Duration: {offer.outbound.total_duration_seconds // 3600}h")
    print(f"  Stops: {offer.outbound.stopovers}")
    print(f"  Refundable: {offer.conditions.get('refund_before_departure', 'unknown')}")
    print(f"  Changeable: {offer.conditions.get('change_before_departure', 'unknown')}")

# Filter: direct flights only
direct = [o for o in flights.offers if o.outbound.stopovers == 0]

# Filter: specific airline
ba = [o for o in flights.offers if "British Airways" in o.airlines]

# Filter: refundable only
refundable = [o for o in flights.offers if o.conditions.get("refund_before_departure") == "allowed"]

# Sort by duration
by_duration = sorted(flights.offers, key=lambda o: o.outbound.total_duration_seconds)

# Cheapest offer
print(f"Best: {flights.cheapest.price} {flights.cheapest.currency}")

Starlink Wi-Fi

Offers may carry starlink: confirmed_all / confirmed_some mean the carrier has fully fitted that aircraft type; likely_all / likely_some mean the rollout on that type is underway but incomplete. Segments carry confirmed or likely.

Only confirmed_* is safe to state as fact — likely_* is a signal, not a promise. Anything ending _some has at least one leg without it. An absent field means no information, not an absence of Wi-Fi.

Full semantics: docs/api-search.md.

Error Handling

from letsfg import LetsFG, LetsFGError
from letsfg.connectors.auth import BearerTokenError

bt = LetsFG()  # reads LETSFG_BEARER_TOKEN (or ~/.letsfg/config.json)

# Handle invalid locations
try:
    flights = bt.search("INVALID", "JFK", "2026-04-15")
except LetsFGError as e:
    if e.status_code == 422:
        # Resolve the location first
        locations = bt.resolve_location("London")
        flights = bt.search(locations[0]["iata_code"], "JFK", "2026-04-15")

# Handle booking (PFS path — no unlock step)
try:
    result = bt.book(
        offer_id=flights.cheapest.id, passengers=[...],
        contact_email="...", search_id=flights.search_id,
    )
    if result.get("error") == "missing_details":
        print(f"Ask the traveller for: {result['missing_fields']}")  # nothing charged
    elif result.get("error") == "payment_method_required":
        print(f"No card connected — {result['add_card_url']}")
    else:
        print(f"Started: {result['booking_ref']} — poll /api/agent-book/status")
except BearerTokenError:
    print("Token missing or revoked — reconnect at https://letsfg.co/connect")

Developer API path adds unlock() before book(), and its own error modes:

from letsfg import LetsFG, LetsFGError, PaymentRequiredError, OfferExpiredError

bt = LetsFG(api_key="letsfg_...")
try:
    booking = bt.book(offer_id=offer_id, search_id=search_id,
                      passengers=[...], contact_email="...")
except PaymentRequiredError:
    print("Run bt.connect_payment() and open the connect_url it returns")
except OfferExpiredError:
    print("Offer expired — search again and book from the fresh results")
except LetsFGError as e:
    print(f"API error ({e.status_code}): {e.message}")
Exception HTTP Code Cause
AuthenticationError 401 Missing or invalid API key (Developer API)
BearerTokenError 401 Missing, expired or revoked Bearer token — reconnect through the MCP (PFS)
PaymentRequiredError 402 No payment method (call connect_payment(), Developer API)
OfferExpiredError 410 Offer no longer available (Developer API)
LetsFGError any Base class for all API errors

Timeout and Retry Pattern

Full cloud search takes 8–10 s to first results (async polling). Use retry with backoff for transient errors:

import time
from letsfg import LetsFG, LetsFGError

bt = LetsFG()

def search_with_retry(origin, dest, date, max_retries=3):
    """Retry with exponential backoff on rate limit or timeout."""
    for attempt in range(max_retries):
        try:
            return bt.search(origin, dest, date)
        except LetsFGError as e:
            if "429" in str(e) or "rate limit" in str(e).lower():
                wait = 2 ** attempt  # 1s, 2s, 4s
                print(f"Rate limited, waiting {wait}s...")
                time.sleep(wait)
            elif "timeout" in str(e).lower() or "504" in str(e):
                print(f"Timeout, retrying ({attempt + 1}/{max_retries})...")
                time.sleep(1)
            else:
                raise
    raise LetsFGError("Max retries exceeded")

Rate Limits

Endpoint Rate Limit Typical Latency
Search No hard limit (billing is the natural governor) 8–10 s to first results
Resolve location 120 req/min < 1 s
Unlock 20 req/min 2–5 s
Book 10 req/min 3–10 s

Search Wide, Book Once

Searching is free (10 per 10 min, 30 per hour, 100 per day per card). On PFS, booking goes through POST /api/agent-book — the fare is held on your card and captured only on a real PNR. No booking fee, no transaction fee — our margin is already in the price you saw. Compare before booking:

# Search multiple dates (free) — compare before booking
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)

# Book only the winner
if best:
    date, result = best
    booking = bt.book(
        offer_id=result.cheapest.id, passengers=[...],
        contact_email="...", search_id=result.search_id,
    )

On the Developer API the same idea applies to the look-to-book allowance: 200 searches are free after every booking, so search every candidate, then book the winner — the booking resets the allowance.

Quick Start (CLI)

# Token: connect once through the MCP (see Authentication), then
export LETSFG_BEARER_TOKEN=eyJ...

# Search (1 adult, one-way, economy — defaults)
letsfg search GDN BER 2026-03-03 --sort price

# Multi-passenger round trip
letsfg search LON BCN 2026-04-01 --return 2026-04-08 --adults 2 --children 1 --cabin M

# Business class, direct flights only
letsfg search JFK LHR 2026-05-01 --adults 3 --cabin C --max-stops 0

# Machine-readable output (for agents) — includes search_id, needed for book
letsfg search LON BCN 2026-04-01 --json

# Book — no booking fee, no transaction fee — our margin is already in the price you saw; no unlock step. Holds the fare on
# your card and starts the LetsFG booking agent; prints the booking_ref to poll.
letsfg book off_xxx --search-id srch_xxx \
  --passenger '{"given_name":"John","family_name":"Doe","born_on":"1990-01-15","gender":"m","nationality":"GB","phone_number":"+447700900123","phone_country":"GB","address_line1":"1 Analytical Way","address_city":"London","address_postal":"N1 9GU","address_country":"GB"}' \
  --email john@example.com

# Resolve location
letsfg locations "Berlin"

Search Flags

Flag Short Default Description
--return -r (one-way) Return date YYYY-MM-DD
--adults -a 1 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 Raw JSON output

All CLI Commands

Command Description Cost
auth Connect a card at letsfg.co/connect and store the token — self-registers, PKCE + loopback redirect, opens a browser. --no-browser prints the URL FREE
search Search flights between any two airports, prints search_id FREE
locations Resolve city name to IATA codes FREE
book Start a booking for an offer from your search (--search-id required). Fare held on your card, captured on a real PNR; poll /api/agent-book/status No booking fee, no transaction fee
me Show agent profile and usage stats FREE
unlock RETIRED 2026-09-08 — prints the replacement and exits non-zero. There is no unlock step
register [Developer API only] Register new Developer API key FREE
connect-payment [Developer API only] Print a link for connecting a payment method. Nothing is charged. setup-payment is an alias FREE

Every command supports --json for machine-readable output.

Environment Variables

Variable Description
LETSFG_BEARER_TOKEN PFS Bearer token (card-backed, from the connect flow). Takes priority over ~/.letsfg/config.json.
LETSFG_API_KEY Developer API key (look-to-book search + booking)
LETSFG_BASE_URL API URL override (default: https://letsfg.co)

How It Works

  1. Search — Free. The server-side engine queries hundreds of airlines and returns real-time offers.
  2. Book — Call POST /api/agent-book with your Bearer token. The fare plus LetsFG's markup is held on your connected card, a LetsFG booking agent buys the ticket from the seller, and the hold is captured only once a real airline PNR exists (4–11 minutes; poll POST /api/agent-book/status). A failed booking releases the hold. Ticket price only, no LetsFG fee, no unlock step.

The Developer API is a separate product with the same booking model. Search there is look-to-book: 200 searches free after every booking you make, then blocks of 500 for $5.00 ($0.01 each). Booking is POST /flights/book — the fare is held on a connected Revolut method and captured only against a real PNR, with no booking fee and no transaction fee; the margin is inside the price the search returned.

Retired 2026-09-08: the unlock step (and its 1% / min $3 fee) no longer exists, and neither do the Stripe onboarding routes. Both answer 410 Gone naming their replacement. See https://letsfg.co/developers/api/docs.


Also Available As

  • MCP Server: npx letsfg-mcpnpm
  • JS/TS SDK: npm install letsfgnpm
  • Try without installing: letsfg.co — search instantly in your browser
  • GitHub: LetsFG/LetsFG

Star the repo — we appreciate the support.

License

MIT

🏨 Hotels — new, and live

Your agent can now book hotels, not just flights. Same API key, same connected payment method.

from letsfg import LetsFG
lfg = LetsFG()

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]
print(hotel["name"], offer["price"], offer["currency"], offer["refundable"])
# prices are in stays["currency"]: USD unless you pass currency=

booking = lfg.book_hotel_and_wait(
    session_id=offer["session_id"],
    hotel_code=hotel["hotel_code"],
    combination_id_v2=offer["combination_id_v2"],
    expected_price=offer["price"],          # copy these four from the offer, verbatim
    expected_cost=offer["expected_cost"],
    currency=offer["currency"],
    fx_rate=offer["fx_rate"],
    city_id=city["Id"], city_name=city["Name"],
    check_in="2026-11-10", check_out="2026-11-12",
    # ONE entry per guest in the room, children included: adults first, then children in child_ages order
    guests=[{"title": "Mr", "first_name": "Jan", "last_name": "Kowalski"},
            {"title": "Mrs", "first_name": "Anna", "last_name": "Kowalska"}],
    email="GUEST_EMAIL", phone="512345678",   # the guest's real e-mail and phone
)
if booking["status"] == "succeeded":
    print(booking["confirmation"], booking["total_price"], booking["currency"])
elif booking["status"] == "failed":
    print("Not booked, nothing charged:", booking["error"])
else:  # "attention": a person is checking it with the supplier, the hold is kept. Do not book again.
    print(booking["status"], booking.get("error"))

How you pay

The full price is held, and taken only once the hotel confirms. Booking holds the offer's price on the Revolut payment method connected to your account — authorised, not charged. LetsFG then books the room with the supplier and pays the supplier itself. The hold is captured only after the supplier has confirmed the booking; if the booking fails for any reason (the rate is gone, the price moved, the supplier declined, a guest detail was rejected), the hold is released and nothing is charged.

There is no reservation fee, no deposit and no pay link, and the guest owes the hotel nothing further. (Those belonged to the process retired on 2026-09-11.)

price is the supplier's cost plus 6.4% (our margin and payment processing) for Revolut Pay or a card issued in the EEA, or 8.3% for a card issued outside the EEA — the search response's markup_rate says which. Nothing is added at booking. Prices are in the currency you search in: USD unless you ask for another.

Cancelling a refundable rate before its free_cancellation_until costs nothing and refunds the charge in full. A cancellation that would cost money is refused (409); the hotel's own ladder is in the booking's terms.

What search costs

Search is metered separately from booking, on either auth path (free PFS Bearer token or Developer API key — both count against the same agent): the first 1,000 search_hotels calls since your last hotel booking are free. Past that, searches are billed in blocks of 1,000 for $5 (~$0.005/search) from your prepaid balance — refused with a 402 if the balance can't cover the next block, never silently allowed. Book a hotel and the count resets to zero. Resolving a city name (hotel_destinations) is not metered, only the search call itself.

Things worth knowing before you build

  • A connected payment method is required for every hotel call, including search. A hotel search opens a real session at the supplier and booking blocks a real rate, so we refuse up front rather than let you reach the point of commitment and discover you cannot pay. The same method authorises flights and hotels — there is no separate hotel signup.
  • Every rate type is sold, refundable and non-refundable. Each offer's refundable and free_cancellation_until say which one you are buying.
  • Booking is asynchronous. book_hotel returns a booking_job_id, not a booking — the real thing takes minutes. Poll hotel_booking(job_id) every ~20 s until status is succeeded, failed or attention, or call book_hotel_and_wait and let the SDK do it. All three are final:
    • succeededconfirmation, total_price + currency (what the guest is charged), supplier_paid + supplier_currency, refundable, free_cancellation_until, cancellation_ladder and terms.
    • failederror, written for the guest. The hold has been released; nothing was charged.
    • attention — the outcome could not be settled automatically. The hold is kept (nothing is charged) while a person checks with the supplier. Do not book again.
  • Copy the offer verbatim. Send expected_price (the offer's price), expected_cost, currency and fx_rate exactly as search returned them. A mis-copied price, or a USD offer sent without its currency, is refused with 400 price_mismatch before anything is held.
  • Guest details are checked before anything is held: Latin-script names, a phone number valid for its country code, and an e-mail. A problem returns 400 invalid_details naming the fields.
  • One name per guest in the room, children included. For a family, search with children and child_ages; the party travels with the offer's session. guests then lists every guest — adults first, then children in child_ages order. The hotel requires a name for every guest: fewer names than guests is refused before anything is submitted, and the hold is released.
  • The guest is e-mailed however it ends: a confirmation with the code and the cancellation term, a note that it did not go through and nothing was charged, or a note that it is being confirmed with the supplier.
  • A retry never books twice. A second book_hotel for the same rate and guest returns the job already under way (duplicate: true); pass idempotency_key to make that explicit. Still, never re-post a booking whose job is running — poll it.

JavaScript

import { LetsFG } from 'letsfg';
const lfg = new LetsFG({ apiKey: process.env.LETSFG_API_KEY });

const [city] = await lfg.hotelDestinations('Warsaw');
const stays = await lfg.searchHotels({
  cityId: city.Id, cityName: city.Name,
  checkIn: '2026-11-10', checkOut: '2026-11-12', adults: 2,
});

const hotel = stays.hotels[0];
const offer = hotel.offers[0];
const booking = await lfg.bookHotelAndWait({
  sessionId: offer.session_id, hotelCode: hotel.hotel_code,
  combinationIdV2: offer.combination_id_v2,
  expectedPrice: offer.price, expectedCost: offer.expected_cost,
  currency: offer.currency, fxRate: offer.fx_rate,
  cityId: city.Id, cityName: city.Name,
  checkIn: '2026-11-10', checkOut: '2026-11-12',
  // ONE entry per guest in the room, children included: adults first, then children in childAges order
  guests: [{ title: 'Mr', first_name: 'Jan', last_name: 'Kowalski' },
    { title: 'Mrs', first_name: 'Anna', last_name: 'Kowalska' }],
  email: 'GUEST_EMAIL', phone: '512345678',
});
console.log(booking.status, booking.confirmation, booking.total_price, booking.currency);

MCP

Five new tools, in the order you call them: resolve_hotel_citysearch_hotelsbook_hotelget_hotel_bookingcancel_hotel_booking.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

letsfg-2026.5.101.tar.gz (114.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

letsfg-2026.5.101-py3-none-any.whl (69.2 kB view details)

Uploaded Python 3

File details

Details for the file letsfg-2026.5.101.tar.gz.

File metadata

  • Download URL: letsfg-2026.5.101.tar.gz
  • Upload date:
  • Size: 114.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for letsfg-2026.5.101.tar.gz
Algorithm Hash digest
SHA256 5bf8cbf576483046cf7c4eaefb2bbfbe3b277caa759256ab260e955c7020f7b2
MD5 5af564f87841d29aea0b8d20cafd8bfc
BLAKE2b-256 23d5b118f791365cf2f23bb0338bce030bf376d687b9138c8a3ac0d529b061f4

See more details on using hashes here.

File details

Details for the file letsfg-2026.5.101-py3-none-any.whl.

File metadata

  • Download URL: letsfg-2026.5.101-py3-none-any.whl
  • Upload date:
  • Size: 69.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for letsfg-2026.5.101-py3-none-any.whl
Algorithm Hash digest
SHA256 8e1786a2543bf86fff5be313cf7ce575688d17bc288a79923b2f39466f22dc91
MD5 5d1cd31023e8fd64c23b56b0cd45cfa1
BLAKE2b-256 c0baa3b877cac2b7ceff9adeb8eef4d0d9a3f2493c9dc48a78617fb9841eacfa

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2026.5.101 This release

2 files

2026.5.100

2 files

2026.5.99

2 files

2026.5.98

2 files

2026.5.97

2 files

2026.5.96

2 files

2026.5.95

2 files

2026.5.94

2 files

2026.5.93

2 files

2026.5.92

2 files

2026.5.91

2 files

2026.5.90

2 files

2026.5.89

2 files

2026.5.88

2 files

2026.5.87

2 files

2026.5.86

2 files

2026.5.85

2 files

2026.5.84

2 files

2026.5.83

2 files

2026.5.82

2 files

2026.5.81

2 files

2026.5.80

2 files

2026.5.79

2 files

2026.5.78

2 files

2026.5.77

2 files

2026.5.76

2 files

2026.5.75

2 files

2026.5.74

2 files

2026.5.73

2 files

2026.5.72

2 files

2026.5.71

2 files

2026.5.70

2 files

2026.4.69

1 file

2026.4.68

1 file

2026.4.67

1 file

2026.4.66

2 files

2026.4.65

2 files

2026.4.64

2 files

2026.4.63

2 files

2026.4.62

2 files

2026.4.61

2 files

2026.4.60

2 files

2026.4.59

2 files

2026.4.58

2 files

2026.4.57

1 file

2026.4.56

2 files

2026.4.55

2 files

2026.4.54

2 files

2026.4.53

2 files

2026.4.52

2 files

2026.4.51

2 files

2026.4.50

2 files

2026.4.49

2 files

2026.4.48

2 files

2026.4.47

2 files

2026.4.46

2 files

2026.4.45

2 files

2026.4.44

2 files

2026.4.43

2 files

2026.4.42

2 files

2026.4.41

2 files

2026.4.40

2 files

2026.4.37

2 files

2026.4.36

2 files

2026.4.35

2 files

2026.4.34

2 files

2026.4.33

2 files

2026.4.32

2 files

2026.4.31

2 files

2026.4.30

2 files

2026.4.29

2 files

2026.4.28

2 files

2026.4.27

2 files

2026.4.26

2 files

2026.4.25

2 files

2026.4.24

2 files

2026.4.23

2 files

2026.4.22

2 files

2026.4.21

2 files

2026.4.20

2 files

2026.4.19

2 files

2026.4.18

2 files

2026.4.17

2 files

2026.4.16

2 files

2026.4.15

2 files

2026.4.14

2 files

2026.4.13

2 files

2026.4.12

2 files

2026.4.11

2 files

2026.4.10

2 files

2026.4.9

2 files

2026.4.8

2 files

2026.4.7

2 files

2026.4.6

2 files

1.10.1

2 files

1.10.0

2 files

1.9.4

2 files

1.9.3

2 files

1.9.2

2 files

1.9.1

2 files

1.9.0

2 files

1.8.1

2 files

1.8.0

2 files

1.7.2

2 files

1.7.1

2 files

1.7.0

2 files

1.6.0

2 files

1.5.33

2 files

1.5.32

2 files

1.5.31

2 files

1.5.30

2 files

1.5.29

2 files

1.5.28

2 files

1.5.27

2 files

1.5.26

2 files

1.5.25

2 files

1.5.24

2 files

1.5.23

2 files

1.5.22

2 files

1.5.21

2 files

1.5.20

2 files

1.5.19

2 files

1.5.18

2 files

1.5.17

2 files

1.5.16

2 files

1.5.15

2 files

1.5.14

2 files

1.5.13

2 files

1.5.12

2 files

1.5.11

2 files

1.5.10

2 files

1.5.9

2 files

1.5.8

2 files

1.5.7

2 files

1.5.6

2 files

1.5.5

2 files

1.5.4

2 files

1.5.3

2 files

1.5.2

2 files

1.5.1

1 file

1.5.0

2 files

1.4.16

1 file

1.4.15

1 file

1.4.14

1 file

1.4.13

1 file

1.4.12

1 file

1.4.11

1 file

1.4.10

1 file

1.4.9

1 file

1.4.8

1 file

1.4.7

1 file

1.4.6

1 file

1.4.5

2 files

1.4.4

2 files

1.4.3

2 files

1.4.2

2 files

1.4.1

2 files

1.4.0

2 files

1.3.9

2 files

1.3.8

2 files

1.3.7

2 files

1.3.6

2 files

1.3.5

2 files

1.3.4

2 files

1.3.3

2 files

1.3.2

2 files

1.3.1

2 files

1.3.0

2 files

1.2.0

2 files

1.1.1

2 files

1.1.0

2 files

1.0.23

2 files

1.0.22

2 files

1.0.21

2 files

1.0.20

2 files

1.0.19

2 files

1.0.18

2 files

1.0.17

2 files

1.0.16

2 files

1.0.15

2 files

1.0.14

2 files

1.0.13

2 files

1.0.12

2 files

1.0.11

2 files

1.0.10

1 file

1.0.9

1 file

1.0.8

1 file

1.0.7

1 file

1.0.6

2 files

1.0.5

2 files

1.0.4

2 files

1.0.3

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page