sondahub

sondahub / Flights API / Bookings

Fake bookings API

3,500 bookings from the Flights API, a fake flight booking API. A seat on a flight. POST {"flight_id","passenger":{...},"cabin"} and the hub assigns a seat and a record locator. Cancel with PATCH {"status":"cancelled"}.

Reads with filters, sorting, search and relations; writes that answer like a real server and stay in your session token. Same ids on every build. Free, no key, CORS open.

Connect

List
https://api.sondahub.com/v1/flights/bookings
One record
https://api.sondahub.com/v1/flights/bookings/{id}
OpenAPI 3
https://api.sondahub.com/v1/flights/openapi.json
GraphQL
https://api.sondahub.com/v1/flights/graphql
JSON file
https://api.sondahub.com/data/flights/bookings.json
MCP
https://api.sondahub.com/mcp · list_records
The first three bookings
curl "https://api.sondahub.com/v1/flights/bookings?limit=3"

Sample records

Records 1 to 3 of 3,500, exactly as GET /v1/flights/bookings/{id} answers them. The data file holds all of them.

[
  {
    "id": 1,
    "created_at": "2026-08-05T17:24:00Z",
    "updated_at": "2026-08-05T17:24:00Z",
    "locator": "QMZHBL",
    "flight_id": 1027,
    "passenger": {
      "first_name": "Omar",
      "last_name": "Costa",
      "email": "[email protected]"
    },
    "seat": "23A",
    "cabin": "economy",
    "status": "confirmed",
    "fare": 690.74,
    "currency": "USD",
    "bags": 2,
    "frequent_flyer": null,
    "special_requests": [],
    "booked_at": "2026-08-05T17:24:00Z",
    "checked_in_at": null
  },
  {
    "id": 2,
    "created_at": "2026-07-29T03:02:00Z",
    "updated_at": "2026-07-29T03:02:00Z",
    "locator": "52W9KH",
    "flight_id": 8,
    "passenger": {
      "first_name": "Lucas",
      "last_name": "Costa",
      "email": "[email protected]",
      "document": "P84927123"
    },
    "seat": "21D",
    "cabin": "economy",
    "status": "boarded",
    "fare": 879.7,
    "currency": "USD",
    "bags": 0,
    "frequent_flyer": null,
    "special_requests": [],
    "booked_at": "2026-07-29T03:02:00Z",
    "checked_in_at": "2026-08-30T06:11:00Z"
  },
  {
    "id": 3,
    "created_at": "2026-08-03T11:30:00Z",
    "updated_at": "2026-08-03T11:30:00Z",
    "locator": "Z8U8VP",
    "flight_id": 123,
    "passenger": {
      "first_name": "Maya",
      "last_name": "Lefebvre",
      "email": "[email protected]",
      "document": "P37645791"
    },
    "seat": "41F",
    "cabin": "economy",
    "status": "boarded",
    "fare": 97.23,
    "currency": "USD",
    "bags": 0,
    "frequent_flyer": "SH886345246",
    "special_requests": [],
    "booked_at": "2026-08-03T11:30:00Z",
    "checked_in_at": "2026-08-31T16:46:00Z"
  }
]

Fields

FieldTypeNotes
idread-onlyintAssigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.
created_atread-onlydatetimeWhen the record was created (ISO 8601, UTC).
updated_atread-onlydatetimeWhen the record last changed.
locatorread-onlystringSix-character record locator, unique.
flight_idrequiredint → flights
passengerrequiredjson { first_name, last_name, email, document? }
seatstringAssigned by the hub on POST when omitted.
cabinenumeconomy premium business first
statusenumconfirmed checked_in boarded cancelled no_show
farefloatmin 0
currencystring
bagsintmin 0, max 5
frequent_flyerstring
special_requestsjson string[]
booked_atdatetime
checked_in_atdatetime

Relations: flight → one flight through flight_id. Use ?expand=flight to embed them, or the nested routes.

Endpoints

