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.