SonaCORE

Referência / Quadra Command API

Products

19 operações em Quadra Command API 0.2.0.

GET/v1/foundry/compiles

List your own compile jobs

Your tenant's compile jobs, newest first. Source is never echoed back.

Parâmetros

NomeTipoDetalhe
limitintegerquery

Respostas

StatusCorpoDetalhe
200FoundryCompileListResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/foundry/compiles

Submit your own Product Bundle to the Foundry

Compile and gate a validator **you** wrote, under your own tenant.

**202, not 201** — the job is accepted, not finished. Poll the companion `GET`.

The submission must carry an authorship `signature` over its `bundle_hash`, made with the key an operator enrolled for your tenant. That signature is what the Certified Product Artifact records as authorship, and it is deliberately a different fact from the API credential that sent the request: credentials rotate, and a certification has to keep answering *who wrote this validator* years later.

A submission that fails a static gate comes back **already REFUSED** and is never queued — the compile slot is the expensive thing, and source that cannot pass a lexer will not pass a compiler. The refusal names the offending rule in the gate report's own vocabulary.

⚠️ Compiling is not binding and certainly not certifying. A green report is evidence; `POST /v1/products/{product_id}` with this `compile_id` is what deploys it at DRAFT.

Corpo da requisição

FoundryCompileRequest — obrigatório. Os campos estão listados em Esquemas, abaixo.

Respostas

StatusCorpoDetalhe
202FoundryCompileResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/foundry/compiles/{compile_id}

Read one of your compile jobs and its gate report

One compile job, at whatever stage it has reached.

The gate report lists **every** gate that ran, passes included, plus a `deferred` block naming what this stage deliberately did not prove. A report showing only failures could not answer "was this checked?", which is the question a countersigner asks.

⛔ Another tenant's `compile_id` and one that never existed are the same DynamoDB miss — the tenant is a partition-key segment, so 404-before-403 holds in its strongest form.

Parâmetros

NomeTipoDetalhe
compile_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200FoundryCompileResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/foundry/quota

How much of your daily compile allowance is left

Used, allowed, and when the window rolls.

⚠️ This **raises rather than reporting zero** when the count cannot be taken. A quota surface answering *"0 of 25 used"* during an outage would be worse than no surface, because a caller would believe it.

⚠️ Its own path rather than `/v1/products/quota`, deliberately: FastAPI matches in declaration order and `/v1/products/{product_id}` is declared above, so `quota` would be captured as a product id and answered `PRODUCT_NOT_FOUND`.

Respostas

StatusCorpoDetalhe
200FoundryQuotaResponseResposta bem-sucedida
GET/v1/openapi

Your tenant's own OpenAPI document

Every action your certified products declare, as a typed API.

⭐ Derived from your manifests on every read, so binding, versioning or suspending a product changes the next response and nothing has to be regenerated. The document describes **your** products and no one else's — the tenant is a segment of the partition key, so another tenant's product is not filtered out here, it is unaddressable.

⛔ Every operation is a shipped generic route with its template filled in. The product id is in the path and the action is a path segment or a `const` in the body; nothing here is a route of its own.

⚠️ `servers` is absent by construction — this service sits behind a gateway and does not know its own public URL, and a caller-supplied one baked into a generated client would be a way to send credentials elsewhere. Use the host you fetched the document from.

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
GET/v1/openapi/sdk/{language}

A generated client for your own products

A single-file client, generated from the document above.

⭐ The reason this is generated rather than left to a codegen tool is `wait_for_state`. Writes here are obligation-first, so an action your validator refuses answers 200 and is refused a beat later; a truthful client polls the instance read for the declared state **and** for `awaiting_index: false`. Dropping that second condition is a race, and no off-the-shelf generator emits it.

Stdlib only, so it runs where you paste it. `base_url` is a constructor argument and is never guessed, for the reason the document gives for omitting `servers`.

Parâmetros

NomeTipoDetalhe
languagestringpathobrigatório

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}

Bind a shipped template as your own DRAFT product

