Deploy an app through cd.hanzo.ai
Builds a git repository into an image and writes the declaration that names it — a values file in `hanzoai/universe` under…
POST /v1/platform/apps
| Address | https://api.hanzo.ai/v1/platform/apps |
| Method | POST |
| Operation | post_platform_apps |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Builds a git repository into an image and writes the declaration that names it — a values file in hanzoai/universe under charts/app/values/<namespace>/<name>.yaml, which the fleet ApplicationSet renders as one Application. That file IS the deployment: nothing else has to be applied.
mode decides whether anything can go live. The default, branch, pushes to deploy/<namespace>/<name>/<tag> and returns a review URL; the generator reads main, so a branch declaration deploys NOTHING and merging the review is the deliberate act. commit writes main, and proves the image is pullable first — a declaration naming an image the registry cannot serve is an ImagePullBackOff with no rollback path.
Omit tag to build; give it to declare an image an earlier call already built, which is how a green build is released without rebuilding it.
An org is its name: the values DIRECTORY, the destination NAMESPACE and the AppProject FENCE are all <org>, and the image is <registry>/<org>/<app>. None of them is a request field — the directory decides what CD admits the sync under and the repository decides what the cluster pulls, so a caller who could name either could reach outside its own org.
org is an ACT-AS, not a placement field: it defaults to the caller's own, and naming another requires SuperAdmin. So does naming a RESERVED org — the platform's own namespace family (the brands and their environments, the control and delivery planes, admin) — even when it is the caller's own, because an IAM org named kube-system does not own Kubernetes. Both refuse rather than downgrade, so an escape attempt is never indistinguishable from a normal request.
A host outside the caller's org subtree is refused: claim and verify a custom domain first.
Request
The document declares no body for POST /v1/platform/apps. The handler is typed in cloud but its shape is not yet emitted, so the fields are not listed here — ask the MCP door's describe for post_platform_apps, which answers from the running route.
Response
The document declares no response body for this operation. It answers 200 on success and the platform error shape on failure — see Errors.
Examples
hanzo platform apps createimport { Configuration, PlatformApi } from 'hanzoai';
const api = new PlatformApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postPlatformApps();from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import PlatformApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = PlatformApi(client).post_platform_apps()cfg := cloud.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := cloud.NewAPIClient(cfg)
resp, _, err := client.PlatformAPI.PostPlatformApps(context.Background()).Execute()
if err != nil {
return err
}use hanzo_cloud::apis::{configuration::Configuration, platform_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = platform_api::post_platform_apps(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.PlatformApi;
ApiClient client = new ApiClient();
client.setRequestInterceptor(b -> b.header("Authorization", "Bearer " + System.getenv("HANZO_API_KEY")));
var result = new PlatformApi(client).postPlatformApps();curl -X POST https://api.hanzo.ai/v1/platform/apps \
-H "Authorization: Bearer $HANZO_API_KEY"The door reaches platform through the platform tool, which names its 39 operations with its own verbs — this one among them, under a name only the door 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": "list_builds"
}
}
}'How is this guide?