{
  "openapi": "3.1.0",
  "info": {
    "title": "fewobird Exposé API",
    "version": "1.0.0",
    "description": "API for fetching vacation rental exposé details, live pricing, availability, and Schema.org structured metadata."
  },
  "servers": [
    {
      "url": "https://buchung.fewobird.de/",
      "description": "fewobird Production Environment"
    }
  ],
  "paths": {
    "/api/expose/{id}": {
      "get": {
        "summary": "Get Vacation Rental Exposé by ID",
        "description": "Returns comprehensive vacation rental information formatted as a Schema.org VacationRental object. If travel dates and person counts are provided, live availability and pricing offers are computed in real time. If the user decides on the property and the offer availability is 'InStock', the agent should direct the user to the offer's 'url' to select optional extra services (Zusatzleistungen) and start the checkout. A reduced Markdown representation of the exposé is also supported via content negotiation on GET /expose/{id} with header 'Accept: text/markdown'.",
        "operationId": "getExposeJson",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Unique numeric identifier of the vacation rental unit.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Arrival date formatted as YYYY-MM-DD (must be greater than today and accompanied by 'to').",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-15"
              ]
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Departure date formatted as YYYY-MM-DD (must be greater than arrival date and accompanied by 'from').",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-22"
              ]
            }
          },
          {
            "name": "persons",
            "in": "query",
            "required": false,
            "description": "Number of adult persons (must be an integer greater than 0 and within unit capacity).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 2
            }
          },
          {
            "name": "children[]",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Ages of accompanying children (each age between 0 and 17, e.g. children[]=5&children[]=10).",
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 0,
                "maximum": 17
              }
            }
          },
          {
            "name": "pets",
            "in": "query",
            "required": false,
            "description": "Number of pets accompanying the guests.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response containing Schema.org VacationRental structured data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VacationRental"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. invalid dates, capacity exceeded).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Vacation rental unit not found.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "410": {
            "description": "Vacation rental unit permanently removed or gone.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/search": {
      "get": {
        "summary": "Search Vacation Rentals",
        "description": "Search for vacation rentals matching destination query or geo data (radius search via lat/lon/distance, or bounding box search via ne/sw coordinates), travel dates, occupancy, and filter criteria. Returns Schema.org structured metadata and offers. If the user decides on a property with an offer availability of 'InStock', the agent should direct the user to the offer's 'url' to select optional extra services (Zusatzleistungen) and start the checkout.",
        "operationId": "getSearchJson",
        "parameters": [
          {
            "name": "destination",
            "in": "query",
            "required": false,
            "description": "Vacation destination query (city, region, country, or province name) resolved automatically via autocompletion.",
            "schema": {
              "type": "string",
              "examples": [
                "Ostsee",
                "Kühlungsborn",
                "Deutschland"
              ]
            }
          },
          {
            "name": "lat",
            "in": "query",
            "required": false,
            "description": "Latitude coordinate for radius search (between -90 and 90). Requires 'lon'.",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90,
              "examples": [
                54.123
              ]
            }
          },
          {
            "name": "lon",
            "in": "query",
            "required": false,
            "description": "Longitude coordinate for radius search (between -180 and 180). Requires 'lat'.",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "examples": [
                11.456
              ]
            }
          },
          {
            "name": "distance",
            "in": "query",
            "required": false,
            "description": "Search radius distance for radius search (e.g. '10km', '500m', '10mi', '100yd', '5000ft', '5nmi'). Can be omitted (default is determined by the search service). Supported units: km (kilometers), m (meters), mi (miles), yd (yards), ft (feet), nmi (nautical miles).",
            "schema": {
              "type": "string",
              "default": "10km",
              "examples": [
                "10km",
                "500m",
                "10mi"
              ]
            }
          },
          {
            "name": "ne[lat]",
            "in": "query",
            "required": false,
            "description": "North-East corner latitude for bounding box search. Requires ne[lon], sw[lat], and sw[lon].",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90,
              "examples": [
                55.0
              ]
            }
          },
          {
            "name": "ne[lon]",
            "in": "query",
            "required": false,
            "description": "North-East corner longitude for bounding box search. Requires ne[lat], sw[lat], and sw[lon].",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "examples": [
                12.0
              ]
            }
          },
          {
            "name": "sw[lat]",
            "in": "query",
            "required": false,
            "description": "South-West corner latitude for bounding box search. Requires ne[lat], ne[lon], and sw[lon].",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90,
              "examples": [
                53.0
              ]
            }
          },
          {
            "name": "sw[lon]",
            "in": "query",
            "required": false,
            "description": "South-West corner longitude for bounding box search. Requires ne[lat], ne[lon], and sw[lat].",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "examples": [
                10.0
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Arrival date formatted as YYYY-MM-DD (must be greater than today and accompanied by 'to').",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-15"
              ]
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Departure date formatted as YYYY-MM-DD (must be greater than arrival date and accompanied by 'from').",
            "schema": {
              "type": "string",
              "format": "date",
              "examples": [
                "2026-10-22"
              ]
            }
          },
          {
            "name": "persons",
            "in": "query",
            "required": true,
            "description": "Number of adult persons (must be an integer greater than 0).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 2
            }
          },
          {
            "name": "children[]",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Ages of accompanying children (each age between 0 and 17, e.g. children[]=5&children[]=10).",
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 0,
                "maximum": 17
              }
            }
          },
          {
            "name": "pets",
            "in": "query",
            "required": false,
            "description": "Number of pets accompanying the guests.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "feature[]",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Filter by feature/amenity IDs (e.g. feature[]=87 for fenced properties). Multiple feature filters are combined with AND logic. Available feature IDs and German labels can be retrieved from /api/search/filters.",
            "schema": {
              "type": "array",
              "items": {
                "type": "integer"
              },
              "examples": [
                [
                  87
                ]
              ]
            }
          },
          {
            "name": "type[]",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": true,
            "description": "Filter by accommodation type IDs (e.g. type[]=45 for caravan). Multiple type filters are combined with OR logic. Available type IDs and German labels can be retrieved from /api/search/filters.",
            "schema": {
              "type": "array",
              "items": {
                "type": "integer"
              },
              "examples": [
                [
                  45
                ]
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of search results to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful search response containing Schema.org structured data (Product aggregation summary and ItemList of matching VacationRental objects).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "Invalid search parameters.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/search/filters": {
      "get": {
        "summary": "Get Available Search Filters and Types",
        "description": "Returns dictionary of active search filter configurations, features, and accommodation types. Filter and accommodation type names are in German and must be queried by their numeric IDs using 'feature[]' (AND logic) and 'type[]' (OR logic) on /api/search.",
        "operationId": "getSearchFiltersJson",
        "responses": {
          "200": {
            "description": "Successful response with filter metadata, features, and accommodation types.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchFilters"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ProblemDetails": {
        "type": "object",
        "description": "RFC 7807 Problem Details representation.",
        "properties": {
          "type": {
            "type": "string",
            "examples": [
              "about:blank"
            ]
          },
          "title": {
            "type": "string",
            "examples": [
              "Bad Request"
            ]
          },
          "status": {
            "type": "integer",
            "examples": [
              400
            ]
          },
          "detail": {
            "type": "string",
            "examples": [
              "Reconsider your request parameters"
            ]
          },
          "violations": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "examples": [
              [
                "Departure date must be greater than arrival date."
              ]
            ]
          }
        },
        "required": [
          "title",
          "status"
        ]
      },
      "VacationRental": {
        "type": "object",
        "description": "Schema.org VacationRental representation.",
        "properties": {
          "@context": {
            "type": "string",
            "enum": [
              "https://schema.org"
            ]
          },
          "@type": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "examples": [
              "VacationRental"
            ]
          },
          "identifier": {
            "type": "string",
            "examples": [
              "12345"
            ]
          },
          "name": {
            "type": "string",
            "examples": [
              "Ferienwohnung Meerblick"
            ]
          },
          "description": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "address": {
            "type": "object",
            "properties": {
              "@type": {
                "type": "string",
                "examples": [
                  "PostalAddress"
                ]
              },
              "addressLocality": {
                "type": "string"
              },
              "postalCode": {
                "type": "string"
              },
              "streetAddress": {
                "type": "string"
              },
              "addressCountry": {
                "type": "string",
                "examples": [
                  "DE"
                ]
              }
            }
          },
          "geo": {
            "type": "object",
            "properties": {
              "@type": {
                "type": "string",
                "examples": [
                  "GeoCoordinates"
                ]
              },
              "latitude": {
                "type": "number"
              },
              "longitude": {
                "type": "number"
              }
            }
          },
          "amenityFeature": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "@type": {
                  "type": "string",
                  "examples": [
                    "LocationFeatureSpecification"
                  ]
                },
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "boolean"
                }
              }
            }
          },
          "photo": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "@type": {
                  "type": "string",
                  "examples": [
                    "ImageObject"
                  ]
                },
                "contentUrl": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "offers": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Offer"
              },
              {
                "$ref": "#/components/schemas/AggregateOffer"
              }
            ]
          }
        },
        "required": [
          "@context",
          "@type",
          "identifier"
        ]
      },
      "Offer": {
        "type": "object",
        "description": "Date-specific live price offer. If the offer availability is 'InStock' and the user decides to choose the property, the agent should direct the user to the offer's 'url'. At this URL, the user can select optional extra services (Zusatzleistungen) and start the checkout.",
        "properties": {
          "@type": {
            "type": "string",
            "examples": [
              "Offer"
            ]
          },
          "price": {
            "type": "number",
            "examples": [
              450.50
            ]
          },
          "priceCurrency": {
            "type": "string",
            "examples": [
              "EUR"
            ]
          },
          "availability": {
            "type": "string",
            "description": "Availability status of the vacation rental ('InStock' if bookable, 'OutOfStock' if unavailable).",
            "examples": [
              "InStock",
              "OutOfStock"
            ]
          },
          "availabilityStarts": {
            "type": "string",
            "format": "date",
            "examples": [
              "2026-10-15"
            ]
          },
          "availabilityEnds": {
            "type": "string",
            "format": "date",
            "examples": [
              "2026-10-22"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Direct URL to the vacation rental offer landing page. When the user decides on the property and the offer availability is 'InStock', the agent should direct the user to this URL, where they can select optional extra services (Zusatzleistungen) and initiate checkout."
          },
          "offeredBy": {
            "type": "object",
            "properties": {
              "@type": {
                "type": "string",
                "examples": [
                  "Organization"
                ]
              },
              "name": {
                "type": "string",
                "examples": [
                  "fewobird"
                ]
              }
            }
          }
        },
        "required": [
          "@type",
          "price",
          "priceCurrency",
          "availability"
        ]
      },
      "AggregateOffer": {
        "type": "object",
        "description": "Date-agnostic seasonal price summary.",
        "properties": {
          "@type": {
            "type": "string",
            "examples": [
              "AggregateOffer"
            ]
          },
          "lowPrice": {
            "type": "number",
            "examples": [
              65.00
            ]
          },
          "highPrice": {
            "type": "number",
            "examples": [
              180.00
            ]
          },
          "offerCount": {
            "type": "integer",
            "examples": [
              1240
            ]
          },
          "priceCurrency": {
            "type": "string",
            "examples": [
              "EUR"
            ]
          },
          "offers": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        },
        "required": [
          "@type",
          "priceCurrency"
        ]
      },
      "AggregateRating": {
        "type": "object",
        "description": "Schema.org AggregateRating representation.",
        "properties": {
          "@type": {
            "type": "string",
            "examples": [
              "AggregateRating"
            ]
          },
          "ratingCount": {
            "type": "integer",
            "examples": [
              450
            ]
          },
          "ratingValue": {
            "type": "number",
            "examples": [
              4.8
            ]
          },
          "bestRating": {
            "type": "integer",
            "examples": [
              5
            ]
          }
        },
        "required": [
          "@type",
          "ratingValue"
        ]
      },
      "SearchResults": {
        "type": "array",
        "description": "Search result array containing a Schema.org SearchProduct summary and a SearchItemList of matching vacation rentals.",
        "items": {
          "oneOf": [
            {
              "$ref": "#/components/schemas/SearchProduct"
            },
            {
              "$ref": "#/components/schemas/SearchItemList"
            }
          ]
        }
      },
      "SearchProduct": {
        "type": "object",
        "description": "Schema.org Product summarizing the vacation rental search results with brand, aggregate pricing, and optional ratings.",
        "properties": {
          "@context": {
            "type": "string",
            "enum": [
              "https://schema.org"
            ]
          },
          "@type": {
            "type": "string",
            "examples": [
              "Product"
            ]
          },
          "name": {
            "type": "string",
            "examples": [
              "Ferienwohnungen und Ferienhäuser in Ostsee"
            ]
          },
          "brand": {
            "type": "string",
            "examples": [
              "fewobird"
            ]
          },
          "offers": {
            "$ref": "#/components/schemas/AggregateOffer"
          },
          "aggregateRating": {
            "$ref": "#/components/schemas/AggregateRating"
          }
        },
        "required": [
          "@context",
          "@type",
          "name",
          "brand",
          "offers"
        ]
      },
      "SearchItemList": {
        "type": "object",
        "description": "Schema.org ItemList containing vacation rental search result items.",
        "properties": {
          "@context": {
            "type": "string",
            "enum": [
              "https://schema.org"
            ]
          },
          "@type": {
            "type": "string",
            "examples": [
              "ItemList"
            ]
          },
          "itemListElement": {
            "type": "array",
            "description": "List of search result items with position ranking and VacationRental data.",
            "items": {
              "$ref": "#/components/schemas/SearchListItem"
            }
          }
        },
        "required": [
          "@context",
          "@type",
          "itemListElement"
        ]
      },
      "SearchListItem": {
        "type": "object",
        "description": "Schema.org ListItem linking a search result ranking position to a VacationRental object.",
        "properties": {
          "@type": {
            "type": "string",
            "examples": [
              "ListItem"
            ]
          },
          "position": {
            "type": "integer",
            "examples": [
              1
            ]
          },
          "item": {
            "$ref": "#/components/schemas/VacationRental"
          }
        },
        "required": [
          "@type",
          "position",
          "item"
        ]
      },
      "SearchFilters": {
        "type": "object",
        "description": "Available search filter features and accommodation types.",
        "properties": {
          "features": {
            "type": "array",
            "description": "List of available feature and amenity filters.",
            "items": {
              "$ref": "#/components/schemas/SearchFilterFeature"
            }
          },
          "types": {
            "type": "array",
            "description": "List of available accommodation type filters.",
            "items": {
              "$ref": "#/components/schemas/SearchFilterType"
            }
          }
        },
        "required": [
          "features",
          "types"
        ]
      },
      "SearchFilterFeature": {
        "type": "object",
        "description": "Feature and amenity search filter item.",
        "properties": {
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ],
            "description": "Numeric feature identifier to be queried using 'feature[]'.",
            "examples": [
              87
            ]
          },
          "name": {
            "type": "string",
            "description": "German label of the feature.",
            "examples": [
              "Eingezäuntes Grundstück"
            ]
          },
          "filterType": {
            "type": "string",
            "description": "Query parameter name for this filter.",
            "examples": [
              "feature[]"
            ]
          },
          "category": {
            "type": "string",
            "description": "Category name of the feature.",
            "examples": [
              "Ausstattung"
            ]
          },
          "currentAmount": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ],
            "description": "Number of matching objects currently available, or '-' placeholder.",
            "examples": [
              142
            ]
          }
        },
        "required": [
          "id",
          "name",
          "filterType",
          "category",
          "currentAmount"
        ]
      },
      "SearchFilterType": {
        "type": "object",
        "description": "Accommodation type search filter item.",
        "properties": {
          "id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ],
            "description": "Numeric accommodation type identifier to be queried using 'type[]'.",
            "examples": [
              45
            ]
          },
          "name": {
            "type": "string",
            "description": "German label of the accommodation type.",
            "examples": [
              "Wohnwagen"
            ]
          },
          "filterType": {
            "type": "string",
            "description": "Query parameter name for this filter.",
            "examples": [
              "type[]"
            ]
          },
          "category": {
            "type": "string",
            "description": "Category name for accommodation types.",
            "examples": [
              "Unterkunftsart"
            ]
          },
          "currentAmount": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ],
            "description": "Number of matching objects currently available, or '-' placeholder.",
            "examples": [
              28
            ]
          }
        },
        "required": [
          "id",
          "name",
          "filterType",
          "category",
          "currentAmount"
        ]
      }
    }
  }
}
