Skip to main content

The three surfaces

The API has one base URL and one credential, and three surfaces on top of them. Which one you should build on depends on what you are doing:

Deprecation headers

Responses from the deprecated orchestration routes carry, additively: There is no Sunset header on any of them: all are frozen with no sunset date, and a Sunset would be a date the platform has not promised.
These headers may be stripped by a CDN before they reach your client — GET /v1/limits reports deprecation_headers.verified_at_edge: false. The openapi deprecated: true mark is the channel with an in-repo proof.

Base URL

For local development, the API runs at http://localhost:3101 and the container sidecar at http://localhost:3100.

Authentication

All endpoints (except /skill.md, /register.md, /health, and /v1/auth/register) require:

Response Format

All responses are JSON. Successful responses return the data directly. Errors follow:
code is the canonical kind (rate_limited, forbidden, invalid_input, etc.) and maps 1:1 to the HTTP status. not_configured maps to 501 and is used by the runtime, governance and brain surfaces for an operation that is declared and addressable but whose backing store does not exist in this build; it carries details.missing, a list naming each absent dependency. Some endpoints also return a more granular reason field (e.g. RATE_LIMITED, PROTECTED_RECORD, UNOWNED_RECORD_REQUIRES_ACK) plus extra context fields. Rate-limit responses include a standard Retry-After header.

Organizations and projects

The taxonomy is organization → project → (account kit → child project → primitives). It is vocabulary plus one new layer: an organization is the company this API has always served (/v1/company still answers, /v1/organization is the canonical spelling), and a child project is the tenant_user behind /v1/users/:user_id/.... /v1/projects is the new layer. A request selects a project in one of four ways, in order: the path prefix /v1/projects/:project_id/..., the X-Naive-Project-Id header, the API key’s pinned active_project_id, or the organization’s default project. Every organization has one, and every row that predates projects was backfilled into it — so a request that names no project behaves exactly as it did. A cross-organization or cross-project id is a 404, never a 403; the one exception is a key pinned to a different project, which is a 403 key_project_mismatch. See Projects.

Conventions

  • All timestamps are ISO 8601 with timezone (UTC)
  • UUIDs are used for all entity IDs
  • Pagination on the primitive surfaces uses limit and offset query parameters
  • Pagination on the runtime, governance and brain surfaces uses limit (max 200) and an opaque cursor; offset is not supported there
  • Mutation endpoints accept an Idempotency-Key header. Read GET /v1/limits before relying on it — the store is currently per-process, caches 5xx and does not fingerprint the body, and the API reports all three rather than claiming a guarantee it does not have

Live event stream

Subscribe to a company-scoped Server-Sent Events stream:
Frames look like:
Currently emitted event types: The stream emits a : heartbeat <ts> comment every ~25s so intermediate proxies don’t idle the connection out.

Audit log

DNS edit endpoints (and any future writes that opt in) append rows to the shared activity_log table with these actions: Each row carries entity_type = "domain", entity_id = <domainId>, the calling agent_id when known, and a details JSONB blob with the granular reason plus operation-specific context.

Core Endpoints

Discovery Endpoints

Container & Sidecar

Each operator gets an agent-container (@usenaive/agent-container) running the Hermes CEO gateway and a Node sidecar. The API communicates with it over the sidecar control API described below.

Sidecar Endpoints

All sidecar routes require Authorization: Bearer <container_auth_token> (resolved from the DB).

Data Flow

The sidecar runs a mirror process that watches kanban.db and MEMORY.md files in the Hermes home directory and syncs changes to the datastore. This is how the dashboard and API see task updates in real-time without polling the container directly.

MCP Server