openapi: 3.1.0
info:
  title: Hermeseus Travel API
  description: >-
    REST API for flights, hotels, and activities. Authentication is session
    based: exchange credentials for a SessionId, then send it with every
    request. Prices are normalized to USD. This file is the source of truth for
    the reference under /docs.
  version: "2026-08-27"
servers:
  - url: https://api.hermeseus.com/api
    description: Production
  - url: https://demo.hermeseus.com/api
    description: Sandbox
tags:
  - name: Authentication
  - name: Flights
  - name: Hotels
  - name: Activities
  - name: Common
security:
  - SessionAuth: []

paths:
  /Authenticate/CreateSession:
    post:
      tags: [Authentication]
      summary: Create a session
      operationId: createSession
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateSessionRequest' }
      responses:
        '200':
          description: A session id, or an error.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SessionResponse' }
  /Authenticate/EndSession:
    post:
      tags: [Authentication]
      summary: End a session
      operationId: endSession
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId]
              properties:
                SessionId: { type: string }
      responses:
        '200':
          description: Result.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SuccessEnvelope' }

  /Air/AirLowFareSearch:
    post:
      tags: [Flights]
      summary: Search flights
      operationId: airLowFareSearch
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AirSearchRequest' }
      responses:
        '200':
          description: Priced itineraries.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AirSearchResponse' }
  /Air/AirLowFareSearchIncremental:
    post:
      tags: [Flights]
      summary: Stream flight search results
      operationId: airLowFareSearchIncremental
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AirSearchRequest' }
      responses:
        '200':
          description: A server-sent event stream of itinerary batches.
          content:
            text/event-stream:
              schema: { type: string }
  /Air/AirPriceCalendar:
    post:
      tags: [Flights]
      summary: Cheapest fare per day
      operationId: airPriceCalendar
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, Origin, Destination, DepartDate]
              properties:
                SessionId: { type: string }
                Origin: { type: string, pattern: '^[A-Za-z]{3}$' }
                Destination: { type: string, pattern: '^[A-Za-z]{3}$' }
                DepartDate: { type: string }
                TripType: { type: string }
                ReturnDate: { type: string }
                CalendarType: { type: string, enum: [departure_date, return_date] }
                Currency: { type: string, pattern: '^[A-Za-z]{3}$', default: USD }
      responses:
        '200':
          description: One cheapest fare per day.
          content:
            application/json:
              schema: { type: object }
  /Air/AirRevalidate:
    post:
      tags: [Flights]
      summary: Revalidate a fare
      operationId: airRevalidate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, FareSourceCode]
              properties:
                SessionId: { type: string }
                FareSourceCode: { type: string }
      responses:
        '200':
          description: The re-priced itinerary.
          content:
            application/json:
              schema: { type: object }
  /Air/AirRules:
    post:
      tags: [Flights]
      summary: Fare rules
      operationId: airRules
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId]
              properties:
                SessionId: { type: string }
                FareSourceCode: { type: string }
                UniqueId: { type: string }
      responses:
        '200':
          description: Fare rule sections.
          content:
            application/json:
              schema: { type: object }
  /Air/AirBaggages:
    post:
      tags: [Flights]
      summary: Baggage allowance
      operationId: airBaggages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, FareSourceCode]
              properties:
                SessionId: { type: string }
                FareSourceCode: { type: string }
      responses:
        '200':
          description: Baggage per segment.
          content:
            application/json:
              schema: { type: object }
  /Air/AirBook:
    post:
      tags: [Flights]
      summary: Book a flight
      operationId: airBook
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AirBookRequest' }
      responses:
        '200':
          description: The held booking.
          content:
            application/json:
              schema: { type: object }
  /Air/AirOrderTicket:
    post:
      tags: [Flights]
      summary: Issue a ticket
      operationId: airOrderTicket
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SessionAndUniqueId' }
      responses:
        '200':
          description: Ticketed.
          content:
            application/json:
              schema: { type: object }
  /Air/AirCancel:
    post:
      tags: [Flights]
      summary: Cancel a held booking
      operationId: airCancel
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SessionAndUniqueId' }
      responses:
        '200':
          description: Cancellation result.
          content:
            application/json:
              schema: { type: object }
  /Air/AirRefundDisplay:
    post:
      tags: [Flights]
      summary: Preview a refund
      operationId: airRefundDisplay
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SessionAndUniqueId' }
      responses:
        '200':
          description: Refund penalties per ticket.
          content:
            application/json:
              schema: { type: object }
  /Air/AirRefund:
    post:
      tags: [Flights]
      summary: Refund a ticket
      operationId: airRefund
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, UniqueId]
              properties:
                SessionId: { type: string }
                UniqueId: { type: string }
                RefundType: { type: integer, default: 1 }
                EticketNumbers: { type: array, items: { type: string } }
                RefundPaymentMode: { type: integer }
      responses:
        '200':
          description: Refunded tickets.
          content:
            application/json:
              schema: { type: object }
  /Air/AirBookingData:
    post:
      tags: [Flights]
      summary: Get a flight booking
      operationId: airBookingData
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BookingLookup' }
      responses:
        '200':
          description: The full booking.
          content:
            application/json:
              schema: { type: object }

  /v2/Hotel/cities/search:
    get:
      tags: [Hotels]
      summary: Search places
      operationId: hotelCitiesSearch
      security: []
      parameters:
        - { name: q, in: query, schema: { type: string, maxLength: 128 } }
        - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 } }
        - { name: type, in: query, schema: { type: string, enum: [city, district, region, country, landmark, hotel] } }
      responses:
        '200':
          description: Matching places.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/cities/lookup:
    post:
      tags: [Hotels]
      summary: Look up saved place ids
      operationId: hotelCitiesLookup
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [external_ids]
              properties:
                external_ids: { type: array, items: { type: string } }
      responses:
        '200':
          description: Resolved places.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelAvailability:
    post:
      tags: [Hotels]
      summary: Search hotels
      operationId: hotelAvailability
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/HotelAvailabilityRequest' }
      responses:
        '200':
          description: Properties or room rates.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelCheckRate:
    post:
      tags: [Hotels]
      summary: Validate a hotel rate
      operationId: hotelCheckRate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, FareSourceCode]
              properties:
                SessionId: { type: string }
                FareSourceCode: { type: string }
      responses:
        '200':
          description: The confirmed rate.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelBook:
    post:
      tags: [Hotels]
      summary: Book a hotel
      operationId: hotelBook
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/HotelBookRequest' }
      responses:
        '200':
          description: The held booking.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelOrder:
    post:
      tags: [Hotels]
      summary: Confirm a hotel booking
      operationId: hotelOrder
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SessionAndUniqueId' }
      responses:
        '200':
          description: The confirmed booking.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelCancelDisplay:
    post:
      tags: [Hotels]
      summary: Preview a hotel cancellation
      operationId: hotelCancelDisplay
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SessionAndUniqueId' }
      responses:
        '200':
          description: Cancellation terms.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelCancel:
    post:
      tags: [Hotels]
      summary: Cancel a hotel booking
      operationId: hotelCancel
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, UniqueId]
              properties:
                SessionId: { type: string }
                UniqueId: { type: string }
                CancelActor: { type: integer, default: 0 }
                RefundPaymentMode: { type: integer, default: 0 }
                HasAnyCanceledUser: { type: boolean, default: false }
      responses:
        '200':
          description: Cancellation result.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelBookingData:
    post:
      tags: [Hotels]
      summary: Get a hotel booking
      operationId: hotelBookingData
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BookingLookup' }
      responses:
        '200':
          description: The booking.
          content:
            application/json:
              schema: { type: object }
  /v2/Hotel/HotelExtendPaymentDeadline:
    post:
      tags: [Hotels]
      summary: Extend the payment deadline
      operationId: hotelExtendPaymentDeadline
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SessionAndUniqueId' }
      responses:
        '200':
          description: The new deadline.
          content:
            application/json:
              schema: { type: object }

  /Activity/v2/products:
    get:
      tags: [Activities]
      summary: List products
      operationId: activityProducts
      parameters:
        - { name: SessionId, in: query, required: true, schema: { type: string } }
        - { name: q, in: query, schema: { type: string } }
        - { name: category, in: query, schema: { type: string } }
        - { name: city, in: query, schema: { type: string } }
        - { name: min_price, in: query, schema: { type: number } }
        - { name: max_price, in: query, schema: { type: number } }
        - { name: sort, in: query, schema: { type: string, enum: [price, -price, date, -date, bestselling, sold, -sold] } }
        - { name: page, in: query, schema: { type: integer, default: 1 } }
        - { name: per_page, in: query, schema: { type: integer, default: 50 } }
      responses:
        '200':
          description: A page of products.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/products/{uuid}:
    get:
      tags: [Activities]
      summary: Get a product
      operationId: activityProduct
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
      responses:
        '200':
          description: The product.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/products/{uuid}/product-types:
    get:
      tags: [Activities]
      summary: List product variants
      operationId: activityProductTypes
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
      responses:
        '200':
          description: The variants.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/product-types/{uuid}:
    get:
      tags: [Activities]
      summary: Variant details and timeslots
      operationId: activityProductType
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
        - { name: date, in: query, schema: { type: string } }
      responses:
        '200':
          description: The variant with timeslots.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/product-types/{uuid}/price-lists:
    get:
      tags: [Activities]
      summary: Bookable dates
      operationId: activityPriceLists
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
        - { name: date_start, in: query, schema: { type: string } }
        - { name: date_end, in: query, schema: { type: string } }
      responses:
        '200':
          description: The date calendar.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/bookings:
    post:
      tags: [Activities]
      summary: Create a booking
      operationId: activityCreateBooking
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ActivityBookingRequest' }
      responses:
        '200':
          description: The reserved booking.
          content:
            application/json:
              schema: { type: object }
    get:
      tags: [Activities]
      summary: List bookings
      operationId: activityListBookings
      parameters:
        - { name: SessionId, in: query, required: true, schema: { type: string } }
        - { name: status, in: query, schema: { type: string } }
        - { name: page, in: query, schema: { type: integer } }
        - { name: per_page, in: query, schema: { type: integer } }
      responses:
        '200':
          description: A page of bookings.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/bookings/{uuid}:
    get:
      tags: [Activities]
      summary: Get a booking
      operationId: activityBooking
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
      responses:
        '200':
          description: The booking.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/bookings/{uuid}/{status}:
    put:
      tags: [Activities]
      summary: Confirm or cancel a booking
      operationId: activityUpdateBookingStatus
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: status, in: path, required: true, schema: { type: string, enum: [confirm, cancel] } }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId]
              properties:
                SessionId: { type: string }
      responses:
        '200':
          description: The updated booking.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/bookings/{uuid}/vouchers:
    get:
      tags: [Activities]
      summary: List vouchers
      operationId: activityVouchers
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
      responses:
        '200':
          description: The vouchers.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/webhook-events/{event}/{uuid}:
    get:
      tags: [Activities]
      summary: Read the latest webhook event
      operationId: activityWebhookEvent
      parameters:
        - name: event
          in: path
          required: true
          schema:
            type: string
            enum:
              - product_available
              - product_updated
              - product_type_available
              - product_type_not_available
              - product_type_content_updated
              - product_type_pricing_updated
              - product_type_availability_updated
              - booking_status_updated
              - booking_data_updated
              - booking_tickets_updated
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
        - { name: history, in: query, schema: { type: boolean } }
        - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 50, default: 20 } }
      responses:
        '200':
          description: The latest event, or the history.
          content:
            application/json:
              schema: { type: object }

  /Common/CreditBalance:
    post:
      tags: [Common]
      summary: Read the credit balance
      operationId: creditBalance
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId]
              properties:
                SessionId: { type: string }
      responses:
        '200':
          description: The balance.
          content:
            application/json:
              schema:
                type: object
                properties:
                  Success: { type: boolean }
                  Balance: { type: number }
                  Currency: { type: string }
                  Error: { $ref: '#/components/schemas/Error' }
  /Common/ErrorDetails:
    post:
      tags: [Common]
      summary: Resolve error codes
      operationId: errorDetails
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, ErrorIds]
              properties:
                SessionId: { type: string }
                ErrorIds: { type: array, items: { type: string } }
      responses:
        '200':
          description: The messages.
          content:
            application/json:
              schema: { type: object }
  /Common/SessionHistory:
    post:
      tags: [Common]
      summary: List calls in a session
      operationId: sessionHistory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId]
              properties:
                SessionId: { type: string }
                TargetSessionId: { type: string }
      responses:
        '200':
          description: The logged requests.
          content:
            application/json:
              schema: { type: object }

  /Air/AirLowFareSearch2:
    post:
      tags: [Flights]
      summary: Search flights (alternate basket)
      operationId: airLowFareSearch2
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AirSearchRequest' }
      responses:
        '200':
          description: Priced itineraries.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AirSearchResponse' }
  /Air/AirSearchData:
    post:
      tags: [Flights]
      summary: Get a past search
      operationId: airSearchData
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, SearchId]
              properties:
                SessionId: { type: string }
                SearchId: { type: integer }
      responses:
        '200':
          description: The stored search.
          content:
            application/json:
              schema: { type: object }
  /Air/AirAddBookingNotes:
    post:
      tags: [Flights]
      summary: Add notes to a booking
      operationId: airAddBookingNotes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [SessionId, UniqueId, Notes]
              properties:
                SessionId: { type: string }
                UniqueId: { type: string }
                Notes: { type: array, items: { type: string } }
      responses:
        '200':
          description: Result.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SuccessEnvelope' }
  /Geo/cities/search:
    get:
      tags: [Common]
      summary: City search
      operationId: geoCitiesSearch
      security: []
      parameters:
        - { name: q, in: query, required: true, schema: { type: string, minLength: 1, maxLength: 128 } }
        - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 50, default: 10 } }
        - { name: country, in: query, schema: { type: string, minLength: 2, maxLength: 2 } }
      responses:
        '200':
          description: Matching cities.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/products/all:
    get:
      tags: [Activities]
      summary: The whole catalogue
      operationId: activityProductsAll
      parameters:
        - { name: SessionId, in: query, required: true, schema: { type: string } }
        - { name: full, in: query, schema: { type: boolean } }
        - { name: per_page, in: query, schema: { type: integer } }
      responses:
        '200':
          description: Every product.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/products/{uuid}/restrictions:
    get:
      tags: [Activities]
      summary: Product restrictions
      operationId: activityProductRestrictions
      parameters:
        - { name: uuid, in: path, required: true, schema: { type: string } }
        - { name: SessionId, in: query, required: true, schema: { type: string } }
      responses:
        '200':
          description: Age and pax rules.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/products/by-location:
    get:
      tags: [Activities]
      summary: Countries and cities
      operationId: activityProductsByLocation
      security: []
      responses:
        '200':
          description: The location tree.
          content:
            application/json:
              schema: { type: object }
  /Activity/v2/config:
    get:
      tags: [Activities]
      summary: Activity configuration
      operationId: activityConfig
      parameters:
        - { name: SessionId, in: query, required: true, schema: { type: string } }
      responses:
        '200':
          description: Reference lists.
          content:
            application/json:
              schema: { type: object }

