Workspaces
Workspaces own billing, members, projects and agent tokens.
| Operation | Method and path |
|---|---|
| List workspaces I belong to | GET /v1/workspaces |
| Create a workspace | POST /v1/workspaces |
| Get a workspace | GET /v1/workspaces/{workspace} |
| Update a workspace | PATCH /v1/workspaces/{workspace} |
| Close a workspace | DELETE /v1/workspaces/{workspace} |
List workspaces I belong to
Section titled “List workspaces I belong to”GET /v1/workspaces- Operation:
listWorkspaces - Scopes:
workspaces:read - Paginated:
?limit=and?cursor=
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
A page of Workspace objects. | WorkspaceList |
Errors: 400, 401, 403, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "data": [ { "id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "slug": "primecarers", "name": "Primecarers", "plan": "pro", "status": "active", "role": "owner", "billing_email": "accounts@primecarers.co.uk", "default_residency": "uk-only", "require_passkeys": true, "trial_ends_at": null, "limits": { "max_vcpu_per_service": 32, "max_memory_mb_per_service": 65536, "max_replicas": 20, "max_custom_domains_per_service": 20, "max_volume_gb": 250, "log_retention_days": 30, "concurrent_builds": 10 }, "member_count": 3, "created_at": "2026-10-22T09:00:00Z", "updated_at": "2026-10-22T09:00:00Z" } ], "next_cursor": "string", "has_more": false}Create a workspace
Section titled “Create a workspace”POST /v1/workspaces- Operation:
createWorkspace - Scopes: any signed-in principal
- Idempotency-Key: required; supports
?dry_run=true
Request body (application/json, required): WorkspaceCreate
| Field | Type | Description |
|---|---|---|
name * |
string | |
slug |
string | |
default_residency |
Residency |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
Dry run. Nothing was changed; this is what would happen. | Plan |
201 Created |
Created. | Workspace |
Errors: 400, 401, 402, 403, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/workspaces \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "slug": "string", "default_residency": "uk-only"}'Example response
{ "id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "slug": "primecarers", "name": "Primecarers", "plan": "pro", "status": "active", "role": "owner", "billing_email": "accounts@primecarers.co.uk", "default_residency": "uk-only", "require_passkeys": true, "trial_ends_at": null, "limits": { "max_vcpu_per_service": 32, "max_memory_mb_per_service": 65536, "max_replicas": 20, "max_custom_domains_per_service": 20, "max_volume_gb": 250, "log_retention_days": 30, "concurrent_builds": 10 }, "member_count": 3, "created_at": "2026-10-22T09:00:00Z", "updated_at": "2026-10-22T09:00:00Z"}Get a workspace
Section titled “Get a workspace”GET /v1/workspaces/{workspace}- Operation:
getWorkspace - Scopes:
workspaces:read
Parameters
| Name | In | Type | Description |
|---|---|---|---|
workspace * |
path | string | Workspace id (ws_…) or slug. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | Workspace |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/workspaces/acme \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "slug": "primecarers", "name": "Primecarers", "plan": "pro", "status": "active", "role": "owner", "billing_email": "accounts@primecarers.co.uk", "default_residency": "uk-only", "require_passkeys": true, "trial_ends_at": null, "limits": { "max_vcpu_per_service": 32, "max_memory_mb_per_service": 65536, "max_replicas": 20, "max_custom_domains_per_service": 20, "max_volume_gb": 250, "log_retention_days": 30, "concurrent_builds": 10 }, "member_count": 3, "created_at": "2026-10-22T09:00:00Z", "updated_at": "2026-10-22T09:00:00Z"}Update a workspace
Section titled “Update a workspace”PATCH /v1/workspaces/{workspace}- Operation:
updateWorkspace - Scopes:
workspaces: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. |
Request body (application/json, required): WorkspaceUpdate
| Field | Type | Description |
|---|---|---|
name |
string | |
slug |
string | |
billing_email |
string (email) | |
default_residency |
Residency | |
require_passkeys |
boolean |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. With dry_run=true: a Plan (application/vnd.guv.plan+json) and nothing changes. |
Workspace |
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 \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "slug": "string", "billing_email": "ada@example.co.uk", "default_residency": "uk-only", "require_passkeys": false}'Example response
{ "id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "slug": "primecarers", "name": "Primecarers", "plan": "pro", "status": "active", "role": "owner", "billing_email": "accounts@primecarers.co.uk", "default_residency": "uk-only", "require_passkeys": true, "trial_ends_at": null, "limits": { "max_vcpu_per_service": 32, "max_memory_mb_per_service": 65536, "max_replicas": 20, "max_custom_domains_per_service": 20, "max_volume_gb": 250, "log_retention_days": 30, "concurrent_builds": 10 }, "member_count": 3, "created_at": "2026-10-22T09:00:00Z", "updated_at": "2026-10-22T09:00:00Z"}Close a workspace
Section titled “Close a workspace”DELETE /v1/workspaces/{workspace}Requires confirm=<slug> and a workspace with no live projects. Data is kept for 30 days, then crypto-shredded.
- Operation:
deleteWorkspace - Scopes: any signed-in principal
- Approval: Always needs a human approval with a passkey, whoever asks, including agents with full scopes.
- 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. |
confirm |
query | string | Typed confirmation for destructive actions. Must equal the resource name (or slug/hostname). Missing or wrong values return confirmation_required. |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
Dry run. Nothing was changed; this is what would happen. | Plan |
202 Accepted |
Accepted. The work continues in the background; follow the operation. | Operation |
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 \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"Example response
{ "id": "op_01jbx2m9k7q4r8t5v6w3y0z1op", "kind": "deployment.create", "status": "running", "summary": "Deploying web to production", "workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws", "project_id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr", "environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en", "resource": { "type": "deployment", "id": "dep_01jbx2m9k7q4r8t5v6w3y0z1dp", "url": "/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1dp" }, "progress": { "current_step": "build", "completed_steps": 1, "total_steps": 6, "percent": 20 }, "steps": [ { "name": "resolve", "title": "Reading your settings", "status": "succeeded", "attempt": 1, "started_at": "2026-10-23T14:02:00Z", "finished_at": "2026-10-23T14:02:01Z" }, { "name": "build", "title": "Building your app", "status": "running", "attempt": 1, "started_at": "2026-10-23T14:02:01Z", "finished_at": null } ], "created_by": { "type": "user", "id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us", "display": "Stewart Webb" }, "created_at": "2026-10-23T14:02:00Z", "links": { "self": "/v1/operations/op_01jbx2m9k7q4r8t5v6w3y0z1op", "events": "/v1/operations/op_01jbx2m9k7q4r8t5v6w3y0z1op/events", "resource": "/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1dp" }}