nessie

API

Vmesnik HTTP API, na katerem stoji vsak odjemalec Nessie, in kako se vanj prijaviti.

Kaj je API

Nessie ima en sam HTTP API. Skrbniška spletna aplikacija, odjemalca za macOS in iOS ter oddaljeni demon izvajalca so vsi običajni odjemalci tega API-ja, do česar koli, kar lahko počnejo, pa ni mogoče priti drugače. Gre za JSON API na strežniku Fastify, ni GraphQL in nima ločenega „javnega“ podnabora: površina, ki jo kličejo vaše lastne skripte, je ista, ki jo kliče izdelek.

V poti ni segmenta z različico. Vse poti so pod /api, razen dohodne končne točke MCP POST /mcp in nekaj dokumentov za odkrivanje v /.well-known/. Združljivost zagotavljamo tako, da polja zgolj dodajamo, zato odjemalec, ki ne prepozna nekaterih polj, še naprej deluje.

Osnovni URL

Nessie gostite sami na svojem strežniku, zato je osnovni URL izvor, na katerem vaša namestitev streže API. Upravljavec ga nastavi kot NESSIE_API_PUBLIC_URL, enaka vrednost pa je tista, ki jo API uporabi, kadar mora sam ustvariti absolutni URL. Na strežniku, ki ga upravljamo mi, je to https://api.nessie.works; razvojna namestitev, zagnana z pnpm dev, pa odgovarja na http://localhost:5454.

Skrbniška spletna aplikacija ima drug izvor kot API, zato so odjemalci v brskalniku podvrženi seznamu dovoljenih izvorov CORS (NESSIE_CORS_ORIGINS). Zahteve iz skripte ali strežnika nimajo izvora, ki bi ga bilo treba preverjati, zato nanje to ne vpliva.

Overjanje

Vsaka zahteva, razen peščice namerno javnih poti, nosi dostopni žeton v standardni glavi:

Authorization: Bearer <token>

Žeton je podpisan JWT, ki ga izda API. Velja kratek čas – privzeto trideset minut (NESSIE_AUTH_TOKEN_TTL) – in je edina poverilnica, ki jo običajni klic kdaj predloži. Nessie nima dolgoživih osebnih API-ključev. Če želite, da skripta kliče API, naj se prijavi enako kot brskalnik osebe in sproti obnavlja svoj žeton.

Pridobitev žetona

POST /api/auth/session ustvari sejo. Odgovori z dostopnim žetonom in identiteto klicatelja ter nastavi osveževalni žeton kot ločen piškotek, dostopen samo prek HTTP.

Kako dokažete, kdo ste, je odvisno od tega, kako je namestitev postavljena. Namestitev v načinu local sprejme e-poštni naslov in geslo. Pri namestitvah hosted ali selfHosted je prijava z geslom zavrnjena z 403 PASSWORD_AUTH_DISABLED, edini vhod pa je nastavljeni ponudnik identitete – tako račun nikoli ne more dobiti druge, šibkejše poti do identitete ob njem.

Prijava prek ponudnika identitete

Enotna prijava je izmenjava avtorizacijske kode OAuth s PKCE v treh korakih. Nessiejev lastni ponudnik identitete je UnlikeOtherAI, ki prav tako upravlja strukturo organizacij in ekip, ki jo namestitev zrcali; izmenjava spodaj je enake oblike za vsakega nastavljenega ponudnika.

  1. GET /api/auth/providers našteje, katere ponudnike namestitev sprejema; vsak ima providerId, oznako in podatek, ali naj stran za prijavo samodejno preusmeri nanj.
  2. GET /api/auth/providers/:providerId/authorize s parametri poizvedbe codeChallenge, redirectUri in state odgovori z { data: { authorizeUrl } }. Osebo pošljite tja.
  3. Ponudnik osebo vrne na vaš redirectUri s kodo. To kodo pošljite nazaj kot POST /api/auth/session z { providerId, code, codeVerifier, redirectUri } – vse štiri vrednosti so obvezne hkrati, nepopoln nabor pa vrne 400 EXTERNAL_AUTH_INCOMPLETE.

Obnova seje

