nessie

API

HTTP API, na ktorom stojí každý klient Nessie, a ako sa pri ňom autentizovať.

Čo je API

Nessie má jediné HTTP API. Webová aplikácia pre správu, klienti pre macOS a iOS aj vzdialený daemon executora sú všetko bežní klienti tohto API a nič, čo dokážu urobiť, nie je dostupné inou cestou. Je to JSON API nad serverom Fastify, nie je to GraphQL a nemá žiadnu samostatnú „verejnú“ časť: rozhranie, ktoré volajú vaše vlastné skripty, je to isté, ktoré volá samotný produkt.

V ceste nie je žiadny segment s verziou. Každá trasa je pod /api, okrem prichádzajúceho MCP endpointu na POST /mcp a niekoľkých dokumentov na objavovanie v /.well-known/. Kompatibilitu zabezpečujeme tak, že sa polia iba pridávajú, takže klient, ktorý ignoruje to, čo nepozná, funguje ďalej.

Základná URL adresa

Nessie prevádzkujete sami, takže základnou URL adresou je ten pôvod (origin), na ktorom vaše nasadenie poskytuje API. Prevádzkovateľ ho nastaví ako NESSIE_API_PUBLIC_URL a tá istá hodnota sa použije, keď si API musí vytvoriť vlastnú absolútnu URL adresu. Na inštancii, ktorú prevádzkujeme my, je to https://api.nessie.works; vývojová inštancia spustená príkazom pnpm dev odpovedá na http://localhost:5454.

Webová aplikácia pre správu beží na inom pôvode než API, takže prehliadačoví klienti podliehajú zoznamu povolených CORS pôvodov (NESSIE_CORS_ORIGINS). Požiadavky zo skriptu alebo zo servera nemajú žiadny pôvod, ktorý by sa kontroloval, a na tie sa to nevzťahuje.

Autentifikácia

Každá požiadavka mimo malej množiny zámerne verejných trás nesie prístupový token v štandardnej hlavičke:

Authorization: Bearer <token>

Token je podpísaný JWT, ktorý vydáva API. Má krátku platnosť — predvolene tridsať minút (NESSIE_AUTH_TOKEN_TTL) — a je to jediný poverovací údaj, aký bežný volajúci kedy predkladá. Nessie nepozná dlhodobé osobné API kľúče. Ak chcete, aby skript volal API, prihlási sa rovnakým spôsobom, akým sa prihlasuje prehliadač človeka, a token si priebežne obnovuje.

Získanie tokenu

POST /api/auth/session vytvorí reláciu. Odpovie prístupovým tokenom a identitou volajúceho a obnovovací token nastaví ako samostatnú cookie s príznakom HTTP-only.

Ako dokážete, kto ste, závisí od toho, ako je inštancia nasadená. Inštancia bežiaca v režime local prijíma e-mail a heslo. Na inštanciách hosted alebo selfHosted sa prihlásenie heslom bez výnimky odmietne s 403 PASSWORD_AUTH_DISABLED a jediná cesta dnu je nakonfigurovaný poskytovateľ identity — účet tak nikdy nemôže získať druhú, slabšiu cestu k identite popri nej.

Prihlásenie cez poskytovateľa identity

Single sign-on je výmena autorizačného kódu OAuth s PKCE v troch krokoch. Vlastným poskytovateľom identity Nessie je UnlikeOtherAI, ktorý zároveň spravuje štruktúru organizácie a tímov, ktorú inštancia zrkadlí; výmena nižšie má rovnaký tvar pre každého nakonfigurovaného poskytovateľa.

  1. GET /api/auth/providers vypíše, koho táto inštancia prijíma. Každý poskytovateľ má providerId, názov a údaj, či má prihlasovacia stránka presmerovať na neho automaticky.
  2. GET /api/auth/providers/:providerId/authorize s parametrami codeChallenge, redirectUri a state v query vráti { data: { authorizeUrl } }. Presmerujte tam osobu.
  3. Poskytovateľ osobu vráti na váš redirectUri s kódom. Ten pošlite späť ako POST /api/auth/session s { providerId, code, codeVerifier, redirectUri } — všetky štyri údaje sú povinné naraz a neúplná sada vráti 400 EXTERNAL_AUTH_INCOMPLETE.

Obnovenie relácie

