Agent tokens
First-class tokens for AI agents, with scopes, environments, a spend budget, expiry and an approval channel.
| Operation | Method and path |
|---|---|
| List agent tokens | GET /v1/workspaces/{workspace}/agent-tokens |
| Create an agent token | POST /v1/workspaces/{workspace}/agent-tokens |
| Get an agent token | GET /v1/workspaces/{workspace}/agent-tokens/{token_id} |
| Change an agent token’s scopes, environments, budget or channel | PATCH /v1/workspaces/{workspace}/agent-tokens/{token_id} |
| Revoke an agent token | DELETE /v1/workspaces/{workspace}/agent-tokens/{token_id} |
List agent tokens
Section titled “List agent tokens”GET /v1/workspaces/{workspace}/agent-tokens- Operation:
listAgentTokens - Scopes:
tokens:read - Paginated:
?limit=and?cursor=
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
status |
query | active, expired, revoked |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
A page of AgentToken objects. | AgentTokenList |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces/acme/agent-tokens \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "data": [ { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "name": "claude-code-on-stewart-laptop", "description": "Claude Code on Stewart's MacBook", "prefix": "guv_agt_Qm4x", "scopes": [ "projects:read", "deploy:preview", "deploy:staging", "logs:read", "secrets:write-only", "db:branch" ], "projects": null, "environments": [ "preview", "staging" ], "budget": { "spend_increase_per_day": { "amount": "10.00", "currency": "GBP", "display": "£10.00" } }, "approval_channel": [ "push", "email" ], "status": "active", "summary": [ "Can deploy to staging and previews.", "Cannot touch production without your approval.", "Can set secrets but never read them.", "Can raise spend by up to £10.00 a day." ], "created_by": { "type": "user", "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" }, "expires_at": "2026-11-22T09:00:00Z", "last_used_at": "2026-10-23T13:58:00Z", "revoked_at": null, "created_at": "2026-10-23T09:00:00Z" } ], "next_cursor": "string", "has_more": false}Create an agent token
Section titled “Create an agent token”POST /v1/workspaces/{workspace}/agent-tokensOnly humans can create agent tokens. The token value is returned once, with ready-made setup snippets.
- Operation:
createAgentToken - Scopes:
tokens:write - CLI:
guv tokens create-agent - Idempotency-Key: required; supports
?dry_run=true
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
Request body (application/json, required): AgentTokenCreate
| Field | Type | Description |
|---|---|---|
name * |
string | |
description |
string | |
scopes * |
array of Scope | |
projects |
array of string or null | |
environments * |
array of string | |
budget |
AgentTokenBudget | |
expires_in |
string | Lifetime, at most 365d. Default 30d. |
approval_channel |
array of ApprovalChannel | Default ["push","email"]. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
Dry run. Nothing was changed; this is what would happen. | Plan |
201 Created |
Created. | AgentTokenCreated |
Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/workspaces/acme/agent-tokens \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "claude-code-on-stewart-laptop", "scopes": [ "projects:read", "deploy:preview", "deploy:staging", "logs:read", "secrets:write-only", "db:branch" ], "environments": [ "preview", "staging" ], "budget": { "spend_increase_per_day": { "amount": "10.00", "currency": "GBP" } }, "expires_in": "30d", "approval_channel": [ "push", "email" ]}'Example response
{ "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "name": "claude-code-on-stewart-laptop", "description": "Claude Code on Stewart's MacBook", "prefix": "guv_agt_Qm4x", "scopes": [ "projects:read", "deploy:preview", "deploy:staging", "logs:read", "secrets:write-only", "db:branch" ], "projects": null, "environments": [ "preview", "staging" ], "budget": { "spend_increase_per_day": { "amount": "10.00", "currency": "GBP", "display": "£10.00" } }, "approval_channel": [ "push", "email" ], "status": "active", "summary": [ "Can deploy to staging and previews.", "Cannot touch production without your approval.", "Can set secrets but never read them.", "Can raise spend by up to £10.00 a day." ], "created_by": { "type": "user", "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" }, "expires_at": "2026-11-22T09:00:00Z", "last_used_at": "2026-10-23T13:58:00Z", "revoked_at": null, "created_at": "2026-10-23T09:00:00Z", "token": "string", "setup": { "env": "export GUV_TOKEN=guv_agt_…", "mcp_command": "claude mcp add guv --transport http https://mcp.guv.dev --header 'Authorization: Bearer guv_agt_…'" }}Get an agent token
Section titled “Get an agent token”GET /v1/workspaces/{workspace}/agent-tokens/{token_id}- Operation:
getAgentToken - Scopes:
tokens:read
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
token_id * |
path | string | Agent token id. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | AgentToken |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces/acme/agent-tokens/tok_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "name": "claude-code-on-stewart-laptop", "description": "Claude Code on Stewart's MacBook", "prefix": "guv_agt_Qm4x", "scopes": [ "projects:read", "deploy:preview", "deploy:staging", "logs:read", "secrets:write-only", "db:branch" ], "projects": null, "environments": [ "preview", "staging" ], "budget": { "spend_increase_per_day": { "amount": "10.00", "currency": "GBP", "display": "£10.00" } }, "approval_channel": [ "push", "email" ], "status": "active", "summary": [ "Can deploy to staging and previews.", "Cannot touch production without your approval.", "Can set secrets but never read them.", "Can raise spend by up to £10.00 a day." ], "created_by": { "type": "user", "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" }, "expires_at": "2026-11-22T09:00:00Z", "last_used_at": "2026-10-23T13:58:00Z", "revoked_at": null, "created_at": "2026-10-23T09:00:00Z"}Change an agent token’s scopes, environments, budget or channel
Section titled “Change an agent token’s scopes, environments, budget or channel”PATCH /v1/workspaces/{workspace}/agent-tokens/{token_id}- Operation:
updateAgentToken - Scopes:
tokens:write - Idempotency-Key: required; supports
?dry_run=true - Concurrency: send the
ETagyou read asIf-Match
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
token_id * |
path | string | Agent token id. |
Request body (application/json, required): AgentTokenUpdate
| Field | Type | Description |
|---|---|---|
name |
string | |
description |
string | |
scopes |
array of Scope | |
projects |
array of string or null | |
environments |
array of string | |
budget |
AgentTokenBudget | |
approval_channel |
array of ApprovalChannel |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. With dry_run=true: a Plan (application/vnd.guv.plan+json) and nothing changes. |
AgentToken |
Errors: 400, 401, 403, 404, 409, 412, 422, 429, 500, as problem+json with a stable code.
Example
curl -X PATCH https://api.guv.dev/v1/workspaces/acme/agent-tokens/tok_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "description": "string", "scopes": [ "deploy:staging" ], "projects": [ "string" ], "environments": [ "string" ], "budget": { "spend_increase_per_day": { "amount": "7.42", "currency": "GBP", "display": "£7.42" }, "max_deploys_per_hour": 1 }, "approval_channel": [ "push" ]}'Example response
{ "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "name": "claude-code-on-stewart-laptop", "description": "Claude Code on Stewart's MacBook", "prefix": "guv_agt_Qm4x", "scopes": [ "projects:read", "deploy:preview", "deploy:staging", "logs:read", "secrets:write-only", "db:branch" ], "projects": null, "environments": [ "preview", "staging" ], "budget": { "spend_increase_per_day": { "amount": "10.00", "currency": "GBP", "display": "£10.00" } }, "approval_channel": [ "push", "email" ], "status": "active", "summary": [ "Can deploy to staging and previews.", "Cannot touch production without your approval.", "Can set secrets but never read them.", "Can raise spend by up to £10.00 a day." ], "created_by": { "type": "user", "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" }, "expires_at": "2026-11-22T09:00:00Z", "last_used_at": "2026-10-23T13:58:00Z", "revoked_at": null, "created_at": "2026-10-23T09:00:00Z"}Revoke an agent token
Section titled “Revoke an agent token”DELETE /v1/workspaces/{workspace}/agent-tokens/{token_id}- Operation:
revokeAgentToken - Scopes:
tokens:write - Idempotency-Key: required; supports
?dry_run=true - Concurrency: send the
ETagyou read asIf-Match
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
token_id * |
path | string | Agent token id. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
Dry run. Nothing was changed; this is what would happen. | Plan |
204 No Content |
Done. No body. | none |
Errors: 400, 401, 403, 404, 409, 412, 422, 429, 500, as problem+json with a stable code.
Example
curl -X DELETE https://api.guv.dev/v1/workspaces/acme/agent-tokens/tok_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"