Osveževalni žeton nikoli ni v telesu odgovora. Nastavljen je kot piškotek, dostopen samo prek HTTP, z imenom nessie_refresh, omejen na pot /api/auth, z življenjsko dobo privzeto trideset dni (NESSIE_AUTH_REFRESH_TOKEN_TTL). Klic POST /api/auth/refresh s tem piškotkom ga porabi, izda nov dostopni žeton in na njegovo mesto nastavi nov piškotek – žetoni se menjajo, zato je ukraden žeton uporaben le do naslednjega osveževanja pravega odjemalca.

Brskalnik, prijavljen v več računov, hrani en tak piškotek za vsako prijavo, imenovan nessie_refresh_<slot>, zahtevo pa z glavo x-nessie-account-slot označi za tisti, na katerega se nanaša. Odjemalec, ki te glave ne pošilja, se nanaša na nessie_refresh, kar je vse, kar potrebuje odjemalec v ukazni vrstici.

Odjemalec v ukazni vrstici zato potrebuje shrambo piškotkov. Pri curl to pomeni --cookie-jar pri klicu za prijavo in --cookie pri osveževanju, kot v spodnjem primeru.

Kaj se preveri pri vsaki zahtevi

Overjanje ni le preverjanje podpisa. Preden se zažene obdelovalnik, API preveri podpis in rok veljavnosti žetona, potrdi, da seja ni bila preklicana (tako s številko različice žetona za uporabnika kot z id-jem posamezne seje), in naloži članstvo klicatelja v organizaciji, ki jo navaja žeton. Dezaktivirano članstvo pomeni 403. Kadar je organizacija vezana na zunanjega ponudnika identitete, se trenutni status klicatelja pri vsaki zahtevi ponovno preveri pri tem ponudniku in ne bere iz žetona, zato dostop, odvzet zunaj, preneha delovati takoj in ne šele ob naslednjem poteku.

Poverilnice, ki niso žetoni sej

Obstajata še dve drugi nosilni poverilnici, vendar nobena ni splošni ključ. Poverilnica glasovne naprave je sprejeta le na poteh za glasovne klice; poverilnica za dostop agenta le na končni točki MCP. Če jo predložite kjer koli drugje, je zavrnjena s kodo 403, ki navaja poverilnico, in ne poskusi znova kot šibkejša seja – glejte MCP in povezana orodja, kako se izda poverilnica agenta.

Ovojnica odgovora

Vsak uspešen odgovor je objekt s ključem data. Ni golega seznama in ni vsebine na korenski ravni, zato odjemalec nikoli ne bo moral razlikovati med oblikami:

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

Končne točke seznamov poleg njega dodajo objekt meta. Na vrhnji ravni se nikoli ne dodaja nič drugega.

Tudi napake imajo eno obliko, ne glede na to, kaj jih je sprožilo:

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

code je strojno berljiv del, po katerem ravnate; message je namenjen človeku. field in details sta prisotna, kadar je napaka dovolj določna, da jo je mogoče natančno opredeliti. Neobdelana napaka strežnika je vedno 500 INTERNAL_ERROR s fiksnim sporočilom – osnovno besedilo napake se zabeleži, nikoli ne vrne, ker je lahko med potjo ujelo podatke zahteve.

Kode napak, s katerimi se boste najprej srečali

StatusKodaPomen
400VALIDATION_ERRORTelo zahteve ali poizvedba ne ustrezata shemi.
401AUTH_REQUIREDNi nosilnega žetona ali pa je bila glava napačno oblikovana.
401TOKEN_EXPIREDDostopni žeton je potekel. Osvežite ga in poskusite znova.
401TOKEN_REVOKEDSeja je bila odjavljena ali pa so bile prisilno odjavljene vse seje.
403ACCOUNT_DEACTIVATEDČlanstvo v tej organizaciji je bilo deaktivirano.
404NOT_FOUNDTake poti ni ali pa zapis ni viden temu klicatelju.
429RATE_LIMITEDOmejitev hitrosti je dosežena. Preberite Retry-After.
500INTERNAL_ERRORNeobdelana napaka strežnika; namenoma brez podrobnosti.

Razdelitev na strani

Končne točke seznamov so razdeljene na strani z neprozornim kazalcem po ključu, ne z odmikom – vrstice se vstavljajo, medtem ko nekdo bere, in pri odmiku druga stran tiho ponovi zapis, ki ga je prva stran že pokazala.

