Integrace do sjednavače

Dokument pro vývojáře sjednavače. Popisuje, co je hotové, co máte udělat a co udělat nesmíte.

K napojení vám stačí tahle stránka a API klíč. Zdrojový kód mít nemusíte — je užitečný jen tehdy, když chcete převzít hotovou React komponentu místo psaní vlastního UI (sekce 3).

API https://adresy.evidentum.cz
tahle příručka https://adresy.evidentum.cz/
interaktivní popis endpointů https://adresy.evidentum.cz/docs
stav služby https://adresy.evidentum.cz/api/health

Na /docs je Swagger — dá se z něj volat rovnou v prohlížeči (vložte klíč přes tlačítko Authorize) a je vždy generovaný z běžícího kódu.


1. K čemu to je

Pojišťovna vyžaduje v payloadu kód adresního místa RÚIAN. Tahle služba ho dodá: uživatel vybere adresu z našeptávače, vy dostanete kód.

uživatel píše ──> našeptávač ──> vybere adresu ──> resolve ──> kód RÚIAN ──> payload

Nemusíte řešit RÚIAN, ČÚZK, ani normalizaci adres. Voláte jedno API.


1b. Přístup — API klíč

Produkční služba běží na https://adresy.evidentum.cz.

Každý partner (každá pronajatá instance sjednavače) má vlastní API klíč. Posílá se v hlavičce u každého volání kromě /api/health a /api/stats:

X-Api-Key: ruian_xxxxxxxxxxxxxxxxxxxxxxxx

Ke klíči je vedený seznam povolených originů. Volání z jiného originu skončí 403, chybějící nebo neplatný klíč 401.

Co klíč je a co není. Cestuje v prohlížeči, takže ho jde najít ve zdroji stránky — není to tajemství a nespoléhejte na něj jako na ochranu. Slouží k tomu, aby šla spotřeba kreditů přiřadit partnerovi, aby šel partner odpojit bez dopadu na ostatní a aby měl rate limit co počítat.

Nový partner nebo nová doména = jeden řádek v registru na serveru. Žádný redeploy, žádný restart — projeví se to samo.

2. Co dostanete

API čtyři endpointy (adresy + parcely), běží na naší straně
React komponenta AddressAutocomplete a ParcelPicker — hotová pole včetně dropdownu, výběru kandidátů a chybových stavů

Zapojit to jde dvěma způsoby:


3. Varianta A — React komponenta

Hotové pole, které si řeší dropdown, ovládání klávesnicí, výběr u nejednoznačné adresy i chybové stavy. Soubory (AddressAutocomplete.tsx, types.ts, styles.css) jsou v našem repozitáři — pokud tuhle variantu chcete, řekněte si o přístup. Bez něj použijte variantu B, API je stejné.

import { AddressAutocomplete } from "./AddressAutocomplete";

const [ruian, setRuian] = useState<number | null>(null);

<AddressAutocomplete
  apiBase="https://adresy.evidentum.cz"
  apiKey="ruian_vas_klic"
  onResolved={(a) => setRuian(a.ruianAddressPointCode)}
  onCleared={() => setRuian(null)}
/>

<button disabled={!ruian} onClick={odeslat}>Odeslat na pojišťovnu</button>

Props

prop povinný popis
apiBase ano https://adresy.evidentum.cz
apiKey ano partnerský klíč, viz sekce 1b
onResolved ano adresa je potvrzená a má kód RÚIAN
onCleared ano adresa už neplatí — zahoďte uložený kód
houseNumberType ne popisne / evidencni — odstraní nejednoznačnost, viz níže
label ne popisek pole, výchozí „Adresa"
placeholder ne výchozí „Začněte psát ulici a číslo…"
debounceMs ne prodleva před dotazem, výchozí 300
minChars ne od kolika znaků se našeptává, výchozí 3

onResolved vám předá celý objekt adresy — strukturované části i kód:

