Build a template
Compile a template document into a golden image, and return immediately with a job to watch. A build takes minutes — an agent image is roughly fifteen — so this never blocks: the answer is 202 with an id, and GET /builds/{id} says what became of it.
ACCOUNT-WIDE KEYS ONLY. Builds are the account’s, like the templates they build: an API key confined to a workspace is a 403 on this route and on every other /builds route, and can launch a computer from a published template by its ref instead.
The body is the document itself, as JSON or YAML, exactly as POST /templates/validate takes it. Validate first if you are iterating; a document that is wrong is refused here too, but the validator tells you every problem at once.
THE NAMESPACE AND THE FAMILY BOTH HAVE TO BE YOURS, and either one is a 403. metadata.namespace has to be your account id, the same rule POST /templates states. spec.family is what the built image is CALLED on a hypervisor, in a directory shared with every computer on that machine — so a build may only write into a family named after your account: golden-<your account id>, or that and a - and a name of your choosing. The message names the family it refused.
THE PARENT HAS TO BE ONE OF OURS. spec.from on a document with spec.build steps or spec.env must name a system template, and anything else is a 400 rather than a 403: it is not a permission, it is that no hypervisor can resolve it. A build layers onto the parent’s image and the only catalogue a hypervisor searches is the one compiled into it, while this request carries your document alone — so there is nothing that could tell it what your-account/base is. Layering onto a template of your own is not supported yet.
SECRETS ARE NAMED, NEVER WRITTEN. spec.secrets lists the secrets a build step may read: each entry is the id of one of yours and the as it appears under as an environment variable. The value is not in the document and never travels in it — a template document is text you publish, copy and review, and a value written there is a value in a file. The values are delivered to the build over a channel of their own and a step sees them only as those variables: we put them in no argument, no staged file and no line of the build log. What a step does with them afterwards is yours — a step that prints its own environment prints the value, and the build log is readable through GET /builds/{id}/progress.
A document may name at most 32 secrets; more is a 400 here. POST /templates/validate does not check that limit, so a document it passes can still be refused for it.
A reference is resolved in YOUR scope at the moment you submit, and the revision current then is the one the build uses: your account-wide secrets. A reference that does not resolve in that scope — a workspace’s, another account’s, one that has been deleted — is a 400 carrying ONE sentence, the same sentence for all three, because which of them it was is not something an answer should tell you. That is the only refusal that is deliberately indistinct: a malformed reference gets a 400 saying what is wrong with it, a secret whose value cannot be delivered gets a 409, and a deployment with no keyring configured gets a 503. Retry logic wants those apart — the 503 is worth retrying, and the two 400s and that 409 are not. The secret 409 carries reason: "unsupported" and is final until the secret is replaced: its value cannot be read under this control plane’s keyring, or is not text an environment variable can carry, or the secret was deleted or left the build’s scope while the request was being admitted. Replace the secret (or name another) and build again.
Freezing the revision is what makes a build reproducible and what makes a rotation land. Two builds of the same document against the same revisions are the same build and the second may reuse the first’s image; rotate a secret and the next build is a different build, and runs. An image built from your secrets is yours alone — another account writing the same document never reaches it, and could not name your secret to begin with.
One build runs per hypervisor at a time. A 409 with reason: "contention" means a host is busy, or has no room on its disk for another build right now, rather than that anything is wrong with your document, and is worth retrying. Your plan sets how many builds you may start in a rolling day; a 429 names the number you have used.
A BUILD YOU KEEP COUNTS AGAINST YOUR STORAGE POOL. A build produces a whole disk image that stays on a hypervisor, so each one your account keeps counts against your plan’s storage pool — the same pool your computers’ disks use — at its template’s disk_gb. A build that would take the pool past its size is a 402 that names the pool, your computers and your kept builds, and costs nothing; creating or growing a computer counts kept builds the same way. A build counts from the moment it is accepted, and stops counting if it fails or reuses an image already built. Each template family keeps its three newest builds on each hypervisor; an older one is removed automatically once no computer or snapshot uses it, and then stops counting — so launching a template whose build was removed is refused until you build it again. Builds made before this rule are kept, never removed to make room: an account over its pool because of them has new builds and computers that need room refused, and its owners are told once by email which families hold what.
A BUILD THAT REUSED AN IMAGE DOES NOT SPEND THAT ALLOWANCE. An identical document, built before, is answered from the image already on disk in a fraction of a second rather than the minutes a real build takes, so resubmitting bytes you have already built does not spend a unit sized against the long case. It is not counted once the fleet reports what it was, which follows the 202 by a moment rather than arriving with it. Passing no_reuse opts out: it is a request for the work, and the work is charged.
THERE IS A SECOND, MUCH LARGER CEILING ON BUILD REQUESTS, ten times the first. Every request that reaches a hypervisor counts against it, whatever comes of it there — a reuse hit is cheap and it is not free: it takes that machine’s one build slot while it runs, and every other build on it is answered 409 for the length of that. Requests refused before any hypervisor is asked — a plan that does not include building, a namespace or a family that is not yours — count against neither ceiling, because nothing was asked of any machine. A document that will not PARSE is not one of those: it is sent on, because the hypervisor that would build it is the tier that reads it, so it costs a request and no build. Both ceilings answer 429, and the message says which one you met. Iterating on a document will not come near the second; a loop resubmitting one will.
A REQUEST A HYPERVISOR REFUSES COSTS NO BUILD — 409 busy or out of room, 400 for a document it will not build, 501 — and it does count as a request: the host started nothing, but it was asked. A build that was admitted (202) counts against the build allowance whatever becomes of it, a build that FAILED included — what that one bounds is a shared machine, and charging only for the builds that worked would make the cheapest way to exhaust a hypervisor a document that always fails. So does a build this API could not get an answer about, since a hypervisor may well be running it.
Requires the member role or higher.
Request
- Base URL: https://app.mandala.computer/api/v1
- URL: https://app.mandala.computer/api/v1/builds
- Auth: HTTP bearer
Query parameters
Build even when an image already carries this document’s build digest. Identical documents normally share an image, which is what makes a repeated build cheap; pass this when you want the work done again anyway. This one does count against your daily allowance whatever it finds — the work is the thing being asked for.
Response
The job. status is running until it is succeeded or failed. A succeeded build has produced an image. Publish that same document, then create a computer using its ref. Launches select the newest successful image for that exact document and verify it on its host; see POST /templates for version selection and unavailable-image behavior.
Changes
No recorded changes to this operation across all 1 revision of this API.