Sprejeti so trije parametri poizvedbe: cursor, limit in direction (forward ali backward). Privzeta stran ima 25 zapisov, zgornja meja je 100; večja vrednost se omeji, ne zavrne. Končne točke, ki tudi razvrščajo ali filtrirajo, dodajo sort, order in prosto besedilno iskanje q.

Objekt meta strani pove, kje ste:

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

nextCursor in prevCursor sta oba resnična: gumba za prejšnjo in naslednjo stran sta nadzora, ki ju oseba pričakuje. Kazalca sta neprozorna – strežnik vanju zakodira svoj ključ za razvrščanje, odjemalec, ki ga razčleni ali sestavi sam, pa se bo pokvaril takoj, ko seznam spremeni način razvrščanja. total je prisoten pri večini seznamov, izpuščen pa tam, kjer štetje ni smiselno, na primer pri razvrščenih rezultatih iskanja.

Omejitve hitrosti

Omejitve veljajo za fiksna časovna okna in se uveljavijo, še preden se sploh prebere telo zahteve. Zavrnjena zahteva je 429 s kodo RATE_LIMITED in glavo Retry-After v sekundah.

Večina kvot je vezanih na IP naslov odjemalca. Tiste, občutljive na poverilnice – prijava, osveževanje, ponovna potrditev gesla, zapisovanje poverilnic MCP – poleg tega vodijo števec za račun in zavrnejo, kadar se sproži katerikoli od obeh, tako da omejitev zadene tako naslov, ki pošilja v mnoge račune, kot račun, ki je napaden z mnogih naslovov. Privzeta vrednost za prijavo je 10 poskusov na IP naslov in 5 na e-poštni naslov v desetih minutah; za objavo sporočila 60 na minuto; za pisanje pod /api/agents 60 na minuto. Vsak prag je mogoče nastaviti za vsako namestitev, zato te vrednosti obravnavajte kot privzete vrednosti ob dobavi, ne kot zavezo. Preverjanja stanja in pretočni tokovi v realnem času so izvzeti.

Realni čas

Za sledenje pogovoru ni prav, da seznam stalno preverjate. Namesto tega obstajajo tri pretočne končne točke:

  • GET /api/events/stream — dogodki, ki jih strežnik pošilja za vse, kar lahko prijavljena oseba vidi.
  • GET /api/threads/:threadId/stream — dogodki za eno nit. Upošteva Last-Event-ID, zato se ob ponovni povezavi nadaljuje, ne začne znova.
  • GET /api/activity — WebSocket, ki prenaša tok dejavnosti.

Brskalniki pri rokovanju WebSocket ne morejo nastavljati glav, zato pot WebSocket prav tako sprejme dostopni žeton kot parameter poizvedbe ?token=. To je edino mesto, kamor žeton sodi v URL; vse druge poti ga sprejmejo v glavi.

Družine virov

Končnih točk je precej več kot tisoč, kar je veliko preveč, da bi jih lahko naštevali. Razvrščene so v družine; ko poznate predpono družine, so posamezne poti predvidljive – zbirka na predponi, zapis pod njo in poimenovana dejanja kot podpoti POST.

