API
HTTP API, kuriuo remiasi visi Nessie klientai, ir kaip jame autentifikuotis.
Kas yra API
Nessie turi vieną HTTP API. Administravimo žiniatinklio programa, macOS ir iOS klientai bei nuotolinio vykdytojo fono tarnyba yra įprasti jo klientai, ir nieko, ką jie gali daryti, nepasieksite kitu būdu. Tai JSON API, veikianti per Fastify serverį; tai ne GraphQL, ir jis neturi atskiro „viešo“ poaibio: sąsaja, kurią kviečia jūsų skriptai, yra ta pati, kurią kviečia produktas.
Kelyje versijos segmento nėra. Visi maršrutai yra po /api, išskyrus gaunamą MCP galinį tašką POST /mcp ir keletą /.well-known/ atradimo dokumentų. Suderinamumas užtikrinamas tik nuolat pridedant laukus, todėl klientas, kuris ignoruoja tai, ko neatpažįsta, toliau veikia.
Bazinis URL
Nessie talpinamas savarankiškai, todėl bazinis URL yra kilmės adresas, kuriuo jūsų diegimas teikia API. Operatorius jį nustato kaip NESSIE_API_PUBLIC_URL, o tą pačią reikšmę API naudoja, kai jam reikia sudaryti savo absoliutų URL. Mūsų diegime tai https://api.nessie.works; kūrimo diegimas, paleistas su pnpm dev, atsako adresu http://localhost:5454.
Administravimo žiniatinklio programa yra kitas kilmės adresas nei API, todėl naršyklės klientams taikomas CORS leidžiamųjų kilmių sąrašas (NESSIE_CORS_ORIGINS). Skriptų ar serverių užklausos neturi kilmės, kurią reikėtų tikrinti, todėl jos nepaveikiamos.
Autentifikavimas
Kiekviena užklausa, išskyrus nedidelį tyčia viešų maršrutų rinkinį, neša prieigos žetoną standartinėje antraštėje:
Authorization: Bearer <token>Žetonas yra pasirašytas JWT, sukurtas API. Jis trumpai galioja — pagal numatytuosius nustatymus trisdešimt minučių (NESSIE_AUTH_TOKEN_TTL) — ir tai vienintelis prisijungimo duomenų tipas, kurį paprastas klientas kada nors pateikia. Nessie nenaudoja ilgaamžių asmeninių API raktų. Jei norite, kad skriptas kviestų API, jis prisijungia taip pat, kaip žmogaus naršyklė, ir atnaujina savo žetoną darbo metu.
Žetono gavimas
POST /api/auth/session sukuria seansą. Atsakyme pateikiamas prieigos žetonas ir prašytojo tapatybė, o atnaujinimo žetonas nustatomas kaip atskiras slapukas, pasiekiamas tik HTTP.
Tai, kaip įrodote, kas esate, priklauso nuo to, kaip diegimas paleistas. Diegimas, veikiantis local režimu, priima el. pašto adresą ir slaptažodį. Diegime hosted ar selfHosted režimu prisijungimas slaptažodžiu visiškai atmetamas su 403 PASSWORD_AUTH_DISABLED, ir vienintelis būdas įeiti yra sukonfigūruotas tapatybės teikėjas — todėl paskyra niekada negali įgyti antros, silpnesnės tapatybės šalia jo.
Prisijungimas per tapatybės teikėją
Vienkartinis prisijungimas yra OAuth autorizacijos kodo mainai su PKCE trijuose žingsniuose. Nessie tapatybės teikėjas yra UnlikeOtherAI, kuris taip pat valdo organizacijos ir komandų struktūrą, kurią atspindi diegimas; mainai žemiau yra tokie patys bet kuriam sukonfigūruotam teikėjui.
GET /api/auth/providersišvardija, ką šis diegimas priima: kiekvieną suproviderId, pavadinimu ir tuo, ar prisijungimo puslapis turi automatiškai nukreipti į jį.GET /api/auth/providers/:providerId/authorizesu užklausos parametraiscodeChallenge,redirectUriirstateatsako{ data: { authorizeUrl } }. Nukreipkite žmogų ten.- Teikėjas grąžina žmogų į jūsų
redirectUrisu kodu. Siųskite jį atgal kaipPOST /api/auth/sessionsu{ providerId, code, codeVerifier, redirectUri }— visi keturi reikalingi kartu, o nepilnas rinkinys yra400 EXTERNAL_AUTH_INCOMPLETE.
Seanso atnaujinimas
Atnaujinimo žetono niekada nėra atsakymo turinyje. Jis nustatomas kaip slapukas tik HTTP, pavadinimu nessie_refresh, apimantis tik kelią /api/auth, o numatytasis galiojimas — trisdešimt dienų (NESSIE_AUTH_REFRESH_TOKEN_TTL). Iškvietus POST /api/auth/refresh su tuo slapuku, jis sunaudojamas, išduodamas naujas prieigos žetonas ir vietoj jo nustatomas naujas slapukas. Žetonai rotuojami, todėl pavogtas žetonas galioja tik tol, kol tikrasis klientas kitą kartą atsinaujins.
Naršyklė, prisijungusi prie kelių paskyrų, kiekvienam prisijungimui laiko po tokį slapuką, pavadintą nessie_refresh_<slot>, o užklausą, kurios reikia, nurodo antrašte x-nessie-account-slot. Klientas, kuris tokios antraštės nesiunčia, kalba apie nessie_refresh, ir to pakanka komandinės eilutės klientui.
Todėl komandinės eilutės klientui reikia slapukų failo. Su curl tai — --cookie-jar prisijungimo užklausoje ir --cookie atnaujinimo užklausoje, kaip žemiau pateiktame darbiniame pavyzdyje.
Ką tikrina kiekviena užklausa
Autentifikavimas nėra vien parašo tikrinimas. Prieš paleidžiant apdorojimo funkciją API patikrina žetono parašą ir galiojimo laiką, įsitikina, kad seansas nebuvo panaikintas (tiek pagal visos naudotojo žetono versiją, tiek pagal atskirą seanso identifikatorių), ir įkelia prašytojo narystę organizacijoje, kurią nurodo žetonas. Išjungta narystė yra 403. Kai organizacija remiasi išorine tapatybės teikėju, dabartinė prašytojo būklė tikrinama pas tą teikėją kiekvienos užklausos metu, o ne skaitoma iš žetono, todėl prieiga, panaikinta išorėje, nustoja veikti iš karto, o ne kitam galiojimo termino pabaigai.
Prisijungimo duomenys, kurie nėra seanso žetonai
Egzistuoja dar du bearer prisijungimo duomenų tipai, ir nė vienas nėra bendrosios paskirties raktas. Balso įrenginio prisijungimo duomenys priimami tik balso skambučių maršrutuose; agento prieigos prisijungimo duomenys priimami tik MCP galiniame taške. Pateikus bet kurį iš jų kitur, užklausa atmetama su 403, nurodant prisijungimo duomenis, o ne bandant kaip silpnesnį seansą — žr. MCP ir prijungtos priemonės, kaip išduodami agento prisijungimo duomenys.
Atsakymo apvalkalas
Kiekvienas sėkmingas atsakymas yra objektas su raktu data. Šakninio lygio masyvo ar tiesioginio turinio nėra, todėl klientui niekada nereikia atskirti pagal formą:
{
"data": { "id": "3f1c…", "label": "engineering" }
}Sąrašų galiniai taškai prie jo prideda objektą meta. Viršutiniame lygyje niekas kitas nepridedama.
Klaidos turi vieną formą, nesvarbu, kas jas sukėlė:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "A message needs content or at least one attachment",
"field": "body",
"details": { "formErrors": [], "fieldErrors": {} }
}
}code yra mašinai skirta dalis, pagal ją ir reikia šakoti; message skirta žmogui. field ir details pateikiami, kai klaida yra pakankamai konkreti, kad ją būtų galima nurodyti. Nepagauta serverio klaida visada yra 500 INTERNAL_ERROR su fiksuotu pranešimu — pagrindinis klaidos tekstas įrašomas į žurnalą, bet niekada negrąžinamas, nes jis galėjo pakeliui pasiimti užklausos duomenų.
Pirmieji klaidų kodai, su kuriais susidursite
| Būsena | Kodas | Reikšmė |
|---|---|---|
| 400 | VALIDATION_ERROR | Turinys ar užklausa neatitiko schemos. |
| 401 | AUTH_REQUIRED | Nėra bearer žetono arba antraštė sugadinta. |
| 401 | TOKEN_EXPIRED | Prieigos žetonas nebegalioja. Atnaujinkite jį ir bandykite dar kartą. |
| 401 | TOKEN_REVOKED | Seansas buvo užbaigtas atsijungiant arba visi seansai priverstinai nutraukti. |
| 403 | ACCOUNT_DEACTIVATED | Šios organizacijos narystė išjungta. |
| 404 | NOT_FOUND | Nėra tokio maršruto arba prašytojas negali matyti tokio įrašo. |
| 429 | RATE_LIMITED | Limitas išnaudotas. Perskaitykite Retry-After. |
| 500 | INTERNAL_ERROR | Nepagauta serverio klaida, tyčia neatskleidžiama. |
Puslapiavimas
Sąrašų galiniai taškai puslapiuoja neskaidriu raktiniu kursoriumi, o ne poslinkiu — eilutės įterpiamos, kol kas nors skaito, o su poslinkiu antras puslapis tyliai pakartotų įrašą, kurį jau parodė pirmas.
Priimami trys užklausos parametrai: cursor, limit ir direction (forward arba backward). Numatytasis puslapis — 25, viršutinė riba — 100; didesnė reikšmė apribojama, o ne atmetama. Galiniai taškai, kurie dar rūšiuoja ar filtruoja, prideda sort, order ir laisvo teksto paiešką q.
Puslapio meta parodo, kur esate:
{
"data": [ … ],
"meta": {
"hasMore": true,
"nextCursor": "2026-09-12T08:31:44.005Z|8b2f…",
"prevCursor": null,
"total": 134
}
}nextCursor ir prevCursor abu yra tikri: „Ankstesnis“ ir „Kitas“ yra valdikliai, kurių žmogus tikisi. Jie neskaidrūs — serveris į juos įkomponuoja savo rūšiavimo raktą, todėl klientas, kuris juos analizuoja ar sudaro, nutrūks, kai sąrašas pakeis tvarką. total yra daugumoje sąrašų, o praleidžiamas ten, kur skaičiuoti nėra prasmės, pavyzdžiui, ranguotiems paieškos rezultatams.
Užklausų limitai
Limitai taikomi fiksuotame laiko lange ir tikrinami dar prieš nuskaitant užklausos turinį. Atmesta užklausa gauna 429 su kodu RATE_LIMITED ir antraštę Retry-After, sekundėmis.
Dauguma limitų skaičiuojami pagal kliento IP. Jautrūs prisijungimo duomenims — prisijungimas, atnaujinimas, slaptažodžio patvirtinimas iš naujo, MCP prisijungimo duomenų įrašymas — dar saugo skaitiklį kiekvienai paskyrai ir atmeta, kai sustoja bet kuris iš jų. Taip ir vienas adresas, bombarduojantis daugybę paskyrų, ir viena paskyra, puolama iš daugybės adresų, atsitrenkia į sieną. Prisijungimas pagal numatytuosius nustatymus leidžia 10 bandymų per IP ir 5 per el. pašto adresą per dešimt minučių; žinutės siuntimas — 60 per minutę; rašymas maršrutuose /api/agents — 60 per minutę. Kiekviena riba konfigūruojama pagal diegimą, todėl šiuos dydžius laikykite numatytaisiais, o ne sutartimi. Sveikatos patikros ir realiojo laiko srautai neribojami.
Realusis laikas
Sekti pokalbį apklausiant sąrašą yra netinkamas būdas. Vietoj to yra trys srautiniai galiniai taškai:
GET /api/events/stream— serverio siunčiami įvykiai visam, ką prisijungęs asmuo gali matyti.GET /api/threads/:threadId/stream— serverio siunčiami įvykiai vienai gijai. Jis palaikoLast-Event-ID, todėl atsijungus ir prisijungus iš naujo srautas tęsiamas, o ne pradedamas iš naujo.GET /api/activity— WebSocket, perduodantis veiklos srautą.
Naršyklės negali nustatyti antraščių WebSocket rankos paspaudimo metu, todėl WebSocket maršrutas taip pat priima prieigos žetoną kaip užklausos parametrą ?token=. Tai vienintelė vieta, kur žetonas priklauso URL; visi kiti maršrutai jį priima antraštėje.
Išteklių šeimos
Galinių taškų yra gerokai daugiau nei tūkstantis — per daug, kad juos visus išvardytume. Jie sugrupuoti į šeimas, ir kai žinote šeimos priešdėlį, atskiri maršrutai nuspėjami: kolekcija priešdėlyje, įrašas po ja ir pavadinti veiksmai kaip POST pakeliai.
| Šeima | Priešdėlis | Ką apima |
|---|---|---|
| Autentifikavimas | /api/auth | Prisijungimas, atnaujinimas, atsijungimas, dabartinė tapatybė, paties asmens seansai. |
| Kanalai ir gijos | /api/channels, /api/threads | Pokalbių modelis: kanalai talpina gijas, gijos talpina žinutes, o atsakymai įsiterpia po pradine žinute. |
| Agentai | /api/agents | Agentų apibrėžimai, jų kanalų susiejimai, pokalbiai, užduotys ir būsena. |
| Projektai ir lentos | /api/projects, /api/tasks, /api/iterations | Darbų sekimas: projekte esančios lentos ir stulpeliai, juose esančios užduotys, jų viršuje — iteracijos. |
| Žinios | /api/knowledge-base | Versijuojamų puslapių ir failų erdvės su komentarais, atgalinėmis nuorodomis ir paieška. |
| Paštas | /api/mail, /api/mailbox-connections | Prijungtos pašto dėžutės, agentų pašto dėžutės ir juodraščiai, kuriuos agentas parengė žmogui patvirtinti. |
| Patvirtinimai | /api/approvals | Veiksmų, kurių agentas negali atlikti savarankiškai, eilė ir vienas iškvietimas, kuris jas išsprendžia. |
| Auditas | /api/audit-log | Organizacijos hash grandine saugomas audito žurnalas su tikrinimo galiniu tašku. Savininkams ir administratoriams. |
| Sąnaudos ir naudojimas | /api/ledger, /api/billing | Žetonų ir kainų apskaita, biudžetai ir paleidimų trukmės; atskirai — kreditai ir papildymai. Savininkams ir administratoriams. |
| Organizacija ir komandos | /api/organizations, /api/teams, /api/users | Nuomininko, komandų ir narystės administravimas, įskaitant kvietimus. |
| Paleidikliai | /api/triggers | Tvarkaraščiai ir webhook'ai, paleidžiantys agentų darbą, su jų paleidimų istorija. |
| Skambučiai ir balsas | /api/calls, /api/voice | Skambinimas kanale ir balso asistento seansas, transkripcija bei įrenginių žetonai. |
| Vykdytojai | /api/executors, /api/execution-environment-templates | Mašinos, kuriose dirba agentai, jų aplinkos ir vykdytojo susiejimo kanalas. |
| Paleidimai | /api/runs | Gyvi agentų paleidimai: atšaukti, tęsti, paleisti iš naujo, susieti su vykdytoju. |
| Įkėlimai | /api/uploads, /api/attachments | Pirmiausia įkelkite failą, tada susiekite gautą identifikatorių su žinute. |
| Paieška | /api/messages/search | Žinučių paieška visoje organizacijoje arba vienam kanalui. |
| Paslaptys ir nustatymai | /api/secrets, /api/settings/scoped | Tik rašymui skirta prisijungimo duomenų saugykla su aiškiais leidimais ir sluoksniuotos konfigūracijos reikšmės. |
| Prijungtos priemonės | /api/mcp | MCP serveriai, prie kurių šis diegimas kreipiasi. Žr. MCP ir prijungtos priemonės. |
| Būklė | /api/health | Gyvybingumas ir parengtis, abu vieši. /api/health/ready taip pat tikrina duomenų bazę. |
Teisės taikomos kiekvienam maršrutui, o ne šeimai. Apibendrinant: audito žurnalas, sąnaudų registras, politikos taisyklės ir modelių vykdymo valdymo plokštuma yra organizacijos savininkų ir administratorių sritys, o pokalbiai, projektai, žinios ir patvirtinimai prieinami bet kuriam nariui ir siaurinami pagal tai, ką tas narys iš tiesų mato.
Darbiniai pavyzdžiai
Prisijunkite ir išsaugokite atnaujinimo slapuką
Diegime, veikiančiame local režimu, su slaptažodžiu. Prieigos žetonas grįžta atsakymo turinyje; atnaujinimo žetonas patenka į slapukų failą.
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
}
}
}
}Pasibaigus žetonui, iškeiskite slapuką į naują:
curl -sS -X POST https://api.example.com/api/auth/refresh \
--cookie nessie.cookies --cookie-jar nessie.cookiesAtsakymas yra toks pat { token, me } formos, o slapukų failas dabar laiko pasuktą atnaujinimo žetoną.
Išvardykite kanalus, kuriuos matote
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
}
]
}Pridėkite ?teamId=…, kad susiaurintumėte iki vienos komandos, arba ?includeArchived=true, kad įtrauktumėte archyvuotus kanalus. defaultThreadId yra gija, į kurią siųsite toliau.
Siųskite žinutę
Žinutei reikia arba kokio nors content, arba bent vieno įkelto priedo. Siųskite Idempotency-Key, ir pakartota užklausa atitiks žinutę, kurią sukūrė pirmasis bandymas, o ne siųs antrą kopiją.
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."}'Nauja žinutė grąžinama su 201:
{
"data": {
"message": {
"id": "d70e…",
"threadId": "c41a…",
"role": "user",
"content": "Deploying the migration now.",
"createdAt": "2026-09-16T09:04:11.882Z"
},
"pendingAgentInvites": []
}
}Pakartotas tas pats idempotencijos raktas atsako 200 su pradine žinute ir tuščiu pendingAgentInvites, nes pirmasis bandymas jau atliko įspėjimą ir siuntimą, kuriuos aprašo masyvas.
Verta atskirai apdoroti du šio maršruto atmetimus. Turinys, viršijantis pokalbio ilgio ribą, yra 413 MESSAGE_TOO_LARGE, ir tinkamas atsakymas — įkelti tekstą kaip failą. Turinys, struktūriškai panašus į prisijungimo duomenis, yra 422 SECRET_INTERCEPTED — serveris atmeta jį prieš išsaugant, siunčiant ar registruojant, o prisijungimo duomenys priklauso /api/secrets.