# OnArrival Flights

> Book real flights (India domestic and international, fares in INR) in three steps: open a search URL, submit one traveller form, and hand the resulting payment link to your user. You never handle payment: the traveller pays on the link, on their own device, and the same link then shows their PNR and e-ticket.

Today is 2026-09-30 (IST). All pages work without JavaScript. Every page below has a markdown twin (append `.md` to the path, or send `Accept: text/markdown`) and a JSON twin (`.json` or `Accept: application/json`).

## Keep your user in the loop — required at every step

Every search, booking form and trip response carries a `tell_user` block (JSON field, the "Tell your user now" section at the top of every markdown page, and a box at the top of every HTML page):

- `message` — send it to your user verbatim (or lightly rephrased) before you do anything else.
- `image_url` — a PNG card of that step (top options, the chosen flight, the pay-by card, the booked ticket). Attach it; in markdown chat use `![alt](image_url)`.
- `quick_replies` — offer these as buttons or suggestions.
- `choices` (search) — the numbered options in the message, so "book 2" maps to an `offer_id` exactly.

Cards you can fetch any time: https://agents.onarrival.com/card/flights.png?<same query as /flights> · https://agents.onarrival.com/card/offer/{offer_id}.png · https://agents.onarrival.com/card/trip/{token}.png (updates as the trip moves from held → paid → booked).

Narrate the whole journey: results → chosen flight → traveller details needed → payment link with the pay-by time → "payment received" → "booked" with PNR and e-ticket. Never go silent while waiting for payment: use the trip's `?wait=30` long-poll and send the new `tell_user` whenever the status changes.

## Skip the pages: MCP server and JSON API

- **MCP** (Streamable HTTP, JSON-RPC over POST): https://agents.onarrival.com/mcp — tools `search_flights`, `get_offer`, `book_flight` (returns `payment_url`), `get_trip_status` (with `wait_seconds`). Every result includes `tell_user` and a PNG card. Send the session as `Authorization: Bearer <token>` on the connection or as `session_token`.
- **JSON**: GET https://agents.onarrival.com/flights.json?… · POST https://agents.onarrival.com/checkout (JSON body) → 201 with `payment_url`, `status_url`, `trip_url` · GET https://agents.onarrival.com/trip/{token}/status?wait=30 → `{status, paid, ticketed, pnrs, ticket_pdf_url, …}` · GET https://agents.onarrival.com/trip/{token}/ticket.pdf → the airline e-ticket PDF once confirmed (409 with a reason before that).
- **payment_url** opens Razorpay checkout directly (one tap for the traveller); after paying they land on the trip page with the ticket.
- Errors are JSON `{error: {code, message, hint, issues: [{field, problem}]}}` — every problem at once, per field.

## 1. Search — a GET URL, no form needed

https://agents.onarrival.com/flights?from=BLR&to=DEL&depart=2026-10-14&adults=1

- `from`, `to`: IATA code or city name ("Bengaluru", "Bombay", "Goa" all work)
- `depart`, `return` (optional): YYYY-MM-DD. With `return`, results are round trips.
- `adults` (1–9), `children` (2–11 yrs), `infants` (<2 yrs, ≤ adults)
- `cabin`: economy | premium_economy | business | first
- `sort`: best (default) | cheapest | fastest | earliest | latest
- `stops=0` non-stop only · `time`: early_morning | morning | afternoon | evening | night (departure window)
- `airline=6E,AI` · `max_price` (total INR) · `limit` (default 8, max 50)

Re-sorting/filtering the same route and date is instant (results are cached for 5 minutes). Each result has an `offer_id` (held 30 minutes) and a Book link.

Markdown example: https://agents.onarrival.com/flights.md?from=Mumbai&to=Goa&depart=2026-10-14&return=2026-10-17&adults=2&sort=cheapest

## 2. Travellers — one form

Open https://agents.onarrival.com/book/{offer_id}. One form covers every traveller plus contact details. All validation problems are reported together, next to each field.

Fields, per traveller N (1-based: adults first, then children, then infants):
- `pN_first_name`, `pN_last_name` — exactly as on government ID; letters and spaces only
- `pN_gender` — male | female
- `pN_dob` — YYYY-MM-DD; required for children and infants, and for everyone on international trips
- international only: `pN_passport_number`, `pN_passport_expiry` (YYYY-MM-DD, valid through the trip), `pN_nationality` (2-letter, default IN)
- `email`, `phone` — the TRAVELLER'S contact (10-digit Indian mobile, or +country code). The payment link and e-ticket are sent here.
- optional `max_price_inr` — refuse if the held fare is above this

Or POST JSON (no browser needed):

    POST https://agents.onarrival.com/checkout
    Content-Type: application/json

    {"offer_id":"of_XXXXXXXX",
     "passengers":[{"first_name":"Asha","last_name":"Rao","gender":"female"}],
     "contact":{"email":"asha@example.com","phone":"9876543210"}}

201 → booking with `payment_url`. 422 → `error.issues[]` listing every bad field. 410 → the offer expired; `error.details.search_href` re-runs the search. Submitting the same travellers for the same offer twice returns the same booking.

## 3. Payment link → ticket

The checkout result (a browser lands on it automatically) is https://agents.onarrival.com/trip/{token} — the payment link.

- Give this URL to your user. Do not pay on their behalf and do not enter card or UPI details.
- The fare is held for 20 minutes.
- Wait for payment without polling in a loop: GET https://agents.onarrival.com/trip/{token}.md?wait=30 returns as soon as the status changes (max 45s).
- Statuses: awaiting_payment → payment_processing → ticketing → confirmed. Also: payment_failed (retry on the same link), expired, cancelled, failed (refunded).
- When confirmed, the page shows the airline PNR, e-ticket (https://agents.onarrival.com/trip/{token}/ticket) and a calendar invite (https://agents.onarrival.com/trip/{token}/calendar.ics).
- Cancellation is two-step and needs the traveller's go-ahead: https://agents.onarrival.com/trip/{token}/cancel shows the refund, then confirm.
- Lost the link? https://agents.onarrival.com/trip/find?reference=OAXXXXXX&last_name=Rao

## Notes

- Prices are totals for all travellers in INR, taxes included.
- Booking is open to any agent; there is no CAPTCHA in the funnel. Please keep to a few requests per second.
- This deployment runs checkout in SANDBOX mode: fares are real, payment and ticketing are simulated. No money moves.
