Skip to content

Projects

View as Markdown

A project is one product or monorepo.

Operation Method and path
List projects GET /v1/workspaces/{workspace}/projects
Create a project POST /v1/workspaces/{workspace}/projects
Get a project GET /v1/projects/{project}
Update a project PATCH /v1/projects/{project}
Delete a project DELETE /v1/projects/{project}
Everything about a project in one call GET /v1/projects/{project}/status
Get a project’s saved canvas layout GET /v1/projects/{project}/canvas
Save a project’s canvas layout PUT /v1/projects/{project}/canvas
Canvas graph for one environment GET /v1/projects/{project}/environments/{environment}/graph
Save canvas node positions PATCH /v1/projects/{project}/environments/{environment}/graph/layout
GET /v1/workspaces/{workspace}/projects
  • Operation: listProjects
  • Scopes: projects:read
  • CLI: guv projects list
  • Paginated: ?limit= and ?cursor=

Parameters

Name In Type Description
workspace * path string Workspace id (ws_…) or slug.
q query string

Responses

Status Meaning Body
200 OK A page of Project objects. ProjectList

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/projects \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

{
"data": [
{
"id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws",
"slug": "primecarers",
"name": "Primecarers",
"description": "Care management platform",
"region": "lon1",
"residency": "uk-only",
"classification": "special-category",
"repo": {
"provider": "github",
"full_name": "primecarers/platform",
"installation_id": "ghi_01jbx2m9k7q4r8t5v6w3y0z1gh",
"default_branch": "main",
"manifest_path": "guv.yaml"
},
"managed_by_manifest": true,
"safety": {
"grade": "A",
"evaluated_at": "2026-10-23T12:00:00Z",
"badge_enabled": true,
"badge_url": "https://guv.dev/safety/k7q4r8t5v6w3y0z1"
},
"created_at": "2026-10-22T09:30:00Z",
"updated_at": "2026-10-23T12:00:00Z"
}
],
"next_cursor": "string",
"has_more": false
}
POST /v1/workspaces/{workspace}/projects
  • Operation: createProject
  • Scopes: projects:write
  • 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): ProjectCreate

Field Type Description
name * string
slug string
description string
region Region
residency Residency
classification Classification
repo RepoBinding
environments array of string Environments to create. Defaults to [production]. Default ["production"].

Responses

Status Meaning Body
200 OK Dry run. Nothing was changed; this is what would happen. Plan
201 Created Created. Project

Errors: 400, 401, 402, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl -X POST https://api.guv.dev/v1/workspaces/acme/projects \
-H "Authorization: Bearer $GUV_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"slug": "string",
"description": "string",
"region": "lon1",
"residency": "uk-only",
"classification": "standard",
"repo": {
"provider": "github",
"full_name": "primecarers/platform",
"installation_id": "string",
"default_branch": "main",
"manifest_path": "guv.yaml"
},
"environments": [
"production"
]
}'

Example response

{
"id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws",
"slug": "primecarers",
"name": "Primecarers",
"description": "Care management platform",
"region": "lon1",
"residency": "uk-only",
"classification": "special-category",
"repo": {
"provider": "github",
"full_name": "primecarers/platform",
"installation_id": "ghi_01jbx2m9k7q4r8t5v6w3y0z1gh",
"default_branch": "main",
"manifest_path": "guv.yaml"
},
"managed_by_manifest": true,
"safety": {
"grade": "A",
"evaluated_at": "2026-10-23T12:00:00Z",
"badge_enabled": true,
"badge_url": "https://guv.dev/safety/k7q4r8t5v6w3y0z1"
},
"created_at": "2026-10-22T09:30:00Z",
"updated_at": "2026-10-23T12:00:00Z"
}
GET /v1/projects/{project}
  • Operation: getProject
  • Scopes: projects:read

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).

Responses

Status Meaning Body
200 OK OK. Project

Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl https://api.guv.dev/v1/projects/shopfront \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

{
"id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws",
"slug": "primecarers",
"name": "Primecarers",
"description": "Care management platform",
"region": "lon1",
"residency": "uk-only",
"classification": "special-category",
"repo": {
"provider": "github",
"full_name": "primecarers/platform",
"installation_id": "ghi_01jbx2m9k7q4r8t5v6w3y0z1gh",
"default_branch": "main",
"manifest_path": "guv.yaml"
},
"managed_by_manifest": true,
"safety": {
"grade": "A",
"evaluated_at": "2026-10-23T12:00:00Z",
"badge_enabled": true,
"badge_url": "https://guv.dev/safety/k7q4r8t5v6w3y0z1"
},
"created_at": "2026-10-22T09:30:00Z",
"updated_at": "2026-10-23T12:00:00Z"
}
PATCH /v1/projects/{project}
  • Operation: updateProject
  • Scopes: projects:write
  • Idempotency-Key: required; supports ?dry_run=true
  • Concurrency: send the ETag you read as If-Match

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).

Request body (application/json, required): ProjectUpdate

