Hanzo
OpenapiProjects

Opens a deployment and hands back a short-lived, prefix-scoped grant to write…

Opens a deployment and hands back a short-lived, prefix-scoped grant to write its bytes straight to object storage. Answers 202.

POST /v1/projects/{slug}/deployments

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

Opens a deployment and hands back a short-lived, prefix-scoped grant to write its bytes straight to object storage. Answers 202.

This is the path for a site too large to send as one archive: a real export is hundreds of megabytes against a 16 MiB body limit, so the bytes deliberately do NOT pass through the API. The answer carries bucket, prefix and upload — a presigned POST policy that S3 itself confines to this site's prefix (starts-with <org>/<slug>/), expires in 30 minutes and bounds each object. So a build writes its own files and holds no standing bucket credential; there is nothing to rotate and nothing that leaks between tenants. Never guess the prefix — it is server-derived, and a guessed one lands where nothing is served.

The deployment is queued until POST .../deployments/{id}/complete flips it live (or error). That completion is also where DELETION happens: the grant authorizes writes only, so a build cannot remove a file, and cloud reconciles the prefix against the keys manifest the completion carries. A build that dies before completing leaves the deployment queued rather than a half-live site.

The grant is on the 202 and NOWHERE else — it is never stored and never replayed on a later read, so it cannot outlive the build it was minted for. A deployment whose grant could not be minted is still created and still completable; it simply carries no upload, and a caller with no other way to write should treat that as the failure it is.

Billing: the hosting gate runs BEFORE anything is created (402 unfunded, 503 commerce unreachable), and the debit lands on the completion that goes live — never on a queued or failed build.

Scope: a validated principal is required (403 without one) and the site is resolved within that principal's org, so another tenant's slug is a 404.

Request

3 fields, body application/json (required).

FieldInTypeRequiredDescription
slugpathstringyesSlug is the site to deploy, from the path.
commitbodystringCommit is the git sha this build was produced from, recorded on the deployment so a released site can be traced back to its source. Optional.
slugbodystringSlug is the site to deploy, from the path.

Response

StatusBodyMeaning
202projectsDeploymentaccepted

202 body — 21 fields.

FieldInTypeAlwaysDescription
bucketbodystringBucket is the object-store bucket its files were written to.
bytesbodyintegerBytes is their total size in bytes.
commitbodystringCommit is the revision that was built, for a deployment that came from a repository.
createdAtbodyintegerCreatedAt is when the deployment was queued, as Unix seconds.
filesbodyintegerFiles is how many objects the deployment published.
idbodystringID identifies this one deployment attempt, and is what CI quotes back to complete it.
liveUrlbodystringLiveURL is where this deployment serves, once it is live.
messagebodystringMessage is what happened, in words — the build's own note, or on a failure why it failed.
prefixbodystringPrefix 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…
projectIdbodystringProjectID is the project this deployment belongs to.
sourcebodystringSource is what caused the deployment — a git push, an uploaded artifact, a generated site.
statusbodystringStatus is where the attempt got to — queued, live, or failed.
updatedAtbodyintegerUpdatedAt is when it last changed state, as Unix seconds — so the gap between the two is how long the build took.
uploadbodyprojectsUploadGrant
upload.expiresAtbodyintegerExpiresAt is when the grant stops being accepted, as Unix seconds.
upload.fieldsbodyobjectFields are form values every POST must carry VERBATIM, alongside key and file.
upload.fields.*bodystring
upload.maxBytesbodyintegerMaxBytes bounds ONE object, not the upload as a whole.
upload.prefixbodystringPrefix is the only place this grant can write: the deployment's own key prefix.
upload.urlbodystringURL is the address to POST each object to.
versionbodyintegerVersion 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 create <slug>

Projects API · All Hanzo APIs · Interactive reference

How is this guide?

On this page