{
  "openapi": "3.1.0",
  "info": {
    "title": "ABA VELA Croatian marina berth prices",
    "version": "1.0.0",
    "description": "Read-only public access to the same verified tariff engine as the marina guide. No authentication or API key. All documented query parameters are scalar; unknown parameters return 400. Without dimensions returns a discoverable catalogue. Numeric amounts retain cents; round to whole euros only for presentation. This is not a booking or binding quote service."
  },
  "servers": [
    {
      "url": "https://abavela.com"
    }
  ],
  "externalDocs": {
    "description": "Usage and interpretation",
    "url": "https://abavela.com/api/marina-berth-prices.md"
  },
  "paths": {
    "/api/marina-berth-prices.php": {
      "get": {
        "operationId": "getMarinaBerthPrices",
        "summary": "Discover marinas or compare prices for explicit boat dimensions",
        "parameters": [
          {
            "name": "v",
            "in": "query",
            "required": false,
            "description": "API major version. Defaults to 1.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ],
              "default": "1"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Sailing hull type. Model names are intentionally not accepted; supply measured dimensions.",
            "schema": {
              "type": "string",
              "enum": [
                "monohull",
                "catamaran"
              ],
              "default": "monohull"
            }
          },
          {
            "name": "loa",
            "in": "query",
            "required": false,
            "description": "Overall length in metres, including projections. Required with beam for prices; omitted together for catalogue discovery.",
            "schema": {
              "type": "number",
              "exclusiveMinimum": 0,
              "maximum": 100
            }
          },
          {
            "name": "beam",
            "in": "query",
            "required": false,
            "description": "Beam in metres; must be smaller than loa. Required with loa for prices.",
            "schema": {
              "type": "number",
              "exclusiveMinimum": 0,
              "maximum": 30
            }
          },
          {
            "name": "use",
            "in": "query",
            "required": false,
            "description": "private means client/boat owner; charter means charter company. Uses marina-specific commercial rules.",
            "schema": {
              "type": "string",
              "enum": [
                "private",
                "charter"
              ],
              "default": "private"
            }
          },
          {
            "name": "duration",
            "in": "query",
            "required": false,
            "description": "Tariff product, not a number of nights. Seasonal monthly ranges and winter-only six-month contracts retain their source terms.",
            "schema": {
              "type": "string",
              "enum": [
                "daily",
                "month",
                "six-month",
                "annual"
              ],
              "default": "daily"
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Canonical marina region. ASCII Sibenik is accepted as an alias for Šibenik.",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "Istria",
                "Kvarner",
                "Zadar",
                "Šibenik",
                "Split",
                "Dubrovnik"
              ],
              "default": "all"
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Required for daily prices: valid MM-DD on a 365-day calendar; 02-29 is not accepted. Selects a recurring tariff band; weekday variations remain a range. Rejected for other durations.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{2}-[0-9]{2}$",
              "example": "07-15"
            }
          },
          {
            "name": "marina",
            "in": "query",
            "required": false,
            "description": "Optional catalogue ID, e.g. aci-split. Unknown ID or region mismatch returns 404.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,80}$"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "price sorts priced entries by minimum amount, then name; unpriced entries last. name sorts alphabetically.",
            "schema": {
              "type": "string",
              "enum": [
                "price",
                "name"
              ],
              "default": "price"
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Catalogue without dimensions, or prices with both loa and beam. Includes sources and limitations. See https://abavela.com/api/marina-berth-prices.php?v=1&type=monohull&loa=12&beam=3.8&use=private&duration=daily&period=07-15&region=Split",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                },
                "description": "Content hash; If-None-Match can return 304."
              },
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Documentation and OpenAPI links."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Catalogue"
                    },
                    {
                      "$ref": "#/components/schemas/Prices"
                    }
                  ]
                }
              }
            }
          },
          "304": {
            "description": "ETag unchanged; no response body."
          },
          "400": {
            "description": "Invalid query or missing dimension/daily period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown marina or marina outside requested region.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed; GET, HEAD and OPTIONS only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Verified tariffs unavailable; no guessed prices returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Source": {
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "tariffYear": {
            "type": [
              "integer",
              "null"
            ]
          },
          "checkedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "pages": {
            "type": [
              "string",
              "null"
            ]
          },
          "validFrom": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "validTo": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          }
        },
        "required": [
          "url",
          "tariffYear",
          "checkedAt",
          "pages",
          "validFrom",
          "validTo"
        ],
        "additionalProperties": false
      },
      "Request": {
        "type": "object",
        "properties": {
          "type": {
            "enum": [
              "monohull",
              "catamaran"
            ]
          },
          "loa": {
            "type": [
              "number",
              "null"
            ]
          },
          "beam": {
            "type": [
              "number",
              "null"
            ]
          },
          "use": {
            "enum": [
              "private",
              "charter"
            ]
          },
          "duration": {
            "enum": [
              "daily",
              "month",
              "six-month",
              "annual"
            ]
          },
          "region": {
            "type": "string"
          },
          "period": {
            "type": [
              "string",
              "null"
            ]
          },
          "marina": {
            "type": [
              "string",
              "null"
            ]
          },
          "sort": {
            "enum": [
              "price",
              "name"
            ]
          }
        },
        "required": [
          "type",
          "loa",
          "beam",
          "use",
          "duration",
          "region",
          "period",
          "marina",
          "sort"
        ],
        "additionalProperties": false
      },
      "Price": {
        "type": "object",
        "properties": {
          "currency": {
            "const": "EUR"
          },
          "unit": {
            "enum": [
              "day",
              "month",
              "six-month contract",
              "year"
            ]
          },
          "minimum": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "maximum": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "isStartingPrice": {
            "type": "boolean"
          },
          "includesApplicableVat": {
            "const": true
          },
          "vatTreatment": {
            "enum": [
              "included",
              "not-applicable"
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "minimum": {
                  "type": "number",
                  "description": "Signed amount; discounts may be negative."
                },
                "maximum": {
                  "type": "number",
                  "description": "Signed amount; discounts may be negative."
                }
              },
              "required": [
                "label",
                "minimum",
                "maximum"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "currency",
          "unit",
          "minimum",
          "maximum",
          "isStartingPrice",
          "includesApplicableVat",
          "vatTreatment",
          "items"
        ],
        "additionalProperties": false
      },
      "Quote": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "status": {
            "enum": [
              "priced",
              "quote-required",
              "unavailable"
            ]
          },
          "price": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Price"
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "$ref": "#/components/schemas/Source"
          },
          "season": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "from": {
                    "type": "string"
                  },
                  "to": {
                    "type": "string"
                  },
                  "label": {
                    "type": "string"
                  }
                },
                "required": [
                  "from",
                  "to",
                  "label"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "billedBand": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "maxLoa": {
                    "type": "number"
                  },
                  "maxBeam": {
                    "type": [
                      "number",
                      "null"
                    ]
                  }
                },
                "required": [
                  "maxLoa",
                  "maxBeam"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "explanation": {
            "type": "string"
          },
          "priceNote": {
            "type": [
              "string",
              "null"
            ]
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unpricedExtras": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "restrictionSourceUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "required": [
          "id",
          "name",
          "region",
          "status",
          "price",
          "source",
          "season",
          "billedBand",
          "explanation",
          "priceNote",
          "notes",
          "unpricedExtras",
          "restrictionSourceUrl"
        ],
        "additionalProperties": false
      },
      "Catalogue": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "apiVersion": {
            "const": "1"
          },
          "mode": {
            "const": "catalogue"
          },
          "request": {
            "$ref": "#/components/schemas/Request"
          },
          "catalogueCount": {
            "type": "integer"
          },
          "documentationUrl": {
            "type": "string",
            "format": "uri"
          },
          "openapiUrl": {
            "type": "string",
            "format": "uri"
          },
          "limitations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "resultCount": {
            "type": "integer"
          },
          "latestSourceCheck": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "options": {
            "type": "object",
            "properties": {
              "types": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "uses": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "durations": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "regions": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "requiredForPrices": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "requiredForDailyPrices": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "types",
              "uses",
              "durations",
              "regions",
              "requiredForPrices",
              "requiredForDailyPrices"
            ],
            "additionalProperties": false
          },
          "exampleUrl": {
            "type": "string",
            "format": "uri"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "region": {
                  "type": "string"
                },
                "source": {
                  "$ref": "#/components/schemas/Source"
                }
              },
              "required": [
                "id",
                "name",
                "region",
                "source"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "ok",
          "apiVersion",
          "mode",
          "request",
          "catalogueCount",
          "documentationUrl",
          "openapiUrl",
          "limitations",
          "resultCount",
          "latestSourceCheck",
          "options",
          "exampleUrl",
          "results"
        ],
        "additionalProperties": false
      },
      "Prices": {
        "type": "object",
        "properties": {
          "ok": {
            "const": true
          },
          "apiVersion": {
            "const": "1"
          },
          "mode": {
            "const": "prices"
          },
          "request": {
            "$ref": "#/components/schemas/Request"
          },
          "catalogueCount": {
            "type": "integer"
          },
          "documentationUrl": {
            "type": "string",
            "format": "uri"
          },
          "openapiUrl": {
            "type": "string",
            "format": "uri"
          },
          "limitations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "resultCount": {
            "type": "integer"
          },
          "latestSourceCheck": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "comparisonUrl": {
            "type": "string",
            "format": "uri"
          },
          "pricedCount": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Quote"
            }
          }
        },
        "required": [
          "ok",
          "apiVersion",
          "mode",
          "request",
          "catalogueCount",
          "documentationUrl",
          "openapiUrl",
          "limitations",
          "resultCount",
          "latestSourceCheck",
          "comparisonUrl",
          "pricedCount",
          "results"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "const": false
          },
          "apiVersion": {
            "const": "1"
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "enum": [
                  "invalid-parameters",
                  "marina-not-found",
                  "method-not-allowed",
                  "tariffs-unavailable"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "ok",
          "apiVersion",
          "error"
        ],
        "additionalProperties": false
      }
    }
  },
  "security": []
}
