OpenAPI Specification
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.