Approvals
Human approval of actions requested by agents or blocked by environment protection. Approving needs a passkey.
| Operation | Method and path |
|---|---|
| List approval requests | GET /v1/workspaces/{workspace}/approvals |
| Ask a human to approve a specific request | POST /v1/approvals |
| Get an approval request | GET /v1/approvals/{approval_id} |
| Approve a request (passkey required) | POST /v1/approvals/{approval_id}/approve |
| Deny a request | POST /v1/approvals/{approval_id}/deny |
| Withdraw a pending request (requester) | POST /v1/approvals/{approval_id}/cancel |
List approval requests
Section titled “List approval requests”GET /v1/workspaces/{workspace}/approvals- Operation:
listApprovals - Scopes:
projects:read - Paginated:
?limit=and?cursor=
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
status |
query | ApprovalStatus | |
project |
query | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
A page of Approval objects. | ApprovalList |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces/acme/approvals \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "data": [ { "id": "apr_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "project_id": "string", "environment": "string", "status": "pending", "action": { "kind": "deployment.create", "summary": "Deploy web (commit a1b2c3d, \"Fix rota export\") to production", "method": "string", "path": "string" }, "reason": "string", "why_required": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "plan": { "plan_hash": "sha256:9f2c1e0b7a4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a49", "dry_run": true, "summary": "1 to update. +£5.00/month at current usage.", "changes": [ { "action": "update", "resource": { "type": "service", "id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv", "name": "web" }, "environment": "production", "summary": "Raise web memory limit from 1 GB to 2 GB", "diff": [ { "path": "/resources/memory_mb", "before": 1024, "after": 2048 } ], "destructive": false, "requires_approval": true, "reason": "production requires approval for changes made by agents" } ], "cost": { "current_monthly": { "amount": "18.20", "currency": "GBP", "display": "£18.20" }, "projected_monthly": { "amount": "23.20", "currency": "GBP", "display": "£23.20" }, "delta_monthly": { "amount": "5.00", "currency": "GBP", "display": "£5.00" }, "confidence": "medium" }, "policy": { "decision": "approval_required", "reasons": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "approver_roles": [ "owner", "admin" ] }, "requires_approval": true, "expires_at": "2026-10-23T15:00:00Z" }, "risk": "low", "approver_roles": [ "owner" ], "requested_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_at": "2026-10-22T13:05:00Z", "decision_note": "string", "operation_id": "string", "result": { "status": 1, "body": {} }, "url": "https://guv.dev/", "expires_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z" } ], "next_cursor": "string", "has_more": false}Ask a human to approve a specific request
Section titled “Ask a human to approve a specific request”POST /v1/approvalsThe request_approval MCP tool. Most approvals are created automatically when a call returns approval_required.
- Operation:
requestApproval - Scopes:
approvals:request - Idempotency-Key: required
Request body (application/json, required): ApprovalCreate
| Field | Type | Description |
|---|---|---|
request * |
object | |
reason |
string |
Responses
| Status | Meaning | Body |
|---|---|---|
201 Created |
Created. | Approval |
Errors: 400, 401, 403, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/approvals \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "request": { "method": "POST", "path": "/v1/projects/primecarers/environments/production/services/web/deployments", "body": {} }, "reason": "string"}'Example response
{ "id": "apr_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "project_id": "string", "environment": "string", "status": "pending", "action": { "kind": "deployment.create", "summary": "Deploy web (commit a1b2c3d, \"Fix rota export\") to production", "method": "string", "path": "string" }, "reason": "string", "why_required": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "plan": { "plan_hash": "sha256:9f2c1e0b7a4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a49", "dry_run": true, "summary": "1 to update. +£5.00/month at current usage.", "changes": [ { "action": "update", "resource": { "type": "service", "id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv", "name": "web" }, "environment": "production", "summary": "Raise web memory limit from 1 GB to 2 GB", "diff": [ { "path": "/resources/memory_mb", "before": 1024, "after": 2048 } ], "destructive": false, "requires_approval": true, "reason": "production requires approval for changes made by agents" } ], "cost": { "current_monthly": { "amount": "18.20", "currency": "GBP", "display": "£18.20" }, "projected_monthly": { "amount": "23.20", "currency": "GBP", "display": "£23.20" }, "delta_monthly": { "amount": "5.00", "currency": "GBP", "display": "£5.00" }, "confidence": "medium" }, "policy": { "decision": "approval_required", "reasons": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "approver_roles": [ "owner", "admin" ] }, "requires_approval": true, "expires_at": "2026-10-23T15:00:00Z" }, "risk": "low", "approver_roles": [ "owner" ], "requested_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_at": "2026-10-22T13:05:00Z", "decision_note": "string", "operation_id": "string", "result": { "status": 1, "body": {} }, "url": "https://guv.dev/", "expires_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z"}Get an approval request
Section titled “Get an approval request”GET /v1/approvals/{approval_id}Agents poll this (or the resulting operation) until the status is executed, failed, denied or expired. Supports ?wait=30 long-polling.
- Operation:
getApproval - Scopes: any signed-in principal
- CLI:
guv approvals wait
Parameters
| Name | In | Type | Description |
|---|---|---|---|
approval_id * |
path | string | |
wait |
query | integer | Seconds to wait for a status change before responding. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | Approval |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/approvals/app_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "id": "apr_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "project_id": "string", "environment": "string", "status": "pending", "action": { "kind": "deployment.create", "summary": "Deploy web (commit a1b2c3d, \"Fix rota export\") to production", "method": "string", "path": "string" }, "reason": "string", "why_required": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "plan": { "plan_hash": "sha256:9f2c1e0b7a4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a49", "dry_run": true, "summary": "1 to update. +£5.00/month at current usage.", "changes": [ { "action": "update", "resource": { "type": "service", "id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv", "name": "web" }, "environment": "production", "summary": "Raise web memory limit from 1 GB to 2 GB", "diff": [ { "path": "/resources/memory_mb", "before": 1024, "after": 2048 } ], "destructive": false, "requires_approval": true, "reason": "production requires approval for changes made by agents" } ], "cost": { "current_monthly": { "amount": "18.20", "currency": "GBP", "display": "£18.20" }, "projected_monthly": { "amount": "23.20", "currency": "GBP", "display": "£23.20" }, "delta_monthly": { "amount": "5.00", "currency": "GBP", "display": "£5.00" }, "confidence": "medium" }, "policy": { "decision": "approval_required", "reasons": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "approver_roles": [ "owner", "admin" ] }, "requires_approval": true, "expires_at": "2026-10-23T15:00:00Z" }, "risk": "low", "approver_roles": [ "owner" ], "requested_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_at": "2026-10-22T13:05:00Z", "decision_note": "string", "operation_id": "string", "result": { "status": 1, "body": {} }, "url": "https://guv.dev/", "expires_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z"}Approve a request (passkey required)
Section titled “Approve a request (passkey required)”POST /v1/approvals/{approval_id}/approveNeeds a step-up passkey assertion with purpose approval bound to this approval. The platform then runs the stored request as the requester and returns the updated approval.
- Operation:
approveApproval - Scopes:
approvals:decide - CLI:
guv approve - Idempotency-Key: required
Parameters
| Name | In | Type | Description |
|---|---|---|---|
approval_id * |
path | string |
Request body (application/json, required): ApprovalDecision
| Field | Type | Description |
|---|---|---|
assertion * |
PasskeyAssertion | |
note |
string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | Approval |
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/approvals/app_01jbx2m9k7q4r8t5v6w3y0z1pr/approve \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "assertion": { "challenge_id": "string", "credential": { "id": "string", "rawId": "string", "type": "public-key", "response": {}, "authenticatorAttachment": "string", "clientExtensionResults": {} } }, "note": "string"}'Example response
{ "id": "apr_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "project_id": "string", "environment": "string", "status": "pending", "action": { "kind": "deployment.create", "summary": "Deploy web (commit a1b2c3d, \"Fix rota export\") to production", "method": "string", "path": "string" }, "reason": "string", "why_required": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "plan": { "plan_hash": "sha256:9f2c1e0b7a4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a49", "dry_run": true, "summary": "1 to update. +£5.00/month at current usage.", "changes": [ { "action": "update", "resource": { "type": "service", "id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv", "name": "web" }, "environment": "production", "summary": "Raise web memory limit from 1 GB to 2 GB", "diff": [ { "path": "/resources/memory_mb", "before": 1024, "after": 2048 } ], "destructive": false, "requires_approval": true, "reason": "production requires approval for changes made by agents" } ], "cost": { "current_monthly": { "amount": "18.20", "currency": "GBP", "display": "£18.20" }, "projected_monthly": { "amount": "23.20", "currency": "GBP", "display": "£23.20" }, "delta_monthly": { "amount": "5.00", "currency": "GBP", "display": "£5.00" }, "confidence": "medium" }, "policy": { "decision": "approval_required", "reasons": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "approver_roles": [ "owner", "admin" ] }, "requires_approval": true, "expires_at": "2026-10-23T15:00:00Z" }, "risk": "low", "approver_roles": [ "owner" ], "requested_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_at": "2026-10-22T13:05:00Z", "decision_note": "string", "operation_id": "string", "result": { "status": 1, "body": {} }, "url": "https://guv.dev/", "expires_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z"}Deny a request
Section titled “Deny a request”POST /v1/approvals/{approval_id}/deny- Operation:
denyApproval - Scopes:
approvals:decide - Idempotency-Key: required
Parameters
| Name | In | Type | Description |
|---|---|---|---|
approval_id * |
path | string |
Request body (application/json, required): ApprovalDeny
| Field | Type | Description |
|---|---|---|
note |
string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | Approval |
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/approvals/app_01jbx2m9k7q4r8t5v6w3y0z1pr/deny \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "note": "string"}'Example response
{ "id": "apr_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "project_id": "string", "environment": "string", "status": "pending", "action": { "kind": "deployment.create", "summary": "Deploy web (commit a1b2c3d, \"Fix rota export\") to production", "method": "string", "path": "string" }, "reason": "string", "why_required": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "plan": { "plan_hash": "sha256:9f2c1e0b7a4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a49", "dry_run": true, "summary": "1 to update. +£5.00/month at current usage.", "changes": [ { "action": "update", "resource": { "type": "service", "id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv", "name": "web" }, "environment": "production", "summary": "Raise web memory limit from 1 GB to 2 GB", "diff": [ { "path": "/resources/memory_mb", "before": 1024, "after": 2048 } ], "destructive": false, "requires_approval": true, "reason": "production requires approval for changes made by agents" } ], "cost": { "current_monthly": { "amount": "18.20", "currency": "GBP", "display": "£18.20" }, "projected_monthly": { "amount": "23.20", "currency": "GBP", "display": "£23.20" }, "delta_monthly": { "amount": "5.00", "currency": "GBP", "display": "£5.00" }, "confidence": "medium" }, "policy": { "decision": "approval_required", "reasons": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "approver_roles": [ "owner", "admin" ] }, "requires_approval": true, "expires_at": "2026-10-23T15:00:00Z" }, "risk": "low", "approver_roles": [ "owner" ], "requested_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_at": "2026-10-22T13:05:00Z", "decision_note": "string", "operation_id": "string", "result": { "status": 1, "body": {} }, "url": "https://guv.dev/", "expires_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z"}Withdraw a pending request (requester)
Section titled “Withdraw a pending request (requester)”POST /v1/approvals/{approval_id}/cancel- Operation:
cancelApproval - Scopes: any signed-in principal
- Idempotency-Key: required
Parameters
| Name | In | Type | Description |
|---|---|---|---|
approval_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | Approval |
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/approvals/app_01jbx2m9k7q4r8t5v6w3y0z1pr/cancel \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"Example response
{ "id": "apr_01jbx2m9k7q4r8t5v6w3y0z1pr", "workspace_id": "string", "project_id": "string", "environment": "string", "status": "pending", "action": { "kind": "deployment.create", "summary": "Deploy web (commit a1b2c3d, \"Fix rota export\") to production", "method": "string", "path": "string" }, "reason": "string", "why_required": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "plan": { "plan_hash": "sha256:9f2c1e0b7a4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0f9e8d7c6b5a49", "dry_run": true, "summary": "1 to update. +£5.00/month at current usage.", "changes": [ { "action": "update", "resource": { "type": "service", "id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv", "name": "web" }, "environment": "production", "summary": "Raise web memory limit from 1 GB to 2 GB", "diff": [ { "path": "/resources/memory_mb", "before": 1024, "after": 2048 } ], "destructive": false, "requires_approval": true, "reason": "production requires approval for changes made by agents" } ], "cost": { "current_monthly": { "amount": "18.20", "currency": "GBP", "display": "£18.20" }, "projected_monthly": { "amount": "23.20", "currency": "GBP", "display": "£23.20" }, "delta_monthly": { "amount": "5.00", "currency": "GBP", "display": "£5.00" }, "confidence": "medium" }, "policy": { "decision": "approval_required", "reasons": [ { "code": "environment_protected", "message": "production requires approval for changes made by agents", "policy": "guv.environment.protection" } ], "approver_roles": [ "owner", "admin" ] }, "requires_approval": true, "expires_at": "2026-10-23T15:00:00Z" }, "risk": "low", "approver_roles": [ "owner" ], "requested_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_by": { "type": "agent", "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "display": "Stewart Webb via agent claude-code-on-stewart-laptop", "via_agent": { "id": "tok_01jbx2m9k7q4r8t5v6w3y0z1tk", "name": "claude-code-on-stewart-laptop" }, "on_behalf_of": { "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" } }, "decided_at": "2026-10-22T13:05:00Z", "decision_note": "string", "operation_id": "string", "result": { "status": 1, "body": {} }, "url": "https://guv.dev/", "expires_at": "2026-10-22T13:05:00Z", "created_at": "2026-10-22T13:05:00Z"}