# Changelog

> What changed in the FX-Port API and in these docs, newest first.

Source: https://fx-port.com/docs/changelog

New entries are added at the top. A change that could break an integration ships under a new API version (the `/api/v1` prefix) and is announced here first; additive changes, such as a new field or a new accepted spelling, do not change the version. See [Conventions and naming](https://fx-port.com/docs/conventions.md).

## 2026-11-01: new documentation, one naming convention, clearer errors, safer defaults

**Nothing was removed.** Every endpoint, request field and response key that worked yesterday works today. The changes below add names, add keys, tell you what to use, and refuse requests that could never have succeeded.

**Documentation**

- The documentation moved from `docs.fx-port.com` to **fx-port.com/docs**. Every old address redirects permanently to its new one, so links, bookmarks and search results keep working.
- A generated **API reference** with every endpoint, its parameters, its responses and examples in nine languages, an **OpenAPI 3.1** file at [/openapi.json](https://fx-port.com/openapi.json), [llms.txt](https://fx-port.com/llms.txt) and [llms-full.txt](https://fx-port.com/llms-full.txt) for AI tools, every page as Markdown (add `.md` to its address), and search.
- The Postman collections were regenerated from the same description of the API: see [Environments and Postman](https://fx-port.com/docs/environments.md).
- The navigation is grouped by product (Flights, Hotels, eSIMs, Account), each with its stages, in the guides and in the API reference. The hotel search around a point is called [geo search](https://fx-port.com/docs/hotels/search.md) everywhere.
- New guides: [Quickstart](https://fx-port.com/docs/quickstart.md), [Conventions and naming](https://fx-port.com/docs/conventions.md), [Legacy names and twins](https://fx-port.com/docs/legacy-names.md), [Errors](https://fx-port.com/docs/errors.md), [Rate limits and fair use](https://fx-port.com/docs/rate-limits.md), [Streaming search results](https://fx-port.com/docs/streaming.md), [Mini and full hotel data](https://fx-port.com/docs/hotels/hotel-data.md) and the guides of [get_ticket_number](https://fx-port.com/docs/flights/get-ticket-number.md), [cancel_quote](https://fx-port.com/docs/flights/cancel-quote.md) and [confirm_cancel](https://fx-port.com/docs/flights/confirm-cancel.md).
- The [flights](https://fx-port.com/docs/flights.md), [hotels](https://fx-port.com/docs/hotels.md) and [eSIMs](https://fx-port.com/docs/esims.md) guides were rewritten against the live API: corrected claims, real responses, the sandbox test hotels, and the [ACD passport uploads](https://fx-port.com/docs/flights/acd-documents.md) reference.

**Naming: one convention, the old names still work**

- `snake_case` is the canonical spelling of every request field. A request that uses an earlier spelling (`searchId`, `offerId`, `bookingType`, `hotelId`, `checkinDate`, `partnerOrderId` ...) is still served. The response then carries a `warnings` entry and the headers `Deprecation`, `Link` and `X-FX-Deprecated-Fields` that name the spelling to use.
- Every `camelCase` key of a response stays, and its `snake_case` twin is added next to it with the same value. `?naming=snake` (or the header `X-FX-Naming: snake`) returns the `snake_case` keys only.
- `GET /api/v1/conventions/naming` publishes the complete map (no key needed). The [reference](https://fx-port.com/docs/api.md) marks each earlier spelling as deprecated and says what replaces it.

**Errors and request ids**

- Every error body now has `errors[]` (`code`, `type`, `title`, `message`, `field`, `details`, `documentation_url`), `meta.request_id` and `request_id`, next to the keys it always had. A reply with HTTP `200` and `success: false` has them too. The code is stable: write `if` statements against `errors[0].code`, not against the message. See [Errors](https://fx-port.com/docs/errors.md).
- Every response carries `X-Request-Id`. Quote it when you contact support.
- A request that could never succeed is refused with `400` and a stable code **before** any supplier is called: an unknown airport code, a date that is impossible or too far away, an absurd passenger count, an unknown value of `cabin_class` or `booking_type`, a hotel stay over 30 nights. These used to come back as `503 all_suppliers_failed`, as `500` or as a `502` that Cloudflare replaced by an HTML page.
- `book_flight` answers a failure with JSON (`409`, `422` or `503`) instead of an HTML `502`.
- Messages no longer carry the raw text of a supplier, of the database or of the code.

**Flights**

- [Streaming](https://fx-port.com/docs/streaming.md) is documented: `stream=true` returns the offers supplier by supplier as server-sent events, `environment` comes first, comment lines keep the connection alive, and `done` is always the last event.
- `booking_type` and `cabin_class` are validated. An unknown `booking_type` used to create a paid instant order with Duffel.
- `flexible_search` with no supplier able to answer returns `422 no_supplier_supports_flexible_search` instead of `503`.
- `failures[]` of a search says why a supplier failed in `cause` (`supplier_timeout`, `supplier_api_error` ...).
- `get_booking` adds `acd_required`, `requires_acd`, a boolean `acd_submitted`, `pdf_url` and `pdf_url_no_price`.
- ACD uploads: `upload_acd_documents` reads the form after authentication, answers `415` to anything but `multipart/form-data`, and has the new codes `INVALID_MULTIPART` and `INVALID_BOOKING_ID`. The existing codes and the limits (10 MiB a file, 25 MiB a request) are unchanged.

**Hotels**

- [Mini and full hotel data](https://fx-port.com/docs/hotels/hotel-data.md): `get_hotel_info` and `hotels/details` accept `detail_level` (`minimal`, `mini` or `full`, default `full`) and `images_limit`. A mini card is about eight times smaller than the full document: use it for search results and read the full document for the hotel page.
- In the sandbox, only the supplier's test hotels can be booked ([Sandbox testing](https://fx-port.com/docs/hotels/sandbox-testing.md)). `pre_book` of any other hotel answers `409 hotel_not_bookable_in_sandbox` instead of a success that could never be booked.
- `pre_book` answers the same request within 60 seconds with the same result, and `book_hotel` refuses a second booking of the same `booking_id` with `409 duplicate_booking` and does not call the supplier again.
- `search_advanced` answers at most 5,000 hotels and says `truncated` when it cut the list. An unknown hotel is `404 hotel_not_found` (it was a `502`). Supplier cost data and debug blocks are no longer in the answers to API keys.

**eSIMs**

- Usage, instructions, top-up packages and top-ups work for the eSIMs of your agency and environment only. Any other ICCID answers `404 iccid_not_found` before the supplier is called.
- `setup-url` returns the install link only. The `search` of the eSIM list no longer fails on special characters, and `usage/bulk` takes up to 50 ICCIDs and answers one entry per ICCID.
- An order or a top-up that the supplier refuses answers `supplier_error` with a fixed message, and no balance is debited.

**Security**

- A booking, a search or an eSIM of another agency answers the same `404` as one that does not exist, on every endpoint. Nothing tells a caller that an identifier exists.
- A request body has a size limit: 64 KB for a search or a price, 256 KB for any other JSON, 26 MB for an ACD upload. A larger body answers `413 request_too_large`.
- A key that is not shaped like an FX-Port key (`fxp_live_` or `fxp_test_` and 16 to 64 letters and digits) answers `401 invalid_api_key_format` at once. A burst of requests with unknown keys from one address is slowed down, and never affects a valid key. See [Rate limits and fair use](https://fx-port.com/docs/rate-limits.md).
- Internal data (net fares, commissions, internal ids) is no longer returned by `get_booking`, `get_ticket_number` and `include_bags`.

**Limits and headers**

- Every response of an API key has `ratelimit-limit`, `ratelimit-remaining`, `ratelimit-reset` and `ratelimit-policy`, and every `429` and `503` has `Retry-After`. New codes: `concurrency_limit_exceeded`, `auth_rate_limited`, `service_overloaded`, `supplier_busy`.
- Search and hotel-content endpoints also limit how many calls of one key run at the same time. The ceilings are far above what an interactive application needs and run in observation mode first: nothing is refused because of them until we announce it here.

## 2026-10-25: ACD passport uploads

**API**

- `POST /api/v1/flights/get_acd_documents` tells you how many passports an ACD booking needs and which travelers already have one.
- `POST /api/v1/flights/upload_acd_documents` adds one passport, several or all of them, and replaces a passport that was already sent. See [ACD passport uploads](https://fx-port.com/docs/flights/acd-documents.md).

## 2026-10-08: void window anchored to the payment day

**API**

- `booking.voidableUntil` is now computed from the day the booking was paid, not from the day it was created. See [Get a flight booking](https://fx-port.com/docs/flights/get-booking.md).

## 2026-08-27: security, eSIMs and hotels

**Documentation**

- The [Security](https://fx-port.com/docs/security.md) guide, the [eSIMs](https://fx-port.com/docs/esims.md) guides and the first [hotels](https://fx-port.com/docs/hotels.md) guides.

## 2026-08-17: first public documentation

**API**

- Flights: search, flexible-date search, price, book (issue or hold), quote, pay, cancel a held booking, get a booking, get the ticket PDF, airports.
- Suppliers and account: the list of suppliers, balances, the balance ledger, booking history and booking detail.
- Self-serve API keys with Read and Read+Write permissions, for the sandbox (`fxp_test_`) and for live (`fxp_live_`), on one base URL.
