Complete deployments — POST /v1/projects/{slug}/deployments/{id}/complete

The CI completion hook that flips a queued git deployment to live (or error) once CI has synced the built site to S3.

POST /v1/projects/{slug}/deployments/{id}/complete

Addresshttps://api.hanzo.ai/v1/projects/{slug}/deployments/{id}/complete
MethodPOST
Operationpost_projects_by_slug_deployments_by_id_complete
AuthAuthorization: Bearer $HANZO_API_KEY

The CI completion hook that flips a queued git deployment to live (or error) once CI has synced the built site to S3.

status must be live or error. On a LIVE completion the public host is claimed FIRST, so the deployment reports the URL it actually OWNS — a CI-supplied liveUrl is a hint that can refine that URL but can never assert a subdomain another tenant holds. keys is the manifest CI just uploaded, relative to the deployment prefix: cloud reconciles the prefix against it so a page deleted from the build actually stops serving. Omit keys and nothing is deleted — the prefix only grows. Reconciliation runs only on a live completion (pruning against a failed build's manifest would delete the site the last good build is still serving) and is best-effort, so a stale leftover never turns a successful deploy into a 500. No completion is charged: the site is billed for the storage it holds, and a live completion re-measures its org.

Scope: a validated principal is required (401 without one). CI authenticates with an org-scoped token through the gateway, so the deployment is resolved within that principal's org and another tenant's slug or deployment id is a 404.

Request

13 fields, body application/json (required).

FieldInTypeRequiredDescription
slugpathstringyesSlug is the project the deployment belongs to, from the path.
idpathstringyesID is the queued deployment to complete, from the path.
bytesbodyinteger (int64)—Bytes is their total size in bytes.
commitbodystring—Commit is the revision that was built, recorded on the deployment.
copybodystring[]—Copy lists the keys to take from CopyFrom's prefix, relative to it.
copyFrombodystring—CopyFrom names another site of the same org whose prefix already holds the bytes of Copy.
filesbodyinteger (int64)—Files is how many objects CI published.
idbodystring—ID is the queued deployment to complete, from the path.
keysbodystring[]—Keys is the manifest CI just uploaded, RELATIVE to the deployment prefix.
liveUrlbodystring—LiveURL is a HINT at the address the site should serve at.
messagebodystring—Message is what happened, in words — on an error completion, why it failed.
slugbodystring—Slug is the project the deployment belongs to, from the path.
statusbodystring—Status is how the build ended: live if it succeeded, error if it did not.

Response

StatusBodyMeaning
200project.projectsDeploymentok
defaultproblem-detailsrefused

200 body — 22 fields.

FieldInTypeAlwaysDescription
bucketbodystring—Bucket is the object-store bucket its files were written to.
bytesbodyinteger (int64)—Bytes is their total size in bytes.
commitbodystring—Commit is the revision that was built, for a deployment that came from a repository.
createdAtbodyinteger (int64)—CreatedAt is when the deployment was queued, as Unix seconds.
filesbodyinteger (int64)—Files is how many objects the deployment published.
idbodystring—ID identifies this one deployment attempt, and is what CI quotes back to complete it.
liveUrlbodystring—LiveURL is where this deployment serves, once it is live.
messagebodystring—Message is what happened, in words — the build's own note, or on a failure why it failed.
prefixbodystring—Prefix is the key prefix within that bucket holding EXACTLY this deployment's objects — the unit an upload grant is scoped to, so a grant for one deployment cannot write over another.
projectIdbodystring—ProjectID is the project this deployment belongs to.
sourcebodystring—Source is what caused the deployment — a git push, an uploaded artifact, a generated site.
statusbodystring—Status is where the attempt got to — queued, live, or failed.
updatedAtbodyinteger (int64)—UpdatedAt is when it last changed state, as Unix seconds — so the gap between the two is how long the build took.
uploadbodyproject.projectsUploadGrant—
upload.copybodyboolean—Copy is true when the completion of this deployment accepts copyFrom and copy.
upload.expiresAtbodyinteger (int64)—ExpiresAt is when the grant stops being accepted, as Unix seconds.
upload.fieldsbodyobject—Fields are form values every POST must carry VERBATIM, alongside key and file.
upload.fields.*bodystring—
upload.maxBytesbodyinteger (int64)—MaxBytes bounds ONE object, not the upload as a whole.
upload.prefixbodystring—Prefix is the only place this grant can write: the deployment's own key prefix.
upload.urlbodystring—URL is the address to POST each object to.
versionbodyinteger (int64)—Version counts deployments of this project from 1, so the history reads as an ordered sequence rather than by timestamp.

Failure carries the platform error shape — see Errors.

Examples

hanzo projects deployments complete <slug> <id>
import { Configuration, ProjectApi } from 'hanzoai';

const api = new ProjectApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postProjectsBySlugDeploymentsByIdComplete({ slug: 'slug', id: 'id', bytes: 0, commit: "<commit>" });
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import ProjectApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = ProjectApi(client).post_projects_by_slug_deployments_by_id_complete(slug='slug', id='id', bytes=0, commit="<commit>")
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.ProjectAPI.PostProjectsBySlugDeploymentsByIdComplete(context.Background()).Execute()
if err != nil {
	return err
}
use hanzo_client::apis::{configuration::Configuration, project_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = project_api::post_projects_by_slug_deployments_by_id_complete(&cfg, Default::default()).await?;
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.ProjectApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new ProjectApi(client).postProjectsBySlugDeploymentsByIdComplete();

The method above is the one at the current release of the document. hanzoai@8.5.914 (npm) and hanzoai@8.5.914 (PyPI) were generated from an earlier release, where this operation carried a different id, so it spells the method differently — regenerating the clients is what makes the two agree. SDKs →

curl -X POST https://api.hanzo.ai/v1/projects/<slug>/deployments/<id>/complete \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "bytes": 0,
       "commit": "<commit>"
     }'

Tool project, op post_projects_by_slug_deployments_by_id_complete — POST the JSON-RPC envelope to https://api.hanzo.ai/v1/mcp.

curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "project",
         "arguments": {
           "op": "post_projects_by_slug_deployments_by_id_complete",
           "input": {
             "slug": "<slug>",
             "id": "<id>",
             "bytes": 0,
             "commit": "<commit>"
           }
         }
       }
     }'

Project API · All Hanzo APIs · Interactive reference

Was this page useful?