🧪 killBottleneck je ve veřejné betě — cloud i self-host.🧪 killBottleneck je v betě.Beta na GitHubu →
Skip to content

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/v1 míří 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_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Klíče vydané před přejmenováním začínají fm_user_ a fungují dál.

Rozsahy

RozsahSmí volat
readvšechny GET endpointy
read_writevš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

LimitHodnota
Požadavků za minutu, read120 na klíč
Požadavků za minutu, read_write30 na klíč
Tělo požadavku2 MB
Položek na jedno volání (uzly)200
Klíčů na účet20

Č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.

ParametrVýznam
archived=1místo aktivních vypíše archivované
json
{
  "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.

json
{
  "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.

PolePovinnéVýznam
titleanoNázev mapy, ořezaný na 200 znaků
treenePole položek (viz níže); celkem max 200 uzlů
descriptionneVolný text
apex_textneText 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.

PolePovinnéVýznam
base_updatedanoVerze, kterou jste načetli (viz optimistické zamykání)
itemsanoPole položek, aspoň jedna, max 200
parent_idneKam 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ě.

PolePovinnéVýznam
nameanonázev (max 120 znaků)
triggerano{"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)
actionsanopole 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)
conditionsneAND ř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_idnepravidlo jen pro jeden uzel; povinné u schedule pravidel s akcemi na uzel
enablednevý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

bash
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.

fair-code — self-hosting a interní použití zdarma, přeprodej jako hostovaná služba ne.