# Changelog

Changes to the public API, newest first. Changes that only add fields or endpoints do not break existing integrations.

## 2026-10-01: API v1 fixes

Response changes in API v1. Nothing was added or removed from the endpoints.

- Hotels: the replay of a confirmation (same `external_reference`) returns the same shape as the first answer, with `idempotent_replay: true`. It is answered before the rates are checked again, so an expired `rate_key` no longer hides a booking that exists. A credential in test mode does not get this shortcut.
- Hotels: `content/locations` no longer returns the supplier code of each location. To drill down, `country_id` and `division_id` are now our own ids: the `id` of a country or division row. The `country_id` and `division_id` of each row are integers (or `null`) with the same ids.
- Hotels: the `provider` field is gone from every response (rates and hotels in `hotelSearch`).
- Disney: cancelling again an order of yours that is already cancelled answers `200` with `{"success": true, "already_cancelled": true}`. Before, it answered `400`. A cancellation that fails midway keeps the tickets already cancelled, and a repeat only tries the rest.
- Disney: messages no longer name the supplier. The `error` labels and the HTTP codes are the same.
- Universal: `id_order` in a replay is a string, as in a new booking. Before, it was an integer.
- Universal: `ticketConfirm` only accepts products that are on sale. A PLU of a product that is not on sale answers like a PLU that does not exist: `400 Ticket not found.`.

## 2026-10-01: API v2 offers and guides

- The offer check is now `POST /offers/check` with the `offer_id` in the JSON body, instead of `POST /offers/{offer_id}/check`. The `offer_id` is a long signed token, and the body is where `POST /bookings` takes it too.
- `expires_at` is now `null` unless the source gives a real expiry. Today that is the Disney resort hotels, after the check. An offer without `expires_at` has no expiry time of its own. To know whether its price still holds, call `POST /offers/check`, which re-quotes live. The booking always re-quotes and answers `PRICE_CHANGED` (with the current offer), `NO_AVAILABILITY` or `OFFER_EXPIRED`. A hotel offer works while its stored search exists, about a day.
- The v2 guides are reorganized. [Booking flow](/developers/guides/v2-booking-flow) describes the steps every product shares. [Transfers](/developers/guides/v2-transfers), [Tickets](/developers/guides/v2-tickets) and [Hotels](/developers/guides/v2-hotels) cover only what is specific to each product. No endpoint changed.
- Tickets: new `GET /tickets/brands` lists each brand with its age categories and traveler requirements. In `GET /tickets/products`, `age_categories` and `booking_requirements` moved to the brand, the product keeps its own choices in `booking_options` (the old `options`), and every product has a `brand` (`UOR`, `WDW`, `DLR`, `UPR` or `OTKT`; never `null`).
- Hotel search has one way to follow it: `POST /hotels/availability` starts the search and answers at once; repeat `GET /hotels/availability/{search_id}` every `poll_after_seconds` until `status` is `completed` (`partial: true` means some sources did not answer). There is no `wait` parameter.

## 2026-10-01: API v2 preview, hotels

API v2 now covers hotels, as a preview, under `/api/v2`. This includes the Disney resort hotels.

- New endpoints: `GET /hotels/destinations`, `GET /hotels/{hotel_id}` for content, `POST /hotels/availability` to start a search and `GET /hotels/availability/{search_id}` to read it. Check, booking, reading, cancelling and the voucher use the same `/offers/check` and `/bookings` endpoints as the other products.
- The search is asynchronous. `poll_after_seconds` tells you when to ask again, `status` is `running` or `completed`, and `offset` and `limit` page the hotels (`total` and `next_offset` in the answer). `partial: true` says that part of the inventory did not answer.
- One offer per room. `hotels[].slots[]` has one entry per room you asked for, and `total` is the price of that room. The rooms of one rate share a `rate_group` and are booked together. `hotel_fees` are paid at the hotel and are not in `total`.
- Each offer carries its `booking_requirements`: some hotels need one holder, others every guest. The offers of Disney resort hotels have `requires_check: true`: the booking checks them for you, and `POST /offers/check` also returns the other packages of the room in `alternatives`.
- A hotel booking has one item per room, of the same hotel and stay. The hotel confirmation number is in `hotel_confirmation`, and `GET /bookings/{booking_id}/voucher?variant=hcn` downloads the voucher that includes it.
- The booking prices every room live again. A moved price answers `409 PRICE_CHANGED` with the current offer of that room.
- New error code: `SEARCH_NOT_FOUND` (`404`), for a search that does not exist, has expired or belongs to another company. New validation issue codes: `DATE_NOT_BOOKABLE` and `UNSUPPORTED_COMBINATION`.
- Change in tickets: when the provider does not answer and we cannot know whether it booked, the booking answers `502 PROVIDER_ERROR` and the `external_reference` stays tied to the attempt. A retry now answers `409 BOOKING_IN_PROGRESS` instead of creating a second booking. Look the booking up with `GET /bookings?external_reference=...`. The same applies to hotels. A rejection the provider states clearly still releases the reference.
- The v1 hotel endpoints are unchanged and have no end date.
- Guides: [Hotels](/developers/guides/v2-hotels) and [Migrating from v1](/developers/guides/v2-migrating-from-v1). Reference: [Hotels](/developers/reference/v2/hotels) and [Bookings](/developers/reference/v2/bookings).

## 2026-09-30: API v2 preview, tickets

API v2 now covers Universal and Disney tickets, as a preview, under `/api/v2`.

