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
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 isorganization → 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
limitandoffsetquery parameters - Pagination on the runtime, governance and brain surfaces uses
limit(max 200) and an opaquecursor;offsetis not supported there - Mutation endpoints accept an
Idempotency-Keyheader. ReadGET /v1/limitsbefore 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:
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 sharedactivity_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 requireAuthorization: Bearer <container_auth_token> (resolved from the DB).
Data Flow
The sidecar runs a mirror process that watcheskanban.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.