{
  "street": "Krakovská",
  "houseNumber": 1363,
  "orientationNumber": 12,
  "orientationLetter": null,
  "cityPart": "Nové Město",
  "city": "Praha",
  "postalCode": "11000",
  "countryCode": "CZ",
  "displayAddress": "Krakovská 1363/12, Praha 1 - Nové Město, 110 00",
  "ruianAddressPointCode": 21711470,
  "normalizedAddress": "Krakovská 1363/12, Nové Město, 11000 Praha 1",
  "codes": {
    "obecKod": 554782, "obecNazev": "Praha",
    "castObceKod": 490148, "castObceNazev": "Nové Město",
    "momcKod": 500054, "momcNazev": "Praha 1",
    "stavebniObjektKod": 21658544, "parcelaId": 2071976101
  },
  "sourceAutocomplete": "mapy_com",
  "sourceResolver": "cuzk_ruian",
  "resolvedAt": "2026-08-03T18:42:11+00:00"
}

Komponenta si sama řeší dropdown, klávesnici, loading, výběr kandidátů u nejednoznačné adresy i chybové hlášky. Vy řešíte jen kód a blokaci odeslání.

Parcela — ParcelPicker

Pro nemovitost bez čísla popisného. Pole kopírují formulář sjednavače: katastrální území (našeptávané), parcelní číslo, typ parcely.

import { ParcelPicker } from "./ParcelPicker";

<ParcelPicker
  apiBase="https://adresy.evidentum.cz"
  onResolved={(p) => setParcelId(p.ruianParcelId)}
  onCleared={() => setParcelId(null)}
/>

Stejný kontrakt jako u adresy — onCleared je stejně povinný a ze stejného důvodu. Přepínání mezi režimem „číslo popisné" a „bez čísla" musí zahodit předchozí výsledek; v demu (App.tsx) je to vidět ve funkci switchMode.


4. Varianta B — vlastní UI

GET /api/address/autocomplete?query=<text>&limit=<n>

Volejte při psaní, s debounce (viz sekce 7 — kredity).

{
  "suggestions": [
    {
      "displayAddress": "Sokolovská 694/100a, Karlín, 18600 Praha 8",
      "street": "Sokolovská",
      "houseNumber": 694,
      "orientationNumber": 100,
      "orientationLetter": "a",
      "cityPart": "Karlín",
      "city": "Praha 8",
      "postalCode": "18600",
      "countryCode": "CZ",
      "sourceRef": "cuzk:1153888"
    }
  ],
  "sourceAutocomplete": "mapy_com"
}

Endpoint nikdy nevrací chybu — když je zdroj nedostupný, přijde prázdný seznam. Našeptávač, který hodí chybu, by zablokoval psaní.

sourceRef nepřekládejte ani neupravujte, jen ho přiložte k resolve.

POST /api/address/resolve-ruian

Volejte až po výběru konkrétní položky, ne při psaní. Jako tělo pošlete vybraný návrh beze změny.

{
  "resolveStatus": "success",
  "ruianAddressPointCode": 78506778,
  "normalizedAddress": "Sokolovská 694/100a, Karlín, 18600 Praha 8",
  "latitude": 50.0784286,
  "longitude": 14.4282364,
  "codes": {
    "obecKod": 554782,        "obecNazev": "Praha",
    "castObceKod": 490148,    "castObceNazev": "Nové Město",
    "momcKod": 500054,        "momcNazev": "Praha 1",
    "stavebniObjektKod": 21658544,
    "parcelaId": 2071976101
  },
  "candidates": [],
  "sourceResolver": "cuzk_ruian",
  "resolvedAt": "2026-08-03T18:42:11+00:00",
  "fromCache": false
}

Souřadnice

latitude a longitude jsou ve WGS84 (běžné GPS, stejné jako Google Maps) a patří samotnému adresnímu bodu — ne středu ulice ani obce.

RÚIAN je vede v S-JTSK; převod dělá ČÚZK na své straně, takže nic nepřepočítáváte ani vy, ani my.

Územní kódy (codes)

pole co to je
obecKod / obecNazev obec
castObceKod / castObceNazev část obce
momcKod / momcNazev městský obvod / městská část
stavebniObjektKod stavební objekt, na kterém adresní místo leží
parcelaId parcela, na které stavební objekt stojí

momcKod je null mimo Prahu a statutární města — městské části jinde neexistují. Nevalidujte ho jako povinný.

