REST API
Malé, záměrně úzké API na čtení a úpravy map z vlastního kódu. Úkol je uzel s řešitelem nebo termínem — žádný samostatný úkolový objekt neexistuje. Je to tatáž plocha, nad kterou stojí MCP server.
Hledáte hotový příklad?
Napojení na Google Sheets je celý recept krok za krokem — kód pro Apps Script i pro n8n, včetně ošetření konfliktu 409.
- Platí pro cloud i vlastní server — hostovaná instance (
vasefirma.killbottleneck.com) má stejné API jako instalace u vás; liší se jen adresa - Základní cesta:
/api/kb/v1— starší prefix/api/flowmap/v1míří na tytéž handlery - Autentizace: API klíč v hlavičce
Authorization. Nikdy ne přes session cookie ani JWT - Formát: JSON dovnitř, JSON ven
- Jazyk: záměrně jen anglicky
Autentizace
Klíč si vytvoříte v aplikaci pod uživatelským menu. Token v čitelné podobě se ukáže jednou — ukládá se jen jeho SHA-256 otisk, takže ztracený klíč nejde získat zpět, jen rotovat.
Authorization: Bearer kb_user_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXKlíče vydané před přejmenováním začínají fm_user_ a fungují dál.
Rozsahy
| Rozsah | Smí volat |
|---|---|
read | všechny GET endpointy |
read_write | všechno včetně POST endpointů |
Klíč s rozsahem read dostane na zápisovém endpointu 403. Výchozí rozsah nového klíče je read.
Co klíč nikdy nemůže
- Vlastník se bere z klíče, nikdy z těla požadavku. Klíč dosáhne jen na mapy a uzly účtu, který ho vytvořil.
- Klíč nemůže eskalovat. Server pro něj nikdy nezakládá session a nečte roli účtu, takže přes API klíč nejdou dělat správcovské věci.
- Cizí ID mapy vrátí 404, ne 403 — API nepotvrzuje, že nějaké ID existuje.
Limity
| Limit | Hodnota |
|---|---|
Požadavků za minutu, read | 120 na klíč |
Požadavků za minutu, read_write | 30 na klíč |
| Tělo požadavku | 2 MB |
| Položek na jedno volání (uzly) | 200 |
| Klíčů na účet | 20 |
Čtení a zápis se počítají zvlášť, takže hromadné čtení nevyhladoví vaše zápisy. Přes limit dostanete 429.
Optimistické zamykání
Každý endpoint, který mění existující mapu, vyžaduje base_updated — hodnotu updated, kterou jste dostali při posledním načtení mapy.
GET /api/kb/v1/maps/{id} → { "updated": "2026-07-30 08:12:44.031Z", … }
POST /api/kb/v1/maps/{id}/nodes ← { "base_updated": "2026-07-30 08:12:44.031Z", … }Když ji vynecháte, dostanete 400. Když pošlete starou, dostanete 409 — někdo mapu mezitím změnil. Načtěte mapu znovu, znovu aplikujte svou změnu a zkuste to znovu.
Je to záměr: znemožňuje to „zapsat bez přečtení“, což je přesně ta chyba, kterou dělá překotný AI asistent.
Endpointy
GET /api/kb/v1/maps
Vypíše mapy vlastníka klíče.
| Parametr | Význam |
|---|---|
archived=1 | místo aktivních vypíše archivované |
{
"maps": [
{ "id": "abc123", "title": "Nový web", "node_count": 14, "updated": "2026-07-30 08:12:44.031Z" }
]
}GET /api/kb/v1/maps/{id}
Jedna mapa jako strom. Bez souřadnic na plátně — tvar, ne kresba.
{
"id": "abc123",
"title": "Nový web",
"description": "",
"archived": false,
"updated": "2026-07-30 08:12:44.031Z",
"tree": [ { "id": "n_1", "title": "Texty", "status": "todo", "children": [] } ],
"notes": []
}Hodnotu updated si nechte — potřebujete ji jako base_updated pro každý zápis.
POST /api/kb/v1/maps
Založí mapu z osnovy. Vyžaduje read_write.
| Pole | Povinné | Význam |
|---|---|---|
title | ano | Název mapy, ořezaný na 200 znaků |
tree | ne | Pole položek (viz níže); celkem max 200 uzlů |
description | ne | Volný text |
apex_text | ne | Text kořenového cíle; výchozí je title |
Každá položka v tree může nést title, description, deadline, owner, status, wait_for_children a children. Rozmístění se dopočítá samo.
Vrací { id, title, updated, tree }.
POST /api/kb/v1/maps/{id}/nodes
Přidá podstrom. Vyžaduje read_write.
| Pole | Povinné | Význam |
|---|---|---|
base_updated | ano | Verze, kterou jste načetli (viz optimistické zamykání) |
items | ano | Pole položek, aspoň jedna, max 200 |
parent_id | ne | Kam připojit; vynechané = pod vrchol |
Vrací { updated, added_ids, tree }.
Tohle přepočítá rozmístění celé mapy
Přidání uzlů posune pozice napříč mapou. Není to chirurgický vpich.
POST /api/kb/v1/maps/{id}/nodes/{nodeId}
Upraví jeden uzel. Vyžaduje read_write a base_updated.
Nastavitelná pole: title, status (todo / in_progress / done), description, deadline (YYYY-MM-DD, prázdný řetězec maže), owner (e-mail, prázdný řetězec maže), wait_for_children, color, executor_kind, executor_name, automation_wanted, automation_note.
Nastavení status na done má záměrně vedlejší účinky: může odblokovat čekající uzly, upozornit jejich řešitele a spustit automatizace, které na nich visí.
POST /api/kb/v1/maps/{id}/nodes/{nodeId}/delete
Smaže uzel včetně celého podstromu. Vyžaduje read_write a base_updated.
Vrchol smazat nejde a celé mapy přes API smazat nejdou vůbec. Není žádné zpět — nejdřív si mapu načtěte a zkontrolujte ID.
GET /api/kb/v1/maps/{id}/rules
Automatizační pravidla mapy („když X → udělej Y“) — id, název, enabled, spouštěč, podmínky, akce, last_fired (poslední časový běh — schedule/deadline_approaching; u událostních pravidel zůstává prázdné) a last_error (neprázdná chyba = pravidlo je rozbité a vlastník mapy o tom dostal zprávu).
POST /api/kb/v1/maps/{id}/rules
Založí pravidlo. Vyžaduje read_write. Limity jsou jen strukturální: 50 pravidel na mapu, 10 akcí a 20 podmínek na pravidlo — počet spuštění se nepočítá ani neúčtuje. Pravidlo platí jen do budoucna, nikdy zpětně.
| Pole | Povinné | Význam |
|---|---|---|
name | ano | název (max 120 znaků) |
trigger | ano | {"type": …} — node_status_changed (volitelně status), node_unblocked, deadline_approaching (when: before/overdue, days 0–365), node_created, file_uploaded, schedule (freq: daily/weekly, weekday 1–7, hour 0–23) |
actions | ano | pole 1–10 akcí, vykonají se popořadě: set_status, set_owner (e-mail člena nebo dynamický cíl deputy_of_node_owner), set_deadline (date, relative_days, nebo advance = daily/weekly/monthly — posune stávající termín cíle o interval a drží rytmus od původního termínu: každé pondělí zůstane pondělí, 31. zůstává 31. s clampem v kratších měsících; prošlé výskyty přeskočí na nejbližší budoucí) — tyto tři umí target: trigger_node (výchozí) / parent / id uzlu, move_node (to = id nového rodiče; přesune SPOUŠTĚCÍ uzel na konec jeho řady — kanban posun; vrchol, zmizelý cíl nebo cyklus = přiznaný skip v logu), create_subnodes (items = stejný strom jako add_nodes, max 50 uzlů), notify (to: node_owner/deputy_of_node_owner/map_owner/e-mail, message), run_agent (agent_name z registru) |
conditions | ne | AND řetěz {field, op, value} — field: status/owner/deadline/executor_kind/parent (id nadřazeného uzlu — „karta pod sloupcem", jen eq/ne); op: eq/ne/empty/not_empty/before/after (jen termín, YYYY-MM-DD) |
node_id | ne | pravidlo jen pro jeden uzel; povinné u schedule pravidel s akcemi na uzel |
enabled | ne | výchozí true |
Časové triggery běží v průběhu hodiny po nastavené hodině (lokální čas serveru) — žádný slib „přesně o půlnoci“; po výpadku se doženou týž den. deadline_approaching s when=overdue vystřelí, když je termín propadlý aspoň days dní — chytí i termíny propadlé dřív, než pravidlo vzniklo — a vystřelí jednou na daný termín (změněný termín smí vystřelit znovu); when=before platí přesně pro den (termín − days). Řetězení pravidel (akce spustí další pravidlo) je dovolené do hloubky 3, pak běh skončí přiznaným skipped záznamem v logu.
Dynamické cíle se rozřeší až za běhu pravidla, ne při uložení — výměna lidí ve firmě pravidlo nerozbije. deputy_of_node_owner = zástupce zodpovědné osoby trigger uzlu: přednost mají zástupci pozic z organizační struktury (víc pozic s různými zástupci → notify jde všem, set_owner se přiznaně přeskočí s radou zacílit konkrétní pozici), osobní zástupce ze Správy organizace je záloha. position:<nodeId> / deputy_of_position:<nodeId> cílí držitele/zástupce pozice org struktury (id vypíše GET /v1/org-structure). Nerozřešitelný cíl (bez zástupce, neobsazená či smazaná pozice) akci přeskočí a log běhu to přizná — pravidlo se NEoznačí za rozbité. Cíle odvozené od trigger uzlu potřebují u celomapového schedule pravidla node_id; cíle position: ne.
POST /api/kb/v1/maps/{id}/rules/{ruleId}
Upraví pravidlo. Jen {"enabled": true/false} = zapnout/vypnout; jinak pošlete celý nový tvar (částečné úpravy polí se neslévají). Úprava vynuluje chybový stav pravidla.
POST /api/kb/v1/maps/{id}/rules/{ruleId}/delete
Smaže pravidlo. Log jeho běhů zůstává (se snímkem názvu).
GET /api/kb/v1/maps/{id}/rule-runs
Log běhů pravidel mapy (nejnovější první, max 100). ?rule= omezí na jedno pravidlo. status: ok / failed / skipped (pojistka proti smyčce nebo strop na jedno uložení — detail říká který).
GET /api/kb/v1/rule-templates
Knihovna šablon pravidel celé instance (tvar pravidla bez mapy a bez scope uzlu). Šablona se „načítá“ tak, že její trigger/conditions/actions pošlete do POST …/rules cílové mapy — vznikne nezávislá kopie.
POST /api/kb/v1/rule-templates
Založí (nebo s id upraví — jen autor či admin) šablonu: name (unikátní), trigger, actions, volitelně conditions. Šablona nesmí mít node_id a create_subnodes smí mířit jen na trigger_node. Vyžaduje read_write.
POST /api/kb/v1/rule-templates/{id}/delete
Smaže šablonu (jen autor či admin). Pravidla z ní načtená v mapách zůstávají.
GET /api/kb/v1/org-structure
Organizační struktura (org mapa): pozice a funkce s id uzlů, držiteli a zástupci. Odpověď: {exists, map_id, positions: [{node_id, title, position_kind, holder, deputy}]}, kde position_kind je position (daná strukturou) nebo function (jmenovaná). node_id použijte jako dynamický cíl pravidla position:<nodeId> (držitel) nebo deputy_of_position:<nodeId> (zástupce té pozice) — obojí se rozřeší až za běhu, výměna lidí pravidla nerozbije. Archivovaná org mapa platí všude jako „struktura neexistuje" (exists: false, cíle na pozice se přiznaně přeskočí). Jen čtení: držitele a zástupce jmenuje admin v aplikaci (Správa organizace) — kontrakt API klíčů role nikdy nečte, zápisový endpoint tu proto není.
/api/kb/v1/tasks — odstraněno
Úkolové endpointy (GET/POST /v1/tasks, POST /v1/tasks/{id}) byly odstraněny a vrací 410 Gone. Úkol v killBottlenecku není samostatný záznam: úkol je uzel s řešitelem (owner) nebo termínem. Nová práce = nový uzel. Práce se zakládá a upravuje přes /v1/maps/{id}/nodes (MCP: add_nodes, update_node); úkol se odbavuje nastavením status na done.
Příklad od začátku do konce
KEY="kb_user_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
HOST="http://localhost:8090"
# 1) najít mapu
curl -s -H "Authorization: Bearer $KEY" "$HOST/api/kb/v1/maps"
# 2) načíst ji — a schovat si `updated`
MAP=abc123
UPDATED=$(curl -s -H "Authorization: Bearer $KEY" "$HOST/api/kb/v1/maps/$MAP" \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["updated"])')
# 3) přidat dva cíle pod vrchol
curl -s -X POST -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d "{\"base_updated\":\"$UPDATED\",\"items\":[
{\"title\":\"Napsat texty\",\"deadline\":\"2026-08-15\"},
{\"title\":\"Nafotit fotky\"}]}" \
"$HOST/api/kb/v1/maps/$MAP/nodes"Chybové kódy
Celou tabulku najdete v Chybových kódech.

