Skip to content

Approvals

View as Markdown

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
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

Terminal window
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
}
POST /v1/approvals

The 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

Terminal window
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 /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

Terminal window
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"
}
POST /v1/approvals/{approval_id}/approve

Needs 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

Terminal window
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"
}
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

Terminal window
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"
}
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

Terminal window
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"
}