Field Type Description
name string
slug string
description string or null
residency Residency
classification Classification
repo RepoBinding or any or null
safety_badge_enabled boolean

Responses

Status Meaning Body
200 OK OK. With dry_run=true: a Plan (application/vnd.guv.plan+json) and nothing changes. Project

Errors: 400, 401, 403, 404, 409, 412, 422, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl -X PATCH https://api.guv.dev/v1/projects/shopfront \
-H "Authorization: Bearer $GUV_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"slug": "string",
"description": "string",
"residency": "uk-only",
"classification": "standard",
"repo": {
"provider": "github",
"full_name": "primecarers/platform",
"installation_id": "string",
"default_branch": "main",
"manifest_path": "guv.yaml"
},
"safety_badge_enabled": false
}'

Example response

{
"id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws",
"slug": "primecarers",
"name": "Primecarers",
"description": "Care management platform",
"region": "lon1",
"residency": "uk-only",
"classification": "special-category",
"repo": {
"provider": "github",
"full_name": "primecarers/platform",
"installation_id": "ghi_01jbx2m9k7q4r8t5v6w3y0z1gh",
"default_branch": "main",
"manifest_path": "guv.yaml"
},
"managed_by_manifest": true,
"safety": {
"grade": "A",
"evaluated_at": "2026-10-23T12:00:00Z",
"badge_enabled": true,
"badge_url": "https://guv.dev/safety/k7q4r8t5v6w3y0z1"
},
"created_at": "2026-10-22T09:30:00Z",
"updated_at": "2026-10-23T12:00:00Z"
}
DELETE /v1/projects/{project}

Stops all services. Databases and volumes are soft-deleted for 7 days, then their backups follow plan retention and are crypto-shredded. Requires confirm=<slug>; agents always need approval.

  • Operation: deleteProject
  • Scopes: projects:delete
  • 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 ETag you read as If-Match

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
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

Terminal window
curl -X DELETE https://api.guv.dev/v1/projects/shopfront \
-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"
}
}
GET /v1/projects/{project}/status
  • Operation: getProjectStatus
  • Scopes: projects:read
  • CLI: guv status

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).

Responses

Status Meaning Body
200 OK OK. ProjectStatus

Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl https://api.guv.dev/v1/projects/shopfront/status \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

{
"project": {
"id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws",
"slug": "primecarers",
"name": "Primecarers",
"description": "Care management platform",
"region": "lon1",
"residency": "uk-only",
"classification": "special-category",
"repo": {
"provider": "github",
"full_name": "primecarers/platform",
"installation_id": "ghi_01jbx2m9k7q4r8t5v6w3y0z1gh",
"default_branch": "main",
"manifest_path": "guv.yaml"
},
"managed_by_manifest": true,
"safety": {
"grade": "A",
"evaluated_at": "2026-10-23T12:00:00Z",
"badge_enabled": true,
"badge_url": "https://guv.dev/safety/k7q4r8t5v6w3y0z1"
},
"created_at": "2026-10-22T09:30:00Z",
"updated_at": "2026-10-23T12:00:00Z"
},
"headline": "All 4 services are live. £7.42 spent of your £400 cap this month. Safety grade A.",
"environments": [
{
"id": "string",
"name": "string",
"status": "healthy",
"services": [
{
"id": "string",
"name": "string",
"kind": "web",
"status": "no_deployment",
"url": "string",
"current_deployment_id": "string",
"last_error": "string",
"cost_today": {
"amount": "7.42",
"currency": "GBP",
"display": "£7.42"
}
}
],
"databases": [
{
"id": "string",
"name": "string",
"engine": "string",
"status": "string",
"last_backup_at": "2026-10-22T13:05:00Z"
}
]
}
],
"recent_deployments": [
{
"id": "dep_01jbx2m9k7q4r8t5v6w3y0z1dp",
"project_id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
"service_id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
"service_name": "web",
"environment_name": "production",
"status": "active",
"status_text": "Live since 14:05",
"trigger": {
"kind": "git_push",
"actor": {
"type": "github",
"id": "stewartwebb",
"display": "stewartwebb pushed to main"
}
},
"source": {
"kind": "git",
"commit": {
"sha": "a1b2c3d4e5f60718293a4b5c6d7e8f9012345678",
"branch": "main",
"message": "Fix rota export",
"author": "Stewart Webb"
}
},
"build_id": "bld_01jbx2m9k7q4r8t5v6w3y0z1bd",
"image": {
"digest": "sha256:4b1f0e9d8c7b6a5948372615f4e3d2c1b0a9f8e7d6c5b4a3928170f6e5d4c3b2",
"signed": true
},
"rollback_of": null,
"operation_id": "op_01jbx2m9k7q4r8t5v6w3y0z1op",
"url": "https://www.primecarers.co.uk",
"failure": null,
"created_at": "2026-10-23T14:02:00Z",
"started_at": "2026-10-23T14:02:01Z",
"active_at": "2026-10-23T14:05:12Z",
"finished_at": "2026-10-23T14:05:12Z",
"duration_ms": 191000
}
],
"spend": {
"month_to_date": {
"amount": "7.42",
"currency": "GBP",
"display": "£7.42"
},
"forecast_month_end": {
"amount": "7.42",
"currency": "GBP",
"display": "£7.42"
},
"cap": {
"amount": "7.42",
"currency": "GBP",
"display": "£7.42"
}
},
"safety_grade": "A",
"pending_approvals": 1,
"open_incidents": 1
}
GET /v1/projects/{project}/canvas
  • Operation: getProjectCanvas
  • Scopes: projects:read

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
environment query string Environment name or id; an environment override is returned when present, otherwise the project layout.

