{
  "openapi": "3.1.0",
  "info": {
    "title": "MapaDanych – API portalu",
    "version": "0.1",
    "description": "Katalog danych, ujednolicone dane wszystkich dostawców, zapytania o miejsce (co jest w punkcie i okolicy, podsumowanie dla gminy) i walidator protokołu. Dokumentacja: https://mapadanych.pl/dokumentacja/api.md, instrukcja dla asystentów AI: https://mapadanych.pl/dokumentacja/asystenci-ai.md"
  },
  "servers": [
    {
      "url": "https://mapadanych.pl"
    }
  ],
  "externalDocs": {
    "url": "https://mapadanych.pl/llms.txt",
    "description": "Przewodnik po dokumentacji dla modeli językowych"
  },
  "paths": {
    "/api/catalog": {
      "get": {
        "operationId": "getCatalog",
        "summary": "Wszyscy dostawcy i zbiory danych",
        "responses": {
          "200": {
            "description": "Katalog",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/data/{provider}/{dataset}": {
      "get": {
        "operationId": "fetchData",
        "summary": "Dane zbioru jako GeoJSON (przez cache portalu)",
        "description": "Dalsze parametry query według `params` zbioru w katalogu. Dane z feature.dm są w properties z prefiksem __dm_.",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dataset",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bbox",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "16.5,49.1,16.7,49.3"
            },
            "description": "minLon,minLat,maxLon,maxLat; wymagane dla zbiorów z mode bbox"
          },
          {
            "name": "zoom",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 24
            },
            "description": "Wymagane dla zbiorów z mode bbox"
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection",
            "headers": {
              "X-DM-Cache": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "hit",
                    "mirror",
                    "miss",
                    "stale"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "const": "FeatureCollection"
                    },
                    "features": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "const": "Feature"
                          },
                          "id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "maxLength": 200
                              },
                              {
                                "type": "number"
                              }
                            ]
                          },
                          "geometry": {
                            "anyOf": [
                              {
                                "oneOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "type": {
                                        "type": "string",
                                        "const": "Point"
                                      },
                                      "coordinates": {
                                        "minItems": 2,
                                        "maxItems": 3,
                                        "type": "array",
                                        "items": {
                                          "type": "number"
                                        }
                                      }
                                    },
                                    "required": [
                                      "type",
                                      "coordinates"
                                    ]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "type": {
                                        "type": "string",
                                        "const": "MultiPoint"
                                      },
                                      "coordinates": {
                                        "type": "array",
                                        "items": {
                                          "minItems": 2,
                                          "maxItems": 3,
                                          "type": "array",
                                          "items": {
                                            "type": "number"
                                          }
                                        }
                                      }
                                    },
                                    "required": [
                                      "type",
                                      "coordinates"
                                    ]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "type": {
                                        "type": "string",
                                        "const": "LineString"
                                      },
                                      "coordinates": {
                                        "minItems": 2,
                                        "type": "array",
                                        "items": {
                                          "minItems": 2,
                                          "maxItems": 3,
                                          "type": "array",
                                          "items": {
                                            "type": "number"
                                          }
                                        }
                                      }
                                    },
                                    "required": [
                                      "type",
                                      "coordinates"
                                    ]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "type": {
                                        "type": "string",
                                        "const": "MultiLineString"
                                      },
                                      "coordinates": {
                                        "type": "array",
                                        "items": {
                                          "minItems": 2,
                                          "type": "array",
                                          "items": {
                                            "minItems": 2,
                                            "maxItems": 3,
                                            "type": "array",
                                            "items": {
                                              "type": "number"
                                            }
                                          }
                                        }
                                      }
                                    },
                                    "required": [
                                      "type",
                                      "coordinates"
                                    ]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "type": {
                                        "type": "string",
                                        "const": "Polygon"
                                      },
                                      "coordinates": {
                                        "type": "array",
                                        "items": {
                                          "minItems": 4,
                                          "type": "array",
                                          "items": {
                                            "minItems": 2,
                                            "maxItems": 3,
                                            "type": "array",
                                            "items": {
                                              "type": "number"
                                            }
                                          }
                                        }
                                      }
                                    },
                                    "required": [
                                      "type",
                                      "coordinates"
                                    ]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "type": {
                                        "type": "string",
                                        "const": "MultiPolygon"
                                      },
                                      "coordinates": {
                                        "type": "array",
                                        "items": {
                                          "type": "array",
                                          "items": {
                                            "minItems": 4,
                                            "type": "array",
                                            "items": {
                                              "minItems": 2,
                                              "maxItems": 3,
                                              "type": "array",
                                              "items": {
                                                "type": "number"
                                              }
                                            }
                                          }
                                        }
                                      }
                                    },
                                    "required": [
                                      "type",
                                      "coordinates"
                                    ]
                                  }
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "properties": {
                            "default": {},
                            "anyOf": [
                              {
                                "type": "object",
                                "propertyNames": {
                                  "type": "string"
                                },
                                "additionalProperties": {}
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "dm": {
                            "type": "object",
                            "properties": {
                              "title": {
                                "description": "Tytuł obiektu w szczegółach",
                                "type": "string",
                                "maxLength": 200
                              },
                              "description": {
                                "type": "string",
                                "maxLength": 2000
                              },
                              "url": {
                                "description": "Odnośnik do szczegółów obiektu u dostawcy",
                                "type": "string",
                                "format": "uri"
                              },
                              "color": {
                                "description": "Nadpisuje kolor z prezentacji",
                                "type": "string",
                                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                              },
                              "chart": {
                                "description": "Wykres zmian wartości w szczegółach obiektu",
                                "type": "object",
                                "properties": {
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 80,
                                    "description": "Co pokazuje wykres, np. Liczba mieszkańców"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "maxLength": 20
                                  },
                                  "decimals": {
                                    "type": "integer",
                                    "minimum": 0,
                                    "maximum": 6
                                  },
                                  "note": {
                                    "description": "Uwaga pod wykresem, np. o zmianie metodyki",
                                    "type": "string",
                                    "maxLength": 200
                                  },
                                  "highlight": {
                                    "description": "Wyróżniony okres (np. wybrany w filtrze czasu) – portal go podświetli, pokaże wartość na jego końcu, a zmianę i trend policzy od jego początku. Te same from i to = jeden wybrany okres (np. rok).",
                                    "type": "object",
                                    "properties": {
                                      "from": {
                                        "type": "string",
                                        "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                        "description": "Rok, miesiąc lub dzień w ISO 8601"
                                      },
                                      "to": {
                                        "type": "string",
                                        "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                        "description": "Rok, miesiąc lub dzień w ISO 8601"
                                      }
                                    },
                                    "required": [
                                      "from",
                                      "to"
                                    ]
                                  },
                                  "points": {
                                    "minItems": 2,
                                    "maxItems": 100,
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "period": {
                                          "type": "string",
                                          "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                          "description": "Rok, miesiąc lub dzień w ISO 8601"
                                        },
                                        "value": {
                                          "type": "number"
                                        }
                                      },
                                      "required": [
                                        "period",
                                        "value"
                                      ]
                                    },
                                    "description": "Wartości uporządkowane od najstarszego okresu"
                                  }
                                },
                                "required": [
                                  "label",
                                  "points"
                                ]
                              },
                              "transit": {
                                "description": "Pojazd transportu publicznego (zbiory z profilem transit_vehicles)",
                                "type": "object",
                                "properties": {
                                  "mode": {
                                    "type": "string",
                                    "enum": [
                                      "rail",
                                      "bus",
                                      "tram",
                                      "metro",
                                      "trolleybus",
                                      "ferry",
                                      "funicular",
                                      "other"
                                    ],
                                    "description": "Rodzaj transportu"
                                  },
                                  "label": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 40,
                                    "description": "Oznaczenie, którego szukają ludzie: pociąg (R 1234), linia (188)"
                                  },
                                  "line": {
                                    "description": "Linia, gdy różni się od oznaczenia (S2)",
                                    "type": "string",
                                    "maxLength": 40
                                  },
                                  "headsign": {
                                    "description": "Cel kursu",
                                    "type": "string",
                                    "maxLength": 120
                                  },
                                  "operator": {
                                    "description": "Przewoźnik",
                                    "type": "string",
                                    "maxLength": 120
                                  },
                                  "delay_min": {
                                    "description": "Opóźnienie w pełnych minutach, ujemne = przed czasem",
                                    "type": "integer",
                                    "minimum": -1440,
                                    "maximum": 1440
                                  },
                                  "delay_band": {
                                    "type": "string",
                                    "enum": [
                                      "on_time",
                                      "minor",
                                      "medium",
                                      "major",
                                      "extreme",
                                      "unknown"
                                    ],
                                    "description": "Przedział opóźnienia: on_time do 4 min, minor 5 do 14, medium 15 do 29, major 30 do 59, extreme 60 i więcej, unknown bez danych"
                                  },
                                  "bearing": {
                                    "description": "Kierunek jazdy w stopniach od północy",
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 360
                                  },
                                  "trip_ref": {
                                    "description": "Stały klucz kursu (ten sam przy kolejnych odświeżeniach danych)",
                                    "type": "string",
                                    "maxLength": 200
                                  },
                                  "observed_at": {
                                    "type": "string",
                                    "maxLength": 40,
                                    "description": "Kiedy zmierzono pozycję (ISO 8601)"
                                  }
                                },
                                "required": [
                                  "mode",
                                  "label",
                                  "delay_band",
                                  "observed_at"
                                ]
                              }
                            }
                          }
                        },
                        "required": [
                          "type",
                          "geometry"
                        ]
                      }
                    },
                    "dm": {
                      "type": "object",
                      "properties": {
                        "protocol": {
                          "type": "string"
                        },
                        "generated": {
                          "description": "Kiedy utworzono odpowiedź (ISO 8601)",
                          "type": "string",
                          "maxLength": 40
                        },
                        "ttl": {
                          "description": "Jak długo (s) odpowiedź jest ważna",
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991
                        },
                        "total": {
                          "description": "Łączna liczba obiektów spełniających zapytanie",
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991
                        },
                        "truncated": {
                          "description": "Odpowiedź nie zawiera wszystkich obiektów (limit)",
                          "type": "boolean"
                        },
                        "next": {
                          "description": "Kursor następnej strony",
                          "type": "string",
                          "maxLength": 500
                        },
                        "notice": {
                          "description": "Krótki komunikat dla użytkownika, np. przybliż mapę",
                          "type": "string",
                          "maxLength": 300
                        },
                        "timeline": {
                          "description": "Liczby obiektów w widoku według okresów za cały czas, który obejmuje zbiór – niezależnie od wybranego okresu i limitu. Portal rysuje z nich wykres przy legendzie.",
                          "maxItems": 400,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "period": {
                                "type": "string",
                                "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                "description": "Rok, miesiąc lub dzień w ISO 8601"
                              },
                              "count": {
                                "type": "integer",
                                "minimum": 0,
                                "maximum": 9007199254740991
                              },
                              "values": {
                                "description": "Rozkład liczby według wartości właściwości, która decyduje o kolorze obiektów (color.field) – wykres koloruje je tak jak legenda",
                                "type": "object",
                                "propertyNames": {
                                  "type": "string",
                                  "maxLength": 100
                                },
                                "additionalProperties": {
                                  "type": "integer",
                                  "minimum": 0,
                                  "maximum": 9007199254740991
                                }
                              }
                            },
                            "required": [
                              "period",
                              "count"
                            ]
                          }
                        },
                        "chart": {
                          "description": "Zbiorczy przebieg wartości dla całego obszaru zbioru lub widoku (np. liczba ludności Polski) – portal pokaże go przy filtrze czasu, gdy odpowiedź nie przesyła dm.timeline",
                          "type": "object",
                          "properties": {
                            "label": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 80,
                              "description": "Co pokazuje wykres, np. Liczba mieszkańców"
                            },
                            "unit": {
                              "type": "string",
                              "maxLength": 20
                            },
                            "decimals": {
                              "type": "integer",
                              "minimum": 0,
                              "maximum": 6
                            },
                            "note": {
                              "description": "Uwaga pod wykresem, np. o zmianie metodyki",
                              "type": "string",
                              "maxLength": 200
                            },
                            "highlight": {
                              "description": "Wyróżniony okres (np. wybrany w filtrze czasu) – portal go podświetli, pokaże wartość na jego końcu, a zmianę i trend policzy od jego początku. Te same from i to = jeden wybrany okres (np. rok).",
                              "type": "object",
                              "properties": {
                                "from": {
                                  "type": "string",
                                  "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                  "description": "Rok, miesiąc lub dzień w ISO 8601"
                                },
                                "to": {
                                  "type": "string",
                                  "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                  "description": "Rok, miesiąc lub dzień w ISO 8601"
                                }
                              },
                              "required": [
                                "from",
                                "to"
                              ]
                            },
                            "points": {
                              "minItems": 2,
                              "maxItems": 100,
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "period": {
                                    "type": "string",
                                    "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                    "description": "Rok, miesiąc lub dzień w ISO 8601"
                                  },
                                  "value": {
                                    "type": "number"
                                  }
                                },
                                "required": [
                                  "period",
                                  "value"
                                ]
                              },
                              "description": "Wartości uporządkowane od najstarszego okresu"
                            }
                          },
                          "required": [
                            "label",
                            "points"
                          ]
                        }
                      }
                    }
                  },
                  "required": [
                    "type",
                    "features"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Nieprawidłowe zapytanie",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Nieznany zbiór danych",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Błąd źródła danych",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/nearby": {
      "get": {
        "operationId": "nearby",
        "summary": "Co jest w punkcie i okolicy według wybranych zbiorów danych",
        "description": "Zbiory GeoJSON: obiekty w odległości do radius, posortowane od najbliższego (distance w metrach, 0 = punkt wewnątrz obszaru). Zbiory rastrowe: elementy bezpośrednio w punkcie (WMS GetFeatureInfo / ArcGIS identify). status ok z pustymi hits = nic tu nie ma, unavailable = zbiór nie podaje wartości w punkcie. Wymagany jest jeden z parametrów datasets, purpose, search. Parametry zbiorów: {provider}/{dataset}.{param}=hodnota.",
        "parameters": [
          {
            "name": "point",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "14.4527,50.0914"
            },
            "description": "lon,lat w WGS84"
          },
          {
            "name": "place",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "Thámova 7, Praha"
            },
            "description": "Miejsce punktu: adres lub nazwa (pierwszy wynik wyszukiwania miejsca)"
          },
          {
            "name": "radius",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 1,
              "maximum": 20000,
              "default": 500
            },
            "description": "Promień okolicy w metrach"
          },
          {
            "name": "datasets",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "vuv/zaplavova-uzemi,cgs/radon"
            },
            "description": "Klucze provider/dataset oddzielone przecinkami, maksymalnie 12"
          },
          {
            "name": "purpose",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "construction",
                "housing",
                "land-purchase",
                "agriculture",
                "investment",
                "transport",
                "tourism",
                "business",
                "public-administration"
              ]
            },
            "description": "Zbiory o tym zastosowaniu, które obejmują punkt"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Zbiory według zgodności z tekstem"
          },
          {
            "name": "max",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 5
            },
            "description": "Maksymalna liczba obiektów na zbiór"
          }
        ],
        "responses": {
          "200": {
            "description": "Wyniki według zbiorów",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PointAnswer"
                }
              }
            }
          },
          "400": {
            "description": "Nieprawidłowe zapytanie",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Nie udało się znaleźć miejsca",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/summary/{provider}/{dataset}": {
      "get": {
        "operationId": "summary",
        "summary": "Podsumowanie zbioru GeoJSON dla całego obszaru lub dla gminy",
        "description": "Liczba obiektów, kategorie, najwyższe i najniższe wartości, dla kartogramu wartości obszaru gminy (own). Dalsze parametry query to parametry zbioru.",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dataset",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "municipality",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "Ostrava"
            },
            "description": "Dowolna gmina w Polsce: nazwa, nazwa z powiatem („Dąbrowa (powiat opolski)”) lub kod TERYT gminy"
          }
        ],
        "responses": {
          "200": {
            "description": "Podsumowanie",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Zbiór rastrowy lub zbiór dostępny tylko po przybliżeniu (podaj gminę)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Nieznany zbiór lub gmina",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Błąd źródła danych",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/validate": {
      "get": {
        "operationId": "checkProvider",
        "summary": "Test na żywo: pobiera manifest i wysyła zapytanie testowe do każdego zbioru",
        "parameters": [
          {
            "name": "manifestUrl",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Raport",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Report"
                }
              }
            }
          },
          "400": {
            "description": "Brak manifestUrl",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "validate",
        "summary": "Kontrola manifestu lub danych bez publikacji",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Manifest"
                  },
                  {
                    "$ref": "#/components/schemas/DataResponse"
                  },
                  {
                    "type": "object",
                    "required": [
                      "manifest"
                    ],
                    "properties": {
                      "manifest": {
                        "$ref": "#/components/schemas/Manifest"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": [
                      "data"
                    ],
                    "properties": {
                      "data": {
                        "$ref": "#/components/schemas/DataResponse"
                      },
                      "dataset": {
                        "type": "object",
                        "description": "Zbiór danych z manifestu"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": [
                      "manifestUrl"
                    ],
                    "properties": {
                      "manifestUrl": {
                        "type": "string",
                        "format": "uri"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Raport",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Report"
                }
              }
            }
          },
          "400": {
            "description": "Nieprawidłowe dane wejściowe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/registration": {
      "post": {
        "operationId": "registerProvider",
        "summary": "Rejestracja dostawcy: test manifestu na żywo i dodanie do danych niezatwierdzonych",
        "description": "Po rejestracji dane są dostępne tylko na stronach zbiorów z ostrzeżeniem; do katalogu trafią po zatwierdzeniu przez operatora. Zatwierdzenie dotyczy konkretnej treści manifestu.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "manifestUrl"
                ],
                "properties": {
                  "manifestUrl": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Już zarejestrowano (stan w polu status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "201": {
            "description": "Zarejestrowano, czeka na zatwierdzenie",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Nieprawidłowe dane wejściowe",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Rejestracja została odrzucona",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Id lub URL manifestu jest już zarejestrowane",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Manifest nie przeszedł testu na żywo (raport w polu check)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Zbyt wiele żądań lub pełna kolejka do zatwierdzenia",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Rejestracja jest niedostępna",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/dokumentacja/dla-agentow-ai.md": {
      "get": {
        "operationId": "documentation_ai_agents",
        "summary": "Instrukcja dla agentów AI",
        "description": "Postępowanie krok po kroku, zasady, szablony kodu i kryteria ukończonej pracy dla agenta, który przygotowuje dane dostawcy.",
        "responses": {
          "200": {
            "description": "Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/dokumentacja/asystenci-ai.md": {
      "get": {
        "operationId": "documentation_ai_assistants",
        "summary": "Dane dla asystentów AI",
        "description": "Jak podłączyć portal MapaDanych do asystenta AI (MCP, HTTP API) i pytać o miejsca i dane.",
        "responses": {
          "200": {
            "description": "Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/dokumentacja/dla-dostawcow.md": {
      "get": {
        "operationId": "documentation_providers",
        "summary": "Dla dostawców danych",
        "description": "Jak podłączyć dane: pliki statyczne, własny endpoint lub WMS; manifest, dane, wizualizacje, weryfikacja, warunki.",
        "responses": {
          "200": {
            "description": "Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/dokumentacja/protokol.md": {
      "get": {
        "operationId": "documentation_protocol",
        "summary": "Protokol 0.1",
        "description": "Normatywna specyfikacja manifestu, zapytania o dane, odpowiedzi i cache.",
        "responses": {
          "200": {
            "description": "Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/dokumentacja/api.md": {
      "get": {
        "operationId": "documentation_api",
        "summary": "API portalu i serwer MCP",
        "description": "Katalog, dane, walidator, narzędzia MCP, linki do mapy i kody wyników walidacji.",
        "responses": {
          "200": {
            "description": "Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/dokumentacja/o-projekcie.md": {
      "get": {
        "operationId": "documentation_about",
        "summary": "O projekcie",
        "description": "Wizja portalu MapaDanych, zasady i plan rozwoju.",
        "responses": {
          "200": {
            "description": "Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Manifest": {
        "type": "object",
        "properties": {
          "$schema": {
            "type": "string"
          },
          "protocol": {
            "type": "string",
            "pattern": "^\\d+\\.\\d+$",
            "description": "Wersja protokołu, według której napisano manifest, np. 0.1"
          },
          "provider": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$",
                "examples": [
                  "mesto-brno",
                  "kontejnery-na-odpad"
                ]
              },
              "name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 120
              },
              "description": {
                "type": "string",
                "maxLength": 1000
              },
              "homepage": {
                "type": "string",
                "format": "uri"
              },
              "logo": {
                "type": "string",
                "format": "uri"
              },
              "contact": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                  },
                  "url": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              },
              "managedBy": {
                "default": "provider",
                "description": "portal = manifest usługi publicznej utrzymuje MapaDanych, a nie właściciel danych",
                "type": "string",
                "enum": [
                  "provider",
                  "portal"
                ]
              }
            },
            "required": [
              "id",
              "name"
            ]
          },
          "license": {
            "description": "Domyślna licencja dla wszystkich zbiorów danych",
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "minLength": 1,
                "description": "Nazwa licencji, np. CC BY 4.0"
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "attribution": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "Tekst atrybucji, który portal wyświetli przy mapie, np. © Państwowy Instytut Geologiczny"
              }
            },
            "required": [
              "name",
              "attribution"
            ]
          },
          "datasets": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "pattern": "^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$",
                  "examples": [
                    "mesto-brno",
                    "kontejnery-na-odpad"
                  ]
                },
                "title": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 120
                },
                "description": {
                  "type": "string",
                  "maxLength": 1000
                },
                "category": {
                  "description": "Zalecane wartości: territory, nature, water, risks, energy, transport, society, economy, infrastructure, sample, other",
                  "type": "string",
                  "maxLength": 40
                },
                "tags": {
                  "maxItems": 30,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "maxLength": 40
                  }
                },
                "keywords": {
                  "description": "Słowa i synonimy, po których zbiór znajdzie użytkownik i asystent AI portalu. Pisz po polsku, także w formach potocznych.",
                  "examples": [
                    [
                      "odpad",
                      "kontejner",
                      "třídění",
                      "popelnice"
                    ]
                  ],
                  "maxItems": 60,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "maxLength": 60
                  }
                },
                "useCases": {
                  "description": "Do czego zbiór jest przydatny. Zalecane wartości: construction, housing, land-purchase, agriculture, investment, transport, tourism, business, public-administration; inne są dozwolone.",
                  "examples": [
                    [
                      "construction",
                      "housing"
                    ]
                  ],
                  "maxItems": 20,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "maxLength": 60
                  }
                },
                "coverage": {
                  "type": "object",
                  "properties": {
                    "bbox": {
                      "type": "array",
                      "prefixItems": [
                        {
                          "type": "number",
                          "minimum": -180,
                          "maximum": 180
                        },
                        {
                          "type": "number",
                          "minimum": -90,
                          "maximum": 90
                        },
                        {
                          "type": "number",
                          "minimum": -180,
                          "maximum": 180
                        },
                        {
                          "type": "number",
                          "minimum": -90,
                          "maximum": 90
                        }
                      ],
                      "items": false,
                      "minItems": 4,
                      "maxItems": 4,
                      "description": "[minLon, minLat, maxLon, maxLat] w WGS84"
                    },
                    "area": {
                      "description": "Słowny opis zasięgu, np. Polska, województwo małopolskie",
                      "type": "string",
                      "maxLength": 60
                    },
                    "minZoom": {
                      "description": "Poniżej tego przybliżenia portal nie wczytuje danych",
                      "type": "number",
                      "minimum": 0,
                      "maximum": 24
                    },
                    "maxZoom": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 24
                    }
                  }
                },
                "temporal": {
                  "type": "object",
                  "properties": {
                    "updated": {
                      "description": "Data ostatniej aktualizacji danych (ISO 8601)",
                      "type": "string",
                      "maxLength": 40
                    },
                    "frequency": {
                      "description": "Jak często zmieniają się dane, np. codziennie",
                      "type": "string",
                      "maxLength": 60
                    },
                    "param": {
                      "description": "Klucz parametru, którym użytkownik wybiera okres (typ range w latach lub date-range). Portal pokaże go jako filtr czasu przy legendzie, z wykresem z dm.timeline.",
                      "type": "string",
                      "maxLength": 32
                    }
                  }
                },
                "license": {
                  "description": "Nadpisuje licencję dostawcy",
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Nazwa licencji, np. CC BY 4.0"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "attribution": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 300,
                      "description": "Tekst atrybucji, który portal wyświetli przy mapie, np. © Państwowy Instytut Geologiczny"
                    }
                  },
                  "required": [
                    "name",
                    "attribution"
                  ]
                },
                "source": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "geojson"
                        },
                        "url": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 2048,
                          "description": "Endpoint zwracający FeatureCollection; może być względny wobec manifestu",
                          "examples": [
                            "https://data.example.cz/datovamapa/kontejnery",
                            "kontejnery.geojson"
                          ]
                        },
                        "mode": {
                          "default": "full",
                          "description": "full = cały zbiór jednym zapytaniem, bbox = portal pyta o bieżący widok mapy",
                          "type": "string",
                          "enum": [
                            "full",
                            "bbox"
                          ]
                        },
                        "maxFeatures": {
                          "description": "Maksymalna liczba obiektów, jaką zwróci dostawca; portal przesyła ją jako limit",
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 5000
                        }
                      },
                      "required": [
                        "type",
                        "url"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "raster"
                        },
                        "tiles": {
                          "minItems": 1,
                          "maxItems": 4,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "pattern": "^https:\\/\\/\\S+$"
                          },
                          "description": "Szablony URL z {z}/{x}/{y} lub {bbox-epsg-3857}"
                        },
                        "tileSize": {
                          "default": 256,
                          "anyOf": [
                            {
                              "type": "number",
                              "const": 256
                            },
                            {
                              "type": "number",
                              "const": 512
                            }
                          ]
                        },
                        "minZoom": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 24
                        },
                        "maxZoom": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 24
                        }
                      },
                      "required": [
                        "type",
                        "tiles"
                      ]
                    }
                  ]
                },
                "presentation": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "circle"
                        },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "categorical"
                                },
                                "values": {
                                  "type": "object",
                                  "propertyNames": {
                                    "type": "string"
                                  },
                                  "additionalProperties": {
                                    "type": "string",
                                    "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                  },
                                  "description": "Wartość właściwości → kolor"
                                },
                                "default": {
                                  "type": "string",
                                  "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "values"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "interpolate"
                                },
                                "stops": {
                                  "minItems": 2,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "string",
                                        "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  },
                                  "description": "Uporządkowane pary [wartość, kolor]"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "stops"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "step"
                                },
                                "default": {
                                  "type": "string",
                                  "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$",
                                  "description": "Kolor dla wartości poniżej pierwszego progu"
                                },
                                "stops": {
                                  "minItems": 1,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "string",
                                        "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  },
                                  "description": "Uporządkowane pary [od wartości, kolor]"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "default",
                                "stops"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "type": {
                                  "type": "string",
                                  "const": "trend"
                                },
                                "threshold": {
                                  "description": "Średnia zmiana w jednym okresie wykresu w % wartości początkowej, poniżej której wartość uznaje się za stałą (domyślnie 0,5)",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 100
                                },
                                "colors": {
                                  "description": "Nadpisuje domyślne kolory (wzrost zielony, stagnacja szara, spadek czerwony) – np. gdy wzrost jest niepożądany",
                                  "type": "object",
                                  "properties": {
                                    "up": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    },
                                    "flat": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    },
                                    "down": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    }
                                  }
                                }
                              },
                              "required": [
                                "type"
                              ]
                            }
                          ]
                        },
                        "radius": {
                          "description": "Promień w pikselach",
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "interpolate"
                                },
                                "stops": {
                                  "minItems": 2,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "number",
                                        "minimum": 0
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  }
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "stops"
                              ]
                            }
                          ]
                        },
                        "opacity": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "strokeColor": {
                          "type": "string",
                          "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                        },
                        "strokeWidth": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 10
                        },
                        "label": {
                          "type": "object",
                          "properties": {
                            "field": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 64,
                              "description": "Właściwość, której wartość wyświetli się jako etykieta"
                            },
                            "minZoom": {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 24
                            },
                            "color": {
                              "type": "string",
                              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                            },
                            "size": {
                              "type": "number",
                              "minimum": 6,
                              "maximum": 32
                            }
                          },
                          "required": [
                            "field"
                          ]
                        },
                        "cluster": {
                          "description": "Grupowanie pobliskich punktów",
                          "anyOf": [
                            {
                              "type": "boolean"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "radius": {
                                  "type": "number",
                                  "minimum": 10,
                                  "maximum": 200
                                },
                                "maxZoom": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 20
                                }
                              }
                            }
                          ]
                        },
                        "legend": {
                          "description": "Własna legenda; w przeciwnym razie portal utworzy ją z kolorów",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "label": {
                                "type": "string",
                                "maxLength": 80
                              },
                              "color": {
                                "type": "string",
                                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                              }
                            },
                            "required": [
                              "label",
                              "color"
                            ]
                          }
                        }
                      },
                      "required": [
                        "type"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "heatmap"
                        },
                        "weight": {
                          "description": "Waga punktu, zwykle z właściwości liczbowej",
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "interpolate"
                                },
                                "stops": {
                                  "minItems": 2,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "number",
                                        "minimum": 0
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  }
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "stops"
                              ]
                            }
                          ]
                        },
                        "radius": {
                          "type": "number",
                          "minimum": 1,
                          "maximum": 100
                        },
                        "intensity": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 10
                        },
                        "colors": {
                          "description": "Skala kolorów od niskiej do wysokiej gęstości",
                          "minItems": 2,
                          "maxItems": 10,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                          }
                        },
                        "opacity": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "legend": {
                          "description": "Własna legenda; w przeciwnym razie portal utworzy ją z kolorów",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "label": {
                                "type": "string",
                                "maxLength": 80
                              },
                              "color": {
                                "type": "string",
                                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                              }
                            },
                            "required": [
                              "label",
                              "color"
                            ]
                          }
                        }
                      },
                      "required": [
                        "type"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "line"
                        },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "categorical"
                                },
                                "values": {
                                  "type": "object",
                                  "propertyNames": {
                                    "type": "string"
                                  },
                                  "additionalProperties": {
                                    "type": "string",
                                    "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                  },
                                  "description": "Wartość właściwości → kolor"
                                },
                                "default": {
                                  "type": "string",
                                  "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "values"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "interpolate"
                                },
                                "stops": {
                                  "minItems": 2,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "string",
                                        "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  },
                                  "description": "Uporządkowane pary [wartość, kolor]"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "stops"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "step"
                                },
                                "default": {
                                  "type": "string",
                                  "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$",
                                  "description": "Kolor dla wartości poniżej pierwszego progu"
                                },
                                "stops": {
                                  "minItems": 1,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "string",
                                        "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  },
                                  "description": "Uporządkowane pary [od wartości, kolor]"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "default",
                                "stops"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "type": {
                                  "type": "string",
                                  "const": "trend"
                                },
                                "threshold": {
                                  "description": "Średnia zmiana w jednym okresie wykresu w % wartości początkowej, poniżej której wartość uznaje się za stałą (domyślnie 0,5)",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 100
                                },
                                "colors": {
                                  "description": "Nadpisuje domyślne kolory (wzrost zielony, stagnacja szara, spadek czerwony) – np. gdy wzrost jest niepożądany",
                                  "type": "object",
                                  "properties": {
                                    "up": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    },
                                    "flat": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    },
                                    "down": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    }
                                  }
                                }
                              },
                              "required": [
                                "type"
                              ]
                            }
                          ]
                        },
                        "width": {
                          "anyOf": [
                            {
                              "type": "number",
                              "minimum": 0
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "interpolate"
                                },
                                "stops": {
                                  "minItems": 2,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "number",
                                        "minimum": 0
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  }
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "stops"
                              ]
                            }
                          ]
                        },
                        "opacity": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "dash": {
                          "minItems": 2,
                          "maxItems": 8,
                          "type": "array",
                          "items": {
                            "type": "number",
                            "minimum": 0
                          }
                        },
                        "label": {
                          "type": "object",
                          "properties": {
                            "field": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 64,
                              "description": "Właściwość, której wartość wyświetli się jako etykieta"
                            },
                            "minZoom": {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 24
                            },
                            "color": {
                              "type": "string",
                              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                            },
                            "size": {
                              "type": "number",
                              "minimum": 6,
                              "maximum": 32
                            }
                          },
                          "required": [
                            "field"
                          ]
                        },
                        "legend": {
                          "description": "Własna legenda; w przeciwnym razie portal utworzy ją z kolorów",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "label": {
                                "type": "string",
                                "maxLength": 80
                              },
                              "color": {
                                "type": "string",
                                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                              }
                            },
                            "required": [
                              "label",
                              "color"
                            ]
                          }
                        }
                      },
                      "required": [
                        "type"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "fill"
                        },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "categorical"
                                },
                                "values": {
                                  "type": "object",
                                  "propertyNames": {
                                    "type": "string"
                                  },
                                  "additionalProperties": {
                                    "type": "string",
                                    "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                  },
                                  "description": "Wartość właściwości → kolor"
                                },
                                "default": {
                                  "type": "string",
                                  "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "values"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "interpolate"
                                },
                                "stops": {
                                  "minItems": 2,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "string",
                                        "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  },
                                  "description": "Uporządkowane pary [wartość, kolor]"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "stops"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "field": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "type": {
                                  "type": "string",
                                  "const": "step"
                                },
                                "default": {
                                  "type": "string",
                                  "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$",
                                  "description": "Kolor dla wartości poniżej pierwszego progu"
                                },
                                "stops": {
                                  "minItems": 1,
                                  "type": "array",
                                  "items": {
                                    "type": "array",
                                    "prefixItems": [
                                      {
                                        "type": "number"
                                      },
                                      {
                                        "type": "string",
                                        "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                      }
                                    ],
                                    "items": false,
                                    "minItems": 2,
                                    "maxItems": 2
                                  },
                                  "description": "Uporządkowane pary [od wartości, kolor]"
                                }
                              },
                              "required": [
                                "field",
                                "type",
                                "default",
                                "stops"
                              ]
                            },
                            {
                              "type": "object",
                              "properties": {
                                "type": {
                                  "type": "string",
                                  "const": "trend"
                                },
                                "threshold": {
                                  "description": "Średnia zmiana w jednym okresie wykresu w % wartości początkowej, poniżej której wartość uznaje się za stałą (domyślnie 0,5)",
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 100
                                },
                                "colors": {
                                  "description": "Nadpisuje domyślne kolory (wzrost zielony, stagnacja szara, spadek czerwony) – np. gdy wzrost jest niepożądany",
                                  "type": "object",
                                  "properties": {
                                    "up": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    },
                                    "flat": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    },
                                    "down": {
                                      "type": "string",
                                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                                    }
                                  }
                                }
                              },
                              "required": [
                                "type"
                              ]
                            }
                          ]
                        },
                        "opacity": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "outlineColor": {
                          "type": "string",
                          "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                        },
                        "outlineWidth": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 10
                        },
                        "label": {
                          "type": "object",
                          "properties": {
                            "field": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 64,
                              "description": "Właściwość, której wartość wyświetli się jako etykieta"
                            },
                            "minZoom": {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 24
                            },
                            "color": {
                              "type": "string",
                              "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                            },
                            "size": {
                              "type": "number",
                              "minimum": 6,
                              "maximum": 32
                            }
                          },
                          "required": [
                            "field"
                          ]
                        },
                        "legend": {
                          "description": "Własna legenda; w przeciwnym razie portal utworzy ją z kolorów",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "label": {
                                "type": "string",
                                "maxLength": 80
                              },
                              "color": {
                                "type": "string",
                                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                              }
                            },
                            "required": [
                              "label",
                              "color"
                            ]
                          }
                        }
                      },
                      "required": [
                        "type"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "raster"
                        },
                        "opacity": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "legend": {
                          "description": "Własna legenda; w przeciwnym razie portal utworzy ją z kolorów",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "label": {
                                "type": "string",
                                "maxLength": 80
                              },
                              "color": {
                                "type": "string",
                                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                              }
                            },
                            "required": [
                              "label",
                              "color"
                            ]
                          }
                        }
                      },
                      "required": [
                        "type"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "const": "auto"
                        },
                        "color": {
                          "type": "string",
                          "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                        },
                        "legend": {
                          "description": "Własna legenda; w przeciwnym razie portal utworzy ją z kolorów",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "label": {
                                "type": "string",
                                "maxLength": 80
                              },
                              "color": {
                                "type": "string",
                                "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                              }
                            },
                            "required": [
                              "label",
                              "color"
                            ]
                          }
                        }
                      },
                      "required": [
                        "type"
                      ]
                    }
                  ]
                },
                "fields": {
                  "maxItems": 100,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "key": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 64
                      },
                      "label": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 80
                      },
                      "type": {
                        "default": "string",
                        "type": "string",
                        "enum": [
                          "string",
                          "number",
                          "integer",
                          "boolean",
                          "date",
                          "datetime",
                          "url",
                          "image",
                          "email",
                          "phone"
                        ]
                      },
                      "unit": {
                        "type": "string",
                        "maxLength": 20
                      },
                      "decimals": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 8
                      },
                      "description": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "primary": {
                        "description": "Wartość służy jako tytuł obiektu w szczegółach",
                        "type": "boolean"
                      }
                    },
                    "required": [
                      "key",
                      "label"
                    ]
                  }
                },
                "params": {
                  "maxItems": 20,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "key": {
                        "type": "string",
                        "pattern": "^[a-zA-Z][a-zA-Z0-9_]{0,31}$"
                      },
                      "label": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 80
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "enum",
                          "multi-enum",
                          "number",
                          "range",
                          "boolean",
                          "date",
                          "date-range",
                          "text"
                        ]
                      },
                      "description": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "options": {
                        "description": "Dla enum i multi-enum",
                        "maxItems": 200,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "value": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 100
                            },
                            "label": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 100
                            }
                          },
                          "required": [
                            "value",
                            "label"
                          ]
                        }
                      },
                      "min": {
                        "type": "number"
                      },
                      "max": {
                        "type": "number"
                      },
                      "step": {
                        "type": "number",
                        "exclusiveMinimum": 0
                      },
                      "unit": {
                        "type": "string",
                        "maxLength": 20
                      },
                      "default": {
                        "type": [
                          "string",
                          "number",
                          "boolean"
                        ]
                      },
                      "required": {
                        "type": "boolean"
                      }
                    },
                    "required": [
                      "key",
                      "label",
                      "type"
                    ]
                  }
                },
                "live": {
                  "description": "Dane na żywo: otwarta mapa sama je odświeża. Interwał nie powinien być krótszy niż cache.ttl.",
                  "type": "object",
                  "properties": {
                    "interval": {
                      "type": "integer",
                      "minimum": 10,
                      "maximum": 3600,
                      "description": "Jak często (w sekundach) mapa odświeża dane, dopóki zbiór jest włączony"
                    }
                  },
                  "required": [
                    "interval"
                  ]
                },
                "profile": {
                  "description": "Rodzaj zbioru ze wspólnym zachowaniem w portalu. transit_vehicles = bieżące pozycje pojazdów transportu publicznego: obiekty są punktami z dm.transit, zbiór ma live; portal pokaże go we wspólnej warstwie transportu z innymi takimi zbiorami.",
                  "type": "string",
                  "enum": [
                    "transit_vehicles"
                  ]
                },
                "detail": {
                  "description": "Szczegóły obiektu na żądanie po kliknięciu (rozkład jazdy, bogatszy opis, wyróżnienie na mapie)",
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 2048,
                      "description": "Szablon adresu szczegółów obiektu z symbolem zastępczym {id} (id obiektu z danych). Odpowiedzią jest FeatureDetail; może być względna wobec manifestu."
                    }
                  },
                  "required": [
                    "url"
                  ]
                },
                "cache": {
                  "type": "object",
                  "properties": {
                    "ttl": {
                      "description": "Jak długo (s) portal może trzymać odpowiedź w cache",
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 31536000
                    },
                    "store": {
                      "description": "Czy portal może zapisać dane w swojej warstwie cache na potrzeby analiz i zestawień (domyślnie tak)",
                      "type": "boolean"
                    }
                  }
                }
              },
              "required": [
                "id",
                "title",
                "source",
                "presentation"
              ]
            }
          }
        },
        "required": [
          "protocol",
          "provider",
          "datasets"
        ]
      },
      "DataResponse": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "const": "FeatureCollection"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "const": "Feature"
                },
                "id": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 200
                    },
                    {
                      "type": "number"
                    }
                  ]
                },
                "geometry": {
                  "anyOf": [
                    {
                      "oneOf": [
                        {
                          "type": "object",
                          "properties": {
                            "type": {
                              "type": "string",
                              "const": "Point"
                            },
                            "coordinates": {
                              "minItems": 2,
                              "maxItems": 3,
                              "type": "array",
                              "items": {
                                "type": "number"
                              }
                            }
                          },
                          "required": [
                            "type",
                            "coordinates"
                          ]
                        },
                        {
                          "type": "object",
                          "properties": {
                            "type": {
                              "type": "string",
                              "const": "MultiPoint"
                            },
                            "coordinates": {
                              "type": "array",
                              "items": {
                                "minItems": 2,
                                "maxItems": 3,
                                "type": "array",
                                "items": {
                                  "type": "number"
                                }
                              }
                            }
                          },
                          "required": [
                            "type",
                            "coordinates"
                          ]
                        },
                        {
                          "type": "object",
                          "properties": {
                            "type": {
                              "type": "string",
                              "const": "LineString"
                            },
                            "coordinates": {
                              "minItems": 2,
                              "type": "array",
                              "items": {
                                "minItems": 2,
                                "maxItems": 3,
                                "type": "array",
                                "items": {
                                  "type": "number"
                                }
                              }
                            }
                          },
                          "required": [
                            "type",
                            "coordinates"
                          ]
                        },
                        {
                          "type": "object",
                          "properties": {
                            "type": {
                              "type": "string",
                              "const": "MultiLineString"
                            },
                            "coordinates": {
                              "type": "array",
                              "items": {
                                "minItems": 2,
                                "type": "array",
                                "items": {
                                  "minItems": 2,
                                  "maxItems": 3,
                                  "type": "array",
                                  "items": {
                                    "type": "number"
                                  }
                                }
                              }
                            }
                          },
                          "required": [
                            "type",
                            "coordinates"
                          ]
                        },
                        {
                          "type": "object",
                          "properties": {
                            "type": {
                              "type": "string",
                              "const": "Polygon"
                            },
                            "coordinates": {
                              "type": "array",
                              "items": {
                                "minItems": 4,
                                "type": "array",
                                "items": {
                                  "minItems": 2,
                                  "maxItems": 3,
                                  "type": "array",
                                  "items": {
                                    "type": "number"
                                  }
                                }
                              }
                            }
                          },
                          "required": [
                            "type",
                            "coordinates"
                          ]
                        },
                        {
                          "type": "object",
                          "properties": {
                            "type": {
                              "type": "string",
                              "const": "MultiPolygon"
                            },
                            "coordinates": {
                              "type": "array",
                              "items": {
                                "type": "array",
                                "items": {
                                  "minItems": 4,
                                  "type": "array",
                                  "items": {
                                    "minItems": 2,
                                    "maxItems": 3,
                                    "type": "array",
                                    "items": {
                                      "type": "number"
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "required": [
                            "type",
                            "coordinates"
                          ]
                        }
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "properties": {
                  "default": {},
                  "anyOf": [
                    {
                      "type": "object",
                      "propertyNames": {
                        "type": "string"
                      },
                      "additionalProperties": {}
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "dm": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "description": "Tytuł obiektu w szczegółach",
                      "type": "string",
                      "maxLength": 200
                    },
                    "description": {
                      "type": "string",
                      "maxLength": 2000
                    },
                    "url": {
                      "description": "Odnośnik do szczegółów obiektu u dostawcy",
                      "type": "string",
                      "format": "uri"
                    },
                    "color": {
                      "description": "Nadpisuje kolor z prezentacji",
                      "type": "string",
                      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
                    },
                    "chart": {
                      "description": "Wykres zmian wartości w szczegółach obiektu",
                      "type": "object",
                      "properties": {
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80,
                          "description": "Co pokazuje wykres, np. Liczba mieszkańców"
                        },
                        "unit": {
                          "type": "string",
                          "maxLength": 20
                        },
                        "decimals": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 6
                        },
                        "note": {
                          "description": "Uwaga pod wykresem, np. o zmianie metodyki",
                          "type": "string",
                          "maxLength": 200
                        },
                        "highlight": {
                          "description": "Wyróżniony okres (np. wybrany w filtrze czasu) – portal go podświetli, pokaże wartość na jego końcu, a zmianę i trend policzy od jego początku. Te same from i to = jeden wybrany okres (np. rok).",
                          "type": "object",
                          "properties": {
                            "from": {
                              "type": "string",
                              "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                              "description": "Rok, miesiąc lub dzień w ISO 8601"
                            },
                            "to": {
                              "type": "string",
                              "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                              "description": "Rok, miesiąc lub dzień w ISO 8601"
                            }
                          },
                          "required": [
                            "from",
                            "to"
                          ]
                        },
                        "points": {
                          "minItems": 2,
                          "maxItems": 100,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "period": {
                                "type": "string",
                                "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                                "description": "Rok, miesiąc lub dzień w ISO 8601"
                              },
                              "value": {
                                "type": "number"
                              }
                            },
                            "required": [
                              "period",
                              "value"
                            ]
                          },
                          "description": "Wartości uporządkowane od najstarszego okresu"
                        }
                      },
                      "required": [
                        "label",
                        "points"
                      ]
                    },
                    "transit": {
                      "description": "Pojazd transportu publicznego (zbiory z profilem transit_vehicles)",
                      "type": "object",
                      "properties": {
                        "mode": {
                          "type": "string",
                          "enum": [
                            "rail",
                            "bus",
                            "tram",
                            "metro",
                            "trolleybus",
                            "ferry",
                            "funicular",
                            "other"
                          ],
                          "description": "Rodzaj transportu"
                        },
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 40,
                          "description": "Oznaczenie, którego szukają ludzie: pociąg (R 1234), linia (188)"
                        },
                        "line": {
                          "description": "Linia, gdy różni się od oznaczenia (S2)",
                          "type": "string",
                          "maxLength": 40
                        },
                        "headsign": {
                          "description": "Cel kursu",
                          "type": "string",
                          "maxLength": 120
                        },
                        "operator": {
                          "description": "Przewoźnik",
                          "type": "string",
                          "maxLength": 120
                        },
                        "delay_min": {
                          "description": "Opóźnienie w pełnych minutach, ujemne = przed czasem",
                          "type": "integer",
                          "minimum": -1440,
                          "maximum": 1440
                        },
                        "delay_band": {
                          "type": "string",
                          "enum": [
                            "on_time",
                            "minor",
                            "medium",
                            "major",
                            "extreme",
                            "unknown"
                          ],
                          "description": "Przedział opóźnienia: on_time do 4 min, minor 5 do 14, medium 15 do 29, major 30 do 59, extreme 60 i więcej, unknown bez danych"
                        },
                        "bearing": {
                          "description": "Kierunek jazdy w stopniach od północy",
                          "type": "number",
                          "minimum": 0,
                          "maximum": 360
                        },
                        "trip_ref": {
                          "description": "Stały klucz kursu (ten sam przy kolejnych odświeżeniach danych)",
                          "type": "string",
                          "maxLength": 200
                        },
                        "observed_at": {
                          "type": "string",
                          "maxLength": 40,
                          "description": "Kiedy zmierzono pozycję (ISO 8601)"
                        }
                      },
                      "required": [
                        "mode",
                        "label",
                        "delay_band",
                        "observed_at"
                      ]
                    }
                  }
                }
              },
              "required": [
                "type",
                "geometry"
              ]
            }
          },
          "dm": {
            "type": "object",
            "properties": {
              "protocol": {
                "type": "string"
              },
              "generated": {
                "description": "Kiedy utworzono odpowiedź (ISO 8601)",
                "type": "string",
                "maxLength": 40
              },
              "ttl": {
                "description": "Jak długo (s) odpowiedź jest ważna",
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              "total": {
                "description": "Łączna liczba obiektów spełniających zapytanie",
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              "truncated": {
                "description": "Odpowiedź nie zawiera wszystkich obiektów (limit)",
                "type": "boolean"
              },
              "next": {
                "description": "Kursor następnej strony",
                "type": "string",
                "maxLength": 500
              },
              "notice": {
                "description": "Krótki komunikat dla użytkownika, np. przybliż mapę",
                "type": "string",
                "maxLength": 300
              },
              "timeline": {
                "description": "Liczby obiektów w widoku według okresów za cały czas, który obejmuje zbiór – niezależnie od wybranego okresu i limitu. Portal rysuje z nich wykres przy legendzie.",
                "maxItems": 400,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "period": {
                      "type": "string",
                      "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                      "description": "Rok, miesiąc lub dzień w ISO 8601"
                    },
                    "count": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 9007199254740991
                    },
                    "values": {
                      "description": "Rozkład liczby według wartości właściwości, która decyduje o kolorze obiektów (color.field) – wykres koloruje je tak jak legenda",
                      "type": "object",
                      "propertyNames": {
                        "type": "string",
                        "maxLength": 100
                      },
                      "additionalProperties": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9007199254740991
                      }
                    }
                  },
                  "required": [
                    "period",
                    "count"
                  ]
                }
              },
              "chart": {
                "description": "Zbiorczy przebieg wartości dla całego obszaru zbioru lub widoku (np. liczba ludności Polski) – portal pokaże go przy filtrze czasu, gdy odpowiedź nie przesyła dm.timeline",
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80,
                    "description": "Co pokazuje wykres, np. Liczba mieszkańców"
                  },
                  "unit": {
                    "type": "string",
                    "maxLength": 20
                  },
                  "decimals": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 6
                  },
                  "note": {
                    "description": "Uwaga pod wykresem, np. o zmianie metodyki",
                    "type": "string",
                    "maxLength": 200
                  },
                  "highlight": {
                    "description": "Wyróżniony okres (np. wybrany w filtrze czasu) – portal go podświetli, pokaże wartość na jego końcu, a zmianę i trend policzy od jego początku. Te same from i to = jeden wybrany okres (np. rok).",
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                        "description": "Rok, miesiąc lub dzień w ISO 8601"
                      },
                      "to": {
                        "type": "string",
                        "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                        "description": "Rok, miesiąc lub dzień w ISO 8601"
                      }
                    },
                    "required": [
                      "from",
                      "to"
                    ]
                  },
                  "points": {
                    "minItems": 2,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "period": {
                          "type": "string",
                          "pattern": "^\\d{4}(?:-\\d{2}(?:-\\d{2})?)?$",
                          "description": "Rok, miesiąc lub dzień w ISO 8601"
                        },
                        "value": {
                          "type": "number"
                        }
                      },
                      "required": [
                        "period",
                        "value"
                      ]
                    },
                    "description": "Wartości uporządkowane od najstarszego okresu"
                  }
                },
                "required": [
                  "label",
                  "points"
                ]
              }
            }
          }
        },
        "required": [
          "type",
          "features"
        ]
      },
      "Issue": {
        "type": "object",
        "required": [
          "path",
          "code",
          "message"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "Miejsce w dokumencie, np. datasets[0].keywords"
          },
          "code": {
            "type": "string",
            "description": "Stabilny kod wyniku, zob. /dokumentacja/api.md#kody-nalezu"
          },
          "message": {
            "type": "string"
          },
          "hint": {
            "type": "string",
            "description": "Wskazówka, jak poprawić problem"
          }
        }
      },
      "Report": {
        "type": "object",
        "required": [
          "valid",
          "errors",
          "warnings",
          "summary"
        ],
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "summary": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "kind": {
            "type": "string",
            "enum": [
              "manifest",
              "data"
            ]
          },
          "featureCount": {
            "type": "integer"
          },
          "manifestUrl": {
            "type": "string"
          },
          "provider": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "datasets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "sourceType": {
                  "type": "string"
                },
                "request": {
                  "type": "string"
                },
                "durationMs": {
                  "type": "integer"
                },
                "featureCount": {
                  "type": "integer"
                },
                "valid": {
                  "type": "boolean"
                },
                "summary": {
                  "type": "string"
                },
                "errors": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Issue"
                  }
                },
                "warnings": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Issue"
                  }
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        }
      },
      "Place": {
        "type": "object",
        "required": [
          "name",
          "type",
          "point"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "adres, ulica, gmina, część gminy…"
          },
          "point": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "maxItems": 2,
            "description": "[lon, lat]"
          },
          "municipality": {
            "type": "object",
            "description": "Gmina, w której leży miejsce; code (kod TERYT gminy) jest jednoznaczny także przy gminach o tej samej nazwie",
            "properties": {
              "slug": {
                "type": "string"
              },
              "code": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "district": {
                "type": "string"
              },
              "region": {
                "type": "string"
              }
            }
          },
          "near": {
            "type": "object",
            "description": "Najbliższe miasto powyżej 20 000 mieszkańców (dla miejsc poza tymi miastami)",
            "properties": {
              "name": {
                "type": "string"
              },
              "km": {
                "type": "number"
              }
            }
          }
        }
      },
      "PointAnswer": {
        "type": "object",
        "required": [
          "point",
          "radius",
          "generated",
          "results",
          "map"
        ],
        "properties": {
          "place": {
            "$ref": "#/components/schemas/Place"
          },
          "point": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "radius": {
            "type": "number"
          },
          "generated": {
            "type": "string",
            "format": "date-time"
          },
          "skipped": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Zbiory ponad limit, o które zapytanie nie pytało"
          },
          "map": {
            "type": "string",
            "format": "uri"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "dataset",
                "title",
                "status",
                "hits"
              ],
              "properties": {
                "dataset": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "legend": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "provider": {
                  "type": "string"
                },
                "attribution": {
                  "type": "string"
                },
                "license": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "ok",
                    "unavailable",
                    "error"
                  ]
                },
                "count": {
                  "type": "integer"
                },
                "radius": {
                  "type": "number"
                },
                "truncated": {
                  "type": "boolean"
                },
                "notice": {
                  "type": "string"
                },
                "error": {
                  "type": "string"
                },
                "code": {
                  "type": "string"
                },
                "hits": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "title",
                      "distance",
                      "values"
                    ],
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "distance": {
                        "type": "number"
                      },
                      "values": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "required": [
                            "label",
                            "value"
                          ],
                          "properties": {
                            "label": {
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "description": {
                        "type": "string"
                      },
                      "url": {
                        "type": "string"
                      },
                      "chart": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}