openapi: 3.1.0
info:
  title: Bundleport Hotels API
  description: |
    **Booking (transactional) API** — search, quote, book, list, detail, and cancel across multiple supplier
    connections. Paths below are `/hotels/v1/...`; on the public gateway they are called as
    `https://api.bundleport.com/connect` + path (see **Servers** / **Try it**).

    **Start here:** [API Reference overview](/api/overview) · [Connect Hotels](/connect-hotels/overview) ·
    [Static vs transactional data](/overview/concepts#static-data-vs-transactional-data) · [Versioning](/reference/versioning) · [Changelog](/changelog).

    Authenticate with `Authorization: ApiKey sk_prod_*` (production host) or `sk_test_*` (test host). Responses use **camelCase**; requests accept camelCase or snake_case.

    **Catalog** (hotels, destinations, rooms) is served by the [Content API](/api/content-api/bundleport-hotel-content-api), not this service.
  version: 1.1.0
  contact:
    name: Bundleport Support
    url: https://bundleport.com/support

servers:
  - url: https://api.bundleport.com/connect
    description: Production gateway (prepend to `/hotels/v1/...` paths for Try it)
  - url: https://test-api.bundleport.com/connect
    description: Test gateway
  - url: http://localhost:8080
    description: Local aggregator (service-internal paths as documented)

tags:
  - name: System
    description: System health and status endpoints
  - name: Hotels - Search
    description: Hotel availability search endpoints
  - name: Hotels - Booking
    description: Hotel booking creation and management endpoints
  - name: Hotels - Booking Management
    description: Booking retrieval and listing endpoints

paths:
  /health:
    servers:
      - url: https://api.bundleport.com/hotels
        description: Production gateway health
      - url: https://test-api.bundleport.com/hotels
        description: Test gateway health
    get:
      tags:
        - System
      summary: Health check
      description: |
        Returns the health status of the Hotels API service.
        Use this endpoint to monitor service availability and operational status.
      operationId: healthCheck
      security: []
      responses:
        '200':
          description: Service is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: OK
                    description: Health status indicator
              examples:
                ok:
                  summary: Healthy
                  value:
                    status: OK

  /openapi.json:
    servers:
      - url: https://api.bundleport.com/hotels
      - url: https://test-api.bundleport.com/hotels
    get:
      tags:
        - System
      summary: OpenAPI specification (JSON)
      description: Returns the OpenAPI specification in JSON format
      operationId: getOpenAPISpec
      security: []
      responses:
        '200':
          description: OpenAPI specification
          content:
            application/json:
              schema:
                type: object
              examples:
                fragment:
                  summary: Spec header (illustrative)
                  value:
                    openapi: "3.1.0"
                    info:
                      title: Bundleport Hotels API
                      version: "1.1.0"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /swagger.json:
    servers:
      - url: https://api.bundleport.com/hotels
      - url: https://test-api.bundleport.com/hotels
    get:
      tags:
        - System
      summary: OpenAPI specification (JSON) - Swagger format
      description: Returns the OpenAPI specification in JSON format (Swagger compatible)
      operationId: getSwaggerSpec
      security: []
      responses:
        '200':
          description: OpenAPI specification
          content:
            application/json:
              schema:
                type: object
              examples:
                fragment:
                  summary: Spec header (illustrative)
                  value:
                    openapi: "3.1.0"
                    info:
                      title: Bundleport Hotels API
                      version: "1.1.0"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /hotels/v1/availability:
    servers:
      - url: https://api.bundleport.com/connect
      - url: https://test-api.bundleport.com/connect
    post:
      tags:
        - Hotels - Search
      summary: Search hotel availability
      description: |
        Searches for hotel availability across multiple providers based on search criteria.
        Supports filtering by hotels, check-in/check-out dates, occupancies, and other criteria.
        The API aggregates responses from multiple providers specified in the connectionCodes array.
        
        Results include available hotel options with pricing, room details, board types, and 
        cancellation policies. The response can be used for subsequent prebooking and booking operations.
        
        **Streaming (opt-in):** Send `Accept: text/event-stream` to receive results as Server-Sent Events (SSE).
        Each event is either `update` (merged snapshot after a provider completes) or `done` (final snapshot).
        Event `data` is JSON with `searchId`, `connectionCode` (update only), `completed`, `total`, `timedOut`, and `snapshot` (SearchResponse shape).
        A comment line `: ping` is sent periodically as a keepalive.
      operationId: searchAvailability
      parameters:
        - name: Accept
          in: header
          required: false
          description: |
            - `application/json` (default) — single JSON response when all providers complete or timeout.
            - `text/event-stream` — SSE stream; each event carries merged snapshot as providers complete.
          schema:
            type: string
            enum: [application/json, text/event-stream]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchRequest'
      responses:
        '200':
          description: |
            Unary JSON or SSE stream. Client and provider failures on this path are still HTTP 200
            with `errors[]` (`ERR_CODE_*` / `ERR_TYPE_*`), not HTTP 400.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
            text/event-stream:
              schema:
                type: string
                description: |
                  SSE stream. Events: `event: update` (data = JSON with searchId, connectionCode, completed, total, timedOut, snapshot);
                  `event: done` (data = JSON with searchId, timedOut, snapshot). Comments `: ping` are keepalives.
        '503':
          description: |
            Search and SSE only. In-flight semaphore full. Body is
            `{ "error": "aggregator saturated", "code": "RESOURCE_EXHAUSTED" }`, not Hotels `errors[]`.
            Quote, book, and cancel are not gated by this limit.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: aggregator saturated
                  code:
                    type: string
                    example: RESOURCE_EXHAUSTED

  /hotels/v1/prebooking:
    servers:
      - url: https://api.bundleport.com/connect
      - url: https://test-api.bundleport.com/connect
    post:
      tags:
        - Hotels - Search
      summary: Get prebooking quote
      description: >-
        Retrieves a detailed quote for a specific hotel option. Pass search
        `options[].id` as `criteria.optionRefId` (never put `searchId`/`search_id`
        there — those are analytics-only). The quote includes final pricing,
        surcharges, cancellation policies, and booking terms, and is valid for a
        limited time. Prefer booking with `optionQuote.optionRefId` after quote.

        **Funnel Tracking:**
        - Optional `search_id` links this quote to a previous search for analytics only.
        - If omitted, the system may fall back to context or correlation_id.
      operationId: getPrebookingQuote
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QuoteRequest'
      responses:
        '200':
          description: Successful response with quote details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuoteResponse'
        '400':
          description: Bad request - invalid quote parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /hotels/v1/booking:
    servers:
      - url: https://api.bundleport.com/connect
      - url: https://test-api.bundleport.com/connect
    post:
      tags:
        - Hotels - Booking
      summary: Create booking
      description: >-
        Creates a hotel booking. Prefer `input.optionRefId` from `optionQuote.optionRefId`
        after prebooking. When the connection allows book-from-search (no `RECHECK` remark),
        you may pass the search option `id` instead. Requires holder and rooms[].paxes.

        **Funnel Tracking (analytics only — not booking tokens):**
        - Optional `search_id` / `quote_id` link Search → Quote → Book in analytics.
        - Do not put `searchId`/`quoteId` into `optionRefId`.
        - If omitted, the system may fall back to context or correlation_id.
      operationId: createBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BookRequest'
      responses:
        '200':
          description: Successful booking creation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BookResponse'
        '400':
          description: Bad request - invalid booking parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /hotels/v1/bookinglist:
    servers:
      - url: https://api.bundleport.com/connect
      - url: https://test-api.bundleport.com/connect
    post:
      tags:
        - Hotels - Booking Management
      summary: List bookings
      description: |
        Retrieves bookings matching **date range** (`BOOKING_LIST_CRITERIA_TYPE_DATES` + `dates`)
        or **references** (`BOOKING_LIST_CRITERIA_TYPE_REFERENCES` + `references` entries with
        `bookingID`, `clientReference`, etc.). The response is a `bookings` array; there is no
        separate pagination object—use narrower date windows for large exports.
      operationId: listBookings
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BookingListRequest'
      responses:
        '200':
          description: Successful response with booking list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BookingListResponse'
        '400':
          description: Bad request - invalid search parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /hotels/v1/bookingdetail:
    servers:
      - url: https://api.bundleport.com/connect
      - url: https://test-api.bundleport.com/connect
    post:
      tags:
        - Hotels - Booking Management
      summary: Get booking details
      description: |
        Retrieves a booking by Bundleport `bookingID`.
        Response `booking` matches proto `BookingDetail`: `status`, `reference`,
        `billingProviderCode`, `price`, `remarks`, and `rooms` (with per-room
        `confirmationReference`). It does **not** include hotel name/code, holder,
        or check-in/out — those belong to search/quote/book request flows.
      operationId: getBookingDetail
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BookingDetailRequest'
      responses:
        '200':
          description: Successful response with booking details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BookingDetailResponse'
        '400':
          description: Bad request - invalid booking ID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /hotels/v1/cancel:
    servers:
      - url: https://api.bundleport.com/connect
      - url: https://test-api.bundleport.com/connect
    post:
      tags:
        - Hotels - Booking
      summary: Cancel booking
      description: >-
        Cancels an existing booking by Bundleport bookingID (optional client/provider
        references when supported). Response is proto CancelResponse with cancelReference
        plus audit/errors/warnings — not a nested booking object or cancel penalties payload.
      operationId: cancelBooking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelRequest'
      responses:
        '200':
          description: Successful cancellation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelResponse'
        '400':
          description: Bad request - invalid cancellation parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Bearer token authentication
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Buyer header `ApiKey sk_test_*` or `ApiKey sk_prod_*`. Do not send `X-API-Key`.

  schemas:
    # Common schemas
    Settings:
      type: object
      description: Common settings for all requests
      required:
        - connectionCodes
      properties:
        requestId:
          type: string
          description: Unique request identifier for tracking
          example: "req-123456789"
        connectionCodes:
          type: array
          description: "List of provider connection codes to query"
          minItems: 1
          example: ["testb-conn-1876", "testb-conn-1877"]
          items:
            type: string
        auditTransactions:
          type: boolean
          description: |
            When true, responses may include `auditData.transactions` with supplier-level traces for debugging.
            Use sparingly in production; redact sensitive data in logs.
          default: false
        timeout:
          type: integer
          format: int32
          description: |
            Client timeout hint in milliseconds; platform and supplier minimums may still apply (especially for book).
            For availability it is also clamped to the server maximum (60000 by default), and the clamped value is
            the budget forwarded to the connections, so a larger figure is silently reduced rather than honoured.
            No schema-level default is declared on purpose: this object is shared by every operation and the
            effective fallback is per-operation (availability uses 10000, book is considerably higher). Omit the
            field to take the server's fallback for the operation you are calling rather than sending one that
            would cut a longer operation short.
        testMode:
          type: boolean
          description: |
            When true, enables non-production / sandbox-oriented behaviour where supported for the connection.
          default: false
        debugData:
          type: object
          additionalProperties: true
          description: Additional debug data

    Pos:
      type: object
      description: Point of sale information
      properties:
        pointOfSale:
          type: string
          description: Point of sale identifier
        businessUnit:
          type: string
          description: Business unit identifier

    AuditData:
      type: object
      description: |
        Audit metadata (`AuditData` proto). Real wire uses `requestId` + `transactions[]`
        (see G2 E2E captures). There is no `processTime` field on this message.
      properties:
        requestId:
          type: string
          description: Request correlation id
        transactions:
          type: array
          items:
            $ref: '#/components/schemas/AuditTransaction'
          description: |
            Provider transaction audit records when `settings.auditTransactions` is true.

    AuditTransaction:
      type: object
      description: |
        One provider HTTP exchange (`Transactions` proto). Populated when
        `settings.auditTransactions` is true.
      properties:
        id:
          type: string
          description: Transaction id
        connectionCode:
          type: string
          description: Connection code that produced this exchange
        request:
          type: string
          description: Outbound request body (as sent to the provider)
        response:
          type: string
          description: Inbound response body (as received from the provider)
        duration:
          type: integer
          format: int32
          description: Round-trip duration in milliseconds
        httpUrl:
          type: string
          description: Provider URL that was called
        httpStatusCode:
          type: integer
          format: int32
          description: HTTP status code (`0` when transport failed before a status)
        httpResponseHeaders:
          type: object
          additionalProperties:
            type: string
          description: Selected response headers from the provider call

    Error:
      type: object
      description: Error information
      properties:
        code:
          type: string
          enum:
            - ERR_CODE_NONE
            - ERR_CODE_UNKNOWN
            - ERR_CODE_CONNECTION_DATA_MISSING
            - ERR_CODE_BAD_RESPONSE
            - ERR_CODE_BAD_REQUEST
            - ERR_CODE_MISSING_FIELDS
            - ERR_CODE_CONFIGURATION
          description: >
            Error code identifier. Transient provider-side failures (integration
            unreachable, HTTP 502/503/504, connection error or open circuit
            breaker) are reported as ERR_CODE_BAD_RESPONSE.
          example: "ERR_CODE_CONNECTION_DATA_MISSING"
        type:
          type: string
          enum:
            - ERR_TYPE_NONE
            - ERR_TYPE_UNKNOWN
            - ERR_TYPE_CLIENT
            - ERR_TYPE_PROVIDER
            - ERR_TYPE_SERVICE
          description: >
            Error type category. Provider-side failures (including transient
            outages) are reported as ERR_TYPE_PROVIDER.
          example: "ERR_TYPE_PROVIDER"
        description:
          type: string
          description: Human-readable error description
        connectionCode:
          type: string
          description: Connection code associated with the error (if applicable)
          example: "testb-conn-1876"
        additionalData:
          type: object
          additionalProperties:
            type: string
          description: |
            Optional string map. When the aggregator recognizes the provider
            message, it may set `retryable` and `recommended_action`
            (`restart_availability`, `requote_new_price`,
            `verify_booking_then_restart`, `backoff_and_retry`, `fix_request`).

    Warning:
      type: object
      description: |
        Warning information. Warnings are non-fatal issues that don't prevent the operation 
        from completing but may indicate configuration issues or sub-optimal results.
        
        Common warnings:
        - INFO_NO_MARKUP_CONFIGURED: Connection has no margin configured; selling price uses provider gross/suggested
        - STAY_DATE_NORMALIZED: Search checkIn/checkOut was not UTC midnight; time-of-day was ignored.
          `additionalData.received` is what the buyer sent; `used` is the civil date searched.
          Severity is INFO. HTTP status remains 200.
      properties:
        code:
          type: string
          description: Warning code identifier
          example: "WARN_CODE_NONE"
        description:
          type: string
          description: Human-readable warning description
          example: "No markup configured for connection; selling price uses provider gross/suggested"
        connectionCode:
          type: string
          description: Connection code associated with the warning
          example: "testb-conn-1876"
        additionalData:
          type: object
          additionalProperties:
            type: string
          description: |
            Additional data providing context about the warning.
            For INFO_NO_MARKUP_CONFIGURED warnings, includes:
            - warning_type: "INFO_NO_MARKUP_CONFIGURED"
            - connection_code: The affected connection code
            For STAY_DATE_NORMALIZED warnings, includes:
            - warning_type: "STAY_DATE_NORMALIZED"
            - severity: "INFO"
            - field: "checkIn" or "checkOut"
            - received: original timestamp string
            - used: civil date actually searched (YYYY-MM-DD)
          example:
            warning_type: "INFO_NO_MARKUP_CONFIGURED"
            connection_code: "testb-conn-1876"

    ErrorResponse:
      type: object
      description: Error response wrapper
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
          description: Array of error details

    # Availability schemas
    SearchRequest:
      type: object
      description: Request payload for availability search
      required:
        - criteria
        - settings
      properties:
        criteria:
          $ref: '#/components/schemas/SearchCriteria'
        settings:
          $ref: '#/components/schemas/Settings'

    SearchCriteria:
      type: object
      description: Search criteria for availability
      required:
        - checkIn
        - checkOut
        - occupancies
      properties:
        checkIn:
          type: string
          format: date-time
          description: |
            Check-in civil date encoded as UTC midnight: `YYYY-MM-DDT00:00:00Z`.
            Only the date prefix is honoured; time-of-day and offsets are ignored
            (`2026-06-01T00:00:00+02:00` searches 1 June, not 31 May). Do not send
            `Date.toISOString()` of a local-midnight Date outside UTC — that yields
            the previous UTC day (e.g. `2026-05-31T22:00:00.000Z` for 1 June in
            Europe) and cannot be recovered. Missing, empty, or unusable dates
            (including strings protojson cannot parse as Timestamp) return HTTP 200
            with `errors[]` (`ERR_CODE_BAD_REQUEST`, `ERR_TYPE_CLIENT`), not 400/5XX.
            Check-in **more than one day** before today's UTC civil date, or checkOut
            not after checkIn, is the same client error and is **not forwarded** to
            providers. Today's and yesterday's UTC dates are always forwarded:
            yesterday's date is still today for a hotel west of UTC, and whether a
            stay is still bookable is the hotel's answer, not a calendar the
            aggregator can evaluate.
            When a time-of-day is stripped on an otherwise valid stay, the response
            includes a `STAY_DATE_NORMALIZED` warning with `received` and `used`.
          example: "2024-12-16T00:00:00Z"
        checkOut:
          type: string
          format: date-time
          description: |
            Check-out civil date encoded as UTC midnight: `YYYY-MM-DDT00:00:00Z`.
            Same contract as `checkIn`: only the date prefix is honoured.
          example: "2024-12-18T00:00:00Z"
        hotels:
          type: array
          items:
            type: string
          description: |
            List of hotel codes to search. There is no `destination` field on availability criteria —
            resolve a destination via Content API (`places` / `hotels/filter`) and pass the resulting codes here.
          example: ["123", "456"]
        occupancies:
          type: array
          items:
            $ref: '#/components/schemas/Occupancy'
          description: Room occupancies
          minItems: 1
        language:
          type: string
          description: Response language code (ISO 639-1)
          example: "en"
        currency:
          type: string
          description: Currency code (ISO 4217)
          example: "USD"
        nationality:
          type: string
          description: Guest nationality code
          example: "US"
        businessRules:
          $ref: '#/components/schemas/BusinessRules'
        exclusions:
          type: array
          items:
            $ref: '#/components/schemas/Exclusion'
          description: Exclusion filters
        additionalParams:
          type: object
          additionalProperties:
            type: string
          description: |
            Additional parameters passed to the search.
            
            Supported parameters:
            - `skipMarkup`: When set to "true", skip margin calculation and return suggested price equal to net price. 
              Useful for testing or when markup is handled externally. If no markup is configured for a connection 
              and skipMarkup is false, a warning will be emitted in the response.
            - `skipHotelCodesMapping`: When set to "true", hotel codes are sent directly to providers without mapping.
          example:
            skipMarkup: "true"
            skipHotelCodesMapping: "true"
        resultFilters:
          $ref: '#/components/schemas/SearchResultFilters'

    SearchResultFilters:
      type: object
      description: |
        Optional post-processing filters applied **after** suppliers respond, before the
        response is returned to the client. They reduce response size and remove options
        that do not match your selection criteria. All fields are optional; omitting
        `resultFilters` (or sending an empty object) is a no-op.

        Filters are stackable: when several are set they are evaluated in a single pass
        as a logical AND (`refundable` AND `boardCodes` AND `cheapestOnly`).
      properties:
        cheapestOnly:
          type: boolean
          description: |
            When `true`, keep at most **one option per `(connectionCode, hotelCode)` group** —
            the cheapest one according to `cheapestStrategy`. Use this to reduce payload size
            on broad searches where the UI only needs one rate per hotel.
          example: true
        refundableFilter:
          $ref: '#/components/schemas/RefundableFilter'
        boardCodes:
          type: array
          items:
            type: string
          description: |
            Whitelist of board codes (e.g. `BB`, `HB`, `RO`, `AI`). Comparison is
            case-insensitive (`bb` matches `BB`) against `boardCode`, falling back to
            `providerBoardCode` when the mapped code is empty. Empty array, `null`, or
            only-blank entries are treated as **no filter**. Up to 100 distinct codes are
            honored; extra entries are ignored defensively.
          example: ["BB", "HB"]
        cheapestStrategy:
          $ref: '#/components/schemas/CheapestStrategy'

    RefundableFilter:
      type: string
      description: |
        Tri-state filter on the cancellation policy of each option.
        - `REFUNDABLE_FILTER_UNSPECIFIED` (or omitted) — no filter.
        - `REFUNDABLE_FILTER_ONLY_REFUNDABLE` — keep only options whose `cancelPolicy.refundable` is true.
        - `REFUNDABLE_FILTER_ONLY_NON_REFUNDABLE` — keep only options whose `cancelPolicy.refundable` is false (or missing).
      enum:
        - REFUNDABLE_FILTER_UNSPECIFIED
        - REFUNDABLE_FILTER_ONLY_REFUNDABLE
        - REFUNDABLE_FILTER_ONLY_NON_REFUNDABLE

    CheapestStrategy:
      type: string
      description: |
        Selects which price field is used to compare options when `cheapestOnly` is true.
        - `CHEAPEST_STRATEGY_UNSPECIFIED` — same as `CHEAPEST_STRATEGY_SUGGESTED` (default).
        - `CHEAPEST_STRATEGY_SUGGESTED` — compare by `price.suggested` (price after markup).
          Recommended for B2C displays where the customer-facing price drives the choice.
        - `CHEAPEST_STRATEGY_NET` — compare by `price.net` (supplier net price). Useful when
          markup configurations vary across hotels and you want the lowest supplier cost.
        When the requested `currency` is set, options matching it are preferred over options
        in a different currency, regardless of nominal price. Currency comparison is
        case-insensitive (`eur` and `EUR` are equivalent).
      enum:
        - CHEAPEST_STRATEGY_UNSPECIFIED
        - CHEAPEST_STRATEGY_SUGGESTED
        - CHEAPEST_STRATEGY_NET

    Occupancy:
      type: object
      description: Room occupancy for search (ages only — names belong on book)
      properties:
        paxes:
          type: array
          items:
            $ref: '#/components/schemas/OccupancyPax'
          description: Guests in the room (age only on search)

    OccupancyPax:
      type: object
      description: Search occupancy guest — proto PaxInput has age only
      required:
        - age
      properties:
        age:
          type: integer
          format: int32
          description: Guest age

    Pax:
      type: object
      description: |
        Guest on the **book request** (`rooms[].paxes`). Search occupancies use `OccupancyPax` (age only).
      properties:
        age:
          type: integer
          format: int32
          description: Guest age
        name:
          type: string
          description: Guest name
        surname:
          type: string
          description: Guest surname
        title:
          type: string
          description: Optional title (MR, MRS, MS, etc.) for the guest

    BusinessRules:
      type: object
      description: Business rules for search
      properties:
        businessRulesType:
          type: string
          description: Type of business rule
          example: "CHEAPER_AMOUNT"
        optionsQuota:
          type: integer
          format: int32
          description: Maximum number of options to return
          example: 5

    Exclusion:
      type: object
      description: Exclusion filter
      properties:
        type:
          type: string
          description: Exclusion type
          example: "connectionCode"
        key:
          type: string
          description: Exclusion key
        values:
          type: array
          items:
            type: string
          description: Exclusion values

    SearchResponse:
      type: object
      description: Response containing availability search results
      properties:
        auditData:
          $ref: '#/components/schemas/AuditData'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/Warning'
        debugData:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Debug type/value pairs when enabled
        options:
          type: array
          items:
            $ref: '#/components/schemas/Option'
          description: Available hotel options
        search_id:
          type: string
          description: |
            Funnel tracking ID for this search. Pass this value in `criteria.search_id` to prebooking
            and in `input.search_id` to booking to link the Search → Quote → Book flow in analytics.
            
            **Note:** In JSON responses, this field appears as `searchId` (camelCase) due to 
            Protobuf JSON mapping. See "JSON Field Naming Convention" in the API description.
          example: "550e8400-e29b-41d4-a716-446655440000"

    Option:
      type: object
      description: |
        Available hotel option (`OptionSearch` proto). Wire JSON uses `id` (not `optionRefId`).
        Pass `id` as quote `criteria.optionRefId` (or book `input.optionRefId` when skipping quote).
      properties:
        id:
          type: string
          description: |
            Unique option id from search. Use as quote `criteria.optionRefId`. After a successful
            quote, prefer book with `optionQuote.optionRefId` (may differ from search `id`).
        connectionCode:
          type: string
          description: Connection that returned this option
        hotelCode:
          type: string
          description: Hotel code
        hotelName:
          type: string
          description: Hotel name
        boardCode:
          type: string
          description: Mapped board code
        boardName:
          type: string
          description: Board display name
        providerBoardCode:
          type: string
          description: Provider-native board code
        providerHotelCode:
          type: string
          description: Provider-native hotel code
        rateRules:
          type: array
          items:
            $ref: '#/components/schemas/RateRule'
          description: Rate rules when provided by the supplier (`OptionSearch.rateRules`)
        price:
          $ref: '#/components/schemas/Price'
        rooms:
          type: array
          items:
            $ref: '#/components/schemas/RoomOption'
          description: Room options
        cancelPolicy:
          $ref: '#/components/schemas/CancelPolicy'
        remarks:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Additional remarks
        surcharges:
          type: array
          items:
            $ref: '#/components/schemas/Surcharge'
          description: |
            Per-option tax and fee breakdown (search). When the integration provides breakdown,
            each line includes amount, currency, whether it is included in the displayed total, and a stable `code`.
            See public documentation for controlled vocabulary.
        paymentType:
          type: string
          description: Payment type when provided by the supplier
        fromCache:
          type: boolean
          description: Whether the option was served from cache

    RateRule:
      type: object
      description: Rate rule on a search option (`RateRule` proto)
      properties:
        type:
          type: string
          description: RateRulesType enum name (e.g. RATE_RULES_PACKAGE)
        description:
          type: string
          description: Human-readable rule description

    SurchargeCategory:
      type: string
      description: High-level grouping for a surcharge line
      enum:
        - SURCHARGE_CATEGORY_UNSPECIFIED
        - TAX
        - FEE
        - DEPOSIT
        - OTHER

    Price:
      type: object
      description: >-
        Price information. Three independent prices coexist: provider cost
        (`net`), provider retail (`gross`/`suggested`), and the org selling price
        (`markupGross`). The org margin configured per connection is applied on
        top of the provider gross, never on net. When no margin is configured,
        `markupGross` equals the provider gross.
      properties:
        net:
          type: number
          format: float
          description: Provider cost (what the agency pays the supplier).
        currency:
          type: string
          description: Currency code
        binding:
          type: boolean
          description: >-
            Provider binding flag. When true the provider gross/suggested is the
            minimum selling price and must be respected (cannot be sold below it).
        suggested:
          type: number
          format: float
          description: Provider suggested retail / minimum selling price (preserved from provider, not overwritten by markup).
        gross:
          type: number
          format: float
          description: Provider retail price before any org markup (falls back to net when the provider does not send a suggested price).
        markupGross:
          type: number
          format: float
          description: Customer selling price = provider gross + org margin. Equals the provider gross when no margin is configured.
        markupNet:
          type: number
          format: float
          description: Provider net cost plus the org margin amount (mandatory field).
        markupCurrency:
          type: string
          description: Currency of the markup (usually same as currency)
        markupBinding:
          type: boolean
          description: Indicates if the markup price must be respected (mandatory field).
        marginAmount:
          type: number
          format: float
          description: Org margin amount applied on provider gross (markupGross - gross).
        marginPercent:
          type: number
          format: float
          description: Effective margin percentage applied on provider gross.
        marginType:
          type: string
          description: Type of margin applied - FIXED or PERCENTAGE

    RoomOption:
      type: object
      description: |
        Room on a search option (`Room` proto). Cancel policy lives on the option, not the room.
      properties:
        occupancyRefId:
          type: integer
          format: int32
          description: Occupancy index matching search criteria
        code:
          type: string
          description: Mapped / type room code (may be coarse taxonomy)
        description:
          type: string
          description: Room description
        providerCode:
          type: string
          description: Provider-native room id
        roomPrice:
          $ref: '#/components/schemas/Price'
          description: Per-room price (JSON field `roomPrice`, not `price`)
        ratePlan:
          type: object
          description: Rate plan when provided
          properties:
            code:
              type: string
            name:
              type: string
            providerCode:
              type: string
        promotions:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
              name:
                type: string
              amount:
                type: string

    CancelPolicy:
      type: object
      description: Cancellation policy
      properties:
        refundable:
          type: boolean
          description: Whether the booking is refundable
        cancelPenalties:
          type: array
          items:
            $ref: '#/components/schemas/CancelPenalty'
          description: Cancellation penalties

    CancelPenalty:
      type: object
      description: Cancellation penalty (`CancelPenalty` proto)
      properties:
        currency:
          type: string
          description: Currency code
        deadline:
          type: string
          format: date-time
          description: Cancellation deadline
        hoursBefore:
          type: integer
          format: int32
          description: Hours before check-in
        penaltyType:
          type: string
          description: |
            Penalty calculation type from wire (`IMPORT` / `NIGHTS` / `PERCENT`).
            Present on real search/quote cancelPenalties (e.g. G2 E2E captures).
          enum:
            - IMPORT
            - NIGHTS
            - PERCENT
        value:
          type: number
          format: float
          description: Penalty amount

    Remark:
      type: object
      description: Remark or note
      properties:
        type:
          type: string
          description: Remark type
        value:
          type: string
          description: Remark value

    # Prebooking schemas
    QuoteRequest:
      type: object
      description: Request payload for prebooking quote
      required:
        - criteria
        - settings
      properties:
        criteria:
          $ref: '#/components/schemas/QuoteCriteria'
        settings:
          $ref: '#/components/schemas/Settings'

    QuoteCriteria:
      type: object
      description: Quote criteria (`CriteriaQuoteInput` proto)
      required:
        - optionRefId
      properties:
        optionRefId:
          type: string
          description: |
            Pass search `options[].id` here. After quote, book with `optionQuote.optionRefId`.
        language:
          type: string
          description: Response language code (ISO 639-1)
          example: "en"
        additionalData:
          type: object
          additionalProperties:
            type: string
          description: |
            Optional string map forwarded to the integration. Aggregator also reads
            `paymentMode` (`MERCHANT` / `DIRECT_ONLY`) for VCC policy and `skipMarkup`.
          example:
            paymentMode: "MERCHANT"
        search_id:
          type: string
          description: |
            **Analytics only (not a booking token).** Funnel search ID from availability
            (`searchId` in JSON). Do **not** pass this value as `optionRefId`.
            
            **How it works:**
            - Pass the `search_id` returned from `/hotels/v1/availability` to link this quote to the original search.
            - Enables funnel analysis: tracks conversion from Search → Quote.
            - If not provided, the system will attempt to link using:
              1. Request context (if same request flow)
              2. Correlation ID (as fallback for cross-request linking)
            - The source of the ID is tracked in analytics (`search_id_source`: "request", "context", "correlation_id").
            
            **Benefits:**
            - Accurate funnel conversion metrics
            - Better analytics and reporting
            - Ability to track user journey across operations
            
            **Example:** `"search_id": "550e8400-e29b-41d4-a716-446655440000"`

    QuoteResponse:
      type: object
      description: Response containing quote details
      properties:
        auditData:
          $ref: '#/components/schemas/AuditData'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/Warning'
        debugData:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Debug type/value pairs when enabled
        optionQuote:
          $ref: '#/components/schemas/OptionQuote'
        quote_id:
          type: string
          description: |
            Funnel tracking ID for this quote. Pass this value in `input.quote_id` to booking
            to link the Search → Quote → Book flow in analytics.
            
            **Note:** In JSON responses, this field appears as `quoteId` (camelCase) due to 
            Protobuf JSON mapping. See "JSON Field Naming Convention" in the API description.
          example: "550e8400-e29b-41d4-a716-446655440001"

    OptionQuote:
      type: object
      description: |
        Quote/prebooking option (`OptionQuote` proto). No hotel or rooms — keep those from search.
      properties:
        optionRefId:
          type: string
          description: Option reference ID to pass to book (may differ from search `id`)
        status:
          type: string
          enum: [STATUS_TYPE_OK, STATUS_TYPE_RQ]
          default: STATUS_TYPE_OK
          description: |
            Quote availability status (`StatusType` proto). REST and MCP JSON use
            `STATUS_TYPE_OK` (immediately bookable) or `STATUS_TYPE_RQ` (on request).
            Do not expect short aliases `OK` / `RQ`.
        price:
          $ref: '#/components/schemas/Price'
        acceptVCard:
          type: boolean
          description: |
            When true, the rate expects a Virtual Credit Card (`paymentCard`) at book.
            Used with quote `criteria.additionalData.paymentMode` (`DIRECT_ONLY` rejects these rates).
        surcharges:
          type: array
          items:
            $ref: '#/components/schemas/Surcharge'
          description: Additional surcharges
        cancelPolicy:
          $ref: '#/components/schemas/CancelPolicy'
        remarks:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Additional remarks

    Surcharge:
      type: object
      description: Surcharge / tax / fee line (canonical breakdown)
      properties:
        type:
          type: string
          description: Legacy provider-specific label (may duplicate code); prefer `code` and `category` for new clients
        description:
          type: string
          description: Human-readable description from the provider
        mandatory:
          type: boolean
          description: Whether the surcharge is mandatory
        included:
          type: boolean
          description: When true, the amount is already included in the option total; when false, typically due at property
        category:
          $ref: '#/components/schemas/SurchargeCategory'
        code:
          type: string
          description: Stable semantic code (e.g. property_fee, mandatory_tax). See surcharge vocabulary in docs.
          example: property_fee
        price:
          $ref: '#/components/schemas/Price'

    # Booking schemas
    BookRequest:
      type: object
      description: Request payload for booking creation
      required:
        - input
        - settings
      properties:
        input:
          $ref: '#/components/schemas/BookInput'
        settings:
          $ref: '#/components/schemas/Settings'

    BookInput:
      type: object
      description: Booking input details
      required:
        - optionRefId
        - rooms
        - holder
      properties:
        optionRefId:
          type: string
          description: |
            Prefer `optionQuote.optionRefId` after prebooking. When skipping quote
            (no `RECHECK` remark on that connection), pass the search option `id`.
        language:
          type: string
          description: Response language code (ISO 639-1)
          example: "en"
        rooms:
          type: array
          items:
            $ref: '#/components/schemas/BookRoom'
          description: Room booking details
          minItems: 1
        holder:
          $ref: '#/components/schemas/Holder'
        additionalData:
          type: object
          additionalProperties:
            type: string
          description: |
            Optional string map. Aggregator currently reads `skipMarkup` (`"true"` / `"1"`) for margin.
            `paymentMode` is enforced at quote/prebooking, not at book — forwarding it does not change book policy.
          example:
            skipMarkup: "false"
        remarks:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: |
            Booking remarks. Must be an array of Remark objects (not a string).
            
            **Example:**
            ```json
            "remarks": [
              {"type": "GENERAL", "value": "Late check-in requested"}
            ]
            ```
            
            **Common Error:** Sending a string like `"remarks": "-"` will cause a proto parsing error.
            Omit the field entirely or send an empty array `"remarks": []` if no remarks are needed.
        priceDelta:
          type: number
          format: float
          description: |
            **Price Tolerance**: Maximum allowed price increase (as percentage) between the quote
            (prebooking) and the final booking price. **Buyer decision — no platform default.**

            **How it works:**
            - When a booking is submitted, the system re-validates the price with the provider.
            - If the current price exceeds the quoted price by more than `priceDelta` percent,
              the booking is rejected.
            - For providers that support an upstream tolerance tag, the value is forwarded
              as-is (percentage units). For all providers it also drives the Bundleport
              price validation.

            **If omitted (or `0`):**
            - Strict matching: any increase of one cent rejects the booking.
            - Some connections receive an explicit zero tolerance tag on the wire (not a
              platform default of 2).

            **Example:**
            - Quote price: 100.00 EUR
            - `priceDelta`: 2.0 (2%)
            - Booking allowed if current price <= 102.00 EUR
            - Booking rejected if current price > 102.00 EUR

            **Buyer guidance:**
            - Send an explicit value when you accept a limited increase (e.g. `2`). The cost
              of any accepted increase is borne by the buyer, not by the provider.
            - Send `0` or omit the field for maximum price control (more confirmation /
              price-change errors expected).
            - Capped at 999.99 for safety.
        clientReference:
          type: string
          description: Client booking reference
        paymentCard:
          $ref: '#/components/schemas/PaymentCard'
        search_id:
          type: string
          description: |
            **Funnel Tracking (Optional)**: Search ID from original availability search operation.
            
            **How it works:**
            - Pass the `search_id` from the original `/hotels/v1/availability` request.
            - Links this booking to the original search for complete funnel tracking.
            - If not provided, the system will attempt to link using:
              1. Request context (if same request flow)
              2. Correlation ID (as fallback for cross-request linking)
            - The source of the ID is tracked in analytics (`search_id_source`: "request", "context", "correlation_id").
            
            **Example:** `"search_id": "550e8400-e29b-41d4-a716-446655440000"`
        quote_id:
          type: string
          description: |
            **Funnel Tracking (Optional)**: Quote ID from prebooking quote operation.
            
            **How it works:**
            - Pass the `quote_id` from the `/hotels/v1/prebooking` request (if available).
            - Links this booking to the prebooking quote for funnel tracking.
            - If not provided, the system will attempt to link using:
              1. Request context (if same request flow)
              2. Correlation ID (as fallback for cross-request linking)
            - The source of the ID is tracked in analytics (`quote_id_source`: "request", "context", "correlation_id").
            - Note: Direct bookings without a quote may not have a quote_id.
            
            **Example:** `"quote_id": "660e8400-e29b-41d4-a716-446655440001"`
            
            **Funnel Flow:**
            ```
            Search (generates search_id)
              ↓
            Quote (receives search_id, generates quote_id)
              ↓
            Book (receives search_id + quote_id)
            ```

    BookRoom:
      type: object
      description: |
        Room payload for the **book request** only (occupancy + guests).
        Book/detail/list **responses** use `BookingDetailRoom` instead.
      properties:
        occupancyRefId:
          type: integer
          format: int32
          description: Reference to occupancy from search
        paxes:
          type: array
          items:
            $ref: '#/components/schemas/Pax'
          description: Guest details for the room

    Holder:
      type: object
      description: Booking holder information
      properties:
        name:
          type: string
          description: Holder name
        surname:
          type: string
          description: Holder surname
        title:
          type: string
          description: Title (MR, MRS, MS, etc.)
        contactInfo:
          $ref: '#/components/schemas/ContactInfo'
          description: Optional contact details (email, phone) for the holder; used by some providers

    PaymentCard:
      type: object
      description: Payment card information
      properties:
        type:
          type: string
          description: Card type (VI, MC, etc.)
        number:
          type: string
          description: Card number
        CVC:
          type: string
          description: Card verification code
        expire:
          $ref: '#/components/schemas/CardExpire'
        holder:
          $ref: '#/components/schemas/CardHolder'
        isVCC:
          type: boolean
          description: Whether it's a virtual credit card
        virtualCreditCard:
          $ref: '#/components/schemas/VirtualCreditCard'
        threeDomainSecurity:
          $ref: '#/components/schemas/ThreeDomainSecurity'

    CardExpire:
      type: object
      description: Card expiration date
      properties:
        month:
          type: integer
          format: int32
          description: Expiration month (1-12)
        year:
          type: integer
          format: int32
          description: Expiration year

    CardHolder:
      type: object
      description: Card holder information
      properties:
        name:
          type: string
          description: Card holder name
        surname:
          type: string
          description: Card holder surname
        title:
          type: string
          description: Title
        contactInfo:
          $ref: '#/components/schemas/ContactInfo'

    ContactInfo:
      type: object
      description: Contact information
      properties:
        email:
          type: string
          format: email
          description: Email address
        phone:
          $ref: '#/components/schemas/Phone'

    Phone:
      type: object
      description: Phone number
      properties:
        countryCode:
          type: string
          description: Country code
        number:
          type: string
          description: Phone number

    VirtualCreditCard:
      type: object
      description: Virtual credit card details
      properties:
        activationDate:
          type: string
          format: date-time
          description: Activation date
        deactivationDate:
          type: string
          format: date-time
          description: Deactivation date
        currentBalance:
          type: number
          format: float
          description: Current balance
        currencyCode:
          type: string
          description: Currency code

    ThreeDomainSecurity:
      type: object
      description: 3D Secure authentication details
      properties:
        version:
          type: string
          description: 3DS version
        DSTransactionID:
          type: string
          description: Directory server transaction ID
        ECI:
          type: string
          description: Electronic commerce indicator
        CAVV:
          type: string
          description: Cardholder authentication verification value
        payerResponse:
          type: string
          description: Payer response
        payerResponseStatus:
          type: string
          description: Payer response status
        cardEnrolledStatus:
          type: string
          description: Card enrolled status
        merchantName:
          type: string
          description: Merchant name
        signatureStatus:
          type: string
          description: Signature status

    BookResponse:
      type: object
      description: Response containing booking confirmation
      properties:
        auditData:
          $ref: '#/components/schemas/AuditData'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/Warning'
        debugData:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Debug type/value pairs when enabled
        booking:
          $ref: '#/components/schemas/Booking'

    Booking:
      type: object
      description: |
        Confirmed or in-progress reservation as returned by book/detail/list
        (proto `BookingDetail`). Nested under `booking` in book/detail responses,
        or under `bookings[]` in list. Wire shape is status + reference + billing
        + price + remarks + rooms — not hotel/holder/stay fields.
      properties:
        status:
          type: string
          description: |
            Reservation lifecycle enum from the aggregator contract (proto
            `BookStatusType`). Use these values for UX and polling — not informal
            labels such as `CONFIRMED` / `PENDING`.
          enum:
            - BOOK_STATUS_TYPE_OK
            - BOOK_STATUS_TYPE_KO
            - BOOK_STATUS_TYPE_ON_REQUEST
            - BOOK_STATUS_TYPE_CANCELLED
            - BOOK_STATUS_TYPE_UNKNOWN
            - BOOK_STATUS_TYPE_PENDING_COMMIT
          example: BOOK_STATUS_TYPE_OK
        reference:
          $ref: '#/components/schemas/BookingReference'
        billingProviderCode:
          type: string
          description: Provider code used for billing (proto field name on aggregator)
          example: "example"
        price:
          $ref: '#/components/schemas/Price'
        remarks:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Booking remarks as `type`/`value` pairs (proto `TypeValue`)
        rooms:
          type: array
          items:
            $ref: '#/components/schemas/BookingDetailRoom'
          description: |
            Booked rooms in the **response** shape (proto `BookingDetailRoom`).
            Do not confuse with request `BookRoom` (occupancy + paxes).

    BookingReference:
      type: object
      description: Booking identifiers (proto `Reference`)
      properties:
        bookingID:
          type: string
          description: Bundleport booking identifier; store for detail, list, and cancel
        clientReference:
          type: string
          description: |
            Your own reference echoed from the book request; use for idempotency
            checks and support (e.g. list by `clientReference`).
        providerReference:
          type: string
          description: Provider/supplier booking reference
        confirmationReference:
          type: string
          description: |
            Hotel confirmation at booking level when the provider sets it.
            The aggregator forwards this field when present. Some providers still
            leave it empty and only populate `rooms[].confirmationReference` —
            prefer room-level when this is blank.

    BookingDetailRoom:
      type: object
      description: Booked room in book/detail/list responses (proto `BookingDetailRoom`)
      properties:
        occupancyRefId:
          type: integer
          format: int32
          description: Occupancy reference from the original search
        code:
          type: string
          description: Room code
        description:
          type: string
          description: Room description
        confirmationReference:
          type: string
          description: |
            Hotel confirmation reference for this room. Often the populated
            confirmation even when `reference.confirmationReference` is empty.
          example: "HBD-3650-102-18690172"

    # Cancellation schemas
    CancelRequest:
      type: object
      description: Request payload for booking cancellation
      required:
        - input
        - settings
      properties:
        input:
          $ref: '#/components/schemas/CancelInput'
        settings:
          $ref: '#/components/schemas/Settings'

    CancelInput:
      type: object
      description: Cancellation input (proto `CancelInput`)
      properties:
        bookingID:
          type: string
          description: Bundleport booking ID to cancel (preferred)
        clientReference:
          type: string
          description: Optional client reference (when allowed by the connection)
        providerReference:
          type: string
          description: Optional provider booking reference
        additionalData:
          type: object
          additionalProperties:
            type: string
          description: Optional provider-specific cancel metadata (proto map)

    CancelResponse:
      type: object
      description: |
        Cancellation result (proto `CancelResponse`). Wire shape is audit/errors/warnings
        plus `cancelReference` — not a nested `booking` or `cancel` object with penalties.
      properties:
        auditData:
          $ref: '#/components/schemas/AuditData'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/Warning'
        debugData:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Debug type/value pairs when enabled (present on real cancel captures)
        cancelReference:
          type: string
          description: Cancel reference returned by the provider when available

    # Booking management schemas
    BookingDetailRequest:
      type: object
      description: Request payload for booking detail
      required:
        - criteria
        - settings
      properties:
        criteria:
          $ref: '#/components/schemas/BookingDetailCriteria'
        settings:
          $ref: '#/components/schemas/Settings'

    BookingDetailCriteria:
      type: object
      description: Booking detail criteria
      properties:
        bookingID:
          type: string
          description: Bundleport booking ID
        clientReference:
          type: string
          description: Client booking reference
        providerReference:
          type: string
          description: Provider booking reference
        additionalParams:
          type: object
          additionalProperties:
            type: string
          description: Optional provider-specific lookup params

    BookingDetailResponse:
      type: object
      description: Response containing booking details
      properties:
        auditData:
          $ref: '#/components/schemas/AuditData'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/Warning'
        debugData:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Debug type/value pairs when enabled
        booking:
          $ref: '#/components/schemas/Booking'

    BookingListRequest:
      type: object
      description: Request payload for booking list
      required:
        - criteria
        - settings
      properties:
        criteria:
          $ref: '#/components/schemas/BookingListCriteria'
        settings:
          $ref: '#/components/schemas/Settings'

    BookingListCriteria:
      type: object
      description: |
        Set `typeSearch` to choose the mode. With `BOOKING_LIST_CRITERIA_TYPE_DATES`, send `dates`.
        With `BOOKING_LIST_CRITERIA_TYPE_REFERENCES`, send `references` (one object per lookup).
      properties:
        typeSearch:
          type: string
          enum: [BOOKING_LIST_CRITERIA_TYPE_DATES, BOOKING_LIST_CRITERIA_TYPE_REFERENCES]
          description: Search mode
        dates:
          $ref: '#/components/schemas/BookingListDates'
        references:
          type: array
          description: Reference-based lookup (booking id, client reference, supplier refs)
          items:
            $ref: '#/components/schemas/BookingListReference'

    BookingListReference:
      type: object
      description: At least one field is typically set per entry
      properties:
        bookingID:
          type: string
          description: Bundleport booking id
        clientReference:
          type: string
          description: Client-supplied reference from the book request
        providerReference:
          type: string
        confirmationReference:
          type: string

    BookingListDates:
      type: object
      description: Date range for booking list
      properties:
        dateType:
          type: string
          enum: [BOOKING_LIST_CRITERIA_DATE_TYPE_BOOKING, BOOKING_LIST_CRITERIA_DATE_TYPE_ARRIVAL]
          description: |
            `ARRIVAL` filters by stay/check-in window; `BOOKING` filters by booking creation time
        start:
          type: string
          format: date-time
          description: Start date
        end:
          type: string
          format: date-time
          description: End date

    BookingListResponse:
      type: object
      description: Response containing booking list
      properties:
        auditData:
          $ref: '#/components/schemas/AuditData'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/Warning'
        debugData:
          type: array
          items:
            $ref: '#/components/schemas/Remark'
          description: Debug type/value pairs when enabled
        bookings:
          type: array
          items:
            $ref: '#/components/schemas/Booking'
          description: List of bookings

security:
  - bearerAuth: []
  - apiKeyAuth: []
