Hanzo
OpenapiPlatform

Creates an application from a git repo or a container image.

Creates an application from a git repo or a container image.

POST /v1/platform/projects/{project}/apps

Addresshttps://api.hanzo.ai/v1/platform/projects/{project}/apps
MethodPOST
Operationpost_platform_projects_by_project_apps
AuthAuthorization: Bearer $HANZO_API_KEY

Creates an application from a git repo or a container image.

It registers a new application under one of the caller org's projects and answers 201 with it. Creating does NOT deploy: the app lands in draft and nothing reaches the cluster until /deploy.

source is git — which requires repo.url — or image, which requires image.repository; anything else is 400. A git app builds with zero-config pack by default and may opt into dockerfile; an image app never builds. The repo URL and Dockerfile path are validated here against the SAME allowlist the privileged build enforces, so an unsafe source is refused before it is ever persisted.

The slug is the app's identity in the cluster: given or derived from name, it must match ^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$, and a slug already used in this project is 409. replicas and storageGb are clamped to the deployment's limits rather than refused.

Env keys must match ^[A-Za-z_][A-Za-z0-9_]*$. A variable marked secret: true is SEALED into KMS and its plaintext is never written to the database — and if KMS is unavailable the create fails 503 rather than falling back to storing a secret in the clear.

The app is seeded with its canonical default host, so it has a working HTTPS URL the moment it deploys. A bare custom domain cannot be attached here — it has to go through add-domain and DNS verification first. Requires a validated principal; 403 without one, and every cluster object it will later create lands in that org's own tenant-<org> namespace.

Request

23 fields, body application/json (required).

FieldInTypeRequiredDescription
projectpathstringyesProject is the project to create the application under, from the path.
buildTypebodystringBuildType is pack — the zero-config default that detects any project — or dockerfile, the explicit escape hatch.
descriptionbodystringDescription is free text about what the application is.
dockerfilebodystringDockerfile is the path to build from, for buildType dockerfile.
domainsbodystring[]Domains are extra ingress hosts. The canonical default host is always attached; a bare custom host is refused here and must go through add-domain → verify…
envbodyEnvVarJSON[]Env is the application's environment. Keys must match ^[A-Za-z_][A-Za-z0-9_]*$; a variable marked secret: true is sealed into KMS and its plaintext is…
env[].keybodystringKey is the variable's name in the container, which must match ^[A-Za-z_][A-Za-z0-9_]*$.
env[].secretbodybooleanSecret says the value lives in KMS and never in the database.
env[].valuebodystringValue is the plaintext, and it is WRITE-ONLY once the entry is secret: a sealed value reads back as "", and sending "" again KEEPS what is sealed rather than…
environmentbodystringEnvironment is the deploy target this app names ("production" by default).
imagebodyimageOrigin
image.repositorybodystringRepository is the image repository.
image.tagbodystringTag is the image tag to deploy; latest when omitted.
namebodystringName is the application's display name.
portbodyintegerPort is the container port the app listens on.
projectbodystringProject is the project to create the application under, from the path.
replicasbodyintegerReplicas is how many copies to run; clamped to the deployment's limit rather than refused.
repobodygitOrigin
repo.branchbodystringBranch is the branch to build; defaults to main for a git source.
repo.urlbodystringURL is the repository clone URL.
slugbodystringSlug is the app's identity in the cluster — its CR name and part of its host.
sourcebodystringSource is git, which requires repo.url, or image, which requires image.repository.
storageGbbodyintegerStorageGB is the persistent volume size in GiB; absent means stateless.

Response

StatusBodyMeaning
201appViewcreated

201 body — 34 fields.

FieldInTypeAlwaysDescription
buildTypebodystringBuildType is how a git app builds: pack, the zero-config default that detects the project, or dockerfile.
createdAtbodyintegerCreatedAt is when the app was created, unix seconds.
currentDeploymentIdbodystringCurrentDeploymentID is the deployment that is live — the pointer a deploy advances monotonically by version, so it never regresses to an older one.
descriptionbodystringDescription is free text about what the app is.
dockerfilebodystringDockerfile is the path inside the repo to build from, for buildType dockerfile.
domainsbodystring[]Domains are the ingress hosts rendered into the app's CR, its own &lt;slug&gt;.&lt;org&gt;.&lt;sites host&gt; first.
envbodyEnvVarJSON[]Env is the app's environment variables, with every SECRET value masked to "" — the plaintext is in KMS and this surface never echoes it.
env[].keybodystringKey is the variable's name in the container, which must match ^[A-Za-z_][A-Za-z0-9_]*$.
env[].secretbodybooleanSecret says the value lives in KMS and never in the database.
env[].valuebodystringValue is the plaintext, and it is WRITE-ONLY once the entry is secret: a sealed value reads back as "", and sending "" again KEEPS what is sealed rather than…
environmentbodystringEnvironment is the deploy target this app names, production when none was given.
healthbodystringHealth rolls ready-vs-desired replicas up to a colour: green (all ready), yellow (some ready, or deliberately scaled to zero), red (none), or "" when the…
idbodystringID is the server-minted application id (app_…).
imagebodyimageView
image.repositorybodystringRepository is the image path without a tag (ghcr.io/acme/api). Required for source image, which runs it as-is.
image.tagbodystringTag is the tag to run: what the create declared, then RE-STAMPED on every transition to live with the tag that actually went live.
namebodystringName is the display name.
namespacebodystringNamespace is where the app's cluster objects live, tenant-&lt;org&gt;.
orgbodystringOrg is the tenant that owns the app.
phasebodystringPhase is the operator's own status.phase for the app's Service CR, read from the cluster on this request.
portbodyintegerPort is the container port traffic is sent to.
projectIdbodystringProjectID is the IAM project the app lives under, and it is that project's NAME — the (org,name) key IAM identifies it by, which is also what the :project
replicasbodyintegerReplicas is how many copies the CR declares.
repobodygitSource
repo.branchbodystringBranch is the branch a push-to-deploy build tracks, main when the create named none — a push to any other branch, and every tag push, builds nothing here.
repo.providerbodystringProvider is derived from the URL — github, gitlab, bitbucket, or git for anything else.
repo.urlbodystringURL is the clone URL a git app builds from, stored as sent once the build path's allowlist accepted it (validateRepoURL).
secretSyncbodystringSecretSync is how far the app's secret env has got into the cluster: ""|pending|syncing|ready|failed (secrets.go).
secretSyncDetailbodystringSecretSyncDetail is the honest reason when the sync is not ready — a missing CRD, an RBAC grant, a per-tenant credential.
slugbodystringSlug is the app's identity in the cluster: the operator CR's name, the first label of its default host, and the :app path segment.
sourcebodystringSource is what the app deploys FROM: git, which builds Repo, or image, which runs Image as it is.
statusbodystringStatus is the lifecycle THIS store records: draft (created, nothing in the cluster yet), building, deploying, live, stopped or error.
storageGbbodyintegerStorageGB is the persistent volume size in GiB.
updatedAtbodyintegerUpdatedAt is when it last changed, unix seconds.

Failure carries the platform error shape — see Errors.

Examples

hanzo platform projects apps create <project>

Platform API · All Hanzo APIs · Interactive reference

How is this guide?

On this page