Blok codes je vyplněný jen u success. U ambiguous ho kandidáti nenesou — viz níže.

Doresolvování podle kódu

Když uživatel vybere z candidates, nemáte územní kódy. Doptejte se přes sourceRef:

POST /api/address/resolve-ruian
{ "sourceRef": "ruian:78506778" }

Vrátí totéž co success včetně codes. Naše komponenta to dělá sama. Použijte to i pro přeověření adresy uložené v DB — stačí vám kód.

Číslo popisné vs. evidenční — řeší se v nabídce

Našeptávač obě varianty rozlišuje už jako dva samostatné řádky:

Labuť 3, Staré Sedliště - Labuť, 348 01           houseNumberType: "popisne"
Labuť ev. č. 3, Staré Sedliště - Labuť, 348 01    houseNumberType: "evidencni"

Každý návrh nese houseNumberType. Když ho přepošlete beze změny do resolve (což je doporučený postup — poslat celý objekt návrhu), vrátí se rovnou success se správným kódem:

vybraný řádek výsledek
Labuť 3 success, kód 15636844
Labuť ev. č. 3 success, kód 15637344

Uživatel vybírá jednou. Žádný druhý select, žádné ambiguous.

Pokud si stavíte tělo požadavku sami, nezapomeňte houseNumberType přiložit — bez něj se obě varianty vyřeší stejně a vrátí se ambiguous s kandidáty, tedy druhý výběr navíc.

Typ čísla ve vašem formuláři

Pokud máte typ čísla jako samostatné pole ve formuláři (popisné / evidenční / bez čísla), můžete ho poslat taky — přebije to, co přišlo z našeptávače:

Typ čísla co poslat
popisné houseNumberType: "popisne"
evidenční houseNumberType: "evidencni"
bez čísla režim parcely, viz sekce 4b

Když pole „Typ čísla" nemáte, nic se neděje — hodnota z našeptávače stačí.

Čtyři stavy, které musíte obsloužit

resolveStatus co to znamená co udělat
success kód je v ruianAddressPointCode uložit, odemknout odeslání
ambiguous adresa sedí na víc míst, seznam je v candidates nechat uživatele vybrat, pak použít kód vybraného kandidáta
not-found v RÚIAN taková adresa není nechat upravit zadání a vybrat znovu
error služba je dočasně nedostupná, důvod v message zobrazit hlášku, neodesílat

U ambiguous vypadá candidates takhle. Kód adresního místa v nich je, ale územní kódy ne — po výběru se doptejte přes sourceRef, viz výše:

"candidates": [
  { "ruianAddressPointCode": 15636844, "normalizedAddress": "Labuť 3, 34801 Staré Sedliště" },
  { "ruianAddressPointCode": 15637344, "normalizedAddress": "Labuť č.ev. 3, 34801 Staré Sedliště" }
]

Provozní endpointy

GET /api/health — stav a jestli je nakonfigurovaný klíč k Mapy.com. GET /api/stats — počty podle statusu, podíl z cache, průměrná doba.


4b. Parcely

Parcela není adresa a nehledá se jako adresa. Nemá ulici ani číslo popisné. Identifikuje ji katastrální území plus parcelní číslo — a číslo samo o sobě nestačí.

Proč nestačí číslo

V katastrálním území Přimda existuje parcelní číslo 233 dvakrát:

id RÚIAN výměra
St. 233 — stavební parcela 675238410 180 m²
233 — pozemková parcela 675655410 324 m²

Dva různé pozemky. A není to výjimka: v tom jediném katastrálním území je do čísla 300 celkem 79 stavebních a 172 pozemkových parcel, řada se překrývá.

Proto je numberingType součást identity parcely, ne filtr. Formulář, který ho neumožní zadat, parcelu ve většině republiky neurčí. V uživatelském rozhraní je to prostě přepínač „St." před polem s číslem.

Praha je výjimka — čísluje v jedné řadě a stavební parcely tam nejsou vůbec.

GET /api/parcel/cadastral-areas?query=<text>

Našeptávání katastrálních území. Dotazuje jen ČÚZK, takže nestojí kredity.