components:
  securitySchemes:
    SessionAuth:
      type: apiKey
      in: query
      name: SessionId
      description: >-
        The SessionId from CreateSession. Send it in the JSON body on POST and
        PUT requests, or in the query string on GET requests.
  schemas:
    Error:
      type: [object, "null"]
      properties:
        Id: { type: string, example: Err0102005 }
        Message: { type: string }
    SuccessEnvelope:
      type: object
      properties:
        Success: { type: boolean }
        Error: { $ref: '#/components/schemas/Error' }
    CreateSessionRequest:
      type: object
      required: [OfficeId, UserName, Password]
      properties:
        OfficeId: { type: string, example: OFC-4821 }
        UserName: { type: string, example: jane.doe }
        Password: { type: string }
    SessionResponse:
      type: object
      properties:
        Success: { type: boolean }
        SessionId: { type: [string, "null"] }
        Error: { $ref: '#/components/schemas/Error' }
    SessionAndUniqueId:
      type: object
      required: [SessionId, UniqueId]
      properties:
        SessionId: { type: string }
        UniqueId: { type: string }
    BookingLookup:
      type: object
      required: [SessionId]
      properties:
        SessionId: { type: string }
        UniqueId: { type: string }
        ClientUniqueId: { type: string }
      description: Send at least one of UniqueId or ClientUniqueId.
    AirSearchRequest:
      type: object
      required: [SessionId, AdultCount, ChildCount, InfantCount, PricingSourceType, RequestOption, OriginDestinationInformations]
      properties:
        SessionId: { type: string }
        AdultCount: { type: integer, minimum: 1 }
        ChildCount: { type: integer, minimum: 0 }
        InfantCount: { type: integer, minimum: 0 }
        PricingSourceType: { type: string, example: All }
        RequestOption: { type: string, example: All }
        NumberOfResults: { type: integer, minimum: 0, maximum: 5000, default: 100 }
        Provider: { type: string }
        TravelPreference:
          type: object
          properties:
            CabinType:
              type: integer
              enum: [1, 2, 3, 4, 5, 6]
              default: 1
              description: 1 Economy, 2 Premium Economy, 3 Business, 4 Premium Business, 5 First, 6 Premium First.
            MaxStopsQuantity: { type: string }
            AirTripType: { type: string }
            VendorPreferenceCodes: { type: array, items: { type: string } }
            VendorExcludeCodes: { type: array, items: { type: string } }
        OriginDestinationInformations:
          type: array
          minItems: 1
          items:
            type: object
            required: [OriginLocationCode, DestinationLocationCode, DepartureDateTime]
            properties:
              OriginLocationCode: { type: string, example: IST }
              DestinationLocationCode: { type: string, example: DXB }
              DepartureDateTime: { type: string, example: "2026-10-12T00:00:00" }
              OriginType: { type: string }
              DestinationType: { type: string }
    AirSearchResponse:
      type: object
      properties:
        Success: { type: boolean }
        SearchId: { type: integer }
        PricedItineraries: { type: array, items: { type: object } }
        Error: { $ref: '#/components/schemas/Error' }
    AirBookRequest:
      type: object
      required: [SessionId, FareSourceCode, TravelerInfo]
      properties:
        SessionId: { type: string }
        FareSourceCode: { type: string }
        ClientUniqueId: { type: string }
        MarkupForAdult: { type: number, default: 0 }
        MarkupForChild: { type: number, default: 0 }
        MarkupForInfant: { type: number, default: 0 }
        TravelerInfo:
          type: object
          required: [PhoneNumber, Email, AirTravelers]
          properties:
            PhoneNumber: { type: string }
            Email: { type: string, format: email }
            AirTravelers:
              type: array
              minItems: 1
              items:
                type: object
                required: [PassengerType, Gender, DateOfBirth, PassengerName]
                properties:
                  PassengerType: { type: integer }
                  Gender: { type: integer, enum: [0, 1], description: 0 Male, 1 Female. }
                  DateOfBirth: { type: string }
                  PassengerName:
                    type: object
                    required: [PassengerFirstName, PassengerLastName]
                    properties:
                      PassengerFirstName: { type: string }
                      PassengerLastName: { type: string }
    HotelAvailabilityRequest:
      type: object
      required: [SessionId, CheckIn, CheckOut, Occupancies]
      properties:
        SessionId: { type: string }
        CheckIn: { type: string, example: "2026-10-15" }
        CheckOut: { type: string, example: "2026-10-16" }
        CityId: { type: [integer, "null"] }
        HotelId: { type: [integer, "null"] }
        Page: { type: integer, minimum: 1, default: 1 }
        PageSize: { type: integer, minimum: 1, maximum: 200 }
        Sort: { type: string }
        Filters: { type: object }
        Map: { type: object }
        lang: { type: string }
        Occupancies:
          type: array
          minItems: 1
          items:
            type: object
            required: [AdultCount]
            properties:
              AdultCount: { type: integer, minimum: 1, maximum: 8 }
              ChildCount: { type: integer, minimum: 0, maximum: 6 }
              ChildAges: { type: array, items: { type: integer, minimum: 0, maximum: 17 } }
      description: Provide exactly one of CityId or HotelId.
    HotelBookRequest:
      type: object
      required: [SessionId, FareSourceCode, PhoneNumber, Email, Rooms, HotelTransfers]
      properties:
        SessionId: { type: string }
        FareSourceCode: { type: string }
        PhoneNumber: { type: string }
        Email: { type: string, format: email }
        Nationality: { type: string }
        ClientUniqueId: { type: string }
        Note: { type: string }
        HotelTransfers: { type: array, items: { type: object } }
        Rooms:
          type: array
          minItems: 1
          items:
            type: object
            required: [Passengers]
            properties:
              Passengers:
                type: array
                minItems: 1
                items:
                  type: object
                  required: [FirstName, LastName, PassengerType, PassengerTitle]
                  properties:
                    FirstName: { type: string }
                    LastName: { type: string }
                    PassengerType: { type: integer }
                    PassengerTitle: { type: integer }
                    NationalId: { type: string }
                    PassportNumber: { type: string }
    ActivityBookingRequest:
      type: object
      required: [SessionId, productTypeUuid, arrivalDate, adults, customer]
      properties:
        SessionId: { type: string }
        productTypeUuid: { type: string }
        arrivalDate: { type: string, example: "2026-10-15" }
        adults: { type: integer, default: 1 }
        children: { type: integer, default: 0 }
        seniors: { type: integer, default: 0 }
        timeSlot: { type: string }
        partnerReference: { type: string }
        customer:
          type: object
          required: [firstName, lastName, email, phone]
          properties:
            salutation: { type: string, default: "Mr." }
            firstName: { type: string }
            lastName: { type: string }
            email: { type: string, format: email }
            phone: { type: string }
