Deployments
Immutable deployments of a service into an environment. Rollback re-promotes an earlier image as a new deployment.
| Operation | Method and path |
|---|---|
| Upload a source tarball (guv up) | POST /v1/projects/{project}/uploads |
| Deployment timeline for a project | GET /v1/projects/{project}/deployments |
| List deployments of a service in an environment | GET /v1/projects/{project}/environments/{environment}/services/{service}/deployments |
| Deploy | POST /v1/projects/{project}/environments/{environment}/services/{service}/deployments |
| Get a deployment | GET /v1/deployments/{deployment_id} |
| Roll back to this deployment | POST /v1/deployments/{deployment_id}/rollback |
| Cancel a deployment that has not gone live | POST /v1/deployments/{deployment_id}/cancel |
| Build and deploy logs of a deployment | GET /v1/deployments/{deployment_id}/logs |
| Why a deployment failed and how to fix it | GET /v1/deployments/{deployment_id}/explanation |
Upload a source tarball (guv up)
Section titled “Upload a source tarball (guv up)”POST /v1/projects/{project}/uploadsBody is a gzip-compressed tar of the working directory (max 500 MB, .gitignore respected by the CLI). Use the returned id as source.upload_id when creating a deployment.
- Operation:
uploadSource - Scopes:
projects:write - Idempotency-Key: required
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/gzip, required): string
Responses
| Status | Meaning | Body |
|---|---|---|
201 Created |
Created. | SourceUpload |
Errors: 400, 401, 403, 404, 409, 413, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/projects/shopfront/uploads \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '"string"'Example response
{ "id": "upl_01jbx2m9k7q4r8t5v6w3y0z1pr", "size_bytes": 1, "sha256": "string", "expires_at": "2026-10-22T13:05:00Z"}Deployment timeline for a project
Section titled “Deployment timeline for a project”GET /v1/projects/{project}/deployments- Operation:
listProjectDeployments - Scopes:
projects:read - Paginated:
?limit=and?cursor=
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 | |
service |
query | string | |
status |
query | DeploymentStatus | |
actor_type |
query | user, agent, system, ai_ops, github |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
A page of Deployment objects. | DeploymentList |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/projects/shopfront/deployments \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "data": [ { "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 } ], "next_cursor": "string", "has_more": false}List deployments of a service in an environment
Section titled “List deployments of a service in an environment”GET /v1/projects/{project}/environments/{environment}/services/{service}/deployments- Operation:
listDeployments - Scopes:
projects:read - Paginated:
?limit=and?cursor=
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. |
service * |
path | string | Service id (svc_…) or name. |
status |
query | DeploymentStatus |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
A page of Deployment objects. | DeploymentList |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/projects/shopfront/environments/production/services/web/deployments \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "data": [ { "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 } ], "next_cursor": "string", "has_more": false}Deploy
Section titled “Deploy”POST /v1/projects/{project}/environments/{environment}/services/{service}/deploymentsBuilds (unless deploying an image or redeploying) and rolls out a new immutable deployment. Returns an operation
whose resource is the new deployment. Fails early with secret_missing if a referenced secret is not set.
- Operation:
createDeployment - Scopes:
deploy:{environment} - CLI:
guv deploy - Approval: In environments with protection turned on (usually production), changes by agents and by roles outside
approver_rolesreturnapproval_required. - Idempotency-Key: required; supports
?dry_run=true
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. |
service * |
path | string | Service id (svc_…) or name. |
Request body (application/json): DeploymentCreate
| Field | Type | Description |
|---|---|---|
source |
object | |
redeploy_of |
string | Rebuild-free redeploy of an existing deployment’s image with current settings and secrets. |
message |
string | |
clear_build_cache |
boolean | Default false. |
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, 402, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/projects/shopfront/environments/production/services/web/deployments \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "source": { "kind": "git", "ref": "main", "image": "string", "upload_id": "string" }, "redeploy_of": "string", "message": "string", "clear_build_cache": false}'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 a deployment
Section titled “Get a deployment”GET /v1/deployments/{deployment_id}- Operation:
getDeployment - Scopes:
projects:read
Parameters
| Name | In | Type | Description |
|---|---|---|---|
deployment_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | Deployment |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1pr \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "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}Roll back to this deployment
Section titled “Roll back to this deployment”POST /v1/deployments/{deployment_id}/rollbackCreates a new deployment that re-promotes this deployment’s image and settings snapshot (with current secret values). Fails with deployment_not_rollbackable if the image has passed retention.
- Operation:
rollbackDeployment - Scopes:
deploy:{environment} - CLI:
guv rollback - Approval: In environments with protection turned on (usually production), changes by agents and by roles outside
approver_rolesreturnapproval_required. - Idempotency-Key: required; supports
?dry_run=true
Parameters
| Name | In | Type | Description |
|---|---|---|---|
deployment_id * |
path | string |
Request body (application/json): DeploymentRollback
| Field | Type | Description |
|---|---|---|
reason |
string |
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, 422, 429, 500, as problem+json with a stable code.
Example
curl -X POST https://api.guv.dev/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1pr/rollback \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "reason": "Checkout is failing after the last deploy"}'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" }}Cancel a deployment that has not gone live
Section titled “Cancel a deployment that has not gone live”POST /v1/deployments/{deployment_id}/cancel- Operation:
cancelDeployment - Scopes:
deploy:{environment} - Idempotency-Key: required; supports
?dry_run=true
Parameters
| Name | In | Type | Description |
|---|---|---|---|
deployment_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. With dry_run=true: a Plan (application/vnd.guv.plan+json) and nothing changes. |
Deployment |
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/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1pr/cancel \ -H "Authorization: Bearer $GUV_TOKEN" \ -H "Idempotency-Key: $(uuidgen)"Example response
{ "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}Build and deploy logs of a deployment
Section titled “Build and deploy logs of a deployment”GET /v1/deployments/{deployment_id}/logsJSON page by default. With Accept: text/event-stream (or ?follow=true) streams log events until the deployment settles.
- Operation:
getDeploymentLogs - Scopes:
logs:read
Parameters
| Name | In | Type | Description |
|---|---|---|---|
deployment_id * |
path | string | |
source |
query | build, deploy, runtime |
|
follow |
query | boolean |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | LogQueryResult |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1pr/logs \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "lines": [ { "id": "lg_9f8e7d6c5b", "timestamp": "2026-10-23T14:04:02.123Z", "source": "runtime", "level": "error", "message": "TypeError: Cannot read properties of undefined (reading 'id')", "service": { "id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv", "name": "web" }, "environment": "production", "deployment_id": "dep_01jbx2m9k7q4r8t5v6w3y0z1dp", "replica": "web-1", "http": null, "attributes": {}, "redacted": false } ], "next_cursor": "string", "has_more": false, "query": "string", "dropped_lines": 1}Why a deployment failed and how to fix it
Section titled “Why a deployment failed and how to fix it”GET /v1/deployments/{deployment_id}/explanation- Operation:
getDeploymentExplanation - Scopes:
projects:read - CLI:
guv doctor
Parameters
| Name | In | Type | Description |
|---|---|---|---|
deployment_id * |
path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 OK |
OK. | DeployExplanation |
Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.
Example
curl https://api.guv.dev/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1pr/explanation \ -H "Authorization: Bearer $GUV_TOKEN"Example response
{ "deployment_id": "dep_01jbx2m9k7q4r8t5v6w3y0z1dp", "status": "available", "category": "port_mismatch", "cause": "Your app listens on port 8080 but we expected 3000.", "fix": { "summary": "Set port: 8080 on the web service.", "actions": [ { "kind": "one_click", "label": "Set port to 8080", "command": "guv services update web --port 8080", "api": { "method": "PATCH", "path": "/v1/projects/primecarers/services/web", "body": { "port": 8080 } } }, { "kind": "open_pr", "label": "Ask AI to fix (opens a PR)" } ] }, "evidence": [ { "source": "runtime_log", "timestamp": "2026-10-23T14:04:02Z", "text": "Server listening on http://0.0.0.0:8080" } ], "confidence": "high", "generated_by": "rules", "ai_generated": false}