{
  "openapi": "3.1.0",
  "info": {
    "title": "Odeva Website Public API",
    "version": "2026-04-17",
    "summary": "Public HTTP endpoints exposed by www.odeva.app.",
    "description": "This description covers the public website endpoints implemented in this repository. It does not describe the separate booking.odeva.app GraphQL product API because that schema and authentication metadata are not published in this codebase.",
    "contact": {
      "name": "Odeva",
      "url": "https://www.odeva.app/contact"
    }
  },
  "servers": [
    {
      "url": "https://www.odeva.app"
    }
  ],
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://www.odeva.app/docs/api/"
  },
  "paths": {
    "/api/tourist-tax": {
      "get": {
        "operationId": "getTouristTaxData",
        "summary": "Read tourist tax metadata or filtered rates",
        "description": "Returns either filter metadata when action=metadata is supplied, or a filtered list of tourist tax records.",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "description": "Set to metadata to return available municipalities, years, and accommodation types.",
            "schema": {
              "type": "string",
              "enum": [
                "metadata"
              ]
            }
          },
          {
            "name": "municipality",
            "in": "query",
            "description": "Exact municipality name to filter by.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "year",
            "in": "query",
            "description": "Start year matched against the source record Valid From field.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{4}$"
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Accommodation type to filter by.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Metadata or filtered tourist tax records.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TouristTaxMetadataResponse"
                    },
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TouristTaxRate"
                      }
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/waitlist": {
      "post": {
        "operationId": "submitWaitlistEntry",
        "summary": "Submit a waitlist request",
        "description": "Creates or de-duplicates a waitlist entry after validating a Cloudflare Turnstile token. Intended for human-assisted submissions, not unattended agents.",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/WaitlistSubmission"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/WaitlistSubmission"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Waitlist submission accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WaitlistSuccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation or CAPTCHA failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "TouristTaxMetadataResponse": {
        "type": "object",
        "required": [
          "municipalities",
          "years",
          "accommodationTypes"
        ],
        "properties": {
          "municipalities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "years": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[0-9]{4}$"
            }
          },
          "accommodationTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "TouristTaxRate": {
        "type": "object",
        "required": [
          "municipality",
          "year",
          "rateValue",
          "rateType",
          "sectors",
          "sectorsString",
          "url",
          "cvdrId",
          "validFrom",
          "validUntil"
        ],
        "properties": {
          "municipality": {
            "type": "string"
          },
          "year": {
            "type": "string",
            "pattern": "^[0-9]{4}$"
          },
          "rateValue": {
            "type": "string"
          },
          "rateType": {
            "type": "string"
          },
          "sectors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sectorsString": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "cvdrId": {
            "type": "string"
          },
          "validFrom": {
            "type": "string"
          },
          "validUntil": {
            "type": "string"
          }
        }
      },
      "WaitlistSubmission": {
        "type": "object",
        "required": [
          "fullName",
          "email",
          "cf-turnstile-response"
        ],
        "properties": {
          "fullName": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "company": {
            "type": "string",
            "default": ""
          },
          "message": {
            "type": "string",
            "default": ""
          },
          "cf-turnstile-response": {
            "type": "string",
            "description": "A valid Cloudflare Turnstile token."
          }
        }
      },
      "WaitlistSuccessResponse": {
        "type": "object",
        "required": [
          "success",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {}
        }
      }
    }
  }
}
