Holidu LOS Push API API

Length of Stay pricing push operations.

OpenAPI Specification

holidu-los-push-api-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Affiliate Apartment LOS Push API API
  version: 1.1.0
  description: Length of Stay pricing push operations.
servers:
- url: https://external-api.holidu.com
tags:
- name: LOS Push API
  description: Length of Stay pricing push operations.
paths:
  /{apartmentId}/los:
    parameters:
    - $ref: '#/components/parameters/ApartmentId'
    put:
      operationId: upsertLos
      tags:
      - LOS Push API
      summary: Create or replace LOS data for an apartment
      servers:
      - url: https://{affiliateHost}/holidu/v1/apartments
        description: Affiliate provider endpoint (base URL agreed upon during onboarding).
        variables:
          affiliateHost:
            default: api.affiliate-example.com
            description: The affiliate's API hostname.
      description: "Holidu calls this endpoint to push the complete LOS data for an apartment to the affiliate.\n\nThis is an idempotent upsert ([RFC 9110 §9.3.4](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.4)):\n- If the affiliate does not yet have LOS data for this apartment, it should store the payload and respond with `201 Created`.\n- If LOS data already exists, the affiliate should **fully replace** it with the provided payload and respond with `204 No Content`.\n\nThe request body always contains the **complete** LOS dataset for the apartment. Any check-in dates the affiliate previously stored but that are absent from this payload are no longer valid and must be removed.\n\nAn empty `los` map (`{}`) means no pricing is available for the apartment — the affiliate should remove all stored LOS data for it.\n\n## Authentication\n\nHolidu authenticates to the affiliate using an OAuth 2.0 Bearer Token ([RFC 6750](https://www.rfc-editor.org/rfc/rfc6750)).\n\n| Property | Value |\n|----------|-------|\n| **Type** | `http` |\n| **Scheme** | `bearer` |\n| **Bearer format** | `JWT` |\n\nToken exchange details are agreed upon during onboarding.\n\n## Request body examples\n\n**Multiple check-in dates with tiered pricing:**\n```json\n{\n  \"los\": {\n    \"2024-06-01\": [\n      { \"currency\": \"EUR\", \"guests\": 2, \"price\": [0, 0, 300.00, 400.00, 500.00] },\n      { \"currency\": \"EUR\", \"guests\": 4, \"price\": [0, 0, 350.00, 460.00, 580.00] }\n    ],\n    \"2024-06-02\": [\n      { \"currency\": \"EUR\", \"guests\": 2, \"price\": [0, 150.00, 280.00] }\n    ]\n  }\n}\n```\n\n**Single check-in date with one pricing tier:**\n```json\n{\n  \"los\": {\n    \"2024-06-01\": [\n      { \"currency\": \"EUR\", \"guests\": 2, \"price\": [0, 0, 300.00, 400.00, 500.00] }\n    ]\n  }\n}\n```\n\n**Empty LOS (no pricing available / fully booked):**\n```json\n{ \"los\": {} }\n```"
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LosDto'
            examples:
              multiDate:
                $ref: '#/components/examples/LosMultiDate'
              singleDate:
                $ref: '#/components/examples/LosSingleDate'
              fullyBooked:
                $ref: '#/components/examples/LosEmpty'
      responses:
        '201':
          description: LOS data created (first push for this apartment) ([RFC 9110 §15.3.2](https://www.rfc-editor.org/rfc/rfc9110#section-15.3.2)). The `Location` header contains the canonical URI of the new resource ([RFC 9110 §10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2)).
          headers:
            Location:
              $ref: '#/components/headers/Location'
        '204':
          description: LOS data replaced successfully — no response body ([RFC 9110 §15.3.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.3.5)).
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  headers:
    RetryAfter:
      description: Indicates how long Holidu should wait before retrying ([RFC 9110 §10.2.3](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.3)). Value is either a number of seconds or an HTTP-date.
      schema:
        type: string
      example: '60'
    Location:
      description: URI of the newly created resource ([RFC 9110 §10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2)).
      schema:
        type: string
        format: uri
      example: /apt-12345/los
  schemas:
    LosItemDto:
      type: object
      description: A price configuration for a specific check-in date, guest count, and currency.
      required:
      - currency
      - guests
      - price
      properties:
        currency:
          type: string
          format: iso-4217
          description: ISO 4217 currency code.
          example: EUR
        guests:
          type: integer
          description: Maximum number of guests this configuration applies to (adults + kids, babies excluded). A configuration with guests=2 applies to searches for 1 or 2 guests. Multiple entries with different guest values may exist for the same check-in date, allowing tiered pricing based on occupancy (e.g., guests=2 for base price, guests=4 for a higher rate).
          example: 2
        price:
          type: array
          description: Accumulated prices indexed by length of stay. Element at index N represents the total price for an (N+1)-night stay starting on the parent check-in date. A value of 0 means checkout is not permitted on that day (encodes minimum stay rules). Maximum 62 entries.
          maxItems: 62
          items:
            type: number
            format: decimal
          example:
          - 0
          - 0
          - 300
          - 400
          - 500
    LosDto:
      type: object
      description: The Length of Stay (LOS) represents accumulated prices per check-in date and length of stay. If the map is empty, no pricing is available for the apartment.
      required:
      - los
      properties:
        los:
          type: object
          description: The key is an ISO calendar date (YYYY-MM-DD) representing the check-in date. The value is a list of price configurations for that date. A single check-in date may have multiple entries with different guest counts, each representing a separate pricing tier.
          additionalProperties:
            type: array
            items:
              $ref: '#/components/schemas/LosItemDto'
          example:
            '2024-06-01':
            - currency: EUR
              guests: 2
              price:
              - 0
              - 0
              - 300
              - 400
              - 500
            - currency: EUR
              guests: 4
              price:
              - 0
              - 0
              - 350
              - 460
              - 580
            '2024-06-02':
            - currency: EUR
              guests: 2
              price:
              - 0
              - 150
              - 280
    ProblemDetail:
      type: object
      description: Error response following [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) Problem Details for HTTP APIs. Affiliates are encouraged to use this format for error responses to aid Holidu in debugging push failures.
      required:
      - type
      - status
      - title
      properties:
        type:
          type: string
          format: uri
          description: A URI reference that identifies the problem type ([RFC 9457 §3.1.1](https://www.rfc-editor.org/rfc/rfc9457#section-3.1.1)).
          example: https://api.affiliate-example.com/problems/validation-error
        title:
          type: string
          description: A short, human-readable summary of the problem type.
          example: Validation Error
        status:
          type: integer
          description: The HTTP status code.
          example: 400
        detail:
          type: string
          description: A human-readable explanation specific to this occurrence of the problem.
          example: Request body is not valid JSON.
        instance:
          type: string
          format: uri
          description: A URI reference that identifies the specific occurrence of the problem.
          example: /apt-12345/los
  examples:
    LosEmpty:
      summary: Empty LOS (no pricing available)
      value:
        los: {}
    LosSingleDate:
      summary: Single check-in date with one pricing tier
      value:
        los:
          '2024-06-01':
          - currency: EUR
            guests: 2
            price:
            - 0
            - 0
            - 300
            - 400
            - 500
    LosMultiDate:
      summary: Multiple check-in dates with tiered pricing
      value:
        los:
          '2024-06-01':
          - currency: EUR
            guests: 2
            price:
            - 0
            - 0
            - 300
            - 400
            - 500
          - currency: EUR
            guests: 4
            price:
            - 0
            - 0
            - 350
            - 460
            - 580
          '2024-06-02':
          - currency: EUR
            guests: 2
            price:
            - 0
            - 150
            - 280
  responses:
    PayloadTooLarge:
      description: The request body exceeds the affiliate's maximum accepted size ([RFC 9110 §15.5.14](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.14)).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://api.affiliate-example.com/problems/payload-too-large
            title: Payload Too Large
            status: 413
            detail: The LOS payload exceeds the maximum allowed size of 5 MB.
    Unauthorized:
      description: Authentication credentials are missing or invalid ([RFC 9110 §15.5.2](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.2)). The affiliate should return a `WWW-Authenticate` header indicating the expected scheme ([RFC 9110 §11.6.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.6.1)).
      headers:
        WWW-Authenticate:
          description: Authentication scheme expected by the affiliate.
          schema:
            type: string
          example: Bearer realm="affiliate-api"
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://api.affiliate-example.com/problems/unauthorized
            title: Unauthorized
            status: 401
            detail: Bearer token is expired or invalid.
    BadRequest:
      description: The request is syntactically invalid (malformed JSON, wrong types, etc.) ([RFC 9110 §15.5.1](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.1)).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://api.affiliate-example.com/problems/bad-request
            title: Bad Request
            status: 400
            detail: Request body is not valid JSON.
    NotFound:
      description: The affiliate does not recognise the apartment ID ([RFC 9110 §15.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.5)). This may indicate a mapping or onboarding issue that Holidu should investigate.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://api.affiliate-example.com/problems/not-found
            title: Not Found
            status: 404
            detail: Apartment 'apt-99999' is not known to this affiliate.
    TooManyRequests:
      description: The affiliate is rate-limiting Holidu ([RFC 6585 §4](https://www.rfc-editor.org/rfc/rfc6585#section-4)). Holidu will respect the `Retry-After` header before retrying.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://api.affiliate-example.com/problems/too-many-requests
            title: Too Many Requests
            status: 429
            detail: Rate limit exceeded. Retry after 60 seconds.
    InternalServerError:
      description: An unexpected error on the affiliate's side ([RFC 9110 §15.6.1](https://www.rfc-editor.org/rfc/rfc9110#section-15.6.1)).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://api.affiliate-example.com/problems/internal-error
            title: Internal Server Error
            status: 500
            detail: An unexpected error occurred.
  parameters:
    ApartmentId:
      name: apartmentId
      in: path
      required: true
      description: Holidu's unique identifier for the apartment. This ID is stable and assigned during onboarding.
      schema:
        type: string
      example: apt-12345
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Holidu authenticates to the affiliate using an OAuth 2.0 Bearer Token ([RFC 6750](https://www.rfc-editor.org/rfc/rfc6750)). Token exchange details are agreed upon during onboarding.