API
HTTP API, na kterém stojí každý klient Nessie, a jak se k němu ověřit.
Co je API
Nessie má jedno HTTP API. Webová aplikace pro správu, klienti pro macOS a iOS i vzdálený démon executoru jsou všechny běžní klienti tohoto API a nic, co dokážou, nelze dosáhnout jinou cestou. Je to JSON API nad serverem Fastify, není to GraphQL a nemá žádnou oddělenou „veřejnou“ podmnožinu: rozhraní, které volají vaše vlastní skripty, je totéž rozhraní, které volá produkt.
V cestě není žádný segment verze. Každá trasa je pod /api, kromě příchozího koncového bodu MCP POST /mcp a několika dokumentů pro objevování na /.well-known/. Kompatibilitu držíme tak, že se pole pouze přidávají, takže klient, který neznámá pole ignoruje, dál funguje.
Základní URL
Nessie provozujete na vlastní infrastruktuře, takže základní URL je ten původ (origin), na kterém vaše nasazení obsluhuje API. Provozovatel jej nastaví jako NESSIE_API_PUBLIC_URL a stejná hodnota slouží API, kdykoli potřebuje vytvořit vlastní absolutní URL. Na instanci, kterou provozujeme my, je to https://api.nessie.works; vývojová instance spuštěná příkazem pnpm dev odpovídá na http://localhost:5454.
Webová aplikace pro správu je jiný původ než API, takže prohlížečoví klienti podléhají seznamu povolených CORS původů (NESSIE_CORS_ORIGINS). Požadavky ze skriptu nebo ze serveru žádný původ nemají, takže je tento seznam neovlivňuje.
Autentizace
Každý požadavek mimo malou sadu záměrně veřejných tras nese přístupový token ve standardní hlavičce:
Authorization: Bearer <token>Token je podepsaný JWT, který vydává API. Je krátkodobý, ve výchozím nastavení třicet minut (NESSIE_AUTH_TOKEN_TTL), a je jediným přihlašovacím údajem, který běžný volající kdy předkládá. Nessie nepoužívá dlouhodobé osobní klíče API. Pokud chcete, aby skript volal API, přihlásí se stejně jako prohlížeč dané osoby a průběžně si svůj token obnovuje.
Získání tokenu
POST /api/auth/session vytvoří relaci. Odpoví přístupovým tokenem a identitou volajícího a obnovovací token nastaví jako samostatnou cookie s příznakem HTTP-only.
Jak se prokazujete, závisí na tom, jak je instance nasazená. Instance běžící v režimu local přijímá e-mail a heslo. Na instanci hosted nebo selfHosted je přihlášení heslem rovnou odmítnuto s 403 PASSWORD_AUTH_DISABLED a jedinou cestou dovnitř je nakonfigurovaný poskytovatel identity. Účet tak nikdy nezíská druhou, slabší cestu k identitě vedle něj.
Přihlášení přes poskytovatele identity
Single sign-on je výměna autorizačního kódu OAuth s PKCE ve třech krocích. Vlastním poskytovatelem identity Nessie je UnlikeOtherAI, který také spravuje strukturu organizací a týmů, kterou instance zrcadlí; výměna níže má stejný tvar u kteréhokoli nakonfigurovaného poskytovatele.
GET /api/auth/providersvypíše, co tato instance přijímá; u každého je uvedenoproviderId, popisek a to, zda má přihlašovací stránka přesměrovat na něj automaticky.GET /api/auth/providers/:providerId/authorizes parametry dotazucodeChallenge,redirectUriastateodpoví hodnotou{ data: { authorizeUrl } }. Pošlete tam danou osobu.- Poskytovatel vrátí osobu na váš
redirectUris kódem. Ten pošlete zpět jakoPOST /api/auth/sessions{ providerId, code, codeVerifier, redirectUri }— všechny čtyři hodnoty jsou vyžadovány společně a neúplná sada vrátí400 EXTERNAL_AUTH_INCOMPLETE.
Obnovení relace
Obnovovací token se nikdy neobjeví v těle odpovědi. Je nastaven jako cookie s příznakem HTTP-only s názvem nessie_refresh, omezený na cestu /api/auth, s výchozí platností třicet dní (NESSIE_AUTH_REFRESH_TOKEN_TTL). Volání POST /api/auth/refresh s touto cookie jej spotřebuje, vydá nový přístupový token a místo něj nastaví novou cookie. Tokeny se rotují, takže ukradený token platí jen do chvíle, kdy se skutečný klient příště obnoví.
Prohlížeč, ve kterém je přihlášeno více účtů, si drží jednu takovou cookie pro každé přihlášení, pojmenovanou nessie_refresh_<slot>, a požadavek, který se týká konkrétního účtu, označí hlavičkou x-nessie-account-slot. Klient, který takovou hlavičku neposílá, se týká nessie_refresh, což je vše, co potřebuje klient z příkazové řádky.
Klient z příkazové řádky tedy potřebuje cookie jar. U curl je to --cookie-jar při přihlášení a --cookie při obnovení, jak ukazuje příklad níže.
Co se kontroluje u každého požadavku
Autentizace není jen kontrola podpisu. Před spuštěním obslužné funkce API ověří podpis a expiraci tokenu, potvrdí, že relace nebyla odvolána (jak podle verze tokenu platné pro celého uživatele, tak podle ID jednotlivé relace), a načte členství volajícího v organizaci, kterou token uvádí. Deaktivované členství vrací 403. Pokud je organizace napojena na externího poskytovatele identity, aktuální stav volajícího se u něj ověřuje přímo při požadavku a nečte se z tokenu. Přístup odebraný u poskytovatele tak přestane fungovat okamžitě, a ne až při dalším vypršení platnosti.
Přihlašovací údaje, které nejsou tokeny relace
Existují dva další přihlašovací údaje typu bearer a ani jeden z nich není univerzální klíč. Přihlašovací údaj hlasového zařízení se přijímá jen na trasách hovorů s hlasem a přístupový údaj agenta jen na koncovém bodu MCP. Předložení kteréhokoli z nich kdekoli jinde je odmítnuto s 403, které pojmenuje dotyčný přihlašovací údaj, a nezkouší se znovu jako slabší relace. Jak se přístupový údaj agenta vydává, je popsáno v MCP a připojené nástroje.
Obálka odpovědi
Každá úspěšná odpověď je objekt s klíčem data. Neexistuje holé pole ani obsah na nejvyšší úrovni, takže klient nikdy nemusí rozlišovat podle tvaru:
{
"data": { "id": "3f1c…", "label": "engineering" }
}Seznamové koncové body přidávají vedle něj objekt meta. Na nejvyšší úrovni se nepřidává nic jiného.
Chyby mají také jeden tvar, bez ohledu na to, co je způsobilo:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "A message needs content or at least one attachment",
"field": "body",
"details": { "formErrors": [], "fieldErrors": {} }
}
}code je strojově čitelná část a podle ní by se měl klient větvit; message je určena člověku. field a details jsou přítomny, když je chyba dost konkrétní, aby se dala lokalizovat. Neošetřená chyba serveru je vždy 500 INTERNAL_ERROR s pevnou zprávou. Původní text chyby se zaloguje, ale nikdy se nevrátí, protože mohl při cestě ven zachytit data z požadavku.
Kódy chyb, se kterými se setkáte nejdřív
| Stav | Kód | Význam |
|---|---|---|
| 400 | VALIDATION_ERROR | Tělo nebo dotaz neodpovídají schématu. |
| 401 | AUTH_REQUIRED | Chybí přístupový token nebo je hlavička poškozená. |
| 401 | TOKEN_EXPIRED | Přístupový token je po expiraci. Obnovte jej a zopakujte požadavek. |
| 401 | TOKEN_REVOKED | Relace byla odhlášena nebo byly všechny relace násilně ukončeny. |
| 403 | ACCOUNT_DEACTIVATED | Členství v této organizaci bylo deaktivováno. |
| 404 | NOT_FOUND | Taková trasa neexistuje, nebo volající nevidí žádný takový záznam. |
| 429 | RATE_LIMITED | Kvóta je vyčerpaná. Přečtěte si hlavičku Retry-After. |
| 500 | INTERNAL_ERROR | Neošetřená chyba serveru, záměrně neprůhledná. |
Stránkování
Seznamové koncové body stránkují pomocí neprůhledného kurzoru podle klíče (keyset), ne pomocí offsetu. Řádky se vkládají, zatímco je někdo čte, a s offsetem by druhá stránka tiše zopakovala záznam, který už ukázala první.
Přijímají se tři parametry dotazu: cursor, limit a direction (forward nebo backward). Výchozí stránka má 25 položek a horní strop je 100; vyšší hodnota se ořízne, místo aby byla odmítnuta. Koncové body, které také řadí nebo filtrují, přidávají sort, order a volný text q.
meta stránky vám řekne, kde se nacházíte:
{
"data": [ … ],
"meta": {
"hasMore": true,
"nextCursor": "2026-09-12T08:31:44.005Z|8b2f…",
"prevCursor": null,
"total": 134
}
}nextCursor a prevCursor jsou obě skutečné: Předchozí a Další jsou ovládací prvky, které člověk očekává. Jsou neprůhledné — server do nich zakóduje vlastní řadicí klíč a klient, který jeden z nich rozebírá nebo sestavuje, se rozbije ve chvíli, kdy seznam změní pořadí. total je přítomen u většiny seznamů a vynechán tam, kde počítání nedává smysl, například u výsledků hledání seřazených podle relevance.
Limity požadavků
Limity platí pro pevná časová okna a vynucují se dřív, než se vůbec přečte tělo požadavku. Zamítnutý požadavek dostane 429 s kódem RATE_LIMITED a hlavičkou Retry-After v sekundách.
Většina kvót je vázána na IP adresu klienta. Ty citlivé na přihlašovací údaje — přihlášení, obnovení, opakované ověření heslem a zápisy přihlašovacích údajů MCP — navíc vedou počítadlo pro každý účet a odmítnou, když překročí limit kterýkoli z nich. Jedna adresa rozesílající pokusy na mnoho účtů i jeden účet napadený z mnoha adres tak narazí na zeď. Přihlášení má výchozí hodnoty 10 pokusů na IP adresu a 5 na e-mailovou adresu za deset minut; odeslání zprávy 60 za minutu; zápisy pod /api/agents 60 za minutu. Každý práh lze nastavit pro konkrétní nasazení, takže tyto hodnoty berte jako výchozí, nikoli jako závazek. Kontroly stavu (health) a streamy v reálném čase jsou vyjmuty.
Realtime
Opakované dotazování seznamu je špatný způsob, jak sledovat konverzaci. Místo toho existují tři streamovací koncové body:
GET /api/events/stream— události odesílané serverem (SSE) pro vše, co přihlášená osoba vidí.GET /api/threads/:threadId/stream— SSE pro jedno vlákno. RespektujeLast-Event-ID, takže se opětovné připojení obnoví, místo aby začalo znovu.GET /api/activity— WebSocket, který přenáší kanál aktivity.
Prohlížeče nemohou nastavovat hlavičky při handshaku WebSocketu, proto trasa WebSocketu přijímá přístupový token také jako query parametr ?token=. Je to jediné místo, kam token v URL patří; každá další trasa jej bere z hlavičky.
Rodiny zdrojů
Koncových bodů je dobře přes tisíc, což je na výčet příliš mnoho. Seskupují se do rodin, a jakmile znáte předponu rodiny, jsou jednotlivé trasy předvídatelné: kolekce na předponě, záznam pod ní a pojmenované akce jako podcesty POST.
| Rodina | Předpona | Co pokrývá |
|---|---|---|
| Autentizace | /api/auth | Přihlášení, obnovení, odhlášení, aktuální identita a vlastní relace osoby. |
| Kanály a vlákna | /api/channels, /api/threads | Model konverzace: kanály obsahují vlákna, vlákna obsahují zprávy a odpovědi se vnořují pod svůj kořen. |
| Agenti | /api/agents | Definice agentů, jejich vazby na kanály, konverzace, úkoly a stav. |
| Projekty a nástěnky | /api/projects, /api/tasks, /api/iterations | Sledování práce: nástěnky a sloupce pod projektem, úkoly na nich a iterace nad nimi. |
| Znalosti | /api/knowledge-base | Prostory verzovaných stránek a souborů s komentáři, zpětnými odkazy a hledáním. |
/api/mail, /api/mailbox-connections | Propojené schránky, schránky agentů a koncepty, které agent připravil pro schválení osobou. | |
| Schválení | /api/approvals | Fronta akcí, které agent nesmí podniknout jednostranně, a jediné volání, které je vyřeší. |
| Audit | /api/audit-log | Hashovaně řetězená auditní stopa organizace s ověřovacím koncovým bodem. Pro vlastníky a správce. |
| Náklady a využití | /api/ledger, /api/billing | Účetnictví tokenů a nákladů, rozpočty a časy běhů; odděleně kredity a dobíjení. Pro vlastníky a správce. |
| Organizace a týmy | /api/organizations, /api/teams, /api/users | Správa organizace, týmů a členství, včetně pozvánek. |
| Spouštěče | /api/triggers | Plány a webhooky, které spouštějí práci agentů, s historií jejich spuštění. |
| Hovory a hlas | /api/calls, /api/voice | Hovory v kanálu a relace hlasového asistenta, jeho přepisy a tokeny zařízení. |
| Executory | /api/executors, /api/execution-environment-templates | Stroje, na kterých agenti pracují, jejich prostředí a kanál párování démona. |
| Běhy | /api/runs | Živé běhy agentů: zrušit, pokračovat, restartovat, navázat na executor. |
| Nahrávání | /api/uploads, /api/attachments | Nejdřív nahrajte soubor, pak k zprávě připojte vrácené ID. |
| Hledání | /api/messages/search | Hledání ve zprávách, napříč organizací nebo omezené na jeden kanál. |
| Tajemství a nastavení | /api/secrets, /api/settings/scoped | Úložiště přihlašovacích údajů pouze pro zápis s výslovnými oprávněními a vrstvené konfigurační hodnoty. |
| Připojené nástroje | /api/mcp | Servery MCP, které tato instance volá. Viz MCP a připojené nástroje. |
| Stav | /api/health | Kontrola živosti a připravenosti, obě veřejné. /api/health/ready kontroluje i databázi. |
Práva se vynucují na úrovni jednotlivé trasy, ne rodiny. Obecně: auditní protokol, účetní kniha nákladů, pravidla zásad a řídicí vrstva inference jsou povrchy pro vlastníky a správce organizace, zatímco konverzace, projekty, znalosti a schválení jsou otevřené každému členovi a omezené tím, co dotyčný člen skutečně vidí.
Příklady
Přihlášení a uložení obnovovací cookie
Na instanci v režimu local s heslem. Přístupový token se vrátí v těle odpovědi; obnovovací token skončí v cookie jar.
curl -sS https://api.example.com/api/auth/session \
--cookie-jar nessie.cookies \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com","password":"…"}'{
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
"me": {
"user": {
"id": "1d4e…",
"email": "ada@example.com",
"displayName": "Ada Lovelace",
"roleIds": ["owner"],
"superAdmin": false
},
"session": {
"sessionId": "9c07…",
"issuedAt": "2026-09-16T09:00:00.000Z",
"expiresAt": "2026-09-16T09:30:00.000Z"
},
"context": {
"organizationId": "5a81…",
"projectId": "7b12…",
"teamId": "2e60…",
"channelId": null,
"bootstrapMode": false
},
"auth": {
"providerId": "local",
"providerType": "local-bootstrap",
"autoRedirectToSso": false
}
}
}
}Když token vyprší, vyměňte cookie za nový:
curl -sS -X POST https://api.example.com/api/auth/refresh \
--cookie nessie.cookies --cookie-jar nessie.cookiesOdpověď má stejný tvar { token, me } a cookie jar nyní drží nový obnovovací token.
Výpis kanálů, které vidíte
curl -sS https://api.example.com/api/channels \
-H "Authorization: Bearer $TOKEN"{
"data": [
{
"id": "8b2f…",
"label": "engineering",
"type": "standard",
"visibility": "public",
"projectId": "…",
"projectName": "Platform",
"teamId": "…",
"defaultThreadId": "c41a…",
"unreadCount": 3,
"lastMessageAt": "2026-09-15T18:22:07.441Z",
"viewerCanManage": true
}
]
}Přidejte ?teamId=… pro omezení na jeden tým, nebo ?includeArchived=true, aby byly zahrnuty archivované kanály. defaultThreadId je místo, kam příště odešlete zprávu.
Odeslání zprávy
Zpráva potřebuje buď nějaký content, nebo alespoň jednu nahranou přílohu. Pošlete Idempotency-Key a opakovaný požadavek se vyřeší na zprávu, kterou vytvořil první pokus, místo aby vznikla druhá kopie.
curl -sS https://api.example.com/api/threads/c41a…/messages \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: 0f9c2d16-8f4a-4c1e-9a77-6b0d4f2e1a53' \
-d '{"content":"Deploying the migration now."}'Nově vytvořená zpráva má stav 201:
{
"data": {
"message": {
"id": "d70e…",
"threadId": "c41a…",
"role": "user",
"content": "Deploying the migration now.",
"createdAt": "2026-09-16T09:04:11.882Z"
},
"pendingAgentInvites": []
}
}Opakování se stejným klíčem idempotence odpoví 200 s původní zprávou a prázdným polem pendingAgentInvites, protože první pokus už provedl upozornění a odeslání, která toto pole popisuje.
Dvě odmítnutí na této trase stojí za výslovné ošetření. Obsah delší než limit délky zprávy vrací 413 MESSAGE_TOO_LARGE a správná reakce je nahrát text jako soubor. Obsah, který strukturálně vypadá jako přihlašovací údaj, vrací 422 SECRET_INTERCEPTED. Server odmítne zprávu dřív, než je uložena, odeslána nebo zalogována, a přihlašovací údaj patří do /api/secrets.