Draft-mode deploy: bind one of the shipped templates for your own tenant.

Bindable **only in a showcase sandbox estate** — faucet money, simulated rails, reset with notice — because a DRAFT artifact has passed no conformance run and no adversarial battery. A production binding is born CERTIFIED naming a certification produced elsewhere, and that is an operator call.

Idempotent on artifact identity: a repeat with a byte-identical manifest answers **200** with `bound: false` and appends no version.

⚠️ Two preconditions that are not about your manifest, both named in the refusal if you meet them: a tenant with no QBRL minting-policy binding cannot resolve its binding params, and a non-incumbent tenant cannot yet receive an inbound credit at all — so it can bind and plan its scenarios, and cannot fund an instance.

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório

Corpo da requisição

TenantDraftBindRequest — obrigatório. Os campos estão listados em Esquemas, abaixo.

Respostas

StatusCorpoDetalhe
201TenantDraftBindResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}/battery

Run the adversarial battery against your own product

Attack your applied script with the generated battery, and report a card.

**202, not 201** — the engine is a bounded job, not a request. Poll the companion `GET`.

The battery evaluates your applied script's **UPLC** against contexts it assembles, fuel-bounded, in a networkless sandbox. It never submits a transaction: most of these attacks cannot be *built* by the platform's own interpreter, and of those that can, the ledger would refuse them before your script ran — so a live-head battery would go green having measured the chain rather than your Haskell.

⚠️ **Grey is not green.** A class whose positive control the script refused anyway proved nothing and is reported `inconclusive`, which a certification treats exactly as it treats a red.

⚠️ One at a time per product: a second run would spend a build slot answering a question already in flight, and two cards for one script make "which one did the certification reference" a guess.

Errors: 404: PRODUCT_NOT_FOUND (also for another tenant's) 409: BATTERY_ALREADY_RUNNING 422: PRODUCT_NOT_PLANNABLE, BATTERY_NOT_PLANNABLE, PRODUCT_NOT_PARAMETRIC 503: PRODUCT_ARTIFACT_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
202Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
GET/v1/products/{product_id}/battery/{battery_id}

Read a battery run and its report card

The run's status and, once `DONE`, where its signed card lives.

⚠️ `RUNNING` for longer than the engine's own ceiling means the task was lost — a background job does not survive a deploy — and starting a new one is then permitted. The row is not silently adopted.

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório
battery_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
GET/v1/products/{product_id}/certification

Your product's certification, and whether it has gone stale

The signed certification for your own binding, its countersignature, staleness.

⭐ **Stale is reported, never enforced.** A battery upgrade does not invalidate a LIVE product: an inventory bump would otherwise be an estate-wide outage triggered by adding an attack class, and the products it would take down are exactly the ones that passed the previous inventory honestly.

⚠️ **A DRAFT product answers 404 `CERTIFICATION_NOT_FOUND`, and that is the expected state, not a fault.** Certification requires a conformance transcript, which needs a live head and a funded instance — and the estate stack that runs one does not exist yet, so a product you bind in the sandbox cannot be certified there today. The refusal says so.

Everything needed to verify the artifact offline is in the response, and the published public keys live beside it in the store. The referenced evidence is one hop away, at `…/certification/evidence/{kind}`.

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}/certification

Certify your own product from the evidence it produced

Assemble, sign and record the Certified Product Artifact for your binding.

⛔ **The body is empty and the evidence is looked up, not named.** An operator naming `{hash, key}` is naming documents it has read; a tenant naming them could name somebody else's, and the certification's integrity checks would not catch it — a valid document about another product is still a valid document. So this route finds what *your own* runs produced: the gate report from your compile (when the product came from one), the transcript from your sealed conformance run, and the card from your completed battery.

⚠️ **The battery card must describe your current applied script.** A card produced before a version bump attests to different bytes, so it reads as absent rather than as evidence — the conservative direction, and the same equality laas-86 puts at the LIVE gate.

