API Reference
The API listens on :8080. Request and response bodies are JSON, except agent specs, which may also be YAML.
Credentials
Section titled “Credentials”| Credential | Header | Who uses it | Reaches |
|---|---|---|---|
| JWT | Authorization: Bearer <access token> | People (console, Cortex) | The user’s tenants, picked with X-Tenant-ID: <id>. Required for tenant and key management. |
| API key | X-API-Key: <key> | Programs, Herald | Its own tenant only. |
| Run token | Authorization: Bearer <token> | An agent mid-run | POST /api/v1/runs/messages/send only. |
| Operator | JWT of a user with the operator role, or X-Operator-Token | Operators | /api/v1/admin/*. An operator’s JWT may also name any tenant in X-Tenant-ID. |
Access tokens last 15 minutes; refresh tokens 7 days. /healthz, /readyz and /auth/* are public.
| Method | Path | Body | Returns |
|---|---|---|---|
POST | /auth/register | email, password (≥ 8), displayName | 201 accessToken, refreshToken, user |
POST | /auth/login | email, password | accessToken, refreshToken, user |
POST | /auth/refresh | refreshToken | A new pair; the old refresh token is revoked |
GET | /api/v1/me | — | The current user: id, email, displayName |
Tenants and API keys
Section titled “Tenants and API keys”JWT only.
| Method | Path | Body | Returns |
|---|---|---|---|
POST | /api/v1/tenants | displayName | 201 id, crName, displayName |
GET | /api/v1/tenants | — | The user’s tenants |
DELETE | /api/v1/tenants/:id | — | Soft-deletes the tenant: its keys stop validating, its agents are retired and its active subscriptions are cancelled |
POST | /api/v1/tenants/:id/keys | label | 201 rawKey (shown once), label |
GET | /api/v1/tenants/:id/keys | — | Keys by hash and label, never the raw key |
DELETE | /api/v1/tenants/:id/keys/:hash | — | Revokes the key (soft delete; versions it authored keep the attribution) |
Agents
Section titled “Agents”JWT or API key. The tenant comes from the credential.
| Method | Path | Notes |
|---|---|---|
POST | /api/v1/agents[?subscription_id=] | Body: the astromesh/v1 spec (YAML or JSON). Creates the agent and version 1. 201. |
GET | /api/v1/agents | The tenant’s live agents. |
GET | /api/v1/agents/:name | The agent and its current spec. |
PUT | /api/v1/agents/:name[?subscription_id=] | Appends a new version and makes it current. Without subscription_id the agent keeps the one it had. |
DELETE | /api/v1/agents/:name | Soft-deletes; history stays readable. |
GET | /api/v1/agents/:name/versions | Version summaries: number, date, author, checksum. |
GET | /api/v1/agents/:name/versions/:number | One version with its spec. :number must be canonical (1, not 01). |
GET | /api/v1/agents/by-id/:id/versions[/:number] | The same, addressed by agent id: unambiguous even after a name is reused. |
A spec that fails validation returns 400 with problems: [...]. A body over the size limit is 413, and a number that cannot be stored without changing its value is 400. With subscription_id, a foreign or unknown subscription is 404 and a cancelled one 422.
POST /api/v1/agents/:name/run
Section titled “POST /api/v1/agents/:name/run”| Field | Type | |
|---|---|---|
query | string | Required. |
session_id | string | Conversation key. Reuse it to continue a conversation. |
context | object | Passed to the agent: prompt variables and caller data. Keys starting with _ are reserved for the runtime. |
Optional header Idempotency-Key: replaying a key returns the existing invocation without running it again.
{ "invocation_id": "…", "status": "ok", "answer": "…", "usage": { "tokens_in": 0, "tokens_out": 0, "by_model": [] }, "credits_charged_micros": 0, "pricing_status": "priced", "data": {}, "chain": {}, "propuestas": []}by_model[]holds provider, model, role and tokens per model, includingtokens_cached.datais present when the agent declaresspec.output_schema(nullif the answer did not validate).chainis present whenspec.chainfired.propuestaslists the writes thatmode: proposetools recorded without executing. Each key is omitted, notnull, when the runtime sent nothing.- At 80 % or more of the period’s credit cap, the response carries
X-Nexus-Credit-Usage: <percent>.
GET /api/v1/agents/:name/run/stream (WebSocket)
Section titled “GET /api/v1/agents/:name/run/stream (WebSocket)”The handshake is a GET, so query and session_id travel as URL parameters. Every HTTP-level check (auth, 404, 422, admission) happens before the upgrade. The socket relays the runtime’s execution events and ends with one terminal event:
{"type": "done", "invocation_id", "status": "ok", "answer", "usage", …}, which carries the same fields as the synchronous response.{"type": "error", "invocation_id", "status", "error_code", "message"}
Closing the socket cancels the run on the server and records it cancelled, charged zero credits.
Run errors
Section titled “Run errors”| Status | When |
|---|---|
400 | Missing query or a malformed body. |
402 | credit_budget_exhausted or subscription_credit_budget_exhausted. |
404 | No such agent in this tenant. |
409 | The Idempotency-Key belongs to another tenant’s invocation. |
422 | The agent has no live version, or subscription_inactive. |
429 | concurrency_exceeded or rate_limited. |
502 | The runtime failed, or the agent could not be loaded. |
503 | Nexus could not resolve the tenant’s limits or record the invocation, and refuses to run unrecorded. |
504 | The run exceeded the run timeout. |
Admission rejections are recorded as invocations with status rejected and the reason in error_code.
Observability
Section titled “Observability”JWT or API key, scoped to the tenant. Provider and infrastructure costs are not included; they are on the operator plane only.
| Method | Path | Returns |
|---|---|---|
GET | /api/v1/agents/:name/status | Recent invocations with status, session_id and errors. |
GET | /api/v1/agents/:name/logs | The same recent invocations (a dedicated log stream does not exist yet). |
GET | /api/v1/agents/:name/metrics[?period=YYYY-MM] | Consumption for the month (current by default) and all-time, by model. |
GET | /api/v1/agents/:name/invocations/:id | One invocation: status, timing, error, usage by model. |
GET | /api/v1/usage[?period=YYYY-MM] | Tenant totals (current month and all-time) and a per-agent ranking by credits, including deleted agents. |
Catalog
Section titled “Catalog”GET /api/v1/catalog lists the tools an agent can declare (builtins and integrations), read live from the runtime pool.
Connections
Section titled “Connections”A connection stores a credential for the tenant, such as an ERP key, an api_<slug> or an mcp_<slug>. Every run carries the tenant’s connections to the runtime, where an integration tool resolves its credential. The tenant comes from the credential, never the path.
| Method | Path | Body / returns |
|---|---|---|
PUT | /api/v1/connections/:name | base_url (optional), material (object, required). Sealed with AES-256-GCM. |
GET | /api/v1/connections | Names, base_url and updated_at. Never the material. |
DELETE | /api/v1/connections/:name | Removes it. |
Without NEXUS_CONNECTIONS_KEY the routes answer 503 and runs go without credentials.
Messaging
Section titled “Messaging”Present only when Herald is configured.
| Method | Path | Credential |
|---|---|---|
POST | /api/v1/messages/send | JWT or API key. |
POST | /api/v1/runs/messages/send | The per-run token Nexus minted for the invocation. |
Body: channel, recipient (both required), text, conversation_ref. Returns 202 with message_id and status. The tenant always comes from the credential. The run token is how an agent’s send_message tool posts back without the shared pool holding any tenant secret.
Subscriptions and usage events
Section titled “Subscriptions and usage events”With the tenant’s credential. Creating and changing subscriptions is operator-only (below).
| Method | Path | |
|---|---|---|
GET | /api/v1/subscriptions?argo=<code> | The tenant’s active subscription for that vertical, with its plan. |
POST | /api/v1/usage/events | event_id, subscription_id, unidad, cantidad, ocurrido_en. Idempotent per subscription and event_id. |
A usage event is rejected when its unit is not in the plan, when it falls outside the subscription’s window or more than five minutes in the future, and with 409 period_closed when its period is already closed. See Plans & Billing.
Operator plane
Section titled “Operator plane”Everything under /api/v1/admin requires the operator role or X-Operator-Token; without either the answer is 401. Every mutation is audited.
| Method | Path | |
|---|---|---|
POST / GET | /admin/tariffs[?at=RFC3339] | File a tariff (append-only) / tariffs in force at an instant. |
POST / GET | /admin/plans | Create a plan (immutable once created) / list plans. |
PUT | /admin/tenants/:id/plan | plan_id: assign a tenant’s base plan. |
POST / GET | /admin/subscriptions[?tenant_id=&period=] | Create (tenant_id, argo_code, plan_id, desde) / list with period counters. |
PUT | /admin/subscriptions/:id/plan | Schedule a plan change for the next period. |
POST | /admin/subscriptions/:id/cancel | Cancel. |
GET | /admin/usage[?period=] | Platform totals and consumption by model. |
GET | /admin/tenants, /admin/tenants/:id | Consumption per tenant with its plan, caps and margin. |
GET | /admin/agents[?period=] | Agent health, with error rate = errors ÷ (errors + ok). |
GET | /admin/invocations | Filters tenant_id, agent_id, status, pricing_status, period; paged with cursor and limit. |
GET | /admin/invocations/:id | Full detail, including provider and infrastructure cost. |
GET | /admin/tenants/:id/statement[?period=] | The tenant’s statement for a period; .csv for one line per charge. |
POST | /admin/billing-periods/:id/facturado | Mark a closed period invoiced (once; 409 if already). |
GET | /admin/billing-periods/overdue | Periods past their grace that are not closed. |
All paths in this table are under /api/v1.
Health
Section titled “Health”| Path | |
|---|---|
GET /healthz | Liveness. |
GET /readyz | Readiness. |
Any other path that is not under /api/ or /auth/ serves the operator console.