Hanzo

API Reference

The one Hanzo PaaS API surface — api.hanzo.ai/v1/platform for projects and apps, api.hanzo.ai/v1/runner for builds.

Hanzo PaaS has one API surface, on the one Hanzo API host.

Base URL

SurfaceBaseAuth
Control planehttps://api.hanzo.ai/v1/platformAuthorization: Bearer <iam-jwt>
Buildshttps://api.hanzo.ai/v1/runnerAuthorization: Bearer <iam-jwt> (org admin) or the fabric build token

platform.hanzo.ai is the Studio — a browser UI. Do not call it programmatically. It answers, which is what makes it a trap:

  • platform.hanzo.ai/v1/<anything>401 {"message":"Unauthorized"} — the same answer for a path that does not exist, and the same answer when you present a valid bearer. It is a browser-session wall, not a challenge a token can satisfy, so a 401 there never means "get a better token". Only /v1/health answers 200.
  • platform.hanzo.ai/api/<anything>404, text/html — the Studio's page shell, not an error you can parse.
  • app.platform.hanzo.ai is the same origin one redirect away: it 301s to platform.hanzo.ai, so every path above behaves identically there.

The programmatic host is api.hanzo.ai, and it distinguishes: api.hanzo.ai/v1/platform/projects403 (real, needs org context), api.hanzo.ai/v1/platform/zzz-bogus404 (no such route). There is no x-api-key header, no tRPC procedure surface on this host, and no /api prefix on any Hanzo endpoint.

Authentication

One bearer, minted from a machine identity in Hanzo KMS or from an interactive Hanzo IAM login:

TOKEN=$(curl -sS -X POST https://api.hanzo.ai/v1/kms/auth/login \
  -H 'Content-Type: application/json' \
  -d "{\"clientId\":\"$KMS_CLIENT_ID\",\"clientSecret\":\"$KMS_CLIENT_SECRET\"}" | jq -r .accessToken)

curl -fsS https://api.hanzo.ai/v1/platform/projects \
  -H "Authorization: Bearer $TOKEN"

See Authentication.

Endpoints

MethodPathPurpose
GET · POST/v1/platform/projectsList / create projects
GET · DELETE/v1/platform/projects/{project}Inspect / delete a project
GET · POST/v1/platform/projects/{project}/appsList / create apps
GET · DELETE/v1/platform/projects/{project}/apps/{app}Inspect / delete an app
POST/v1/platform/projects/{project}/apps/{app}/deployRoll the app forward
POST/v1/platform/projects/{project}/apps/{app}/startStart the workload
POST/v1/platform/projects/{project}/apps/{app}/stopStop the workload
GET/v1/platform/projects/{project}/apps/{app}/deploymentsDeployment history
GET/v1/platform/projects/{project}/apps/{app}/deployments/{id}One deployment
GET/v1/platform/projects/{project}/apps/{app}/deployments/{id}/logsDeployment logs
GET · POST/v1/platform/sitesStatic sites
GET/v1/platform/healthLiveness
POST/v1/runnerEnqueue an in-cluster image build

Request format

JSON in, JSON out. Requests are plain REST — no envelope, no procedure names:

curl -fsS -X POST https://api.hanzo.ai/v1/platform/projects \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "slug": "web", "name": "Web" }'

Error responses

Errors are a flat JSON object with the HTTP status echoed in the body:

{ "status": 403, "error": "X-Org-Id required" }
StatusMeaning
400Invalid input
401Missing or invalid bearer
403Validated principal lacks the scope (or no org context)
404Resource does not exist
409Conflict (stale version, duplicate slug)
500Server error

Rate limits

Rate-limit headers ride every response:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97

How is this guide?

On this page