This reaches **CERTIFIED**. It does not reach LIVE: that needs a human countersignature the platform cannot mint, produced under a role no task role can assume.

Errors: 404: PRODUCT_NOT_FOUND 409: CONFORMANCE_REQUIRED, BATTERY_REQUIRED, PRODUCT_NOT_CERTIFIABLE 422: CERTIFICATION_EVIDENCE_REFUSED (an evidence verdict is not `accepted`) 503: CERTIFICATION_POLICY_UNAVAILABLE, GOLDEN_VECTOR_CAPTURE_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
GET/v1/products/{product_id}/certification/evidence/{kind}

One evidence document a certification references

The gate report, the conformance transcript, the battery card, or the vectors.

A certification staples its evidence together **by reference**, because a hashed document cannot be rewritten and a battery card carries a whole transaction context per case. This is the dereference: the document at the key the signed body names, re-hashed against the hash the signed body names.

⛔ **Byte-exact, with nothing stripped.** Your recourse is to re-hash these bytes and compare, so a friendlier projection would break the only property that makes the evidence worth reading.

Each document carries its own claims and disclaims *inside* the hashed body — what it proves and what it explicitly does not. Read them: a renderer cannot omit what it does not control, and that is the point of them being there.

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório
kindstringpathobrigatório

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}/conformance

Open a conformance run against your own product

Derive the plan, resolve the roster, and open a run you drive step by step.

A conformance run is what turns a *declared* manifest into a *proved* one: every action it declares executed against the compiled script on a real head, with the schema IR round-tripping the datums the script accepted onto the chain.

**You supply only accounts you own.** The platform resolves their verification keys itself — no read publishes one, and a synthesised key produces an instance nobody can sign for — and it chooses every payload from the manifest, because an action driven with a value nobody chose proves nothing.

⚠️ An incomplete plan does **not** refuse here. An uncovered action, an unreached terminal state or a dead-end state each becomes a failed finding and a `refused` transcript, which is more useful than no document at all.

Errors: 403: DRAFT_RUN_NOT_AVAILABLE (a DRAFT product outside a sandbox estate) 404: PRODUCT_NOT_FOUND, ACCOUNT_NOT_FOUND (both also for another tenant's) 409: PRODUCT_NOT_RUNNABLE (SUSPENDED or RETIRED) 422: PRODUCT_NOT_PLANNABLE, ROSTER_TOO_SMALL, ROSTER_NOT_DISTINCT, ACCOUNT_NOT_USABLE 503: PRODUCT_ARTIFACT_UNAVAILABLE, ACCOUNT_KEY_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório

Corpo da requisição

ConformanceRunOpenRequest — obrigatório. Os campos estão listados em Esquemas, abaixo.

Respostas

StatusCorpoDetalhe
201Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
GET/v1/products/{product_id}/conformance/{run_id}

Read a conformance run, its steps and its verdict

The run's plan with each step's recorded outcome merged in.

One read answers both *what is left* and *what happened*, because a client that has to join two lists will eventually join them wrong. The rules a truthful driver must honour travel in the response's own `driving` block.

⛔ Another tenant's `run_id` and one that never existed are the same 404 — the tenant is a partition-key segment.

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório
run_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}/conformance/{run_id}/steps/{index}

Drive one step of a conformance run

Drive step `index`, then observe it from the head and record what happened.

The platform takes a UTxO snapshot before the step, drives it through the same generic write route you would call yourself, waits a bounded time for the chain's answer, snapshots again, and records the value deltas and the datum round-trip. **The observations are ours, taken from the head** — which is what makes a run you drive usable as evidence.

⛔ **A step is judged by `chain_outcome`, never by this call's status.** The write path is obligation-first: an action your validator refuses answers 200 and is refused a beat later.

Steps run **in order**, one per request, starting at the run's `next_step`. A retry of the same index is safe and replays: the step's own conditional write is the claim lock, and the idempotency key handed to the write is derived from (run, index).

The last step **seals** the run and publishes its transcript; the response carries the verdict.

