> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dev.gojinko.com/llms.txt
> Use this file to discover all available pages before exploring further.

# hotel-ai-search

> Search hotels from one sentence, with follow-ups

Send the traveller's request in one sentence. The answer comes within about 20 seconds with `200`: the hotels, or a question to answer in the same conversation. When the search takes longer, the answer is `202` with the early reply and a `Location` to read until the task ends. Continue the conversation with its `context_id`.

> [!NOTE]
>
> New to hotel AI search? The [Hotel AI search guide](https://docs.dev.gojinko.com/ai/hotel-search/overview.md) walks through the whole flow: the first call, the questions it asks, follow-ups, `202` and streaming, and booking a result.


## OpenAPI

````yaml api-reference/public-api.yaml POST /v1/hotel_ai_search
openapi: 3.0.0
info:
  title: Jinko Public API
  version: 0.111.0
  description: >-
    Curated public REST surface for Jinko. Authenticated with jnk_ API keys. See
    https://docs.gojinko.com for guides.


    ### Per-end-user attribution


    On booking calls you may send an optional `X-End-User-Id` request header to
    attribute the booking to one of your own end users (for per-end-user
    attribution and rate-limiting). The value is an **opaque, tenant-scoped**
    identifier that you choose — not a Jinko account id. Omit it to book as the
    tenant. Values prefixed `user_` or `org_` are rejected.
servers:
  - url: https://api.gojinko.com
    description: Production
  - url: https://api.sandbox.gojinko.com
    description: Sandbox
security: []
paths:
  /v1/hotel_ai_search:
    post:
      tags:
        - Hotels
      summary: Search hotels from one sentence, with follow-ups
      description: >-
        Send the traveller's request in one sentence. The answer comes within
        about 20 seconds with `200`: the hotels, or a question to answer in the
        same conversation. When the search takes longer, the answer is `202`
        with the early reply and a `Location` to read until the task ends.
        Continue the conversation with its `context_id`.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 200
            description: >-
              Makes a retried message safe: a retry with the same key answers
              the first message again instead of sending a second one. Keys are
              scoped to the caller, not to the conversation, and the retried
              body is not compared: a different message needs a new key. 1–200
              characters.
          required: false
          name: Idempotency-Key
          in: header
        - schema:
            type: string
            maxLength: 200
            description: >-
              `wait=N` (RFC 7240): answer after at most N seconds, never more
              than 20, with `202` and the early reply if the task has not ended
              by then. `wait=0` answers at once. Without it the wait is 20
              seconds. The wait applied is returned in `Preference-Applied`.
            example: wait=0
          required: false
          name: Prefer
          in: header
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HotelAiSearchRequest'
      responses:
        '200':
          description: >-
            The task ended this turn; or, with `Accept: text/event-stream`, the
            turn as it happens.
          headers:
            Preference-Applied:
              schema:
                type: string
              description: >-
                The wait applied, as `wait=<seconds>`, when the request sent
                `Prefer: wait=N`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HotelAiSearchAnswer'
            text/event-stream:
              schema:
                type: string
                description: >-
                  Server-Sent Events, one per task event: `id` is its sequence
                  number (send it back as `Last-Event-ID` to resume), `event` is
                  `task.status` (`status` `submitted` or `working`),
                  `agent.message` (the early reply first), `hotels.page`, or
                  `task.completed` / `task.input_required` / `task.failed` /
                  `task.canceled` / `task.expired` for the status that ends the
                  turn; `data` is JSON and carries `task_id` and `context_id`.
                  The stream ends with the turn, or after 45 seconds: resume it
                  with the `Last-Event-ID` of the last event received.
        '202':
          description: >-
            The search is still running: the early reply. Read `Location` after
            Retry-After.
          headers:
            Location:
              schema:
                type: string
              description: The task to read for the final answer.
            Retry-After:
              schema:
                type: string
              description: Seconds to wait before reading the task again.
            Preference-Applied:
              schema:
                type: string
              description: >-
                The wait applied, as `wait=<seconds>`, when the request sent
                `Prefer: wait=N`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HotelAiSearchAnswer'
        '400':
          description: >-
            Bad request: malformed JSON, or an invalid header such as a reserved
            `X-End-User-Id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: BAD_REQUEST
                  message: Malformed JSON in request body
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: AUTH_REQUIRED
                  message: Invalid or expired API key.
                  doc_url: https://docs.gojinko.com/authentication/api-keys
        '402':
          description: >-
            The organization's balance is below what a search turn needs. The
            message carries the top-up link. **`PAYMENT_REQUIRED`** — The
            organization's balance cannot cover this call. Top up at the link in
            the message. Retrying never fills an empty wallet.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: PAYMENT_REQUIRED
                  message: >-
                    Insufficient balance — a hotel AI search turn needs at least
                    $0.20 and your organization has $0.0500 available. Top up at
                    https://dashboard.gojinko.com/developers/billing/topup
        '403':
          description: >-
            The key is valid but is not a tenant API key (`jnk_t_…`), is not
            granted the `search_live` scope, or Travel AI search is not enabled
            for this account. **`FORBIDDEN`** — The credential is valid, and
            this request is refused anyway. Do not rotate the key — it is
            working. Check that it is entitled to this operation, and on this
            environment.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: FORBIDDEN
                  message: >-
                    This API key is not granted the "search_live" scope required
                    by this endpoint
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: NOT_FOUND
                  message: Resource not found.
                  doc_url: https://docs.gojinko.com/concepts/errors
        '410':
          description: The resource this request names no longer exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: GONE
                  message: The resource no longer exists.
                  doc_url: https://docs.gojinko.com/concepts/errors
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: BAD_REQUEST
                  message: A required field is missing or invalid.
                  doc_url: https://docs.gojinko.com/concepts/errors
        '429':
          description: Rate limit or quota exceeded
          headers:
            Retry-After:
              description: >-
                Seconds to wait before retrying. Absent when no interval
                applies.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: RATE_LIMITED
                  message: Too many requests. Retry after the Retry-After delay.
                  doc_url: https://docs.gojinko.com/concepts/errors
        '502':
          description: The travel provider rejected the request, or an upstream call failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: UPSTREAM_REJECTED
                  message: The request was declined for this offer. Try another offer.
                  doc_url: https://docs.gojinko.com/concepts/errors
        '503':
          description: No travel provider can serve the request right now
          headers:
            Retry-After:
              description: >-
                Seconds to wait before retrying. Absent when no interval
                applies.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: UPSTREAM_UNAVAILABLE
                  message: >-
                    The service is temporarily unavailable. Retry after the
                    Retry-After delay.
                  doc_url: https://docs.gojinko.com/concepts/errors
        '504':
          description: The travel provider did not answer in time
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: UPSTREAM_TIMEOUT
                  message: >-
                    The request timed out before a result was available. Retry
                    the request.
                  doc_url: https://docs.gojinko.com/concepts/errors
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
      servers:
        - url: https://api.gojinko.com
          description: Production
components:
  schemas:
    HotelAiSearchRequest:
      type: object
      properties:
        text:
          type: string
          minLength: 1
          maxLength: 2000
          description: >-
            The traveller's request in one sentence, or the answer to the
            question asked in the previous turn.
          example: A hotel in Paris next weekend for 2 adults with breakfast included
        context_id:
          type: string
          minLength: 1
          maxLength: 100
          description: >-
            The conversation to continue, from an earlier answer. Omit to start
            a new conversation.
          example: ctx_example
        task_id:
          type: string
          minLength: 1
          maxLength: 100
          description: >-
            The task of that conversation the message answers. Optional: without
            it, a message continues the task waiting for an answer, or starts a
            new one.
          example: atk_example
        currency:
          type: string
          pattern: ^[A-Za-z]{3}$
          description: Currency of the prices (ISO 4217).
          example: EUR
        guest_nationality:
          type: string
          pattern: ^[A-Za-z]{2}$
          description: Nationality of the guests (ISO 3166-1 alpha-2).
          example: FR
        effort:
          type: string
          enum:
            - low
            - medium
            - high
          description: >-
            How much the search may do before it answers. `low` answers soonest;
            `high` checks the most and searches the most options. Defaults to
            `medium`.
          example: medium
        timezone:
          type: string
          description: >-
            The traveller's IANA time zone. Relative dates such as "next
            weekend" or "tonight" are computed in it.
          example: Europe/Paris
      required:
        - text
        - timezone
    HotelAiSearchAnswer:
      type: object
      properties:
        context_id:
          type: string
          nullable: true
          description: The conversation; send it with the next message to continue.
          example: ctx_example
        task_id:
          type: string
          example: atk_example
        status:
          type: string
          enum:
            - working
            - input_required
            - completed
            - failed
            - canceled
          description: >-
            `working`: the search is still running, read the task again.
            `input_required`: the message asks a question; answer it in the same
            conversation. `completed`: the hotels are in the answer. `failed`:
            see `error`. `canceled`: a later message or a cancel replaced it.
        message:
          type: string
          description: The reply to show the traveller.
          example: Found 37 hotels in Paris for Oct 24–25 (1 night, 2 adults, 1 room).
        question:
          type: string
          description: What the reply asks for, when `status` is `input_required`.
          example: dates
        criteria:
          type: object
          additionalProperties:
            nullable: true
          description: >-
            The search the request was understood as, in the `hotel_search`
            request fields, plus `board_types` and `refundable_only` for the
            rate filters applied to the results.
        notes:
          type: array
          items:
            type: object
            additionalProperties:
              nullable: true
          description: Assumptions and adjustments made while understanding the request.
        hotels:
          type: array
          items:
            $ref: '#/components/schemas/HotelAiSearchHotel'
        has_more:
          type: boolean
          description: More hotels are available; ask for more in the same conversation.
        reference:
          type: boolean
          description: >-
            The hotels are a 1-night reference search shown while the check-out
            date is asked.
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
          required:
            - code
            - message
          description: Why the task failed, when `status` is `failed`.
        superseded_by:
          type: string
          description: The task that replaced this one, when `status` is `canceled`.
        charge:
          $ref: '#/components/schemas/HotelAiSearchCharge'
      required:
        - context_id
        - task_id
        - status
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - INVALID_SEGMENTS_TO_EXCHANGE
                - PARTIAL_EXCHANGE_UNSUPPORTED
                - LEG_ALREADY_DEPARTED
                - DEPARTURE_DATE_IN_PAST
                - LEG_DATES_OUT_OF_ORDER
                - INVALID_EXCHANGE_REQUEST
                - NOT_EXCHANGEABLE
                - CREDENTIAL_FORMAT_INVALID
                - PAYMENT_TYPE_NOT_ENABLED
                - PAYMENT_CREDENTIAL_INVALID
                - TRIP_OWNED_BY_OTHER_PAYMENT
                - IDEMPOTENCY_KEY_REUSED
                - ATTEMPT_IN_PROGRESS
                - ATTEMPT_TERMINAL
                - TEMPORARILY_UNAVAILABLE
                - AUTH_REQUIRED
                - PAYMENT_REQUIRED
                - RATE_LIMITED
                - BAD_REQUEST
                - FORBIDDEN
                - NOT_FOUND
                - CONFLICT
                - GONE
                - QUOTE_PENDING
                - QUOTE_EXPIRED
                - TRIP_EXPIRED
                - TRIP_STATE_CONFLICT
                - OFFER_EXPIRED
                - OFFER_UNAVAILABLE
                - MISSING_CUSTOMER_DETAILS
                - INVALID_PHONE_NUMBER
                - INVALID_FLIGHT_NUMBER
                - CURRENCY_UNSUPPORTED
                - HOTEL_NAME_LOW_CONFIDENCE
                - DESTINATION_LOW_CONFIDENCE
                - UPSTREAM_REJECTED
                - UPSTREAM_UNAVAILABLE
                - UPSTREAM_TIMEOUT
                - UPSTREAM_ERROR
                - INTERNAL
              description: >-
                What went wrong, as a stable machine-readable code. This is a
                closed set — branch on it rather than on `message`, which is
                prose and may change. New codes arrive in a minor version, so
                treat an unknown one as its HTTP status. A code can also stop
                being emitted: it leaves this set in a minor version, named in
                the changelog, and a branch you wrote for it goes unreached
                rather than wrong.
              example: BAD_REQUEST
            message:
              type: string
              description: >-
                What went wrong, in prose. These codes always carry the same
                message, and it never includes text from a supplier:
                `RATE_LIMITED` — "Too many requests. Retry after the Retry-After
                delay."; `OFFER_EXPIRED` — "This offer has expired. Search
                again."; `OFFER_UNAVAILABLE` — "This offer is no longer
                available. Search again."; `UPSTREAM_REJECTED` — "The request
                was declined for this offer. Try another offer.";
                `UPSTREAM_UNAVAILABLE` — "The service is temporarily
                unavailable. Retry after the Retry-After delay.";
                `UPSTREAM_TIMEOUT` — "The request timed out before a result was
                available. Retry the request."; `UPSTREAM_ERROR` — "The request
                could not be completed.".
            doc_url:
              type: string
            field:
              type: string
              description: >-
                On a 400 `BAD_REQUEST` that names one refused input: the path of
                that field in your request, e.g. `selections[1].quantity` for
                the second selection of a `select_ancillaries` call. Absent when
                the refusal names no single field.
              example: selections[1].quantity
          required:
            - code
            - message
      required:
        - error
    HotelAiSearchHotel:
      allOf:
        - $ref: '#/components/schemas/Hotel'
        - type: object
          properties:
            match_score:
              type: integer
              minimum: 0
              maximum: 100
              description: >-
                How well the hotel fits the request, 0–100. The hotels come best
                first. Relative to this search, not comparable across searches.
                Absent on some hotels.
              example: 87
      description: >-
        A hotel of an AI search answer: the `hotel_search` hotel with its rooms
        and offers, and how well it fits the request.
    HotelAiSearchCharge:
      type: object
      properties:
        turn:
          type: integer
          description: >-
            The message of the conversation this charge is for, from 1: the
            first message is 1 and each next message adds 1, whether it answers
            a question or asks for something new.
          example: 1
        llm_usd:
          type: number
          description: The language-model part of the charge, in USD.
          example: 0.0165
        api_usd:
          type: number
          description: The hotel search part of the charge, in USD.
          example: 0.0645
        total_usd:
          type: number
          description: '`llm_usd` + `api_usd`.'
          example: 0.081
        currency:
          type: string
          enum:
            - USD
      required:
        - turn
        - llm_usd
        - api_usd
        - total_usd
        - currency
      description: >-
        What a turn was charged to the organization's balance, once the turn has
        ended (`completed`, `input_required`, `failed` or `canceled`); every
        amount is 0 when the turn cost nothing. Absent while the task is
        `working`. Carried on JSON answers only: an event stream does not carry
        it, so read it with `GET /v1/hotel_ai_search/tasks/{task_id}`.
    Hotel:
      type: object
      properties:
        hotel_id:
          type: string
          description: >-
            Opaque hotel identifier. Pass it to hotel_details, hotel_reviews and
            `hotel_ids` exactly as received; do not parse or build it. The value
            a hotel is known by can change between contract versions, so read it
            from a fresh hotel_search rather than keeping it.
          example: lp1d2c3
        hotel_ref:
          type: string
          description: >-
            Deprecated: use `hotel_id` (search) or `id` (details, reviews). The
            hotel's identifier behind a source prefix, as earlier contract
            versions returned it; hotel_details and hotel_reviews still accept
            it. Pass it back exactly as received; do not parse or build it.
          example: h1:lp1d2c3
          deprecated: true
        name:
          type: string
          example: Hôtel Le Marais
        address:
          type: string
          example: 12 Rue de Rivoli
        city:
          type: string
          example: Paris
        country:
          type: string
          description: >-
            ISO 3166-1 alpha-2 country code, LOWER case as the platform sends
            it.
          example: fr
        star_rating:
          type: number
          example: 4
        category:
          type: string
          description: >-
            The provider's own category wording, which `star_rating` cannot
            express. Free text.
          example: 4 KEYS
        lodging_type:
          type: string
          example: Aparthotel
        rating:
          type: number
          description: Guest score out of 10.
          example: 8.6
        review_count:
          type: number
          description: Number of guest reviews behind `rating`.
          example: 1243
        main_photo:
          type: string
          description: Full-size hero image URL.
          example: https://images.example.com/hotels/main.jpg
        thumbnail:
          type: string
          description: Small preview image URL.
          example: https://images.example.com/hotels/thumb.jpg
        latitude:
          type: number
          example: 48.8566
        longitude:
          type: number
          example: 2.3522
        distance_km:
          type: number
          minimum: 0
          description: Straight-line distance from the search center, in kilometers.
        recommendation_score:
          type: number
          minimum: 0
          maximum: 1
          description: >-
            How well the hotel fits `intent.user_intent`, from 0 to 1, present
            when the intent re-ranked the results, which are then ordered by it.
            Without an intent the results keep the order `sort_by` names. Not a
            guest rating.
        rooms:
          type: array
          items:
            $ref: '#/components/schemas/HotelRoom'
        offers:
          type: array
          items:
            $ref: '#/components/schemas/HotelOffer'
          description: >-
            Bookable whole-stay offers. Choose one and add its `trip_item_token`
            to the trip exactly once.
      description: >-
        A hotel and its available rooms. Until v0.2.0 this schema declared
        `images`, `thumbnail_url` and `country_code`, none of which hotel search
        has ever sent; the real names are `main_photo`, `thumbnail` and
        `country`.
    HotelRoom:
      type: object
      properties:
        room_id:
          type: string
          example: rm_1
        room_name:
          type: string
          example: Superior Double
        description:
          type: string
          description: Free-text room description, when the provider supplied one.
        requested_occupancy:
          type: integer
          description: >-
            The occupancy these rates were priced for — an echo of what you
            searched, not a property of the room. Pricing a different party size
            means searching again.
          example: 2
        room_capacity:
          type: integer
          description: >-
            How many the room sleeps, from the provider’s content catalogue.
            Absent when the catalogue carries no figure — absent means unknown,
            never zero. Same field as on hotel_details and on a hotel trip item.
          example: 2
        max_occupancy:
          type: integer
          description: >-
            Deprecated: an alias of `requested_occupancy` (same value), never
            the room’s capacity. Read `requested_occupancy` for the priced party
            size and `room_capacity` for how many the room sleeps.
          deprecated: true
          example: 2
        images:
          type: array
          items:
            type: string
        amenities:
          type: array
          items:
            type: string
        beds:
          type: array
          items:
            $ref: '#/components/schemas/HotelBed'
        rates:
          type: array
          items:
            $ref: '#/components/schemas/HotelRate'
          description: >-
            DEPRECATED compatibility projection. Read the hotel-level `offers[]`
            list for new integrations and add an offer’s `trip_item_token` to
            the trip. Multi-room searches return this as an empty array.
          deprecated: true
    HotelOffer:
      type: object
      properties:
        offer_id:
          type: string
          description: 'Deprecated: use `trip_item_token` instead. Same value.'
          example: htl_2d67a7441c60e5de
          deprecated: true
        board_type:
          type: string
          example: RO
        board_name:
          type: string
          example: Room Only
        total_amount:
          type: number
          description: >-
            Deprecated: use `total_amount_money` instead. Price for the whole
            stay in `currency`, in MAJOR units at the currency’s own precision.
          example: 1818.4
          deprecated: true
        total_amount_display:
          type: string
          description: >-
            Deprecated: use `total_amount_money` instead. The rate total as a
            string ready to show: the ISO 4217 code, a space, then
            `total_amount` at the currency’s ISO digits, e.g. "EUR 606.13".
          example: EUR 606.13
          deprecated: true
        currency:
          type: string
          description: >-
            Deprecated: use `total_amount_money` instead. The currency of
            `total_amount`.
          example: EUR
          deprecated: true
        total_amount_money:
          allOf:
            - $ref: '#/components/schemas/MoneyValue'
            - description: Price for the whole stay.
        is_refundable:
          type: boolean
        free_cancellation_until:
          type: string
          description: >-
            Last instant the stay can be cancelled at no charge. RFC 3339 with
            the supplier’s declared UTC offset. Absent when the supplier
            declared no timezone — the platform never invents an offset, so a
            deadline it cannot place on the clock is withheld rather than
            published ambiguously — and absent when the rate is non-refundable
            or the provider named no deadline.
          example: '2026-08-18T10:00:00+02:00'
        cancellation_schedule:
          type: array
          items:
            $ref: '#/components/schemas/CancellationStep'
          description: >-
            The full penalty ladder, chronological. Absent when the provider
            published none — which is not a statement that cancelling is free.
        taxes_breakdown:
          type: array
          items:
            $ref: '#/components/schemas/TaxLine'
        payment_types:
          type: array
          items:
            $ref: '#/components/schemas/HotelPaymentType'
          description: How the rate can be settled. Each value appears at most once.
          example:
            - pay_now
        promotions:
          type: array
          items:
            $ref: '#/components/schemas/HotelOfferPromotion'
        trip_item_token:
          type: string
          description: >-
            The token `trip(add_item)` takes as `trip_item_token`. Add it once
            even when `room_rates` contains several occupancies.
          example: htl_2d67a7441c60e5de
        room_rates:
          type: array
          items:
            $ref: '#/components/schemas/HotelRoomRate'
          description: >-
            One entry per requested occupancy. One occupancy means one room;
            multiple occupancies mean a multi-room offer.
      required:
        - offer_id
        - total_amount
        - currency
        - is_refundable
        - taxes_breakdown
        - trip_item_token
        - room_rates
    HotelBed:
      type: object
      properties:
        bed_type:
          type: string
        count:
          type: integer
          minimum: 1
      required:
        - bed_type
        - count
    HotelRate:
      type: object
      properties:
        offer_id:
          type: string
          description: >-
            Legacy rooms[].rates[] compatibility token. New integrations use the
            hotel-level `offers[].trip_item_token`; add that token to the trip
            exactly once.
          example: htl_2d67a7441c60e5de
        board_type:
          type: string
          example: RO
        board_name:
          type: string
          example: Room Only
        total_amount:
          type: number
          description: >-
            Deprecated: use `total_amount_money` instead. Price for the whole
            stay in `currency`, in MAJOR units at the currency’s own precision.
          example: 1818.4
          deprecated: true
        total_amount_display:
          type: string
          description: >-
            Deprecated: use `total_amount_money` instead. The rate total as a
            string ready to show: the ISO 4217 code, a space, then
            `total_amount` at the currency’s ISO digits, e.g. "EUR 606.13".
          example: EUR 606.13
          deprecated: true
        currency:
          type: string
          description: >-
            Deprecated: use `total_amount_money` instead. The currency of
            `total_amount`.
          example: EUR
          deprecated: true
        total_amount_money:
          allOf:
            - $ref: '#/components/schemas/MoneyValue'
            - description: Price for the whole stay.
        is_refundable:
          type: boolean
          example: false
        free_cancellation_until:
          type: string
          description: >-
            Last instant the stay can be cancelled at no charge. RFC 3339 with
            the supplier’s declared UTC offset. Absent when the supplier
            declared no timezone — the platform never invents an offset, so a
            deadline it cannot place on the clock is withheld rather than
            published ambiguously — and absent when the rate is non-refundable
            or the provider named no deadline.
          example: '2026-08-18T10:00:00+02:00'
        cancellation_schedule:
          type: array
          items:
            $ref: '#/components/schemas/CancellationStep'
          description: >-
            The full penalty ladder, chronological. Absent when the provider
            published none — which is not a statement that cancelling is free.
        taxes_breakdown:
          type: array
          items:
            $ref: '#/components/schemas/TaxLine'
          description: >-
            Taxes and fees on this rate. ALWAYS present, so an empty array means
            "no tax is known" and can be shown as such; check `included` per
            line before adding anything to `total_amount_money`.
        payment_types:
          type: array
          items:
            $ref: '#/components/schemas/HotelPaymentType'
          description: How the rate can be settled. Each value appears at most once.
          example:
            - pay_now
        promotions:
          type: array
          items:
            $ref: '#/components/schemas/HotelRatePromotion'
        booking_scope:
          type: string
          description: >-
            LEGACY-ONLY compatibility metadata. Current canonical `offers[]`
            never returns `booking_scope`; use `room_rates.length` to determine
            how many rooms an offer covers.
          example: room_bundle
        num_rooms:
          type: integer
          minimum: 1
          description: >-
            LEGACY-ONLY compatibility metadata. Current canonical `offers[]`
            represents room count through `room_rates.length` and never returns
            `num_rooms`.
          example: 2
        rooms:
          type: array
          items:
            $ref: '#/components/schemas/HotelBundleRoom'
          description: >-
            LEGACY-ONLY compatibility room details. Current canonical `offers[]`
            returns `room_rates[]` and never returns this `rooms` field.
      description: >-
        Deprecated compatibility shape under `rooms[].rates[]`. Current
        canonical `offers[]` does not return `booking_scope`, `num_rooms`, or
        `rooms`; use `room_rates[]` instead.
    MoneyValue:
      type: object
      properties:
        value:
          type: integer
          description: >-
            Integer amount in MINOR units at the ISO 4217 digits of `currency`:
            divide by 10 ** decimal_places to get the amount. Signed where the
            field says so (a price change delta).
          example: 41250
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          description: ISO 4217 currency code.
          example: USD
        decimal_places:
          type: integer
          description: >-
            The ISO 4217 digits of `currency` (2 for USD/EUR, 0 for JPY/KRW, 3
            for BHD/KWD), and the scale of `value`.
          example: 2
        display:
          type: string
          description: >-
            The same figure as a string ready to show: the ISO 4217 code, a
            space, then the amount at `decimal_places`, e.g. "USD 412.50". Show
            this; compute with `value`.
          example: USD 412.50
      required:
        - value
        - currency
        - decimal_places
        - display
      description: >-
        Money as every new field carries it: `value` is an INTEGER in minor
        units at the ISO 4217 digits of `currency` (`decimal_places`), and
        `display` is the same figure ready to show. All four members are always
        present; a figure the platform does not know is absent, never `{value:
        0}`. New integrations read the `*_money` fields (and `value` on the
        objects that carry it); the two-scale rule described on `Money` applies
        only to the deprecated fields.
    CancellationStep:
      type: object
      properties:
        cancel_time:
          type: string
          description: >-
            Deadline after which this tier applies. RFC 3339 with the supplier’s
            declared UTC offset. Steps whose deadline has no declared timezone
            are omitted from the ladder — the platform never invents an offset —
            so a schedule can be shorter than the supplier’s own. Tiers are
            chronological, earliest first, so the first entry is the deadline
            that matters.
          example: '2026-08-18T10:00:00+02:00'
        amount:
          type: number
          description: >-
            Deprecated: use `amount_money` instead. Read `amount_money`,
            `percent` or `nights`, whichever this step carries. What the guest
            is charged on or after `cancel_time`: a sum in MAJOR units of
            `currency`, a percentage or a number of nights, as `type` says.
          example: 606.13
          deprecated: true
        currency:
          type: string
          description: 'Deprecated: use `amount_money` instead. The currency of `amount`.'
          example: EUR
          deprecated: true
        type:
          type: string
          description: >-
            How the charge is expressed — a sum ("amount", "flat_fee"; read
            `amount_money`), a percentage ("percent", "percentage"; read
            `percent`) or a number of nights ("nights"; read `nights`).
          example: amount
        display:
          type: string
          description: >-
            Deprecated: use `amount_money` instead. The same figure as a string
            ready to show: the ISO 4217 code, a space, then the amount, e.g.
            "USD 159.77". With decimal_places it is written at exactly that
            scale (value 1561500, JPY, decimal_places 2 is "JPY 15615.00");
            without, at the ISO digits of the currency. Show this; compute with
            the number. Absent when the figure is not money (a cancellation step
            expressed as a percent or a number of nights) or could not be read
            unambiguously.
          example: EUR 606.13
          deprecated: true
        amount_money:
          allOf:
            - $ref: '#/components/schemas/MoneyValue'
            - description: >-
                What the guest is charged on or after `cancel_time`, when this
                step is a sum. Absent on a percentage or nights step, and when
                the supplier named no currency.
        percent:
          type: number
          description: >-
            The charge as a percentage of the stay price, when this step is a
            percentage, on the 0–100 scale the supplier states it in: 50 is half
            the stay price, 100 the whole of it. Never a 0–1 fraction. Absent
            otherwise.
          example: 50
        nights:
          type: number
          description: >-
            The charge as a number of nights of the stay, when this step is
            expressed in nights. Absent otherwise.
          example: 1
    TaxLine:
      type: object
      properties:
        amount:
          type: number
          description: >-
            Deprecated: use `amount_money` instead. The tax in MAJOR units of
            `currency`.
          example: 164.49
          deprecated: true
        currency:
          type: string
          description: 'Deprecated: use `amount_money` instead. The currency of `amount`.'
          example: EUR
          deprecated: true
        amount_money:
          allOf:
            - $ref: '#/components/schemas/MoneyValue'
            - description: >-
                The tax. When the supplier named no currency for the line, it is
                the currency the rate is priced in.
        description:
          type: string
          description: The provider’s own wording for the tax. Free text, not a code.
          example: 19, VAT National taxes on accommodation
        included:
          type: boolean
          description: >-
            True when the amount is ALREADY inside `total_amount_money`; false
            when the guest pays it at the property on top. Getting this
            backwards misquotes the trip.
          example: true
        display:
          type: string
          description: >-
            Deprecated: use `amount_money` instead. The same figure as a string
            ready to show: the ISO 4217 code, a space, then the amount, e.g.
            "USD 159.77". With decimal_places it is written at exactly that
            scale (value 1561500, JPY, decimal_places 2 is "JPY 15615.00");
            without, at the ISO digits of the currency. Show this; compute with
            the number. Absent when the figure is not money (a cancellation step
            expressed as a percent or a number of nights) or could not be read
            unambiguously.
          example: EUR 164.49
          deprecated: true
    HotelPaymentType:
      type: string
      enum:
        - pay_now
        - pay_at_property
        - deposit
      description: >-
        How the rate can be settled. `pay_now` — paid when the booking is made.
        `pay_at_property` — paid to the hotel at the property. `deposit` — a
        deposit is taken.
    HotelOfferPromotion:
      type: object
      properties:
        name:
          type: string
        remark:
          type: string
      description: >-
        A provider promotion applied to the offer, as it is to be shown to the
        guest: its name and the remark that goes with it.
    HotelRoomRate:
      type: object
      properties:
        room_id:
          type: string
          description: References one entry in this hotel’s `rooms[]` metadata.
        occupancy_number:
          type: integer
          minimum: 1
          description: Stable one-based occupancy slot from the search request.
        occupancy:
          $ref: '#/components/schemas/Occupancy'
        room_name:
          type: string
        board_type:
          type: string
        board_name:
          type: string
        max_occupancy:
          type: integer
        taxes_and_fees:
          type: array
          items:
            $ref: '#/components/schemas/TaxLine'
        policies:
          type: array
          items:
            $ref: '#/components/schemas/HotelBundleRoomPolicy'
        is_refundable:
          type: boolean
        cancellation_policy:
          type: array
          items:
            $ref: '#/components/schemas/CancellationStep'
        free_cancellation_until:
          type: string
        payment_types:
          type: array
          items:
            $ref: '#/components/schemas/HotelPaymentType'
          description: How the rate can be settled. Each value appears at most once.
          example:
            - pay_now
        remarks:
          type: string
      required:
        - room_id
        - occupancy_number
        - occupancy
        - taxes_and_fees
        - is_refundable
      description: >-
        Display and policy details for one requested room occupancy. It carries
        no customer price allocation; the containing offer owns the
        authoritative whole-stay total.
    HotelRatePromotion:
      type: object
      properties:
        code:
          type: string
        name:
          type: string
        remark:
          type: string
    HotelBundleRoom:
      type: object
      properties:
        occupancy_number:
          type: integer
          minimum: 1
          description: Stable one-based room slot within this bundle.
          example: 1
        room_id:
          type: string
        mapped_room_id:
          type: integer
        room_name:
          type: string
          example: Superior Double
        rate_id:
          type: string
        occupancy:
          $ref: '#/components/schemas/Occupancy'
        board_type:
          type: string
          example: BB
        board_name:
          type: string
          example: Breakfast Included
        max_occupancy:
          type: integer
        taxes_and_fees:
          type: array
          items:
            $ref: '#/components/schemas/TaxLine'
        policies:
          type: array
          items:
            $ref: '#/components/schemas/HotelBundleRoomPolicy'
        is_refundable:
          type: boolean
        cancellation_policy:
          type: array
          items:
            $ref: '#/components/schemas/CancellationStep'
        free_cancellation_until:
          type: string
        payment_types:
          type: array
          items:
            $ref: '#/components/schemas/HotelPaymentType'
          description: How the rate can be settled. Each value appears at most once.
          example:
            - pay_now
        remarks:
          type: string
      required:
        - occupancy_number
        - occupancy
      description: >-
        One room of a hotel item — the single room a one-room item books, or one
        slot of a room-bundle rate — with the party it was priced for
        (`occupancy`) and its display and policy details. The containing item
        owns the customer-facing total; supplier net, suggested retail,
        commission and room-local supplier price figures are intentionally not
        part of this public shape.
    Occupancy:
      type: object
      properties:
        adults:
          type: integer
          minimum: 1
        children_ages:
          type: array
          items:
            type: integer
            minimum: 0
            maximum: 17
      required:
        - adults
      description: >-
        The party one room is requested or priced for: the number of adults and
        the age of each child.
    HotelBundleRoomPolicy:
      type: object
      properties:
        type:
          type: string
        description:
          type: string
        fee_amount:
          type: number
          description: >-
            Deprecated: use `fee_amount_money` instead. Customer policy fee in
            MAJOR units of `fee_currency`.
          deprecated: true
        fee_currency:
          type: string
          description: >-
            Deprecated: use `fee_amount_money` instead. The currency of
            `fee_amount`.
          deprecated: true
        fee_amount_money:
          allOf:
            - $ref: '#/components/schemas/MoneyValue'
            - description: >-
                Customer cancellation or policy fee, with exact minor units and
                currency precision.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
    BearerAuth:
      type: http
      scheme: bearer

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.