# Onward Flights

> Real-looking onward flight tickets (proof of onward travel) built from real flight itineraries. A ticket costs $5 in USDC ($10 when departing Australia, Bahamas, Belgium, Bermuda, Denmark, Finland, France, Hong Kong, Iceland, Ireland, Israel, Japan, Kuwait, Luxembourg, New Zealand, Norway, Singapore, Sweden, Switzerland, United Kingdom or United States) and is unscrambled as soon as it's paid for. People buy them in the browser; AI agents can search and buy over MCP or a JSON API paid with the Machine Payments Protocol (MPP).

Airlines and immigration officers often ask travellers entering a country on a one-way ticket for proof they'll leave. Onward Flights finds a real flight out of that country and makes a ticket for it with the passenger's name, as a web page and a PDF. Nothing is booked with the airline.

## For AI agents

1. Find the 3 letter IATA code of the airport the traveller will leave from (`find_airports`, or `GET /api/airports?q=bangkok`).
2. Search for flights from there to a different country, dated before their permitted stay ends. Pick a different airline from the one they're flying in with, going to a different country from the one they're coming from: check-in staff are more likely to look up a ticket on their own airline (`search_flights`, or `GET /api/flights?origin=BKK&destination=SIN&date=YYYY-MM-DD`). Each flight has an `id` and `price_usd`. Ids expire a day after the search.
3. Buy one with the passenger's first and last name as on their passport (`buy_ticket`, or `POST /api/purchase`). The first call returns what to pay. Send the USDC, then call again with the transaction hash. You get back the ticket link (`url`) and `pdf`, and it's emailed if you gave an `email`.

If you can't send USDC, give the human the `pay_in_browser` link and they can pay with their own wallet.

### MCP

- Server: `https://onward.flights/mcp` (Streamable HTTP, stateless, no auth)
- Claude Code: `claude mcp add --transport http onward-flights https://onward.flights/mcp`
- Other clients: `{"mcpServers": {"onward-flights": {"type": "http", "url": "https://onward.flights/mcp"}}}`
- Tools: `find_airports`, `search_flights`, `buy_ticket`

`buy_ticket` follows the MPP JSON-RPC transport: without payment it fails with error `-32042` and `error.data.challenges`. Retry with the credential in `params._meta["org.paymentauth/credential"]`, or with the `tx_hash` and `chain` arguments. The receipt is in `result._meta["org.paymentauth/receipt"]`.

### HTTP API

- `GET https://onward.flights/api/airports?q=lisbon`
- `GET https://onward.flights/api/flights?origin=LIS&destination=MAD&date=YYYY-MM-DD`
- `GET https://onward.flights/api/tickets/{id}`: one flight, its price and how to pay
- `POST https://onward.flights/api/purchase` with JSON `{"ticket_id": "…", "first_name": "…", "last_name": "…", "email": "optional"}`

Without payment, the purchase returns `402 Payment Required` with one `WWW-Authenticate: Payment` challenge per chain (`method="evm"`, `intent="charge"`, `credentialTypes: ["hash"]`). Send the USDC transfer, wait for it to be mined, then repeat the same request with `Authorization: Payment <base64url JSON>`:

```json
{"challenge": {"id": "…", "realm": "onward.flights", "method": "evm", "intent": "charge", "request": "…", "expires": "…", "description": "…"}, "payload": {"type": "hash", "hash": "0x…"}}
```

Echo the challenge exactly as it was sent. Or skip MPP and send `"tx_hash": "0x…", "chain": "base"` in the JSON body. A successful purchase returns `200` with a `Payment-Receipt` header. OpenAPI with MPP discovery extensions: https://onward.flights/openapi.json

### Payment

- Pay to: `0xF846dbB11d80E5065B4f7566C803bbA79eA0eE53`
- Amount: the ticket's `price_usd` in USDC, exactly (6 decimals, so $5 is `5000000`)
- Base (chain id 8453): USDC `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`
- Ethereum (chain id 1): USDC `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`
- Optimism (chain id 10): USDC `0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85`
- Polygon (chain id 137): USDC `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359`
- Base is cheapest. The transaction must be mined within the 30 minutes the challenge is open for, or within a day for a bare `tx_hash`. Each transaction buys one ticket.

## For people

Paste this into ChatGPT, Claude or any assistant that can browse, and fill in the brackets:

```
I need an onward flight ticket (proof of onward travel) for my trip. Get me one from https://onward.flights – read https://onward.flights/llms.txt first, it explains how.

- I'm flying into: [CITY OR COUNTRY]
- I arrive on: [DATE]
- The airline I'm flying in with: [AIRLINE]
- My name, as on my passport: [FIRST NAME] [LAST NAME]

Find a few one-way flights out of that country a week or two after I arrive, with a different airline from the one I'm flying in with, to a different country from the one I'm coming from. Show me the options with times and airlines, then buy the one I choose (it's about $5 in USDC). If you can't pay, send me the link so I can pay myself.
```

Or search on https://onward.flights, pick a flight and pay with a browser wallet.

## Docs

Every page is also available as Markdown by adding `.md` to its URL.

- [Home](https://onward.flights/index.md)
- [AI agents](https://onward.flights/agents.md): setup for MCP clients and the API
- [FAQ](https://onward.flights/faq.md)
- [Countries](https://onward.flights/countries.md): which countries ask for proof of onward travel
- [Terms](https://onward.flights/terms.md)

## Optional

- [OpenAPI](https://onward.flights/openapi.json)
- [Sitemap](https://onward.flights/sitemap.xml)
- [MPP specification](https://paymentauth.org)