Errors: 404: RUN_NOT_FOUND, STEP_NOT_FOUND 409: RUN_NOT_OPEN, STEP_OUT_OF_ORDER, SCENARIO_HAS_NO_INSTANCE 422: RUN_PRODUCT_MISMATCH 503: HEAD_SNAPSHOT_UNAVAILABLE, QBRL_POLICY_UNBOUND, TRANSCRIPT_STORE_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório
run_idstringpathobrigatório
indexintegerpathobrigatório

Corpo da requisição

ConformanceStepRequest — obrigatório. Os campos estão listados em Esquemas, abaixo.

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}/instances

Create an instance of a tenant product

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

ProductInstanceCreateRequest — obrigatório. Os campos estão listados em Esquemas, abaixo.

Respostas

StatusCorpoDetalhe
201Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}/instances/{instance_id}/actions/{action}

Drive a declared action on a product instance

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório
instance_idstringpathobrigatório
actionstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

ProductActionRequest — obrigatório. Os campos estão listados em Esquemas, abaixo.

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
POST/v1/products/{product_id}/instances/{instance_id}/close

Close a product instance and release its value

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório
instance_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

ProductCloseRequest — obrigatório. Os campos estão listados em Esquemas, abaixo.

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação
GET/v1/products/{product_id}/scenarios

The scenarios this product's manifest declares

Every declared action and terminal state, as a runnable plan.

⭐ The plan is the one a conformance run derives — same pure function of the same manifest — with the exact generic-route request per step. Run them yourself: this route executes nothing.

⛔ **Assert the outcome, never the HTTP status.** The write path is obligation-first, so an action the script refuses answers 200 and is refused on chain a beat later. The rules a truthful runner has to honour are in `driving`, in the response, because that is where somebody writing one will read them.

⚠️ A step whose payload needs a real account's verification key comes back with `drivable: false` and `unsynthesizable` populated: no read publishes a key, so the platform cannot hand you one to send. The plan is still worth reading.

Parâmetros

NomeTipoDetalhe
product_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200Resposta bem-sucedidaO contrato não declara um modelo para esta resposta, então a forma dela não está documentada aqui. Um roteiro de demonstração mostra a forma que ela realmente devolve.
422HTTPValidationErrorErro de validação

Esquemas

Os modelos que as operações acima aceitam e devolvem. Campos opcionais estão marcados como tal; um campo tipado como outro modelo está documentado sob o nome dele.

BundleSignature

The detached authorship signature that rides a bundle submission.

CampoTipoDetalhe
signaturestringobrigatóriobase64 DER ECDSA-P256 signature over the **32 raw bytes** of bundle_hash — prehashed, never the hash re-hashed. `openssl pkeyutl -sign -pkeyopt digest:sha256`, not `openssl dgst -sign`.
signing_pubkey_fprstringOptional echo of the key used. Compared when present and never trusted: it exists so an author who has rotated is told they signed with the superseded key instead of reading a bare verification failure.Padrão ""

ConformanceRunOpenRequest

``POST /v1/products/{product_id}/conformance`` (LaaS-88). ⛔ **The only thing a caller supplies is a roster of accounts it owns.** No params, no amounts, no deadlines: those are synthesised from the manifest by the one producer both conformance drivers use, because an action driven with a value nobody chose proves nothing about the product. ⭐ Account **ids**, never keys. Two catalog products need a 32-byte counterparty verification key at create and no read publishes one (laas-82 finding 6), so the platform resolves the keys internally from ids the caller owns. Key material crosses this API in neither direction.

CampoTipoDetalhe
account_idsarray de stringobrigatórioDistinct CUSTOMER accounts you own — one to act, plus one per counterparty key this product's datums name. The run refuses up front if there are too few, naming how many it needs.

ConformanceStepRequest

``POST …/conformance/{run_id}/steps/{index}``. Deliberately empty. ⚠️ A body exists only so the route has a schema and `extra="forbid"` can refuse one: a caller who sends params has misunderstood who chooses them, and being told so beats having them silently ignored.

