Nexara Connect docs0.1.0

REST API

Generated by docs/site/gen-reference.mjs from the route registrations in server/src/app.ts and server/src/http/*.ts (98 routes). Do not edit by hand: change the code or the description map in the generator, then run node docs/site/gen-reference.mjs && node docs/site/build.mjs.

Base URL: https://dev.nexara.ac (staging) or https://app.nexara.ac (production). JSON in and out. Errors look like {"error":{"code","message"},"code"}; step-up gates return 403 with code step_up_required.

Auth column

CodeMeaning
PPublic, no credentials
SWeb session cookie. Unsafe methods also need X-CSRF-Token echoed from the nxc_csrf cookie. Workspace from X-Nexara-Workspace, ?workspace= or the session default
KAgent key: Authorization: Bearer nxc_...
OOAuth access token, MCP only (/api/v1 refuses it with 401): Authorization: Bearer nxa_...
GGit token nxg_... as the HTTP Basic password. Refused everywhere except /git
+UStep-up within the last 5 minutes (POST /api/auth/stepup). Agents can never satisfy it
ownWorkspace owner. (read), (write) etc. name the grant action checked for agents

Rate limits: 120 requests/min per principal on /api/v1 (burst 30), bundle 30/min, import 5/hour, login and sign-up 5/min per IP, git 60/min per IP.

Health

MethodPathAuthWhat it does
GET/healthzPLiveness: version, node count, indexed_at
GET/readyzPReadiness: DB check, version, git_sha, embeddings status

Auth and sessions

MethodPathAuthWhat it does
POST/api/v1/auth/signupPCreate account + own workspace. SIGNUPS=invite requires an invite token
POST/auth/signupPAlias of /api/v1/auth/signup
POST/api/auth/signupPAlias of /api/v1/auth/signup
POST/api/auth/loginPEmail + password. Returns totp_required or totp_enroll_required when applicable
POST/api/auth/totp/verifyS (pending)Second factor after password
POST/api/auth/totp/enrollSWithout code: returns otpauth URI. With code: confirms and enables TOTP
POST/api/auth/stepupSStep-up for 5 min (TOTP code, or password when TOTP is not enrolled)
GET/api/auth/meSCurrent user, workspaces, current workspace
POST/api/auth/logoutSEnd session, clear cookies
GET/api/auth/sessionsSList your active sessions
DELETE/api/auth/sessions/:idSRevoke one of your sessions
GET/loginPHTML sign-in form (OAuth consent fallback)
POST/loginPHTML sign-in form post
POST/login/totpS (pending)HTML TOTP form post
GET/invite/:tokenPInvite landing page (HTML)
POST/invite/:tokenSAccept invite (HTML form, CSRF)

Identity and workspaces

MethodPathAuthWhat it does
POST/api/v1/invites/:token/acceptSAccept invite (JSON, X-CSRF-Token)
GET/api/v1/meS KWho you are (humans: email, role, totp; agents: grants)
PATCH/api/v1/meSChange display name
GET/api/v1/workspacesS KWorkspaces you belong to
POST/api/v1/workspacesSCreate a workspace (humans only)
GET/api/v1/membersSMembers of the current workspace
GET/api/v1/workspaces/:ws/membersSMembers of workspace :ws
PATCH/api/v1/members/:idS ownChange a member role
PATCH/api/v1/workspaces/:ws/members/:idS ownChange a member role in :ws
DELETE/api/v1/members/:idS ownRemove a member (or leave, for yourself)
DELETE/api/v1/workspaces/:ws/members/:idS ownRemove a member from :ws
GET/api/v1/invitesS ownList invites
GET/api/v1/workspaces/:ws/invitesS ownList invites of :ws
POST/api/v1/invitesS ownCreate an invite; returns accept_url (no mailer yet)
POST/api/v1/workspaces/:ws/invitesS ownCreate an invite in :ws
DELETE/api/v1/invites/:idS ownRevoke an invite
DELETE/api/v1/workspaces/:ws/invites/:idS ownRevoke an invite in :ws
POST/api/v1/workspaces/:ws/lockdownS own +UKill switch: bump token epoch (every key dies), drop other sessions
POST/api/v1/nodes/:id/threads/messagesS K (collab)Alias of POST /threads
GET/api/v1/whoamiS KIdentity, workspace, role, via, grants

Spaces and folders

MethodPathAuthWhat it does
GET/api/v1/spacesS KSpaces you can see
POST/api/v1/spacesS K (admin)Create a Space ({id, name})
GET/api/v1/spaces/:s/treeS KFolder tree with summaries. ?path, ?depth, ?include_archived
POST/api/v1/clusters/*S K (write)POST /clusters/<space>/<folder>/archive (humans +U) or /restore
PUT/api/v1/clusters/*S K (admin)PUT /clusters/<space>/<folder>/lifecycle {auto_archive_days, half_life_days}

Pages (nodes)

MethodPathAuthWhat it does
POST/api/v1/nodesS K (write)Create a page ({path, content} or {space, cluster_path, title, body, frontmatter}). Returns ETag
GET/api/v1/nodes/:idS K (read)Page by id or path, redacted to your ceiling. ?format=md, ?at=<sha>, ?section. Counts as a read
PUT/api/v1/nodes/:idS K (write)Replace. If-Match or base_sha: clean merge lands, conflict returns 409 + proposal
PATCH/api/v1/nodes/:idS K (write)Partial update, same conflict rules
DELETE/api/v1/nodes/:idS +U, K (admin)Delete (a commit; history keeps it)
POST/api/v1/nodes/:id/moveS K (write)Move; a wider audience needs step-up (agents: becomes a proposal)
GET/api/v1/nodes/:id/historyS K (read)Versions (commits)
GET/api/v1/nodes/:id/diffS K (owner-level read)?from=<sha>&to=<sha>. Raw content, so secret-level read is required
GET/api/v1/nodes/:id/backlinksS K (read)Pages linking here
GET/api/v1/nodes/:id/relatedS K (read)Links, backlinks, folder neighbours, shared tags
POST/api/v1/nodes/:id/archiveS K (write, else proposal)Archive with reason closed|stale|superseded|manual
POST/api/v1/nodes/:id/restoreS K (write)Return to active

Threads and inbox

MethodPathAuthWhat it does
GET/api/v1/nodes/:id/threadsS K (read)Thread messages on a page
POST/api/v1/nodes/:id/threadsS K (collab)Post {body, kind, reply_to, mentions}
POST/api/v1/nodes/:id/threads/readS KMark the thread read
POST/api/v1/nodes/:id/threads/unlockS (editor+)Unlock a thread locked by the loop breaker
GET/api/v1/inboxS KYour events. ?state=unread|read|done|all, ?after, ?limit, ?wait<=25 (long-poll)
POST/api/v1/inbox/ackS KMark done {up_to} or {seqs}

Retrieval

MethodPathAuthWhat it does
GET/api/v1/searchS K (search)?q, space, cluster, tags, mode=hybrid|fts|vector, limit, include_archived
POST/api/v1/bundleS K (read){intent, budget_tokens, scope, include_links, include_archived}. Accept: text/markdown for raw markdown. 30/min
GET/api/v1/bundleS K (read)Same as POST, parameters in the query string

Proposals

MethodPathAuthWhat it does
GET/api/v1/proposalsS KList proposals. ?status=open|accepted|rejected|superseded
POST/api/v1/proposalsS K (propose)Create {path or node_id, content, reason}
GET/api/v1/proposals/:idS KOne proposal (full content only for humans)
POST/api/v1/proposals/:id/acceptS (editor+)Accept, optionally with edited content
POST/api/v1/proposals/:id/rejectS (editor+)Reject {reason}

Agents, grants and tokens

MethodPathAuthWhat it does
GET/api/v1/principalsS KHumans and agents in the workspace (agents see id, name, kind only)
POST/api/v1/principalsSCreate an agent {name, grants, ceiling}
GET/api/v1/principals/:idS KOne agent
DELETE/api/v1/principals/:idS (creator or owner)Delete an agent
GET/api/v1/principals/:id/grantsS KAgent grants
PUT/api/v1/principals/:id/grantsS (creator or owner), +U for secretReplace grants. Never above your own role ceiling
GET/api/v1/principals/:id/tokensS (creator or owner)Agent keys (hints only)
POST/api/v1/principals/:id/tokensS (creator or owner)Mint an nxc_ key (secret shown once) {name, expires_in_days, ip_pin, ceiling}
DELETE/api/v1/principals/:id/tokens/:tidS (creator or owner)Revoke a key (immediate)
POST/api/v1/me/git-tokensS +UMint your own nxg_ git token (default 365 days)
POST/api/v1/elevationsS own +UTime-boxed elevation for an agent (the only way to reach secret)

Operations

MethodPathAuthWhat it does
GET/api/v1/lifecycle/candidatesS KAuto-archive candidates, mode, next run, last digest
POST/api/v1/lifecycle/runS own (+U for apply)Run the lifecycle job now {mode: dry|apply}
POST/api/v1/importS K (write)Zip upload (multipart field file + space), raw application/zip, or JSON {space, files[]}. 50 MB, 5/hour
GET/api/v1/auditS ownHash-chained audit log. ?limit, cursor, principal, action, node
POST/api/v1/logS K (propose)Append to a Space or Folder log.md {scope, entry}

OAuth 2.1

MethodPathAuthWhat it does
GET/.well-known/oauth-authorization-serverPRFC 8414 authorization server metadata
GET/.well-known/oauth-authorization-server/*PSame, path-suffixed form
GET/.well-known/openid-configurationPSame metadata (compatibility alias)
GET/.well-known/oauth-protected-resourcePRFC 9728 protected resource metadata for /mcp
GET/.well-known/oauth-protected-resource/*PPath-aware form: /mcp or /w/<ws>/mcp, resource equals the requested URL (RFC 9728 3.3); other paths 404
POST/oauth/registerPDynamic client registration (10/min per IP). Loopback or allowlisted redirect URIs only
GET/oauth/authorizeSConsent page (HTML) or JSON consent descriptor. Redirects to /login when signed out
POST/oauth/authorizeSApprove or deny; needs the consent csrf_token. Owners and editors only
POST/oauth/tokenPauthorization_code (PKCE S256) and refresh_token grants. resource must be /mcp or /w/<ws>/mcp and match the authorization, else invalid_target. 30/min per IP
POST/oauth/revokePRevoke an access or refresh token

MCP

MethodPathAuthWhat it does
ALL/mcpK OMCP streamable HTTP (stateless). 401 with WWW-Authenticate resource_metadata when no token. OAuth tokens must be bound to /mcp
ALL/w/:slug/mcpK OSame as /mcp, pinned to workspace slug (token must belong to it). Own OAuth resource: accepts tokens bound to /w/:slug/mcp or /mcp; 401 points at the path-aware metadata

Git

MethodPathAuthWhat it does
ALL/git/:repo.git/*GGit smart HTTP (Basic auth, password = nxg_ token). Fetch needs workspace-wide secret read; push needs write + admin

Examples

URL=https://dev.nexara.ac
# who am I (agent key)
curl -s $URL/api/v1/whoami -H "Authorization: Bearer $NEXARA_KEY"
# a context bundle as markdown
curl -s $URL/api/v1/bundle -H "Authorization: Bearer $NEXARA_KEY" \
  -H "Content-Type: application/json" -H "Accept: text/markdown" \
  -d '{"intent":"DLP project status","budget_tokens":2000}'
# update a page without clobbering someone else's edit
curl -s -X PUT $URL/api/v1/nodes/<id> -H "Authorization: Bearer $NEXARA_KEY" \
  -H 'If-Match: "<hash from the ETag>"' -H "Content-Type: application/json" \
  -d '{"content":"---\ntitle: DLP\n---\nNew body"}'
Generated from api.md by docs/site/build.mjs. Edit the Markdown, then rebuild.