# Create build

URL: https://docs.hanzo.ai/docs/openapi/platform/post-build

> Triggers a native build — an image, or the binaries a repo declares.

`POST /v1/build`

> [Platform →](https://docs.hanzo.ai/docs/openapi/platform) · [All API references →](https://docs.hanzo.ai/docs/openapi) · [Get started →](https://docs.hanzo.ai/docs/guides)

|               |                                        |
| ------------- | -------------------------------------- |
| **Address**   | `https://api.hanzo.ai/v1/build`        |
| **Method**    | `POST`                                 |
| **Operation** | `post_build`                           |
| **Auth**      | `Authorization: Bearer $HANZO_API_KEY` |

Triggers a native build — an image, or the binaries a repo declares.

The fabric's own build trigger, and what `hanzo build` and git-push-to-deploy
call. It answers 202 with the build job id: a queued build, not a pushed
artifact.

Two lanes, and a build is exactly one of them. The IMAGE lane takes `repo` and
the output `image` and launches a BuildKit Job that pushes it. The ARTIFACT lane
takes `binaries` — the same recipe the repo's hanzo.yml declares — and publishes
to object storage instead; it must carry no `image`, because a build produces
binaries or an image, never both.

PRIVILEGED, and A BUILD BELONGS TO THE ORGANIZATION ITS CREDENTIAL NAMES. Two
credentials, never a third:

- one that NAMES an organization — a person who administers it (the `hanzo
  build` path, so one IAM login authorizes a build with no separate build
  token), or that organization's own machine identity (the pipeline path). The
  build is attributed to that org and confined to what it owns.
- the shared build-callback token, compared in constant time. It names NO
  organization, which is both why the fabric's own release can publish across
  brands with it and why anything that CAN name one is read first.

Both are bounded by the owned-registry allowlist. The org path is bounded again,
by the org: the image's registry namespace must be one that organization owns, so
it publishes into its own brand and can never overwrite another's through the
shared push credential. The same confinement applies to the artifact lane's repo
owner. There is no request field naming an organization — the attribution is read
off the credential, so there is nothing for a caller to write it with.

The output image is parsed and validated as a single well-formed OCI ref before
any authorization decision reads it, so a crafted ref cannot smuggle a
build-exporter attribute past the check.

## Request

24 fields, body `application/json` (required).

| Field                  | In   | Type                   | Required | Description                                                                                                                                                                                                           |
| ---------------------- | ---- | ---------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `arch`                 | body | string                 | —        | Arch is the target architecture for the artifact lane.                                                                                                                                                                |
| `args`                 | body | object                 | —        | Args are --build-arg values.                                                                                                                                                                                          |
| `args.*`               | body | string                 | —        |                                                                                                                                                                                                                       |
| `binaries`             | body | platform.binarySpec\[] | —        | Binaries selects the ARTIFACT lane (artifact.go): build what the repo's hanzo.yml `binaries:` block declares — a Go binary, an npm tarball, a Rust binary — and publish it to hanzoai/s3 instead of pushing an image. |
| `binaries[].image`     | body | string                 | —        | Image is the toolchain image the recipe runs in, a Go bookworm image by default.                                                                                                                                      |
| `binaries[].ldflags`   | body | string                 | —        | Ldflags are the Go linker flags, `-s -w` when the recipe names none, on one line.                                                                                                                                     |
| `binaries[].main`      | body | string                 | —        | Main is the Go package to build, repo-relative (`.` or `./cmd/x`), and it selects the GO LANE.                                                                                                                        |
| `binaries[].name`      | body | string                 | —        | Name is the artifact's base name: the prefix of every file published for this entry, and the name a host later asks for.                                                                                              |
| `binaries[].out`       | body | string                 | —        | Out is the glob of files `run` produced, relative to the repo root; matching nothing FAILS the build rather than publishing an empty entry.                                                                           |
| `binaries[].platforms` | body | string\[]              | —        | Platforms are the `&lt;os&gt;/&lt;arch&gt;` pairs the Go lane cross-compiles, \[linux/amd64] by default.                                                                                                              |
| `binaries[].run`       | body | string                 | —        | Run is any other toolchain's build command, run by `sh -c` in this entry's image, and it selects the OTHER LANE.                                                                                                      |
| `branch`               | body | string                 | —        | Branch is the branch to build when no SHA or Ref is given.                                                                                                                                                            |
| `bucket`               | body | string                 | —        | Bucket mirrors hanzo.yml's `bucket:` — where the artifact lane publishes.                                                                                                                                             |
| `context`              | body | string                 | —        | Context is the build context path within the repo.                                                                                                                                                                    |
| `dockerTarget`         | body | string                 | —        | DockerTarget is the multi-stage build target to stop at.                                                                                                                                                              |
| `dockerfile`           | body | string                 | —        | Dockerfile is the path to build from; empty uses the zero-config frontend.                                                                                                                                            |
| `image`                | body | string                 | —        | Image is the output image ref to push.                                                                                                                                                                                |
| `os`                   | body | string                 | —        | OS is the target operating system for the artifact lane.                                                                                                                                                              |
| `platforms`            | body | string\[]              | —        | Platforms are the `&lt;os&gt;/&lt;arch&gt;` pairs the image is built for.                                                                                                                                             |
| `ref`                  | body | string                 | —        | Ref is the git ref to build when no SHA is given.                                                                                                                                                                     |
| `repo`                 | body | string                 | —        | Repo is the repository clone URL to build.                                                                                                                                                                            |
| `sha`                  | body | string                 | —        | SHA is the commit to pin; it wins over Ref and Branch.                                                                                                                                                                |
| `tag`                  | body | string                 | —        | Tag is the publish path segment, so both entry points write ONE index at ONE URL.                                                                                                                                     |
| `tags`                 | body | string\[]              | —        | Tags are more tags of Image's own repository, pushed onto the same manifest by the same export, so every one names the digest Image does — by construction, not by a second push agreeing with the first.             |

## Response

| Status    | Body                     | Meaning  |
| --------- | ------------------------ | -------- |
| `202`     | platform.runnerBuildResp | accepted |
| `default` | problem-details          | refused  |

`202` body — 9 fields.

| Field        | In   | Type      | Always | Description                                                                                                                                                                       |
| ------------ | ---- | --------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `buildJobId` | body | string    | —      | BuildJobID is the queued build's id, and what its progress is read by.                                                                                                            |
| `image`      | body | string    | —      | Image is the ref the image lane will push.                                                                                                                                        |
| `index`      | body | string    | —      | Index is the binaries.json URL the artifact lane will publish.                                                                                                                    |
| `platforms`  | body | string\[] | —      | Platforms are the architectures the image lane will publish, echoed back.                                                                                                         |
| `reason`     | body | string    | —      | Reason is why a failed build failed, as the cluster said it: the solve's error line (`error: failed to solve: ...`), a container waiting on what it cannot have, or the deadline. |
| `runnerPool` | body | string    | —      | RunnerPool is the runner class the build was placed on.                                                                                                                           |
| `status`     | body | string    | —      | Status is `queued` until the build finishes, then `succeeded` or `failed`.                                                                                                        |
| `tags`       | body | string\[] | —      | Tags are the extra tags the image lane will write beside Image, onto the same manifest: the request's, deduplicated.                                                              |
| `target`     | body | string    | —      | Target is the multi-stage build target, echoed back.                                                                                                                              |

Failure carries the platform error shape — see [Errors](https://docs.hanzo.ai/docs/errors).

## Examples

**CLI**

```bash
hanzo build create
```

**SDK**

**.ts**

```ts
import { Configuration, PlatformApi } from 'hanzoai';

const api = new PlatformApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postBuild({ arch: "<arch>", args: {} });
```

**.py**

```python
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_build(arch="<arch>", args={})
```

**.go**

```go
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.PlatformAPI.PostBuild(context.Background()).Execute()
if err != nil {
	return err
}
```

**.rs**

```rust
use hanzo_client::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_build(&cfg, Default::default()).await?;
```

**.java**

```java
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.PlatformApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new PlatformApi(client).postBuild();
```

**HTTP**

```bash
curl -X POST https://api.hanzo.ai/v1/build \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "arch": "<arch>",
       "args": {}
     }'
```

**MCP**

MCP reaches **platform** through the `platform` tool, which names its 38 operations with its own verbs — this one among them, under a name only MCP declares. `describe` explains any of them:

```bash
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_build"
         }
       }
     }'
```

---

[Platform API](https://docs.hanzo.ai/docs/openapi/platform) · [All Hanzo APIs](https://docs.hanzo.ai/docs/openapi) · [Interactive reference](https://docs.hanzo.ai/docs/openapi/reference)
