API reference
Authentication
One tag: method, path, summary, auth, and scopes. Request and response fields ship in this page — expand a row to read the contract.
Endpoints
4
POST
/api/v1/agent_tokens
Exchange API key for access token
/api/v1/agent_tokens
Exchange API key for access token
Description
Unauthenticated exchange: send a primary workspace or service-agent API key (agk_<base64>.<base64>) in the x-agent-api-key header or as api_key in the JSON body. Returns a 30-day access token. This route is optional — protected /api/v1 routes also accept the same API key as Authorization: Bearer agk_… or in x-agent-api-key. A Bearer token on this exchange returns 400.
Auth
NoneRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| scopes | array<string> | No | Optional subset of the credential's scopes to request |
| api_key | string | No | API key in format agk_<base64>.<base64> (alternative to x-agent-api-key) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| x-agent-api-key | header | string | No | API key in format agk_<base64>.<base64>. Underscore names are not read. |
Responses
200
Token issued
Returns: TokenResponse
Token issued
Returns: TokenResponse
Response Body
| Field | Type | Required | Description |
|---|---|---|---|
| token | string | Yes | 30-day access token |
| scopes | array<string> | Yes | Granted scopes |
| credential_id | string | Yes | API credential UUID |
| expires_in | integer | Yes | Seconds until expiry (2,592,000) |
| service_agent_id | string | Yes | Service agent UUID |
| workspace_id | string | Yes | Workspace UUID |
Example
{
"token": "SFMyNTY.g2gDdAAAAARtAAAADWNyZWRlbnRpYWxfaWRtAAAACMzZODNiNDMzLTAyZjUtNGJjYy04NWNhLTdhM2QwYTgzNjI1Ym0AAAAGc2NvcGVzbQAAAAMAAAAIZnJvbV9vcHNtAAAACXRvX29iamVjdG0AAAAJdG9fYWN0aW9ubgYBy_T1yQFiAAFTgA.ABC123def456",
"scopes": [
"traces:write",
"eval_runs:read",
"eval_runs:write",
"eval_suites:read",
"eval_suites:write",
"gateway:check",
"replays:write",
"workflow_targets:read",
"workflow_targets:write"
],
"credential_id": "3e83b433-02f5-4bcc-85ca-7a3d0a83625b",
"expires_in": 2592000,
"service_agent_id": "a91720d1-1c45-4343-bb45-786e20432f04",
"workspace_id": "e65ef764-9b2c-4e24-b918-99c7be33506a"
}
400
Authorization: Bearer was sent. This endpoint accepts an API key (agk_...), not a Bearer token. Use x-agent-api-key or api_key.
Authorization: Bearer was sent. This endpoint accepts an API key (agk_...), not a Bearer token. Use x-agent-api-key or api_key.
401
Missing, invalid, expired, archived, or revoked API key. Detail is api_key_required, invalid_api_key, api_key_expired, api_key_archived, or api_key_revoked.
Missing, invalid, expired, archived, or revoked API key. Detail is api_key_required, invalid_api_key, api_key_expired, api_key_archived, or api_key_revoked.
Example
{
"detail": "api_key_revoked",
"status": 401,
"title": "Unauthorized",
"type": "https://robotscenter.net/problems/unauthorized"
}
403
Credential is recognized but refused. Detail is service_agent_inactive or insufficient_scopes. Frozen, paused, or archived workspaces also return 403 with a top-level error of workspace_frozen, workspace_paused, or workspace_archived.
Credential is recognized but refused. Detail is service_agent_inactive or insufficient_scopes. Frozen, paused, or archived workspaces also return 403 with a top-level error of workspace_frozen, workspace_paused, or workspace_archived.
Example
{
"detail": "This workspace is frozen. Machine traffic is refused until the freeze is lifted.",
"error": "workspace_frozen",
"status": 403,
"title": "Forbidden",
"type": "https://robotscenter.net/problems/forbidden"
}
POST
/api/v1/register
Register new user with API access
/api/v1/register
Register new user with API access
Description
Creates a new user account, workspace, service agent, and API credentials in a single request. Returns everything needed for immediate API access.
Auth
NoneRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | No | Optional display name (2–120 characters). When omitted, register_via_api derives it from the email local part. |
| password | string | Yes | Password (12–72 characters) |
| string | Yes | User email address | |
| agent_name | string | Yes | Name for the default service agent |
| workspace_name | string | Yes | Name for the new workspace |
Responses
201
Account, workspace, service agent, agk_ API key, and 30-day access token issued
Account, workspace, service agent, agk_ API key, and 30-day access token issued
Response Body
| Field | Type | Required | Description |
|---|---|---|---|
| user | object | Yes | Created user |
| user.id | string | Yes | User UUID |
| user.name | string | No | Display name |
| user.email | string | Yes | Normalized email |
| user.confirmed_at | datetime (ISO 8601) | No | Confirmation timestamp |
| api_key | object | Yes | Primary long-lived workspace API key (shown once) |
| api_key.type | string (api_key) | Yes | Always api_key |
| api_key.key | string | Yes | agk_ secret (prefix.secret) |
| api_key.scopes | array<string> | Yes | Granted scopes |
| api_key.credential_id | string | Yes | API credential UUID |
| api_key.service_agent_id | string | Yes | Service agent UUID |
| access_token | object | Yes | Optional 30-day bearer token for the same credential |
| access_token.type | string (bearer) | Yes | Always bearer |
| access_token.token | string | Yes | Access token |
| access_token.scopes | array<string> | Yes | Granted scopes |
| access_token.credential_id | string | Yes | API credential UUID |
| access_token.expires_in | integer | Yes | Seconds until expiry (2,592,000) |
| access_token.service_agent_id | string | Yes | Service agent UUID |
| service_agent | object | Yes | Default service agent |
| service_agent.id | string | Yes | Service agent UUID |
| service_agent.name | string | Yes | Agent name |
| service_agent.status | string | Yes | Agent status |
| service_agent.slug | string | Yes | Agent slug |
| workspace | object | Yes | Created workspace |
| workspace.id | string | Yes | Workspace UUID |
| workspace.name | string | Yes | Workspace name |
| workspace.status | string | Yes | Workspace status |
| workspace.plan | string | Yes | Plan slug |
| workspace.slug | string | Yes | Workspace slug |
Example
{
"user": {
"id": "7c2f0a11-4b8e-4d3a-9f21-0c1b2a3d4e5f",
"name": "Ops",
"email": "[email protected]",
"confirmed_at": null
},
"api_key": {
"type": "api_key",
"key": "agk_abc123.def456",
"scopes": [
"traces:write",
"gateway:check"
],
"credential_id": "3e83b433-02f5-4bcc-85ca-7a3d0a83625b",
"service_agent_id": "a91720d1-1c45-4343-bb45-786e20432f04"
},
"access_token": {
"type": "bearer",
"token": "SFMyNTY.example.access-token",
"scopes": [
"traces:write",
"gateway:check"
],
"credential_id": "3e83b433-02f5-4bcc-85ca-7a3d0a83625b",
"expires_in": 2592000,
"service_agent_id": "a91720d1-1c45-4343-bb45-786e20432f04"
},
"service_agent": {
"id": "a91720d1-1c45-4343-bb45-786e20432f04",
"name": "Default agent",
"status": "active",
"slug": "default-agent"
},
"workspace": {
"id": "e65ef764-9b2c-4e24-b918-99c7be33506a",
"name": "Example Workspace",
"status": "active",
"plan": "starter",
"slug": "example-workspace"
}
}
422
Validation error
Validation error
POST
/api/v1/socket_tokens
Agent Token
Issue short-lived socket token
sockets:connect
/api/v1/socket_tokens
Agent Token
Issue short-lived socket token
Description
Returns a short-lived socket token for websocket authentication. Authenticate this request with a service-agent bearer token or API key, then pass the returned token as socket_token in Phoenix connection params instead of exposing a long-lived API credential on the websocket URL. Transport notes: /socket rejects frames above 65 536 bytes (64 KB). Ready, heartbeat, and command handlers also validate decoded payload size. Unrecognized agent events receive %{reason: "unknown_event"}. Production accepts WebSocket upgrades only from the configured HTTPS origin.
Auth
Agent TokenRequired Scopes
Responses
200
Socket token issued
Returns: SocketTokenResponse
Socket token issued
Returns: SocketTokenResponse
Response Body
| Field | Type | Required | Description |
|---|---|---|---|
| scopes | array<string> | Yes | Granted scopes carried into the socket connection |
| socket_path | string | Yes | Phoenix socket path to connect to. Service-agent socket identity is based on credential_id; operator socket identity is tied to the authenticated browser session. |
| expires_in | integer | Yes | Seconds until the socket token expires |
| service_agent_id | string | Yes | Service agent UUID bound to the token |
| workspace_id | string | Yes | Workspace UUID bound to the token |
| socket_token | string | Yes | Short-lived socket token for websocket authentication |
Example
{
"scopes": [
"sockets:connect",
"events:read",
"agent_commands:read"
],
"socket_path": "/socket",
"expires_in": 600,
"service_agent_id": "a91720d1-1c45-4343-bb45-786e20432f04",
"workspace_id": "e65ef764-9b2c-4e24-b918-99c7be33506a",
"socket_token": "SFMyNTY.g3QAAAABbQAAAA1jcmVkZW50aWFsX2lkbQAAACQzZTgzYjQzMy0wMmY1LTRiY2MtODVjYS03YTNkMGE4MzYyNWJtAAAAAXMAAAANc29ja2V0X3Njb3Blc20AAAABAAAAD3NvY2tldHM6Y29ubmVjdA.a1b2c3d4"
}
401
Invalid, missing, or expired credential
Invalid, missing, or expired credential
403
Credential is valid but lacks sockets:connect (detail: The token does not have sufficient scope). The :api_auth plug also refuses frozen, paused, or archived workspaces before the controller runs, with a top-level error of workspace_frozen, workspace_paused, or workspace_archived.
Credential is valid but lacks sockets:connect (detail: The token does not have sufficient scope). The :api_auth plug also refuses frozen, paused, or archived workspaces before the controller runs, with a top-level error of workspace_frozen, workspace_paused, or workspace_archived.
Example
{
"detail": "This workspace is frozen. Machine traffic is refused until the freeze is lifted.",
"error": "workspace_frozen",
"status": 403,
"title": "Forbidden",
"type": "https://robotscenter.net/problems/forbidden"
}
POST
/api/v1/enrollments/claim
Claim an agent or fleet enrollment token
/api/v1/enrollments/claim
Claim an agent or fleet enrollment token
Description
Claims an enrollment token. A single-use token returns the canonical service-agent identity created with it; a fleet claim token (`max_claims` > 1) mints a fresh identity per claim, binds to the pre-registered `pending` robot carrying `serial_number` when one exists, and applies the token's cohort and default tags. Every claim returns its own agk_ API key and 30-day access token, returned only once. The claim token itself is never usable as an API credential.
Auth
NoneRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| token | string | Yes | One-time enrollment token in age_prefix.secret format |
| serial_number | string | No | Serial of the claiming unit. Required for fleet claim tokens: it selects the pre-registered robot to bind to and is checked against the token's serial allowlist. |
| agent | object | No | Optional runtime metadata advertised during claim |
Responses
201
Enrollment claimed and machine credentials issued
Enrollment claimed and machine credentials issued
400
Serial not on the token's allowlist, serial already claimed, or no serial supplied for a fleet claim token
Serial not on the token's allowlist, serial already claimed, or no serial supplied for a fleet claim token
401
Invalid enrollment token
Invalid enrollment token
403
The workspace is not accepting machine traffic, with a machine-readable `error` of `workspace_frozen`, `workspace_paused` or `workspace_archived`. Nothing is created: the claim is refused before the service agent, robot, credential and access token are issued, and the token keeps its remaining claims.
The workspace is not accepting machine traffic, with a machine-readable `error` of `workspace_frozen`, `workspace_paused` or `workspace_archived`. Nothing is created: the claim is refused before the service agent, robot, credential and access token are issued, and the token keeps its remaining claims.
Example
{
"detail": "This workspace is frozen. Machine traffic is refused until the freeze is lifted.",
"error": "workspace_frozen",
"status": 403,
"title": "Forbidden",
"type": "https://robotscenter.net/problems/forbidden"
}
409
Enrollment was already claimed, exhausted or revoked
Enrollment was already claimed, exhausted or revoked
410
Gone. type problems/enrollment-expired when the token is past expires_at. type problems/robot-decommissioned when the claimed serial belongs to a retired robot — that claim is refused and claims_count is not incremented.
Gone. type problems/enrollment-expired when the token is past expires_at. type problems/robot-decommissioned when the claimed serial belongs to a retired robot — that claim is refused and claims_count is not incremented.
429
Plan robot or agent quota reached
Plan robot or agent quota reached