API
HTTP API na kojem radi svaki Nessie klijent i kako se autentificirati pri korištenju.
Šta je API
Nessie ima jedan HTTP API. Web aplikacija za administraciju, klijenti za macOS i iOS i daemon izvršitelja na udaljenom računaru su obični klijenti tog API-ja, i ništa što oni mogu da rade nije dostupno na drugi način. To je JSON API zasnovan na Fastify serveru, nije GraphQL, i nema posebnu „javnu“ podgrupu: površina koju vaše vlastite skripte pozivaju je ista površina koju poziva proizvod.
U putanji nema segmenta za verziju. Sve rute nalaze se pod /api, osim ulaznog MCP endpointa na POST /mcp i nekoliko dokumenata za otkrivanje pod /.well-known/. Kompatibilnost se održava tako što se uvijek samo dodaju polja, pa klijent koji ignoriše ono što ne prepoznaje nastavlja da radi.
Osnovni URL
Nessie je samostalno hostiran, pa je osnovni URL bilo koji origin na kojem vaša instalacija služi API. Operator ga postavlja kao NESSIE_API_PUBLIC_URL, a ista vrijednost je ono što API koristi kada mora sam da sastavi apsolutni URL. Na instanci koju mi pokrećemo to je https://api.nessie.works; razvojna instanca pokrenuta sa pnpm dev odgovara na http://localhost:5454.
Web aplikacija za administraciju je drugi origin u odnosu na API, pa klijenti u pregledniku podliježu CORS listi dozvoljenih (NESSIE_CORS_ORIGINS). Zahtjevi iz skripte ili sa servera nemaju origin koji bi se provjeravao i nisu time pogođeni.
Autentifikacija
Svaki zahtjev izvan malog skupa namjerno javnih ruta nosi pristupni token u standardnom zaglavlju:
Authorization: Bearer <token>Token je potpisani JWT koji izdaje API. Kratkog je vijeka — podrazumijevano trideset minuta (NESSIE_AUTH_TOKEN_TTL) — i to je jedina vjerodajnica koju obični pozivalac ikada predstavlja. Nessie nema dugotrajne lične API ključeve. Ako želite da skripta poziva API, ona se prijavljuje na isti način kao preglednik osobe i obnavlja svoj token dok radi.
Dobijanje tokena
POST /api/auth/session kreira sesiju. Odgovara pristupnim tokenom i identitetom pozivaoca i postavlja token za obnavljanje kao zasebni HTTP-only kolačić.
Kako dokazujete ko ste, zavisi od načina na koji je instanca postavljena. Instanca koja radi u local režimu prihvata e-mail i lozinku. Na instanci hosted ili selfHosted prijava lozinkom se odmah odbija sa 403 PASSWORD_AUTH_DISABLED, a jedini ulaz je konfigurisani pružatelj identiteta, tako da nalog nikada ne može dobiti drugi, slabiji put identiteta pored njega.
Prijava preko pružatelja identiteta
Jedinstvena prijava (SSO) je OAuth razmjena autorizacionog koda uz PKCE, u tri koraka. Nessiev vlastiti pružatelj identiteta je UnlikeOtherAI, koji takođe posjeduje strukturu organizacija i timova koju instanca preslikava; razmjena u nastavku ima isti oblik za bilo kojeg konfigurisanog pružatelja.
GET /api/auth/providersnavodi šta ova instanca prihvata, svaki saproviderId, nazivom i informacijom da li stranica za prijavu treba automatski da preusmjeri na njega.GET /api/auth/providers/:providerId/authorize, sacodeChallenge,redirectUriistatekao parametrima upita, odgovara sa{ data: { authorizeUrl } }. Pošaljite osobu tamo.- Pružatelj vraća osobu na vaš
redirectUrisa kodom. Pošaljite ga nazad kaoPOST /api/auth/sessionsa{ providerId, code, codeVerifier, redirectUri }— sva četiri su obavezna zajedno, a nepotpun skup je400 EXTERNAL_AUTH_INCOMPLETE.
Obnavljanje sesije
Token za obnavljanje nikada nije u tijelu odgovora. Postavlja se kao HTTP-only kolačić pod nazivom nessie_refresh, ograničen na putanju /api/auth, sa podrazumijevanim trajanjem od trideset dana (NESSIE_AUTH_REFRESH_TOKEN_TTL). Poziv POST /api/auth/refresh sa tim kolačićem troši ga, izdaje novi pristupni token i postavlja novi kolačić umjesto njega — tokeni se rotiraju, pa ukraden token vrijedi samo dok stvarni klijent sljedeći put ne obnovi.
Preglednik prijavljen na više naloga čuva jedan takav kolačić za svaku prijavu, pod nazivom nessie_refresh_<slot>, i navodi onaj na koji se zahtjev odnosi zaglavljem x-nessie-account-slot. Klijent koji ne šalje takvo zaglavlje odnosi se na nessie_refresh, što je sve što treba komandnoj liniji.
Klijent sa komandne linije zato treba spremište kolačića. Sa curl, to je --cookie-jar na pozivu za prijavu i --cookie pri obnavljanju, kao u radnom primjeru ispod.
Šta se provjerava na svakom zahtjevu
Autentifikacija nije samo provjera potpisa. Prije nego što se obrađivač pokrene, API provjerava potpis i rok važenja tokena, potvrđuje da sesija nije opozvana (i globalnom verzijom tokena za korisnika i pojedinačnim ID-jem sesije) i učitava članstvo pozivaoca u organizaciji koju token navodi. Deaktivirano članstvo je 403. Kada je organizacija zasnovana na vanjskom pružatelju identiteta, trenutni status pozivaoca se ponovo provjerava kod tog pružatelja pri svakom zahtjevu, umjesto da se čita iz tokena, pa pristup koji je spolja uklonjen prestaje odmah, a ne na sljedeći istek.
Vjerodajnice koje nisu tokeni sesije
Postoje još dvije vjerodajnice tipa bearer, i nijedna nije opšti ključ. Vjerodajnica glasovnog uređaja prihvata se samo na rutama za glasovne pozive; vjerodajnica za pristup agentu samo na MCP endpointu. Predstavljanje bilo koje od njih bilo gdje drugdje odbija se sa 403 koji imenuje vjerodajnicu, a ne ponovo pokušava kao slabija sesija — pogledajte MCP i povezani alati za to kako se vjerodajnica agenta izdaje.
Omotač odgovora
Svaki uspješan odgovor je objekat sa ključem data. Nema golog niza niti sadržaja na najvišem nivou, pa klijent nikada ne mora da razlikuje oblik:
{
"data": { "id": "3f1c…", "label": "engineering" }
}Krajnje tačke za liste dodaju objekat meta pored njega. Na najvišem nivou se nikada ne dodaje ništa drugo.
I greške koriste jedan oblik, bez obzira na to šta ih je izazvalo:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "A message needs content or at least one attachment",
"field": "body",
"details": { "formErrors": [], "fieldErrors": {} }
}
}code je dio koji mašina čita i na osnovu kojeg treba grananje; message je za osobu. field i details su prisutni kada je greška dovoljno specifična da se lokalizuje. Neobrađena serverska greška je uvijek 500 INTERNAL_ERROR sa fiksnom porukom — tekst osnovne greške se bilježi, nikada se ne vraća, jer je mogao pokupiti podatke zahtjeva dok izlazi van.
Kodovi grešaka koje ćete prvo sresti
| Status | Kod | Značenje |
|---|---|---|
| 400 | VALIDATION_ERROR | Tijelo ili upit ne odgovaraju šemi. |
| 401 | AUTH_REQUIRED | Nema bearer tokena ili je zaglavlje neispravno. |
| 401 | TOKEN_EXPIRED | Pristupni token je istekao. Obnovite ga i pokušajte ponovo. |
| 401 | TOKEN_REVOKED | Sesija je odjavljena, ili su sve sesije prisilno prekinute. |
| 403 | ACCOUNT_DEACTIVATED | Članstvo u ovoj organizaciji je deaktivirano. |
| 404 | NOT_FOUND | Nema takve rute ili nema takvog zapisa vidljivog ovom pozivaocu. |
| 429 | RATE_LIMITED | Ograničenje za ovaj zahtjev je iskorišteno. Pročitajte Retry-After. |
| 500 | INTERNAL_ERROR | Neobrađena serverska greška, namjerno neprozirna. |
Paginacija
Krajnje tačke za liste stranicu prave neprozirnim keyset kursorom, a ne offsetom — redovi se umeću dok neko čita, i sa offsetom druga stranica tiho ponavlja zapis koji je prva već prikazala.
Prihvataju se tri parametra upita: cursor, limit i direction (forward ili backward). Podrazumijevana stranica ima 25 stavki, a gornja granica je 100; veća vrijednost se ograničava, a ne odbija. Krajnje tačke koje takođe sortiraju ili filtriraju dodaju sort, order i slobodan tekst q.
meta stranice vam govori gdje se nalazite:
{
"data": [ … ],
"meta": {
"hasMore": true,
"nextCursor": "2026-09-12T08:31:44.005Z|8b2f…",
"prevCursor": null,
"total": 134
}
}nextCursor i prevCursor su oba stvarna: Prethodno i Sljedeće su obje kontrole koje osoba očekuje. Oni su neprozirni — server u njih kodira vlastiti ključ sortiranja, pa će klijent koji ih parsira ili konstruiše prestati raditi čim lista promijeni redoslijed. total je prisutan na većini lista, a izostavlja se tamo gdje brojanje nema smisla, kao kod rangiranih rezultata pretrage.
Ograničenja broja zahtjeva
Ograničenja važe po fiksnom prozoru i provode se prije nego što se tijelo zahtjeva uopšte pročita. Odbijen zahtjev je 429 sa kodom RATE_LIMITED i zaglavljem Retry-After u sekundama.
Većina ograničenja vezana je za IP adresu klijenta; ona osjetljiva na vjerodajnice — prijava, obnavljanje, ponovna provjera lozinke, pisanje MCP vjerodajnica — imaju i brojač po nalogu i odbijaju kada se aktivira bilo koji, pa i jedna adresa koja šalje zahtjeve na mnogo naloga i jedan nalog napadnut sa mnogo adresa udare u zid. Prijava podrazumijevano dozvoljava 10 pokušaja po IP adresi i 5 po e-mail adresi u deset minuta; slanje poruke podrazumijevano 60 u minuti; pisanje pod /api/agents 60 u minuti. Svaki prag se može podešavati po instalaciji, pa ove vrijednosti tretirajte kao podrazumijevane vrijednosti, a ne kao ugovor. Provjere zdravlja i realtime tokovi su izuzeti.
Realtime
Učitavanje liste u petlji je pogrešan način praćenja razgovora. Umjesto toga postoje tri krajnje tačke za strimovanje:
GET /api/events/stream— server-sent events za sve što prijavljena osoba može da vidi.GET /api/threads/:threadId/stream— server-sent events za jednu nit. PoštujeLast-Event-ID, pa se ponovno povezivanje nastavlja, a ne počinje ispočetka.GET /api/activity— WebSocket koji nosi feed aktivnosti.
Preglednici ne mogu postavljati zaglavlja pri WebSocket handshake-u, pa WebSocket ruta takođe prihvata pristupni token kao parametar upita ?token=. To je jedino mjesto gdje token pripada u URL-u; svaka druga ruta ga prima kroz zaglavlje.
Porodice resursa
Postoji znatno više od hiljadu krajnjih tačaka, što je previše da bi se sve nabrojale. Grupisane su u porodice, a kada znate prefiks porodice, pojedinačne rute su predvidljive — kolekcija na prefiksu, zapis ispod nje i imenovane radnje kao POST podputanje.
| Porodica | Prefiks | Šta obuhvata |
|---|---|---|
| Autentifikacija | /api/auth | Prijava, obnavljanje, odjava, trenutni identitet i vlastite sesije osobe. |
| Kanali i niti | /api/channels, /api/threads | Model razgovora: kanali sadrže niti, niti sadrže poruke, a odgovori se gnijezde pod korijenom. |
| Agenti | /api/agents | Definicije agenata, njihova povezivanja s kanalima, razgovori, zadaci i status. |
| Projekti i table | /api/projects, /api/tasks, /api/iterations | Praćenje rada: table i kolone unutar projekta, zadaci na njima i iteracije nad njima. |
| Znanje | /api/knowledge-base | Prostori sa verzionisanim stranicama i datotekama, uz komentare, povratne veze i pretragu. |
| Pošta | /api/mail, /api/mailbox-connections | Povezani poštanski sandučići, sandučići agenata i nacrti koje je agent napisao da ih osoba odobri. |
| Odobrenja | /api/approvals | Red radnji koje agent ne smije preduzeti samostalno, i jedan poziv kojim se one rješavaju. |
| Revizija | /api/audit-log | Revizioni trag organizacije sa lancem heševa i krajnjom tačkom za provjeru. Vlasnici i admini. |
| Troškovi i upotreba | /api/ledger, /api/billing | Obračun tokena i troškova, budžeti i trajanje izvršavanja; zasebno, krediti i dopune. Vlasnici i admini. |
| Organizacija i timovi | /api/organizations, /api/teams, /api/users | Administracija tenanta, tima i članstva, uključujući pozivnice. |
| Okidači | /api/triggers | Rasporedi i webhookovi koji pokreću rad agenata, sa njihovom historijom aktiviranja. |
| Pozivi i glas | /api/calls, /api/voice | Pozivi unutar kanala, te sesija glasovnog asistenta, transkript i tokeni uređaja. |
| Izvršitelji | /api/executors, /api/execution-environment-templates | Računari na kojima agenti rade, njihova okruženja i kanal za uparivanje daemona. |
| Izvršavanja | /api/runs | Aktivna izvršavanja agenata: otkazivanje, nastavak, ponovno pokretanje, vezivanje za izvršitelja. |
| Otpremanja | /api/uploads, /api/attachments | Prvo otpremite datoteku, zatim povežite vraćeni ID sa porukom. |
| Pretraga | /api/messages/search | Pretraga poruka, za cijelu organizaciju ili ograničena na jedan kanal. |
| Tajne i postavke | /api/secrets, /api/settings/scoped | Skladište vjerodajnica samo za pisanje sa eksplicitnim dozvolama, i slojevite konfiguracijske vrijednosti. |
| Povezani alati | /api/mcp | MCP serveri kojima ova instanca šalje zahtjeve. Pogledajte MCP i povezani alati. |
| Zdravlje | /api/health | Provjera živosti i spremnosti, obje javne. /api/health/ready takođe provjerava bazu podataka. |
Prava se provode po ruti, a ne po porodici. Uopšteno: revizioni dnevnik, evidencija troškova, pravila politike i kontrolna ravan za inferenciju su površine za vlasnike i admine organizacije, dok su razgovori, projekti, znanje i odobrenja otvoreni svakom članu i sužavaju se prema onome što taj član zaista može da vidi.
Radni primjeri
Prijava i čuvanje kolačića za obnavljanje
Na instanci u local režimu, sa lozinkom. Pristupni token se vraća u tijelu odgovora; token za obnavljanje ide u spremište kolačića.
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
}
}
}
}Kada token istekne, zamijenite kolačić za novi:
curl -sS -X POST https://api.example.com/api/auth/refresh \
--cookie nessie.cookies --cookie-jar nessie.cookiesOdgovor ima isti oblik { token, me }, a spremište kolačića sada sadrži rotirani token za obnavljanje.
Navedite kanale koje možete vidjeti
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 suzite na jedan tim, ili ?includeArchived=true da uključite arhivirane kanale. defaultThreadId je ono na šta sljedeće šaljete.
Pošaljite poruku
Poruka treba da ima neki content ili bar jedan otpremljeni prilog. Pošaljite Idempotency-Key, pa će ponovljeni zahtjev dati poruku koju je kreirao prvi pokušaj, a ne poslati drugu kopiju.
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."}'Nova poruka je 201:
{
"data": {
"message": {
"id": "d70e…",
"threadId": "c41a…",
"role": "user",
"content": "Deploying the migration now.",
"createdAt": "2026-09-16T09:04:11.882Z"
},
"pendingAgentInvites": []
}
}Ponavljanje istog ključa idempotentnosti vraća 200 sa originalnom porukom i praznim pendingAgentInvites, jer je prvi pokušaj već obavio obavještavanje i slanje koje taj niz opisuje.
Dva odbijanja na ovoj ruti vrijedi posebno obraditi. Sadržaj iza granice dužine poruke je 413 MESSAGE_TOO_LARGE, a ispravan odgovor je otpremiti tekst kao datoteku. Sadržaj koji strukturno liči na vjerodajnicu je 422 SECRET_INTERCEPTED — server odbija prije nego što se poruka sačuva, pošalje ili zabilježi, a vjerodajnica pripada u /api/secrets.