Nenhum campo declarado.

FoundryCompileListResponse

CampoTipoDetalhe
compilesarray de FoundryCompileResponseobrigatório
next_cursorstring, opcional
tenantstringobrigatório

FoundryCompileRequest

One Product Bundle submitted for compilation and gating. ⛔ **The source travels by value and the compiled bytes never do.** That is the inverse of the binding API, and deliberately so: `TenantProductBindRequest` refuses a `cbor_hex` because pre-Foundry there is no compile provenance (laas-80 D1). This endpoint is where provenance is *created*, so source is exactly what it must accept — and the thing it will not accept is somebody else's already-compiled bytes. ⚠️ Compiling does not bind. A green report is evidence; certification (laas-86) is what turns evidence into a bindable product, and nothing here writes to `script_params.PARAMETRIC_TEMPLATES`.

CampoTipoDetalhe
manifestobject, opcionalThe product manifest. Optional only so a compile can be smoke-run without one; a submission without a manifest is gated on the source alone and the report says so.
product_idstringobrigatórioNamespaced product id, `tnt.{tenant}.{name}`
signatureBundleSignature, opcionalDetached authorship signature over `bundle_hash` (LaaS-88 D1). **Required on the tenant-facing route** and optional on the operator one, where an operator submitting for support is attributed by its own client id instead. A signature that is supplied is verified on either route — an unverifiable one is never recorded as authorship.
sourcestringobrigatórioThe tenant's `Tenant.Product` module, verbatim. Its header, its single export and its allowed imports are published in docs/product-author-contract.md.
verify_determinismbooleanCompile twice into different build directories and compare the bytes (laas-83 D9). Doubles the job; off by default.Padrão false

FoundryCompileResponse

A compile job, at whatever stage it has reached.

CampoTipoDetalhe
applied_size_bytesinteger, opcional
authorship_fprstring, opcionalFingerprint of the enrolled key whose signature verified over `bundle_hash`. **Absent means nothing signed this submission** — an operator submitted it, attributed by `actor` instead. The two facts stay separable rather than collapsing into one field.
bundle_hashstring, opcionalsha256 over `quadra.product-bundle/1 ‖ tenant ‖ product_id ‖ source_hash ‖ manifest_hash`, newline-joined. This is the value an author signs, and it is recorded whether or not anything signed it.
compile_idstringobrigatório
created_atstring, opcional
gate_reportobject, opcional
gate_report_hashstring, opcional
gate_report_keystring, opcionalWhere the gate report is published in the artifact store. A certification references it by {hash, key}; before LaaS-88 nothing published it, so a Foundry-compiled product could not be certified.
manifest_hashstring, opcional
product_idstringobrigatório
script_size_budget_bytesinteger, opcional
script_size_bytesinteger, opcional
source_hashstring, opcional
source_keystring, opcionalWhere the submitted source is published (SSE-KMS, platform-only). The bytes are never echoed by this API; the P6 countersigner reads them through the operator route.
statusstringobrigatórioQUEUED | COMPILING | ACCEPTED | REFUSED | ERROR
substratestring, opcional
template_hashstring, opcionalsha256 over the compiled template's raw script bytes. NOT a Plutus script hash: an unapplied parametric template has no address until a binding applies this tenant's params (laas-79 D2).
tenantstringobrigatório
updated_atstring, opcional

FoundryQuotaResponse

The tenant-facing view of the compile meter (LaaS-88). ⚠️ Narrower than the operator's ``TenantQuotaResponse`` on purpose: it carries no ``updated_by``, because who inside the platform set a tenant's cap is our business and not theirs. The laas-87 D7 split, in a second place.

CampoTipoDetalhe
quotaintegerobrigatório
quota_sourcestringPadrão "estate_default"
remainingintegerobrigatório
tenantstringobrigatório
usedintegerobrigatório
windowstringPadrão "utc_day"
window_resets_atstring, opcional
window_started_atstring, opcional

HTTPValidationError

CampoTipoDetalhe
detailarray de ValidationError