- New endpoints: `GET /tickets/products` and `POST /tickets/availability`. Booking, reading, cancelling and the voucher use the same `/bookings` endpoints as transfers.
- The catalog gives each ticket our `product_id` and the codes it has outside our platform in `external_id` and `external_ids`, and `booking_requirements` with the traveler fields and options to collect.
- Universal asks for first name, last name, birth date and nationality of every traveler. Disney asks for the same and accepts an optional phone. `options.delivery_method` (`eticket` or `kiosk_voucher`) is required when the product and your credential allow both.
- `availability` answers a price per category (`unit_prices`), a `total`, and one offer per time slot for products with slots. If some products cannot be priced, the answer carries `partial: true` and the others are returned.
- The booking prices the ticket live again. A moved price answers `409 PRICE_CHANGED` with the current offer and nothing is booked.
- Infants under 3 do not need a ticket and are not part of a ticket booking.
- The v1 Universal and Disney endpoints are unchanged and have no end date.
- Guides: [Tickets](/developers/guides/v2-tickets) and [Migrating from v1](/developers/guides/v2-migrating-from-v1). Reference: [Tickets](/developers/reference/v2/tickets) and [Bookings](/developers/reference/v2/bookings).

## 2026-09-30: API v2 preview, transfers

API v2 is available as a preview for transfers, under `/api/v2`.

- New flow: `GET /transfers/products`, `POST /transfers/availability`, optional `POST /offers/check`, then `POST /bookings`. Reading, cancelling and the voucher are on `/bookings/{booking_id}`, and `GET /bookings?external_reference=...` finds a booking by your reference.
- Prices come with a signed `offer_id`. The booking takes the `offer_id`, not the price. `expires_at` is `null` unless the source gives a real expiry.
- Every error uses `{"error": {"code", "message", "request_id", "details"}}` with a closed catalog of codes.
- The Bearer credential and the rate limit are the same as in v1. The v1 Transfers endpoints are unchanged and have no end date.
- Guides: [API v2 overview](/developers/guides/v2-overview), [Booking flow](/developers/guides/v2-booking-flow), [Transfers](/developers/guides/v2-transfers), [v2 errors](/developers/guides/v2-errors) and [Migrating from v1](/developers/guides/v2-migrating-from-v1).

## 2026-09-30: Transfers

The Transfers API was reworked to match the Disney API and is ready for partners.

- A Bearer credential is required on every Transfers endpoint. A request without it returns `401`. The `id_company` field is not accepted.
- `transferConfirm` takes a lead traveler: `pax[0]` with `name`, `surname`, `phone` and `nationality` (ISO 3166-1 alpha-2). Other passengers are optional and can be fewer than the booking. Before, every passenger had to be listed.
- Sandbox credentials now run the whole booking and keep a snapshot. You can cancel the test booking and download its voucher. The earlier `MOCK-TRANSFER-...` ids and the empty voucher are gone.
- New endpoint: `GET /api/v1/transfer/pdf?order_id=...` returns the voucher PDF of an order of your account.
- Every Transfers error uses the same envelope: `error`, `message`, `code`, `request_id`. This includes the answer of a cancellation that is not allowed.
- `getPrice` and `transferConfirm` return the same price for the same date and passengers.

## 2026-09-23: Disney

- `nationality` is required for every passenger and is checked against the ISO 3166-1 alpha-2 list. The alpha-3 code or the country name is converted.
- `phone` is optional. The passenger email is not used.
- `ticketConfirm` returns only `id_order` and `pdf_voucher`.

## 2026-09-22: Disney

The Disney endpoints were rewritten with the same shape as Universal: a catalog with one entry per product code, a price per unit and date, a direct confirmation, and `GET /api/v1/disney/pdf` for the voucher. Bearer is required. Adult and child tickets are separate product codes.

## 2026-09-05: Universal and hotels

- Universal `ticketConfirm` prices each ticket first and then multiplies by the quantity. The total matches the unit prices from `getTicketPrice` to the cent. Before, rounding on the total could differ by 0.01 and reject a correct `total_amount`.
- Hotels: `bookingCancelation` takes `id_orden`. `bookingDetail` and `bookingHcn` read a booking by `id_orden`. `bookingConfirm` returns the voucher link `pdf_voucher`. All `error` values are in English.

## 2026-09-01: Hotels

Every error from `/api/v1/hotel/*` has the same four fields: `error`, `message`, `code`, `request_id`. The `error` value is a stable label you can branch on. A supplier refusal is now `400 Booking rejected` or `400 Cancellation rejected`, with a short reason in `message`.

## 2026-08-26: Hotels, one room per slot

`hotelSearch` returns one slot per requested room, in the order of `occupancies`. `price` and `cancelation_fees[].amount` are per room. The total of a grouped rate is in `price_total` and `amount_total`. In `bookingConfirm`, `ratekey` has one entry per room. A grouped key repeated a wrong number of times returns `400 Invalid rate_key repetition`.

## 2026-08-23: Idempotency on every confirmation

Duplicate protection by `external_reference` (or the `X-Idempotency-Key` header) is active for all accounts on the four confirmation endpoints. See [Conventions](/developers/guides/conventions#idempotency).

## 2026-07-22: Hotels, adults only

Hotels that do not accept children carry `adults_only: true` and, when known, `adults_min_age`. The fields appear in `hotelSearch`, `hotelCheckPrice` and `content/hotelData`.

## 2026-07-04: Voucher links and idempotency

- Voucher links use a random key that cannot be guessed. Follow the URL that each confirmation returns.
- Confirmations accept `external_reference` to prevent duplicates. A repeat returns the same order with `idempotent_replay: true`, and a concurrent repeat returns `409 ORDER_CONFIRMATION_IN_PROGRESS`.

## 2026-05-09: Universal voucher endpoint

New endpoint: `GET /api/v1/universal/pdf?order_id=...` returns the voucher PDF of an order. The random-key link that `ticketConfirm` returns keeps working.