[
  { "kod": 727181, "nazev": "Nové Město", "obecKod": 554782, "obecNazev": "Praha" },
  { "kod": 706418, "nazev": "Nové Město na Moravě", "obecKod": 595462, "obecNazev": "Nové Město na Moravě" }
]

Katastrálních území stejného jména je víc — proto se v nabídce zobrazuje obec.

POST /api/parcel/resolve-ruian

{
  "cadastralAreaCode": 736112,
  "parcelNumber": "1375/42",
  "numberingType": "building"
}
pole popis
cadastralAreaCode kód KÚ z našeptávače. Preferujte ho.
cadastralAreaName + municipality alternativa, když kód nemáte
parcelNumber celé číslo tak, jak ho uživatel napsal1375/42, 233, St. 233
numberingType building (St.) nebo land. Výchozí land.
stemNumber + subdivisionNumber alternativa k parcelNumber, když už máte číslo rozložené

parcelNumber je jedno textové pole, protože přesně tak to má formulář sjednavače. Rozložení na kmenové číslo a podlomení řešíme my. Prefix St. v textu přebije hodnotu v numberingType — kdo napíše St. 233, chce stavební parcelu, ať je v selectu cokoli.

{
  "resolveStatus": "success",
  "ruianParcelId": 675238410,
  "parcelNumber": "233",
  "numberingType": "building",
  "cadastralAreaCode": 736112,
  "cadastralAreaName": "Přimda",
  "obecKod": 561151,
  "obecNazev": "Přimda",
  "areaSquareMetres": 180.0,
  "latitude": 49.6759536,
  "longitude": 12.6732778,
  "postalCode": "34806",
  "postalCodeSource": "odvozeno z 41 z 41 adresnich mist do 150 m"
}

PSČ u parcely je odvozené, ne z registru

Pojišťovny PSČ u pozemků vyžadují, ale RÚIAN vazbu parcela → PSČ nemá. PSČ je vlastnost adresního místa a pozemek žádné mít nemusí — u pole nebo lesa prostě neexistuje.

Bereme proto PSČ, které převládá mezi adresními místy nejblíž parcele. Hledá se v okruhu 150 m, a když tam není nic, postupně 500 m a 2 km.

postalCodeSource popisuje, jak hodnota vznikla:

"odvozeno z 13 z 13 adresnich mist do 150 m"    ← jednomyslné
"odvozeno z 46 z 50 adresnich mist do 150 m"    ← převažující

Ukládejte postalCodeSource spolu s PSČ. Odvozený údaj musí jít odlišit od údaje z registru — kód parcely a souřadnice jsou z RÚIAN, PSČ ne. U reklamace je to rozdíl, na kterém záleží.

Když se PSČ odvodit nepodaří, přijde null — parcela se tím nezneplatní, identifikátor je ruianParcelId.

Souřadnice parcely

latitude / longitude ve WGS84 ukazují na definiční bod parcely (vnitřní bod plochy), ne na její roh ani na budovu.

Stavy jsou stejné čtyři jako u adres. ambiguous tu znamená i nejednoznačné katastrální území — pak je vyplněné message a uživatel musí upřesnit obec.

ruianParcelId je pro parcelu totéž, co kód adresního místa pro adresu.

subdivisionNumber: null znamená parcelu bez podlomení. Číslo 233 a 233/7 jsou různé pozemky, resolver je nezaměňuje.


5. Pravidla, která musíte dodržet

Bez kódu se neodesílá. Formulář nesmí jít odeslat, dokud nemáte ruianAddressPointCode. Platí i pro ambiguous — kandidáti nejsou výsledek, dokud uživatel nevybere.

Při změně pole zahoďte kód. Když uživatel po potvrzení adresu upraví, starý kód musí okamžitě zmizet. Tohle dělá onCleared. Když to neuděláte, odejde na pojišťovnu kód patřící k jiné adrese — a nikde to nebude vidět, protože adresa i kód budou samy o sobě vypadat platně. Nejhorší možná chyba v celé integraci.

Kód nikdy neskládejte ani neodvozujte na frontendu. Vždy jen ten, co přišel z resolve. Neukládejte si mapování „adresa → kód" u sebe.

Ukládejte i normalizovanou adresu. normalizedAddress je tvar z registru. Když bude reklamace, dohledá se podle něj, co přesně uživatel vybral.

