{
  "openapi": "3.1.0",
  "info": {
    "title": "Garden Apartments Janša Live Availability and Pricing API",
    "description": "Read-only live availability, booking restrictions and total pricing for the six apartments at Garden Apartments Janša in Radovljica, Slovenia. All figures are calculated by the property's Bentral system at request time. Static prices shown on the website are indicative ranges only and must not be quoted as booking prices.",
    "version": "1.2.0",
    "contact": {
      "name": "Garden Apartments Janša",
      "email": "jansa.joze@gmail.com",
      "url": "https://apartmaji-jansa.net/"
    }
  },
  "servers": [
    {
      "url": "https://apartmaji-jansa.net/api",
      "description": "Production"
    }
  ],
  "paths": {
    "/bentral.php": {
      "get": {
        "operationId": "getAvailabilityAndPricing",
        "summary": "Check live availability and total price for a stay",
        "description": "Returns per-apartment availability, booking restrictions and a full price breakdown for the requested dates and guest count. Omit all parameters to receive a self-describing usage document instead of an error.",
        "parameters": [
          {
            "name": "arrival",
            "in": "query",
            "required": true,
            "description": "Arrival date.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "example": "2026-10-15"
            }
          },
          {
            "name": "departure",
            "in": "query",
            "required": true,
            "description": "Departure date. Must be later than arrival.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "example": "2026-10-20"
            }
          },
          {
            "name": "adults",
            "in": "query",
            "required": true,
            "description": "Number of adult guests.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "example": 2
            }
          },
          {
            "name": "children",
            "in": "query",
            "required": false,
            "description": "Number of children.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "example": 0
            }
          },
          {
            "name": "apartment",
            "in": "query",
            "required": false,
            "description": "Restrict the result to one apartment. When omitted, every apartment large enough for the guest count is returned.",
            "schema": {
              "type": "string",
              "enum": [
                "lavender",
                "rose",
                "carnation",
                "sunrise",
                "sunflower",
                "strawberry"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Availability and pricing, or a usage document when no parameters were supplied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AvailabilityResponse": {
        "type": "object",
        "properties": {
          "api": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "version": { "type": "string" },
              "read_only": { "type": "boolean" },
              "live_data": { "type": "boolean" },
              "data_source": { "type": "string", "example": "Bentral" },
              "currency": { "type": "string", "example": "EUR" }
            }
          },
          "success": { "type": "boolean" },
          "requested_at": {
            "type": "string",
            "format": "date-time",
            "description": "UTC timestamp of the calculation."
          },
          "search": {
            "type": "object",
            "properties": {
              "arrival": { "type": "string", "format": "date" },
              "departure": { "type": "string", "format": "date" },
              "nights": { "type": "integer" },
              "adults": { "type": "integer" },
              "children": { "type": "integer" },
              "guests": { "type": "integer" }
            }
          },
          "apartments": {
            "type": "array",
            "description": "Present when no apartment parameter was supplied.",
            "items": { "$ref": "#/components/schemas/ApartmentResult" }
          },
          "apartment": {
            "description": "Present instead of apartments when the apartment parameter was supplied.",
            "$ref": "#/components/schemas/ApartmentResult"
          }
        }
      },
      "ApartmentResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "lavender"
          },
          "name": {
            "type": "string",
            "example": "Lavender Apartment"
          },
          "url": { "type": "string", "format": "uri" },
          "bentral_id": { "type": "string" },
          "capacity": {
            "type": "integer",
            "description": "Maximum number of guests."
          },
          "available": {
            "type": "boolean",
            "description": "True only when the stay is genuinely bookable. False when a restriction applies or no price could be calculated. Never infer availability from the website alone."
          },
          "price": {
            "description": "Null when the stay cannot be priced. Amounts are decimal strings.",
            "type": ["object", "null"],
            "properties": {
              "accommodation": {
                "type": "string",
                "description": "Base accommodation cost for the whole stay.",
                "example": "245.00"
              },
              "surcharge": {
                "type": "string",
                "description": "Length-of-stay surcharge. Falls as the stay gets longer.",
                "example": "18.00"
              },
              "tourist_tax": {
                "type": "string",
                "description": "Radovljica tourist tax for the whole stay.",
                "example": "25.00"
              },
              "total": {
                "type": ["string", "null"],
                "description": "Final total as calculated by Bentral, including surcharge and tourist tax.",
                "example": "288.00"
              },
              "currency": { "type": "string", "example": "EUR" }
            }
          },
          "restrictions": {
            "type": "array",
            "description": "Reasons the stay cannot be booked, such as a minimum-stay requirement or an arrival-day restriction. An empty array means no restriction applies.",
            "items": { "type": "string" }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "const": false },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "UNKNOWN_APARTMENT",
                  "INVALID_DATE",
                  "INVALID_DATE_RANGE",
                  "INVALID_ADULT_COUNT",
                  "INVALID_CHILD_COUNT",
                  "CAPACITY_EXCEEDED"
                ]
              },
              "message": { "type": "string" }
            }
          }
        }
      }
    }
  }
}
