Publish a template
Store a template document under a ref of your own, so POST /computers can launch it by name.
ACCOUNT-WIDE KEYS ONLY. Templates are the account’s catalogue, not a workspace’s: an API key confined to a workspace can launch a computer from a template by its ref and list them with GET /templates, but publishing, reading one of the account’s documents back and retiring are a 403 for it.
THE NAMESPACE IS YOUR ACCOUNT. metadata.namespace has to be your account id, which is the namespace part of the ref (<account id>/name@version) on every template GET /templates shows you as yours; anything else is a 403, including system, which is reserved for the templates we publish. Your templates are private: no other account can see or launch them, and there is no registry.
A REF IS IMMUTABLE. namespace/name@version names one document for ever. Publishing the identical document again succeeds and changes nothing, so a pipeline that republishes on every commit is safe; publishing a DIFFERENT document under the same ref is a 409, and the fix is to bump metadata.version. What counts as different is the digest, so a changed label is a change.
FOR EVER SURVIVES RETIRING. A ref you have retired with DELETE /templates/{namespace}/{name} is still spoken for: publishing it again is a 409 that names the date it went, and that is true even of the identical bytes. Retiring frees the ROW, which is what the ceiling counts — it does not free the name.
There is a ceiling on how many templates one account holds, and a publish past it is a 409 that says where you stand. Retire a version you no longer launch and publish again.
There is a SECOND, much larger ceiling on how many refs one account may ever claim — live and retired together. Retiring does not clear that one, because a retired ref can never be published again and so still counts. A 409 naming it is the one refusal here you cannot fix from your side; get in touch and we will raise it. refs_claimed on a retire response is where you stand.
NONE OF THESE FOUR 409s IS WORTH SENDING AGAIN AS IT IS, and each says so in reason: a different document under a taken ref and a retired ref carry reason: "exists" (bump metadata.version), and both ceilings carry reason: "unsupported" (retire a template, or get in touch).
The body is the document itself, as JSON or YAML, exactly as POST /templates/validate takes it — and validating first is worth it while you are iterating, since that route reports every problem at once and claims no ref. A document that is not valid is a 400 here, carrying the same list: {error: "That document is not valid.", problems: [...]}, every problem the validator found.
A spec.hardware.disk_gb below the disk floor of the family, or of the spec.from parent, is a 400 naming the floor. The validator does not check this; publish a new version with at least that much.
PUBLISHING IS NOT BUILDING, and what you can launch today follows from that. A document naming a spec.family the fleet already has an image for is launchable the moment it is published — which is how you give yourself one of our templates with your own label, sizing and defaults on it, and it needs no build at all.
A DOCUMENT THAT DECLARES spec.build STEPS OR spec.env HAS TO NAME A FAMILY OF YOUR OWN, because a build WRITES into the family it names, and naming one that is not yours is a 403 — the same answer, and the same rule, as POST /builds. Yours are the ones named after your account: golden-<your account id>, or that and a - and a name of your choosing. A document with neither is under no such rule — it names a family to launch FROM, and naming one of ours is the point of it.
A DOCUMENT THAT DECLARES spec.build STEPS OR spec.env MAY ONLY LAYER ONTO ONE OF OURS. spec.from has to name a template in the system namespace, and anything else is a 400 — here and at POST /templates/validate, which reports it first. A build layers onto the parent’s IMAGE, and a hypervisor resolves a parent only in the catalogue compiled into it: a build request carries the child document alone, so nothing there could work out what your-account/base is. Layering onto a template of your own is not supported yet. Note the asymmetry with the family rule above, because the two read alike and point opposite ways: the family you WRITE into must be yours, and the template you BUILD ONTO must be ours. A document with neither spec.build steps nor spec.env is under neither rule, and may record any spec.from it likes.
After a successful POST /builds, create a computer using the published template ref. Each pinned template version selects the highest image version successfully built from that exact document; an unpinned ref first selects the newest published template version. Image versions are allocated fleet-wide and never reused after cleanup. A forced rebuild can advance the image selected for future creates; existing computers keep their original image. If no verified holder has capacity, a create prepares an on-demand replica and returns 409 with code: template_image_preparing, progress in preparation, and a template_transfer retry token. Repeat the create after Retry-After seconds with that token to keep the exact selected build. No computer is created while preparing. Placement uses only hosts with verified matching bytes and does not fall back to an older image if the selected build is unavailable. A missing, withdrawn or not-yet-verified image returns 409; an incomplete fleet build inventory returns 503. Builds made before custom-image launch support need the same document submitted once more to record its launch provenance; the normal reuse path can reuse matching image bytes.
Requires the member role or higher.
Request
- Base URL: https://app.mandala.computer/api/v1
- URL: https://app.mandala.computer/api/v1/templates
- Auth: HTTP bearer
Response
The template as stored. document is the canonical form — the bytes doc_digest is over — so it may differ from what you sent in key order and whitespace, and not in meaning.
Changes
No recorded changes to this operation across all 1 revision of this API.