Obnovovací token sa nikdy nenachádza v tele odpovede. Nastaví sa ako cookie s príznakom HTTP-only s názvom nessie_refresh, obmedzené na cestu /api/auth, s predvolenou platnosťou tridsať dní (NESSIE_AUTH_REFRESH_TOKEN_TTL). Volanie POST /api/auth/refresh s touto cookie ju spotrebuje, vydá nový prístupový token a namiesto nej nastaví novú cookie. Tokeny sa rotujú, takže ukradnutý token platí len dovtedy, kým skutočný klient nabudúce obnoví reláciu.

Prehliadač prihlásený do viacerých účtov si nechá jednu takú cookie pre každé prihlásenie, s názvom nessie_refresh_<slot>, a požiadavku, ktorej sa týka, označí hlavičkou x-nessie-account-slot. Klient, ktorý takú hlavičku neposiela, sa týka nessie_refresh, a to je všetko, čo potrebuje klient z príkazového riadku.

Klient z príkazového riadku preto potrebuje cookie jar. Pri curl je to --cookie-jar pri volaní prihlásenia a --cookie pri obnovení, ako v praktickom príklade nižšie.

Čo sa kontroluje pri každej požiadavke

Autentifikácia nie je iba kontrola podpisu. Pred spustením handlera API overí podpis a platnosť tokenu, potvrdí, že relácia nebola odvolaná (a to podľa verzie tokenu platnej pre celého používateľa aj podľa identifikátora jednotlivej relácie), a načíta členstvo volajúceho v organizácii, ktorú token uvádza. Deaktivované členstvo vráti 403. Ak je organizácia napojená na externého poskytovateľa identity, aktuálne postavenie volajúceho sa pri požiadavke overí u tohto poskytovateľa a nečíta sa z tokenu, takže prístup odobraný na strane poskytovateľa prestane fungovať okamžite, nie až pri ďalšom vypršaní platnosti.

Poverovacie údaje, ktoré nie sú tokeny relácie

Existujú ešte dva iné bearer poverovacie údaje a ani jeden nie je všeobecný kľúč. Hlasové zariadenie sa prijíma iba na trasách hovorov a prístupový údaj agenta iba na endpointe MCP. Ak sa ktorýkoľvek z nich predloží inde, odmietne sa s 403, ktorý ho pomenuje, a nevyskúša sa ako slabšia relácia — o tom, ako sa prístupový údaj agenta vydáva, pozrite MCP a pripojené nástroje.

Obálka odpovede

Každá úspešná odpoveď je objekt s kľúčom data. Na koreni nie je žiadne holé pole ani payload, takže klient nikdy nemusí rozlišovať podľa tvaru:

{
  "data": { "id": "3f1c…", "label": "engineering" }
}

Zoznamové endpointy pridávajú vedľa neho objekt meta. Na najvyššej úrovni sa nikdy nepridáva nič iné.

Chyby majú takisto jednotný tvar, bez ohľadu na to, čo ich vyvolalo:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "A message needs content or at least one attachment",
    "field": "body",
    "details": { "formErrors": [], "fieldErrors": {} }
  }
}

code je strojovo čitateľná časť a podľa nej by ste mali rozhodovať; message je určený človeku. field a details sú prítomné, keď je chyba dostatočne konkrétna, aby sa dala lokalizovať. Neošetrená chyba servera je vždy 500 INTERNAL_ERROR s pevnou správou — text podkladovej chyby sa zapíše do logu, nikdy sa nevráti, lebo mohol na ceste von zachytiť údaje z požiadavky.

Chybové kódy, na ktoré narazíte najskôr

StavKódVýznam
400VALIDATION_ERRORTelo požiadavky alebo parametre dotazu nezodpovedajú schéme.
401AUTH_REQUIREDChýba bearer token alebo je hlavička poškodená.
401TOKEN_EXPIREDPlatnosť prístupového tokenu vypršala. Obnovte ho a zopakujte požiadavku.
401TOKEN_REVOKEDRelácia bola odhlásená alebo boli všetky relácie násilne ukončené.
403ACCOUNT_DEACTIVATEDČlenstvo v tejto organizácii bolo deaktivované.
404NOT_FOUNDTaká trasa neexistuje alebo tento volajúci nevidí takýto záznam.
429RATE_LIMITEDKapacita limitu je vyčerpaná. Prečítajte si hlavičku Retry-After.
500INTERNAL_ERRORNeošetrená chyba servera, úmyselne neurčitá.