ProductActionRequest

``POST /v1/products/{product_id}/instances/{instance_id}/actions/{action}``. The action is a **path segment**, never a body field: that is what makes one route entry serve N actions at every edge surface.

CampoTipoDetalhe
account_idstringobrigatórioThe account acting on the instance.
paramsobject

ProductCloseRequest

``POST /v1/products/{product_id}/instances/{instance_id}/close``. ``action`` may be omitted when the manifest declares exactly one close action; a product with several must name one, because guessing which terminal state to drive an instance into is not a default anything should have.

CampoTipoDetalhe
account_idstringobrigatórioThe account closing the instance.
actionstring, opcionalWhich declared close action to drive.
paramsobject

ProductInstanceCreateRequest

``POST /v1/products/{product_id}/instances``. The manifest declares exactly one ``create`` action, so the body names no action — which is also why the route key needs no action segment.

CampoTipoDetalhe
account_idstringobrigatórioThe custody account the instance's value comes from.
paramsobjectThe create action's declared payload parameters, by name. One of them is the amount in centavos (the manifest's ``amount_from``).

TenantDraftBindRequest

A tenant binds one of the shipped templates for **itself**, at DRAFT (LaaS-87). The playground's write. Deliberately the *narrowest* body that can express a binding, and every field the operator request carries and this one does not is a decision a tenant must not make: * no ``lifecycle`` — it is forced to DRAFT. CERTIFIED costs evidence (laas-86 D5) and a body that could name its own lifecycle would be the free edge that ticket exists to close. * no ``accounting`` — the GL node is derived. A caller-chosen node would let a tenant point their product's legs at ``gl_safeswap_escrow`` and silently re-book somebody else's value. * no ``script.catalog`` and no ``script.certification`` — a tenant cannot bind an incumbent at the platform's own static address, and cannot inherit evidence that was produced for someone else. * no ``acknowledge_open_instances`` — that flag lets a version bump strand new value under a superseded binding, which is an operator's call to make. ``extra="forbid"`` so a body that *tries* any of the above is refused by name rather than having the field silently ignored — a caller who thinks they set ``lifecycle: CERTIFIED`` and got a 201 has been misled.

CampoTipoDetalhe
compile_idstring, opcionalAn **ACCEPTED** compile of your own source (laas-88, discharging laas-83 D11). The template bytes and the manifest both come off that job's row, so the two cannot disagree and `manifest_hash` is provably the hash of the document the gates passed. Exactly one of this and `template`.
manifestobject, opcionalThe manifest document, validated by the same loader the committed contracts/manifests/*.json go through. `tenant` and `product_id` inside it are overwritten from the path and the caller's own tenant. ⛔ **Forbidden with `compile_id`**, and not merely redundant: the Foundry already gated the manifest it compiled against, so a second copy here could disagree with it and the bind would certify a document nothing had judged.
templatestring, opcionalWhich parametric template to bind, from the shipped allowlist. A template is committed, compiled and byte-compared in CI, which is what laas-83..86 exist to gate. Exactly one of this and `compile_id`.

TenantDraftBindResponse

One binding, in the **tenant-facing** projection. ⛔ Not `TenantProductResponse`. That is the operator read model and it carries `artifact_bucket`, `artifact_key` and the `accounting` block — estate topology and our chart of accounts. This response goes to a browser.

CampoTipoDetalhe
actionsobjectPadrão {}
addressstringobrigatório
artifact_hashstring, opcional
boundbooleanFalse when the identical artifact was already bound and no version was appended — the laas-67 `provisioned: false` shape, answered 200.Padrão true
ir_versionintegerPadrão 1
lifecyclestringobrigatório
product_idstringobrigatório
release_targetsarray de stringPadrão []
script_hashstringobrigatório
tenantstringobrigatório
updated_atstring, opcional
versionintegerobrigatório

ValidationError

CampoTipoDetalhe
ctxobject
inputnão declarado
locarray de string ou integerobrigatório
msgstringobrigatório
typestringobrigatório