Deploy projects
Takes a built site live at https://<slug>.hanzo.app in one call.
POST /v1/projects/{slug}/deploy
| Address | https://api.hanzo.ai/v1/projects/{slug}/deploy |
| Method | POST |
| Operation | post_projects_by_slug_deploy |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Takes a built site live at https://<slug>.hanzo.app in one call. The body is the site itself — a zip or tar.gz holding index.html at its root (or a single wrapper directory that does), sent raw or as a multipart file part. It is unpacked to the site's own storage prefix and served immediately, answering the finished deployment.
It is bounded by the edge body limit (16 MiB by default), and that bound is the whole reason the other path exists: an oversized POST is refused by the server BEFORE any handler runs and surfaces as an opaque 400 Error when parsing request that reads like a malformed payload rather than a size cap. A site too large for one archive opens a deployment with POST /v1/project/{slug}/deployments instead and writes its files straight to storage against the scoped grant that answers with — no body limit, and no bytes through this API at all.
Publishing is free: no deploy is charged, and an org with no balance can publish and republish. A site is billed for the storage its org holds past the free tier, metered hourly; an org already past the tier must be able to pay a month of that storage, or the upload is refused 402 (503 when commerce is unreachable) BEFORE anything is parsed or written. A failed upload never flips the live site, and a redeploy replaces the site's files and answers the SAME URL, because slug and apex are stable.
Scope: a validated principal is required (401 without one) and the site is resolved within that principal's org, so another tenant's slug is a 404. Object storage must be configured (503); an archive that does not walk is a 400 and one over the size cap is a 413.
Request
2 fields, body application/octet-stream.
| Field | In | Type | Required | Description |
|---|---|---|---|---|
slug | path | string | yes | |
(body) | body | string (binary) | yes |
Response
| Status | Body | Meaning |
|---|---|---|
2XX | projectsDeployment | Success |
2XX body — 22 fields.
| Field | In | Type | Always | Description |
|---|---|---|---|---|
bucket | body | string | — | |
bytes | body | integer | — | |
commit | body | string | — | |
createdAt | body | integer | — | |
files | body | integer | — | |
id | body | string | — | |
liveUrl | body | string | — | |
message | body | string | — | |
prefix | body | string | — | |
projectId | body | string | — | |
source | body | string | — | |
status | body | string | — | |
updatedAt | body | integer | — | |
upload | body | projectsUploadGrant | — | |
upload.copy | body | boolean | — | |
upload.expiresAt | body | integer | — | |
upload.fields | body | object | — | |
upload.fields.* | body | string | — | |
upload.maxBytes | body | integer | — | |
upload.prefix | body | string | — | |
upload.url | body | string | — | |
version | body | integer | — |
Failure carries the platform error shape — see Errors.
Examples
hanzo projects deploy <slug>import { Configuration, ProjectApi } from 'hanzoai';
const api = new ProjectApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postProjectsBySlugDeploy({ slug: 'slug' });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_deploy(slug='slug')cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)
resp, _, err := client.ProjectAPI.PostProjectsBySlugDeploy(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_deploy(&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).postProjectsBySlugDeploy();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>/deploy \
-H "Authorization: Bearer $HANZO_API_KEY"MCP reaches project through the project tool, which names its 52 operations with its own verbs — this one among them, under a name only MCP declares. describe explains any of them:
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe",
"arguments": {
"op": "get_project"
}
}
}'