DružinaPredponaKaj zajema
Overjanje/api/authPrijava, obnova, odjava, trenutna identiteta in lastne seje osebe.
Kanali in niti/api/channels, /api/threadsModel pogovora: kanali vsebujejo niti, niti sporočila, odgovori pa so gnezdeni pod korenskim sporočilom.
Agenti/api/agentsOpredelitve agentov, njihove povezave s kanali, pogovori, opravila in stanje.
Projekti in table/api/projects, /api/tasks, /api/iterationsSledenje delu: table in stolpci pod projektom, naloge nanje in iteracije nad njimi.
Znanje/api/knowledge-baseProstori z različicami strani in datotek, s komentarji, povratnimi povezavami in iskanjem.
Pošta/api/mail, /api/mailbox-connectionsPovezani poštni predali, poštni predali agentov in osnutki, ki jih je agent napisal, da jih oseba odobri.
Odobritve/api/approvalsVrsta dejanj, ki jih agent ne sme izvesti sam, in en klic, ki jih razreši.
Revizija/api/audit-logRevizijska sled organizacije z verižnim zgoščevanjem in končno točko za preverjanje. Za lastnike in skrbnike.
Stroški in poraba/api/ledger, /api/billingObračun tokenov in stroškov, proračuni ter trajanje izvajanj; ločeno kreditne točke in polnjenja. Za lastnike in skrbnike.
Organizacija in ekipe/api/organizations, /api/teams, /api/usersUpravljanje najemnika, ekip in članstev, vključno z vabili.
Sprožilci/api/triggersUrniki in webhooki, ki sprožijo delo agentov, z zgodovino sprožitev.
Klici in glas/api/calls, /api/voiceKlicanje znotraj kanala ter seja glasovnega pomočnika, prepis in žetoni naprav.
Izvajalci/api/executors, /api/execution-environment-templatesStroji, na katerih agenti delajo, njihova okolja in kanal za povezovanje demona.
Izvajanja/api/runsIzvajanja agentov v živo: preklic, nadaljevanje, ponovni zagon, povezava z izvajalcem.
Nalaganja/api/uploads, /api/attachmentsNajprej naložite datoteko, nato vrnjeni id povežite s sporočilom.
Iskanje/api/messages/searchIskanje sporočil po celi organizaciji ali omejeno na en kanal.
Skrivnosti in nastavitve/api/secrets, /api/settings/scopedShramba poverilnic samo za pisanje z izrecnimi dovoljenji ter večplastne konfiguracijske vrednosti.
Povezana orodja/api/mcpStrežniki MCP, h katerim namestitev kliče. Glejte MCP in povezana orodja.
Stanje sistema/api/healthŽivost in pripravljenost, obe javni. /api/health/ready preveri tudi bazo podatkov.

Pravice se uveljavljajo za vsako pot posebej, ne za družino. Na splošno so revizijski dnevnik, knjiga stroškov, pravila in nadzorna ravnina za sklepanje površine za lastnike in skrbnike organizacije, medtem ko so pogovori, projekti, znanje in odobritve odprti vsakemu članu in zoženi na to, kar ta član dejansko lahko vidi.

Primeri

Prijava in shranjevanje piškotka za obnovo

Na namestitvi v načinu local, z geslom. Dostopni žeton se vrne v telesu odgovora; osveževalni žeton pristane v shrambi piškotkov.

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
      }
    }
  }
}

Ko žeton poteče, piškotek zamenjajte za novega:

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

Odgovor ima enako obliko { token, me }, shramba piškotkov pa zdaj hrani zamenjani osveževalni žeton.

Seznam kanalov, ki jih vidite

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
    }
  ]
}

Dodajte ?teamId=…, da zožite na eno ekipo, ali ?includeArchived=true, da vključite arhivirane kanale. defaultThreadId je tisto, kamor boste objavili naslednje.

Objava sporočila

Sporočilo potrebuje bodisi nekaj content bodisi vsaj eno naloženo priponko. Pošljite Idempotency-Key, in ponovljena zahteva se razreši v sporočilo, ki ga je ustvaril prvi poskus, namesto da bi objavila drugo kopijo.

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."}'

Novo sporočilo je 201:

{
  "data": {
    "message": {
      "id": "d70e…",
      "threadId": "c41a…",
      "role": "user",
      "content": "Deploying the migration now.",
      "createdAt": "2026-09-16T09:04:11.882Z"
    },
    "pendingAgentInvites": []
  }
}

Ponovitev z istim ključem idempotentnosti odgovori s 200, z izvirnim sporočilom in praznim pendingAgentInvites, ker je prvi poskus že opravil opozarjanje in pošiljanje, ki ju polje opisuje.

Dve zavrnitvi na tej poti je vredno obravnavati posebej. Vsebina, ki presega omejitev dolžine sporočila, je 413 MESSAGE_TOO_LARGE; pravilen odgovor je, da besedilo naložite kot datoteko. Vsebina, ki je po strukturi videti kot poverilnica, je 422 SECRET_INTERCEPTED – strežnik zavrne sporočilo, preden je shranjeno, poslano ali zabeleženo, poverilnica pa spada v /api/secrets.