Stránkovanie

Zoznamové endpointy stránkujú pomocou nepriehľadného kurzora typu keyset, nie offsetu — záznamy sa vkladajú, kým ich niekto číta, a pri offsete druhá stránka potichu zopakuje záznam, ktorý ukázala prvá stránka.

Prijímajú sa tri parametre: cursor, limit a direction (forward alebo backward). Predvolená stránka má 25 položiek a maximum je 100; vyššia hodnota sa orezáva, nie odmieta. Endpointy, ktoré triedia alebo filtrujú, pridávajú sort, order a voľnotextové q.

Objekt meta na stránke vám povie, kde sa nachádzate:

{
  "data": [ … ],
  "meta": {
    "hasMore": true,
    "nextCursor": "2026-09-12T08:31:44.005Z|8b2f…",
    "prevCursor": null,
    "total": 134
  }
}

nextCursor aj prevCursor sú skutočné, lebo Predchádzajúca aj Ďalšia sú ovládacie prvky, ktoré človek očakáva. Sú nepriehľadné — server do nich zakóduje vlastný triediaci kľúč a klient, ktorý ich rozloží alebo vytvorí sám, sa rozbije v momente, keď zoznam zmení poradie. total je prítomný pri väčšine zoznamov a vynecháva sa tam, kde počítanie nedáva zmysel, napríklad pri zoradených výsledkoch vyhľadávania.

Limity požiadaviek

Limity platia pre pevné časové okná a presadzujú sa skôr, než sa vôbec prečíta telo požiadavky. Odmietnutá požiadavka dostane 429 s kódom RATE_LIMITED a hlavičkou Retry-After v sekundách.

Väčšina limitov sleduje IP adresu klienta. Citlivé na poverovacie údaje — prihlásenie, obnovenie, opätovné overenie heslom, zápisy MCP poverovacích údajov — navyše vedú počítadlo pre účet a odmietnu, keď ktorýkoľvek z nich zlyhá, takže aj jedna adresa, ktorá rozosiela pokusy na mnoho účtov, aj jeden účet napadnutý z mnohých adries narazia na múr. Prihlásenie predvolene dovoľuje 10 pokusov na IP adresu a 5 na e-mailovú adresu za desať minút; odoslanie správy predvolene 60 za minútu; zápisy pod /api/agents 60 za minútu. Každý prah sa dá nastaviť pre konkrétne nasadenie, takže tieto hodnoty berte ako predvolené hodnoty dodané so softvérom, nie ako záväzný kontrakt. Kontroly stavu a streamy v reálnom čase sú z limitov vyňaté.

Reálny čas

Sledovať konverzáciu opakovaným načítavaním zoznamu je zlý spôsob. Namiesto toho existujú tri streamovacie endpointy:

  • GET /api/events/stream — udalosti odosielané serverom (server-sent events) pre všetko, čo prihlásená osoba vidí.
  • GET /api/threads/:threadId/stream — server-sent events pre jedno vlákno. Rešpektuje Last-Event-ID, takže opätovné pripojenie pokračuje a nezačína odznova.
  • GET /api/activity — WebSocket, ktorý prenáša kanál aktivít.

Prehliadače nemôžu nastavovať hlavičky pri WebSocket handshaku, takže trasa WebSocket prijíma prístupový token aj ako query parameter ?token=. Je to jediné miesto, kam token v URL patrí; všetky ostatné trasy ho berú z hlavičky.

Skupiny zdrojov

Existuje vyše tisíc endpointov, čo je na výpis príliš veľa. Sú zoskupené do skupín a keď poznáte predponu skupiny, jednotlivé trasy sú predvídateľné — kolekcia na predpone, záznam pod ňou a pomenované akcie ako podcesty POST.