Resolve nevolejte při psaní. Jen po výběru položky.


6. Co je čí

kdo
našeptávání, překlad adresy na kód RÚIAN, fallback stavy my
uložení adresy a kódu do vaší DB vy
blokace odeslání formuláře vy
složení payloadu pro webovou službu pojišťovny vy
validace ostatních polí formuláře vy

7. Kredity a limity

Našeptávač jede přes Mapy.com. Basic tarif = 250 000 kreditů měsíčně zdarma, jeden dotaz stojí 4 kredity → 62 500 dotazů měsíčně.

Při debounce 300 ms vychází jedna vyplněná adresa zhruba na 4 dotazy, tedy ~15 000 vyplnění měsíčně. Resolve proti ČÚZK je zdarma a bez limitu, platí se jen za psaní.

Proto: nesnižujte debounceMs a nevolajte našeptávač od prvního znaku. Každý ušetřený keystroke je ušetřený kredit.


8. Na co si dát pozor

Číslo popisné vs. evidenční. „Labuť 3" a „Labuť č.ev. 3" jsou dvě různé adresy se dvěma různými kódy. Proto u nich přijde ambiguous. Nevybírejte první — nechte vybrat uživatele.

Adresy bez ulice. Na vesnicích ulice neexistuje a street je null. Nevalidujte ho jako povinné pole; povinný je houseNumber, city, postalCode a kód RÚIAN.

Městská část jen ve velkých městech. momcKod je null všude mimo Prahu a statutární města.

Stavební vs. pozemková parcela. Bez numberingType parcelu neurčíte — viz sekce 4b.

Psaní bez diakritiky a malými písmeny funguje. ČÚZK porovnává názvy case-sensitive a bez tolerance diakritiky, takže slan ani nove m by samy o sobě nenašly nic — řešíme to na naší straně. Vy nemusíte nic normalizovat.

Diakritika v payloadu. Adresy chodí v UTF-8 s diakritikou. Ověřte si, že ji vaše serializace do payloadu pro pojišťovnu přenese beze změny.

Latence. Resolve trvá 200–900 ms podle toho, jestli je adresa v cache. Počítejte s tím v UI, komponenta na to má spinner.


9. Jak si to vyzkoušet hned

Nemusíte nic instalovat. Nejrychlejší je Swagger na https://adresy.evidentum.cz/docs — vložte klíč přes tlačítko Authorize a volejte přímo z prohlížeče.

Nebo z příkazové řádky:

curl -H "X-Api-Key: VAS_KLIC"   "https://adresy.evidentum.cz/api/address/autocomplete?query=Sokolovsk%C3%A1%20694"

curl -X POST -H "X-Api-Key: VAS_KLIC" -H "Content-Type: application/json"   -d '{"street":"Krakovská","houseNumber":1363,"orientationNumber":12,"city":"Praha","postalCode":"110 00"}'   https://adresy.evidentum.cz/api/address/resolve-ruian

Vstupy, na kterých se dá chování osahat:

vstup co se stane
Krakovská 1363/12 success, kód 21711470
Sokolovská 694/100a success — pozor na písmeno, 694/100 je jiná adresa
Labuť 3 ambiguous — č.p. vs č.ev., viz houseNumberType
KÚ Přimda, 233, stavební vs pozemková dvě různé parcely se stejným číslem

Stav služby kdykoli na https://adresy.evidentum.cz/api/health. Hlídejte status — hodnota jiná než "ok" znamená, že našeptávač jede z náhradního zdroje a je horší, i když odpovídá.


10. Stav služby

Služba je nasazená na produkci, běží na HTTPS a našeptávání zajišťuje Mapy.com. Po každém nasazení projíždí kontrola 13 bodů proti živým datům: adresy, územní kódy, obě parcely s kolidujícím číslem a ověření, že API bez klíče odmítne.

Kdyby něco nefungovalo, pošlete nám prosím:

Nejčastější dva stavy: 401 znamená chybějící nebo neplatný klíč, 403 znamená, že doména, ze které voláte, není u klíče povolená — v tom případě nám tu doménu napište a přidáme ji.