REST API#
Every Lens Agents surface is built on one REST API. The CLI is a client of it, the admin UI consumes it, and the MCP endpoint delegates to it. All three enforce the same identity, RBAC, policies, and audit.
Base path and OpenAPI#
https://agents.example.com/v1
Each install serves the OpenAPI 3 document for the exact version it is running:
https://agents.example.com/v1/openapi.json
That document is authoritative. Generate a client from it rather than hand-writing one against this page.
Authentication#
Bearer tokens, in an Authorization header. Three kinds are accepted:
| Token | From |
|---|---|
| OIDC JWT | An interactive sign-in through your identity provider. |
| API token | api-token create. |
| Cluster JWT | Issued to a sandbox for its kubeconfig, with a 15-minute lifetime. The only token the cluster's Kubernetes proxy path accepts. |
curl -fsS -H "Authorization: Bearer $LENS_AGENTS_TOKEN" \
https://agents.example.com/v1/auth/me
GET /v1/auth/me returns the identity type behind the token, which is the quickest way to confirm a credential works and is what you think it is.
Two endpoints need no authentication: GET /v1/installation and the activation device flow, because they run before an install has any identities.
Errors#
Failures use RFC 9457 problem details with an application/problem+json content type:
{
"type": "https://api.lens.dev/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "Sandbox not found"
}
A 429 from an /llm/* route means a spending limit was reached. The sandbox keeps running; only model access stops.
Endpoint groups#
Identity and tenancy#
| Group | Base |
|---|---|
| Current identity | /auth/me |
| Organizations and members | /orgs, /orgs/{orgId}/members/{userId} |
| Projects and keys | /orgs/{orgId}/projects, /projects/{projectId}, /projects/{projectId}/rotate-keys |
| Project members | /projects/{projectId}/members, .../members/users/{userId}, .../members/api-tokens/{apiTokenId} |
| Invitations | /orgs/{orgId}/invitations, /invitations |
| Emergency halt | /orgs/{orgId}/halt |
| API tokens | /orgs/{orgId}/api-tokens, /api-tokens/{tokenId} |
GET /orgs/{orgId}/halt is readable by any org member; POST and DELETE require org administration. See Emergency halt.
Projects also publish /projects/{projectId}/public-key and /projects/{projectId}/.well-known/jwks.json, which the cluster relay uses to verify platform-signed requests.
Sandboxes#
| Operation | Endpoint |
|---|---|
| List, create | /projects/{projectId}/sandboxes |
| Get, update, delete | /projects/{projectId}/sandboxes/{sandboxId} |
| Start, stop, restart | .../start, .../stop, .../restart |
| Revisions, rollback | .../revisions, .../rollback |
| Effective policy | .../effective-policy |
| Exposed-port readiness | .../port-readiness |
| Sandbox tokens | /projects/{projectId}/sandbox-tokens, /sandbox-tokens/{id} |
Interactive exec is a WebSocket, not a REST call:
wss://agents.example.com/v1/projects/{projectId}/sandboxes/{sandboxId}/exec
Query parameters: command, tty, cols, rows.
It multiplexes stdin, stdout, stderr, and terminal resize frames. Use nexusctl sandbox exec unless you are building a terminal.
Governance#
| Group | Base |
|---|---|
| Project policies | /projects/{projectId}/policies |
| Org policies | /orgs/{orgId}/policies |
| Project bindings | /projects/{projectId}/policy-bindings |
| Org bindings | /orgs/{orgId}/policy-bindings |
| Binding drift | /orgs/{orgId}/policy-bindings/drift |
| Credentials | /projects/{projectId}/credentials |
Connections#
| Group | Base |
|---|---|
| Clusters | /projects/{projectId}/clusters, /clusters/{clusterId} |
| Tunnel token rotation | /clusters/{clusterId}/rotate-tunnel-token |
| AWS connections | /projects/{projectId}/aws-connections, /aws-connections/{connectionId} |
| Connectors | /projects/{projectId}/mcp-servers, /mcp-servers/{serverId} |
| Tool re-discovery | /mcp-servers/{serverId}/sync |
| HTTP connector from OpenAPI | /projects/{projectId}/mcp-servers/http |
| Discovery, preview, and connection test | .../discover/preview, .../test-connection, /mcp-servers/{connectorId}/discover/url |
| Pending specs | /mcp-servers/{connectorId}/specs/pending, .../specs/{specId}, .../diff, .../promote |
| Connector credentials | /projects/{projectId}/mcp-servers/{serverId}/credentials, .../{credentialId}/oauth/start |
| OAuth applications | /projects/{projectId}/oauth-applications |
| Tool entries and visibility | /mcp-servers/{connectorId}/entries, .../{entryName}/visibility |
| Tool call | /mcp-servers/{serverId}/tools/call |
| Tool call through the project MCP endpoint | /projects/{projectId}/mcp-servers/tools/call |
GET /projects/{projectId}/oauth-applications lists the OAuth applications the operator configured for the install, for project admins. It returns no client secrets. See MCP connectors.
The API has no AWS or Kubernetes proxy for scripts. AWS calls are re-signed inside the sandbox, and /clusters/{clusterId}/proxy/{path} accepts only the cluster token issued to a sandbox, refusing an API token or an OIDC session with 401. See AWS and Kubernetes.
Inference#
| Provider | Route |
|---|---|
| Configured providers | /inference/providers |
| Providers for an org, and whose key each uses | /orgs/{orgId}/inference/providers |
| Org inference keys | /orgs/{orgId}/inference/keys, /orgs/{orgId}/inference/keys/{source} |
| Bedrock | /projects/{projectId}/llm/bedrock/{region}/{path} |
| Foundry — Claude | /projects/{projectId}/llm/azure/anthropic/{path} |
| Foundry — GPT | /projects/{projectId}/llm/azure/openai/{path} |
| Foundry — realtime voice | /projects/{projectId}/llm/azure/openai/v1/realtime?model=<deployment-name> (WebSocket) |
| Foundry — GPT-Live voice | /projects/{projectId}/llm/azure/openai/v1/live/sessions (WebSocket) |
| Bedrock Mantle — Claude | /projects/{projectId}/llm/bedrock-mantle/anthropic/{region}/{path} |
| Bedrock Mantle — GPT | /projects/{projectId}/llm/bedrock-mantle/openai/{region}/{path} |
| OpenAI | /projects/{projectId}/llm/openai/{path} |
| OpenAI — realtime voice | /projects/{projectId}/llm/openai/v1/realtime (WebSocket) |
| OpenAI — GPT-Live voice | /projects/{projectId}/llm/openai/v1/live/sessions (WebSocket) |
| OpenRouter — Anthropic wire format | /projects/{projectId}/llm/openrouter/anthropic/{path} |
| OpenRouter — OpenAI wire format | /projects/{projectId}/llm/openrouter/openai/{path} |
| LiteLLM — Anthropic wire format | /projects/{projectId}/llm/litellm/anthropic/{path} |
| LiteLLM — OpenAI wire format | /projects/{projectId}/llm/litellm/openai/{path} |
The proxy routes are project-scoped. Each HTTP route, not the WebSocket ones, is also served without the /projects/{projectId} prefix, for a caller with access to exactly one project; any other caller gets 400. /inference/providers is deployment-wide: it reads which backends the install has configured, not a model, and returns defaultProvider, the backend a policy that names none gets in an organization without its own Bedrock key. The org key routes need a signed-in org administrator; API tokens and sandbox tokens are refused. See Models.
Observability#
| Group | Base |
|---|---|
| Audit trail | /orgs/{orgId}/audit-trail, .../stats, .../timeseries |
| Usage costs | /orgs/{orgId}/usage-costs, .../timeseries |
| Spending limits | /orgs/{orgId}/spending-limits, .../status |
The audit trail paginates by cursor — pass the ISO 8601 timestamp from the previous response. See Audit trail.
Installation#
| Operation | Endpoint |
|---|---|
| Status | GET /installation |
| Start device flow | POST /installation/activation |
| Poll device flow | GET /installation/activation/{sessionId} |
Other surfaces#
| Surface | Path |
|---|---|
| Health | /health |
| MCP, org-scoped | /mcp |
| MCP, project-scoped | /projects/{projectId}/mcp |
| Sandbox exposed ports | https://<sandbox-slug>.<sandboxIngress.host> |
The MCP endpoints sit at the root, not under /v1.
Related#
- CLI reference — the same operations from a terminal
- Platform tools — the same operations over MCP
- Set up the CLI — authentication and environment defaults