POST needs passenger.first_name and last_name, refuses cancelled or departed flights and sold-out ones (409), picks a free seat in the cabin when you give none, prices the fare from the flight, and mints a six-character locator. Cancelling gives the seat back.
GET/v1/flights/bookingsA page, with every filter, sort, search, field and expand option.
POST/v1/flights/bookingsCreate one: 201 with the record, its id, a Location header and the session token that keeps it; 422 names each field that is wrong.
GET/v1/flights/bookings/{id}One record, with an ETag; If-None-Match earns a 304.
PATCH/v1/flights/bookings/{id}Change the fields you send.
PUT/v1/flights/bookings/{id}Replace the record; required fields must all be there.
DELETE/v1/flights/bookings/{id}Answers 200 with what was removed (a real server’s 204 lives at /v1/utils/status/204); gone for the session.
GET/v1/flights/bookings/{id}/flightThe flight this record points at.

Try it

List with a filter
curl "https://api.sondahub.com/v1/flights/bookings?cabin=premium&fare_gte=10&expand=flight&limit=3"
One record
curl https://api.sondahub.com/v1/flights/bookings/1?expand=flight
Create
curl -i -X POST https://api.sondahub.com/v1/flights/bookings \
  -H "Content-Type: application/json" \
  -d '{"flight_id":1,"passenger":{"first_name":"Ada","last_name":"Lovelace","email":"[email protected]"},"seat":"14C","cabin":"economy","status":"confirmed"}'
Read it back: newest first (send the session token)
curl "https://api.sondahub.com/v1/flights/bookings?sort=-id&limit=3" \
  -H "X-Sondahub-Session: THE_TOKEN_FROM_THE_CREATE"
Change one field
curl -X PATCH https://api.sondahub.com/v1/flights/bookings/1 \
  -H "Content-Type: application/json" \
  -d '{"cabin":"premium"}'
Delete the one you created
curl -X DELETE https://api.sondahub.com/v1/flights/bookings/3501 \
  -H "X-Sondahub-Session: THE_TOKEN_FROM_THE_CREATE"

Query recipes

Every list option works on bookings; these are ready to paste. All the options.

WhatRequest
Page 2, 50 at a time (of 3,500)/v1/flights/bookings?page=2&limit=50
Only cabin = economy/v1/flights/bookings?cabin=economy
Fare between two values, largest first/v1/flights/bookings?fare_gte=1&fare_lte=500&sort=-fare
Newest first by created at/v1/flights/bookings?sort=-created_at&limit=5
Seat contains “23a”/v1/flights/bookings?seat_like=23a
Full-text search/v1/flights/bookings?q=23a
Only some fields/v1/flights/bookings?fields=id,seat&limit=5
Embed the flight/v1/flights/bookings/1?expand=flight
Just the count/v1/flights/bookings?limit=1&fields=id

GraphQL

The same bookings as the bookings query on https://api.sondahub.com/v1/flights/graphql, and one booking as booking(id: 1). Introspection is on. More on the GraphQL API.

{
  bookings(limit: 3, sort: "-id", filter: { cabin: economy }) {
    total
    data {
      id locator flight_id seat
      flight { number }
    }
  }
}
Run it
curl https://api.sondahub.com/v1/flights/graphql -H "Content-Type: application/json" -d '{"query": "{ bookings(limit: 3, sort: \"-id\", filter: { cabin: economy }) { total data { id locator flight_id seat flight { number } } } }"}'

From an AI agent (MCP)

The MCP server reaches the same rows with list_records, get_record, create_record, update_record and delete_record, and as the resource sondahub://flights/bookings.

tools/call
curl https://api.sondahub.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_records","arguments":{"api":"flights","collection":"bookings","filters":{"cabin":"economy"},"limit":3}}}'

More in the Flights API

airports (50) · airlines (6) · flights (2,500)

The live streams, and the whole API on one page: Flights API. Other worlds: fake e-commerce API, fake IoT API, fake banking API, fake social media API, fake helpdesk API, fake user directory API.