Responses

Status Meaning Body
200 OK OK. ProjectCanvas

Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl https://api.guv.dev/v1/projects/shopfront/canvas \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

{
"project_id": "string",
"environment_id": "string",
"scope": "project",
"canvas": {
"layout": "manual",
"direction": "LR",
"nodes": {
"services.web": {
"x": 0,
"y": 0
}
},
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"etag": "\"1\"",
"managed_by_manifest": false,
"drift": {
"detected": false,
"reason": "none",
"manifest_canvas": {
"layout": "manual",
"direction": "LR",
"nodes": {
"services.web": {
"x": 0,
"y": 0
}
},
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
}
},
"warnings": [
{
"path": "/canvas/nodes/services.web",
"code": "canvas_node_unknown",
"message": "Canvas node is not declared.",
"fix": "Remove this canvas node or declare the resource."
}
],
"source": "api",
"updated_at": "2026-10-22T13:05:00Z",
"updated_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"
}
}
}
PUT /v1/projects/{project}/canvas
  • Operation: updateProjectCanvas
  • Scopes: projects:write
  • Idempotency-Key: required; supports ?dry_run=true
  • Concurrency: send the ETag you read as If-Match

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
environment query string Environment name or id for an environment-specific override.

Request body (application/json, required): CanvasLayout

Field Type Description
layout auto, manual Default auto.
direction LR, TB Default LR.
nodes map of string to CanvasNodePosition
groups array of CanvasGroup
viewport CanvasViewport

Responses

Status Meaning Body
200 OK Updated layout, or a Plan when dry_run=true. ProjectCanvas

Errors: 400, 401, 403, 404, 409, 412, 422, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl -X PUT https://api.guv.dev/v1/projects/shopfront/canvas \
-H "Authorization: Bearer $GUV_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"layout": "manual",
"direction": "LR",
"nodes": {
"services.web": {
"x": 0,
"y": 0
}
},
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
}'

Example response

{
"project_id": "string",
"environment_id": "string",
"scope": "project",
"canvas": {
"layout": "manual",
"direction": "LR",
"nodes": {
"services.web": {
"x": 0,
"y": 0
}
},
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"etag": "\"1\"",
"managed_by_manifest": false,
"drift": {
"detected": false,
"reason": "none",
"manifest_canvas": {
"layout": "manual",
"direction": "LR",
"nodes": {
"services.web": {
"x": 0,
"y": 0
}
},
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
}
},
"warnings": [
{
"path": "/canvas/nodes/services.web",
"code": "canvas_node_unknown",
"message": "Canvas node is not declared.",
"fix": "Remove this canvas node or declare the resource."
}
],
"source": "api",
"updated_at": "2026-10-22T13:05:00Z",
"updated_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"
}
}
}
GET /v1/projects/{project}/environments/{environment}/graph
  • Operation: getProjectGraph
  • Scopes: projects:read

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
environment * path string Environment id (env_…) or name.

Responses

Status Meaning Body
200 OK OK. ProjectGraph

Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl https://api.guv.dev/v1/projects/shopfront/environments/production/graph \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

{
"environment_id": "string",
"nodes": [
{
"id": "string",
"type": "service",
"name": "string",
"status": "string",
"position": {
"x": 0.5,
"y": 0.5
},
"data": {}
}
],
"edges": [
{
"id": "string",
"from": "string",
"to": "string",
"kind": "reference",
"observed": false,
"label": "string"
}
],
"canvas": {
"layout": "manual",
"direction": "LR",
"nodes": {
"services.web": {
"x": 0,
"y": 0
}
},
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
}
}
PATCH /v1/projects/{project}/environments/{environment}/graph/layout
  • Operation: updateProjectGraphLayout
  • Scopes: projects:read
  • Idempotency-Key: required
  • Concurrency: send the ETag you read as If-Match

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
environment * path string Environment id (env_…) or name.

Request body (application/json, required): GraphLayoutUpdate

Field Type Description
positions * map of string to object Node id to canvas position.

Responses

Status Meaning Body
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

Terminal window
curl -X PATCH https://api.guv.dev/v1/projects/shopfront/environments/production/graph/layout \
-H "Authorization: Bearer $GUV_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"positions": {
"key": {
"x": 0.5,
"y": 0.5
}
}
}'