# API portálu DatováMapa

Strojové rozhraní portálu pro aplikace a AI agenty: katalog dat, data ze všech zdrojů ve sjednoceném tvaru, dotazy na místo (co je v bodě a okolí, souhrn za obec), validátor a registrace pro poskytovatele a MCP server. Vše je veřejné, bez autentizace, s CORS `*`. Formální popis je v [OpenAPI](https://datovamapa.cz/openapi.json).

## Přehled

| Metoda a cesta | Účel |
|---|---|
| `GET /api/katalog` | všichni poskytovatelé a datové sady (JSON) |
| `GET /api/data/{provider}/{dataset}` | data sady jako GeoJSON, přes cache portálu |
| `GET /api/misto?dotaz=…` | hledání adresy, ulice nebo obce → souřadnice |
| `GET /api/okoli?bod=…` | co je v bodě a okolí, z vybraných sad |
| `GET /api/souhrn/{provider}/{dataset}` | souhrn sady za celé území nebo za obec |
| `GET /api/validovat?manifestUrl=…` | živý test poskytovatele |
| `POST /api/validovat` | kontrola manifestu nebo dat bez zveřejnění |
| `POST /api/registrace` | registrace poskytovatele (data čekají na schválení) |
| `POST /mcp` | MCP server (Streamable HTTP) |
| `GET /llms.txt`, `/llms-full.txt` | rozcestník a celá dokumentace pro jazykové modely |
| `GET /index.md`, `/zdroje.md`, `/dokumentace/{slug}.md` | stránky portálu v markdownu |
| `GET /schema/0.1/manifest.json`, `/schema/0.1/data.json` | JSON Schema protokolu |
| `GET /schema/0.1/poskytovatel-openapi.json` | OpenAPI kontrakt, který implementuje poskytovatel |
| `GET /priklady/{soubor}.json` | platné ukázkové manifesty a odpovědi |

## Katalog

`GET /api/katalog`

```json
{
  "protocol": "0.1",
  "generated": "2026-10-06T08:00:00.000Z",
  "providers": [{ "id": "cgs", "name": "Česká geologická služba", "status": "ok", "datasetCount": 2, "managedBy": "portal" }],
  "datasets": [
    {
      "key": "cgs/radon",
      "providerId": "cgs",
      "providerName": "Česká geologická služba",
      "title": "Radonový index",
      "category": "rizika",
      "categoryLabel": "Rizika a omezení",
      "keywords": ["radon"],
      "useCases": ["stavba", "bydleni"],
      "source": { "type": "raster", "tiles": ["https://…"] },
      "presentation": { "type": "raster", "opacity": 0.45 },
      "attribution": "© Česká geologická služba",
      "links": { "data": null, "map": "/?d=cgs/radon" }
    }
  ]
}
```

Katalog obsahuje jen schválená data. Sady poskytovatelů, kteří se zaregistrovali sami a zatím nejsou schválení, v něm nejsou (viz [Registrace](#registrace)).

Datové sady nesou všechna pole z manifestu poskytovatele (`description`, `fields`, `params`, `coverage`…) kromě URL zdroje – GeoJSON data se čtou přes portál (`links.data`), rastrové dlaždice přímo ze zdroje (`source.tiles`). Stejný obsah čitelný pro lidi i modely: [zdroje.md](https://datovamapa.cz/zdroje.md).

## Data

`GET /api/data/{provider}/{dataset}`

| Parametr | Kdy | Popis |
|---|---|---|
| `bbox` | sady s `source.mode = "bbox"` (povinný) | `minLon,minLat,maxLon,maxLat` ve WGS84; portál ho zarovná na dlaždice |
| `zoom` | sady s `source.mode = "bbox"` (povinný) | úroveň přiblížení 0–24 |
| `cursor` | volitelně | kurzor z `dm.next` |
| `{param}` | podle `params` sady | hodnoty ve formátu protokolu (`a,b`, `od,do`); nevyplněné dostanou `default` |

Odpověď je GeoJSON `FeatureCollection`. Údaje z `feature.dm` poskytovatele jsou přesunuté do `properties` s prefixem `__dm_` (`__dm_title`, `__dm_description`, `__dm_url`, `__dm_color`, `__dm_chart`). U sad s `color.type = "trend"` přidá portál `__dm_trend` (`roste`, `stagnuje`, `klesá`) spočítaný z `dm.chart`. Metadata odpovědi:

```json
{ "dm": { "protocol": "0.1", "dataset": "aopk/pamatne-stromy", "generated": "…", "ttl": 86400, "total": 13, "truncated": false, "notice": null } }
```

Hlavička `X-DM-Cache`: `hit` (z cache), `miss` (čerstvě ze zdroje), `stale` (zdroj nedostupný, poslední známá data – viz `dm.notice`).

Chyby mají tvar `{ "error": "zpráva", "code": "kod" }`: `400` neplatný dotaz, `404` neznámá sada, `502` chyba zdroje.

## Místo a okolí

Dotazy pro AI asistenty a aplikace, které odpovídají na otázky o konkrétním místě. Vrací lidsky popsané hodnoty (popisky a jednotky podle `fields` sady) bez geometrií, s atribucí a odkazem na mapu. Návod pro uživatele asistentů: [Data pro AI asistenty](https://datovamapa.cz/dokumentace/ai-asistenti.md).

### Hledání místa

`GET /api/misto?dotaz=Thámova 7, Praha` (volitelně `max`, výchozí 5, nejvýš 10)

Hledá v registru adres RÚIAN (© ČÚZK, CC BY 4.0) adresy, ulice, obce, části obcí a další územní prvky. Zadejte jen adresu nebo název; upřesnění jako okres nebo „u Zlína“ služba nezná. `municipality` je obec nad 10 000 obyvatel, ve které místo leží – pro ni umí [souhrn](#souhrn) data za celou obec. U ostatních míst je `near` nejbližší taková obec a vzdálenost v km; podle ní se rozliší stejnojmenná místa.

```json
{
  "query": "Thámova 7, Praha",
  "count": 1,
  "places": [{ "name": "Thámova 221/7, Karlín, 18600 Praha 8", "type": "adresa", "point": [14.452653, 50.091436], "municipality": { "slug": "praha", "name": "Praha" } }],
  "attribution": "© ČÚZK, RÚIAN (CC BY 4.0)"
}
```

### Co je v bodě a okolí

`GET /api/okoli`

| Parametr | Popis |
|---|---|
| `bod` | `lon,lat` ve WGS84 |
| `misto` | místo `bod`: adresa nebo název, použije se první nález hledání místa |
| `polomer` | poloměr okolí v metrech, výchozí 500, nejvýš 20 000 |
| `sady` | klíče `provider/dataset` oddělené čárkou, nejvýš 12 |
| `ucel` | místo `sady`: sady s tímto účelem (`useCases`), které bod pokrývají |
| `hledat` | místo `sady`: sady podle shody s textem, např. `rizika pro stavbu` |
| `max` | nejvýš objektů na sadu, výchozí 5, nejvýš 50 |
| `{provider}/{dataset}.{param}` | parametr sady, stejně jako v [odkazu na mapu](#odkaz-na-mapu) |

Jedno z `sady`, `ucel`, `hledat` je povinné. Automatický výběr bere jen sady, které na bod umí odpovědět: nejdřív rizika a omezení, podkladové mapy nakonec. Sady nad limit vrátí v `skipped`.

- **GeoJSON sady:** objekty do vzdálenosti `polomer` seřazené od nejbližšího. `distance` je v metrech, 0 = bod leží uvnitř plochy (např. obec u kartogramu). `count` je počet objektů v okolí. Sady, které se načítají jen při velkém přiblížení, okolí zmenší (`radius`, `notice`). U celých sad (`mode: full`), které v okolí nic nemají, vrátí aspoň nejbližší objekt (např. měřicí stanici).
- **Rastrové sady:** portál se zeptá zdroje přímo na bod. Dotaz odvodí ze šablony dlaždic: WMS `GetMap` → `GetFeatureInfo`, ArcGIS `MapServer/export` → `identify`, `ImageServer/exportImage` → `identify` s tabulkou tříd rastru. Hodnoty jsou atributy zdroje (názvy polí, jak je zdroj vrací). K výkladu kódů pomůže `description` a `legend`.

| `status` | Význam |
|---|---|
| `ok` | dotaz proběhl; prázdné `hits` = v okolí / v bodě nic není (např. mimo záplavové území) |
| `nelze` | sada hodnotu v bodě neposkytuje (dlaždice jsou jen obraz) nebo bod leží mimo pokrytí |
| `chyba` | zdroj selhal (`error`, `code`) |

```json
{
  "place": { "name": "Thámova 221/7, Karlín, 18600 Praha 8", "type": "adresa", "point": [14.452653, 50.091436] },
  "point": [14.452653, 50.091436],
  "radius": 500,
  "generated": "2026-10-06T16:00:00.000Z",
  "results": [
    {
      "dataset": "cgs/radon",
      "title": "Radonový index",
      "provider": "Česká geologická služba",
      "attribution": "© Česká geologická služba",
      "status": "ok",
      "hits": [{ "title": "Radonový index", "distance": 0, "values": [{ "label": "radonovériziko", "value": "přechodný" }, { "label": "stupeňradonovéhoindexu", "value": "2" }] }]
    },
    {
      "dataset": "npu/kulturni-pamatky",
      "title": "Kulturní památky",
      "provider": "Národní památkový ústav",
      "attribution": "Národní památkový ústav",
      "license": "CC BY-SA 4.0",
      "status": "ok",
      "count": 27,
      "radius": 500,
      "hits": [
        {
          "title": "továrna Breitfeld-Daněk",
          "distance": 91,
          "values": [{ "label": "Rejstříkové číslo ÚSKP", "value": "105958" }, { "label": "Stav ochrany", "value": "památkově chráněno" }],
          "url": "https://pamatkovykatalog.cz/x-14624751"
        }
      ]
    }
  ],
  "map": "https://datovamapa.cz/?d=cgs/radon&d=npu/kulturni-pamatky#15/50.09144/14.45265"
}
```

### Souhrn

`GET /api/souhrn/{provider}/{dataset}?obec=Ostrava` (ostatní query parametry jsou parametry sady)

Souhrn GeoJSON sady za celé území, nebo s `obec` (název nebo slug obce nad 10 000 obyvatel) jen za obec: `count`, `categories` (počty podle kategorie barvy), `rankings` (nejvyšší a nejnižší hodnoty) a u kartogramu `own` – hodnoty plochy, ve které obec leží. Jsou to stejná čísla, jaká ukazuje stránka sady. Sady načítané jen při velkém přiblížení mají souhrn jen za obec. Rastrové sady souhrn nemají.

## Validátor

Nástroj pro poskytovatele a jejich AI agenty. Vrací vždy HTTP 200 a report:

```json
{
  "valid": false,
  "summary": "Manifest není platný: 1 chyb, 2 doporučení.",
  "errors": [{ "path": "datasets[0].source.tiles[0]", "code": "raster_bez_sablony", "message": "Šablona dlaždic neobsahuje {z}/{x}/{y} ani {bbox-epsg-3857}." }],
  "warnings": [{ "path": "datasets[0].keywords", "code": "chybi_klicova_slova", "message": "Sada nemá klíčová slova.", "hint": "Doplňte 5–15 slov…" }]
}
```

- `POST /api/validovat` s tělem:
  - manifest (objekt s `datasets`) nebo `{ "manifest": … }` – statická kontrola,
  - GeoJSON `FeatureCollection` nebo `{ "data": …, "dataset": … }` – kontrola dat; s `dataset` (objekt sady z manifestu) i soulad s manifestem,
  - `{ "manifestUrl": "https://…" }` – živý test.
- `GET /api/validovat?manifestUrl=https://…` – živý test: stáhne manifest, zkontroluje ho a na každou sadu pošle testovací dotaz jako portál (u `bbox` na střed `coverage.bbox`, zoom 12 nebo `coverage.minZoom`; u rastru jednu dlaždici). Report má navíc `provider` a `datasets[]` s `request`, `durationMs`, `featureCount`, `errors`, `warnings`.

## Registrace

`POST /api/registrace` s tělem `{ "manifestUrl": "https://…" }`. Portál manifest zkontroluje živým testem (jako validátor). Když projde, zaregistruje poskytovatele mezi neschválená data:

- Data jsou dostupná přes `/api/data/…` i na stránkách sad `/mapa/{provider}/{dataset}`. Stránka nejdřív ukáže varování, že data nahrála třetí strana a provozovatel je neschválil. Data do mapy načte až po potvrzení. Stránka má `noindex`.
- Do katalogu, vyhledávání, `llms.txt`, MCP nástroje `katalog` a na stránky za obce se data dostanou až po schválení provozovatelem.
- Schválení platí pro otisk (SHA-256) obsahu manifestu. Po změně manifestu je poskytovatel zase neschválený, dokud ho provozovatel neschválí znovu.
- Přehled neschválených poskytovatelů: [/neschvalena-data](https://datovamapa.cz/neschvalena-data).

```json
{
  "registered": true,
  "status": "ceka_na_schvaleni",
  "message": "Registrováno. …",
  "provider": { "id": "obec-priklad", "name": "Obec Příklad" },
  "links": { "review": "/neschvalena-data#obec-priklad", "datasets": ["/mapa/obec-priklad/lavicky"] },
  "check": { "summary": "Poskytovatel je platný bez výhrad.", "warnings": [] }
}
```

| HTTP | `code` | Význam |
|---|---|---|
| 201 | – | registrováno, čeká na schválení |
| 200 | – | už registrováno; `status` je `ceka_na_schvaleni` nebo `schvaleno` |
| 400 | `neplatny_vstup`, `neplatna_url` | chybí nebo je neplatná `manifestUrl` |
| 403 | `zamitnuto` | registraci provozovatel zamítl |
| 409 | `id_obsazeno`, `url_registrovana` | `provider.id` už v portálu je / URL je registrovaná pod jiným id |
| 422 | `manifest_neprosel` | živý test neprošel; report je v `check` |
| 429 | `prilis_mnoho_pozadavku`, `fronta_plna` | víc než 5 pokusů za minutu z jedné adresy / ke schválení čeká přes 100 poskytovatelů |
| 503 | `registrace_nedostupna` | registrace teď nefunguje |

## MCP server

Endpoint `https://datovamapa.cz/mcp`, transport Streamable HTTP (bezstavový, odpovědi JSON), bez autentizace.

| Nástroj | Vstup | Výstup |
|---|---|---|
| `dokumentace` | `tema`: `pro-ai-agenty`, `ai-asistenti`, `protokol`, `pro-poskytovatele`, `api`, `o-projektu` | markdown dokumentu |
| `schema` | `typ`: `manifest`, `data`, `poskytovatel-openapi` | JSON Schema / OpenAPI |
| `priklad` | `nazev`: `manifest-minimalni`, `manifest-kompletni`, `data-body`, `data-plochy` | platný ukázkový JSON |
| `validovat_manifest` | `manifest` (objekt) nebo `manifestUrl` (živý test) | report validátoru |
| `validovat_data` | `data`, volitelně `dataset` | report validátoru |
| `registrovat_poskytovatele` | `manifestUrl` | výsledek [registrace](#registrace) |
| `katalog` | volitelně `hledat` (volný text), `bod` (`[lon, lat]`) | datové sady v portálu, seřazené podle shody; `pointQuery` = sada odpoví `v_okoli` |
| `najit_misto` | `dotaz`, `maxVysledku` | jako [hledání místa](#hledani-mista) |
| `v_okoli` | `bod` nebo `misto`; `sady`, `ucel` nebo `hledat`; `polomer`, `maxObjektu`, `parametry` (`{ "provider/dataset": { "param": "hodnota" } }`) | jako [co je v bodě a okolí](#co-je-v-bode-a-okoli) |
| `souhrn` | `dataset`, volitelně `obec`, `parametry` | jako [souhrn](#souhrn) |
| `nacist_data` | `dataset` (`provider/dataset`), `bbox` nebo `obec`, `zoom`, `parametry`, `maxObjektu` | GeoJSON (zkrácený na `maxObjektu`) |

Připojení:

```bash
claude mcp add --transport http datovamapa https://datovamapa.cz/mcp
```

```json
{ "mcpServers": { "datovamapa": { "type": "http", "url": "https://datovamapa.cz/mcp" } } }
```

## Odkaz na mapu

`https://datovamapa.cz/?d={provider}/{dataset}&d=…&{provider}/{dataset}.{param}={hodnota}#{zoom}/{lat}/{lon}`

Každá sada má i vlastní stránku s mapou a popisem: `https://datovamapa.cz/mapa/{provider}/{dataset}`, celostátní GeoJSON sady také za obce nad 10 000 obyvatel: `https://datovamapa.cz/mapa/{provider}/{dataset}/{obec}` (např. [/mapa/chmu/kvalita-ovzdusi/ostrava](https://datovamapa.cz/mapa/chmu/kvalita-ovzdusi/ostrava)). Odkaz na stránku sady je v katalogu v `links.map`. Na stránce sady (i sestavené mapy `/mapy/{slug}`) se do `?d=…` zapisuje jen rozdíl proti výchozímu výběru: bez `d` platí sady stránky, `d` vyjmenuje celý výběr (`?d=` = nic zapnuto) a parametr se uvádí, jen když se liší od výchozího.

Příklad – dopravní nehody v Brně souhrnně za roky 2019–2023: [/?d=brno/dopravni-nehody&brno/dopravni-nehody.obdobi=2019,2023#13/49.195/16.608](https://datovamapa.cz/?d=brno/dopravni-nehody&brno/dopravni-nehody.obdobi=2019,2023#13/49.195/16.608)

## Kódy nálezů

Stabilní kódy chyb (`errors`) a doporučení (`warnings`) validátoru a proxy.

### Manifest

| Kód | Úroveň | Význam |
|---|---|---|
| `schema_*` | chyba | porušení JSON Schema (`schema_invalid_type`, `schema_too_small`, `schema_invalid_format`, `schema_invalid_value`, `schema_custom`…), `path` ukazuje místo |
| `nepodporovana_verze` | chyba | jiná hlavní verze protokolu |
| `raster_bez_sablony` | chyba | URL dlaždic bez `{z}/{x}/{y}` i `{bbox-epsg-3857}` |
| `geojson_s_rastrovou_prezentaci` | chyba | GeoJSON zdroj s `presentation.type: "raster"` |
| `parametr_bez_moznosti` | chyba | `enum` / `multi-enum` bez `options` |
| `neplatny_default` | chyba | `default` parametru neodpovídá typu nebo možnostem |
| `casovy_parametr_chybi` | chyba | `temporal.param` odkazuje na parametr, který není v `params` |
| `casovy_parametr_typ` | chyba | časový parametr není typu `range` ani `date-range` |
| `casovy_parametr_bez_rozsahu` | doporučení | časový parametr typu `range` nemá `min` a `max` |
| `neznamy_typ_prezentace` | doporučení | portál typ nezná, kreslí `auto` |
| `rastr_bez_rastrove_prezentace` | doporučení | rastr se vždy kreslí jako `raster` |
| `chybi_popis`, `chybi_klicova_slova`, `chybi_ucely` | doporučení | sadu hůř najdou lidé i asistent |
| `chybi_kategorie`, `neznama_kategorie` | doporučení | sada skončí v „Ostatní“ |
| `chybi_pole` | doporučení | detail objektu ukáže surové názvy vlastností |
| `pole_neni_popsane`, `pole_neni_cislo` | doporučení | prezentace odkazuje na vlastnost mimo `fields` / s nečíselným typem |
| `bbox_bez_omezeni` | doporučení | sada `bbox` bez `coverage.minZoom` a `maxFeatures` |
| `chybi_pokryti` | doporučení | sada `bbox` bez `coverage.bbox` |
| `chybi_licence`, `chybi_web` | doporučení | chybí licence / web poskytovatele |

### Data

| Kód | Úroveň | Význam |
|---|---|---|
| `souradnice_mimo_rozsah` | chyba | souřadnice mimo WGS84 (typicky nepřevedené S-JTSK) |
| `neuzavreny_polygon` | chyba | prstenec polygonu není uzavřený |
| `prilis_mnoho_objektu` | doporučení | víc objektů než `limit` / 5 000 |
| `chybi_casova_rada` | doporučení | sada má `temporal.param`, odpověď neposílá `dm.timeline` ani `dm.chart` |
| `chybi_graf_vyvoje` | doporučení | sada barví podle číselné hodnoty a období volí parametrem, objekty ale neposílají `dm.chart` |
| `trend_bez_grafu` | doporučení | sada se barví podle trendu, některé objekty nemají `dm.chart` (zůstanou šedé) |
| `prohozene_souradnice` | doporučení | souřadnice zřejmě v pořadí `[lat, lon]` |
| `mimo_pokryti` | doporučení | většina objektů mimo `coverage.bbox` |
| `geometrie_neodpovida_prezentaci` | doporučení | např. plochy u `circle` |
| `pole_chybi_v_datech`, `chybi_vlastnost_prezentace` | doporučení | vlastnost z manifestu v datech chybí |
| `chybi_id` | doporučení | objekty bez `id` |
| `prazdna_geometrie` | doporučení | objekty s `geometry: null` se přeskočí |

### Živý test a proxy

| Kód | Význam |
|---|---|
| `neplatna_url`, `vyzadovano_https` | neplatná URL / zdroj není na HTTPS |
| `zdroj_nedostupny`, `casovy_limit`, `http_chyba` | zdroj neodpovídá, nestihl 10 s, vrátil HTTP chybu |
| `neplatny_json`, `prazdne_telo`, `prilis_velka_odpoved` | odpověď není JSON / je prázdná / má víc než 15 MB |
| `neplatny_manifest`, `nesouhlasi_id` | manifest registrovaného poskytovatele neprošel / má jiné `provider.id` |
| `registrace_nedostupna`, `prilis_mnoho_pozadavku`, `fronta_plna`, `manifest_neprosel`, `id_obsazeno`, `url_registrovana`, `zamitnuto` | chyby [registrace](#registrace) |
| `data_mimo_schema` | data od zdroje neodpovídají schématu |
| `prazdna_odpoved`, `pomala_odpoved` | testovací dotaz vrátil 0 objektů / trval přes 3 s |
| `dlazdice_http_chyba`, `dlazdice_neni_obrazek`, `dlazdice_nedostupna` | testovací rastrová dlaždice selhala |
| `chyba_zdroje` | jiná chyba při komunikaci se zdrojem (podrobnosti v `message`) |
| `neplatny_dotaz`, `neznama_sada`, `rastrova_sada`, `neplatny_vstup`, `interni_chyba` | chyby dotazu na portál |
| `chybi_misto`, `nezname_misto` | dotaz na místo bez bodu i místa / místo (adresa, obec) se nepodařilo najít |
| `chybi_vyber_sad` | dotaz na okolí bez `sady`, `ucel` i `hledat` |
| `souhrn_jen_pro_misto` | sada se dá načíst jen po přiblížení, souhrn za celé území nemá – zadejte obec |
| `nezname_schema`, `neznamy_priklad` | neexistující schéma / příklad (odpověď obsahuje seznam `dostupne`) |