SkupinaPredponaČo pokrýva
Autentifikácia/api/authPrihlásenie, obnovenie, odhlásenie, aktuálna identita a vlastné relácie osoby.
Kanály a vlákna/api/channels, /api/threadsModel konverzácie: kanály obsahujú vlákna, vlákna obsahujú správy a odpovede sa zanorujú pod koreň.
Agenti/api/agentsDefinície agentov, ich väzby na kanály, konverzácie, úlohy a stav.
Projekty a tabule/api/projects, /api/tasks, /api/iterationsSledovanie práce: tabule a stĺpce v rámci projektu, úlohy na nich a iterácie nad nimi.
Znalosti/api/knowledge-basePriestory verzovaných stránok a súborov s komentármi, spätnými odkazmi a vyhľadávaním.
Pošta/api/mail, /api/mailbox-connectionsPripojené poštové schránky, poštové schránky agentov a koncepty, ktoré agent napísal na schválenie osobou.
Schválenia/api/approvalsFront akcií, ktoré agent nesmie vykonať samostatne, a jediné volanie, ktorým sa vyriešia.
Audit/api/audit-logHašovo reťazený auditný záznam organizácie s overovacím endpointom. Pre vlastníkov a správcov.
Náklady a využitie/api/ledger, /api/billingÚčtovanie tokenov a nákladov, rozpočty a časy behov; oddelene kredity a dobíjanie. Pre vlastníkov a správcov.
Organizácia a tímy/api/organizations, /api/teams, /api/usersSpráva organizácie, tímov a členstiev vrátane pozvánok.
Spúšťače/api/triggersPlány a webhooky, ktoré spúšťajú prácu agentov, s históriou spustení.
Hovory a hlas/api/calls, /api/voiceHovory v kanáli a relácia hlasového asistenta, jeho prepis a tokeny zariadení.
Executory/api/executors, /api/execution-environment-templatesPočítače, na ktorých agenti pracujú, ich prostredia a kanál párovania daemona.
Behy/api/runsŽivé behy agentov: zrušenie, pokračovanie, reštart, väzba na executor.
Nahrávanie/api/uploads, /api/attachmentsNajprv nahrajte súbor, potom k správe priraďte vrátené id.
Vyhľadávanie/api/messages/searchVyhľadávanie v správach, v celej organizácii alebo obmedzené na jeden kanál.
Tajné údaje a nastavenia/api/secrets, /api/settings/scopedÚložisko poverovacích údajov len na zápis s explicitnými oprávneniami a vrstvené konfiguračné hodnoty.
Pripojené nástroje/api/mcpServery MCP, ktoré táto inštancia volá. Pozri MCP a pripojené nástroje.
Stav služby/api/healthKontrola živosti a pripravenosti, obe verejné. /api/health/ready navyše kontroluje databázu.

Oprávnenia sa presadzujú na úrovni trasy, nie skupiny. Vo všeobecnosti: auditný záznam, účtovná kniha nákladov, pravidlá politík a riadiaca rovina inferencie sú povrchy pre vlastníkov a správcov organizácie, zatiaľ čo konverzácie, projekty, znalosti a schválenia sú otvorené každému členovi a zúžené podľa toho, čo tento člen naozaj vidí.

Praktické príklady

Prihlásenie a uchovanie cookie na obnovenie

Na inštancii v režime local, s heslom. Prístupový token príde v tele odpovede; 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
      }
    }
  }
}

Keď token vyprší, vymeňte cookie za nový:

curl -sS -X POST https://api.example.com/api/auth/refresh \
  --cookie nessie.cookies --cookie-jar nessie.cookies

Odpoveď má rovnaký tvar { token, me } a cookie jar teraz obsahuje nový obnovovací token.

Zoznam kanálov, ktoré 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
    }
  ]
}

Pridajte ?teamId=… na zúženie na jeden tím alebo ?includeArchived=true, aby sa zahrnuli archivované kanály. defaultThreadId je vlákno, do ktorého posielate ďalšiu správu.

Odoslanie správy

Správa potrebuje buď nejaký content, alebo aspoň jednu nahranú prílohu. Pošlite hlavičku Idempotency-Key a zopakovaná požiadavka sa vyrieši na správu, ktorú vytvoril prvý pokus, namiesto odoslania druhej kópie.

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á sprá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": []
  }
}

Opakovanie s rovnakým kľúčom idempotencie odpovie 200 s pôvodnou správou a prázdnym poľom pendingAgentInvites, lebo prvý pokus už vykonal upozornenia a odoslanie, ktoré pole popisuje.

Dve odmietnutia na tejto trase stoja za osobitné ošetrenie. Obsah presahujúci limit dĺžky chatu je 413 MESSAGE_TOO_LARGE a správnou reakciou je nahrať text ako súbor. Obsah, ktorý štruktúrou pripomína poverovací údaj, je 422 SECRET_INTERCEPTED — server odmietne správu skôr, než ju uloží, odošle alebo zaloguje, a poverovací údaj patrí do /api/secrets.