SonaCORE

Referência / Quadra Command API

Operator

31 operações em Quadra Command API 0.2.0.

POST/v1/evidence/{evidence_id}/resolve

Manually match an unmatched evidence to an obligation

Manual match: settle the operator-pinned obligation and unwind the suspense park this evidence created (≤ 2 Hydra txs, each leg idempotent). The evidences row flips to MANUALLY_MATCHED; a second call 409s.

Parâmetros

NomeTipoDetalhe
evidence_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

EvidenceResolveRequest — 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/evidence/{evidence_id}/retry

Retry a failed evidence ingest

Re-run a stored `status=ERROR` evidence row through the ingest pipeline once its cause is fixed (zero recorded effects only). A still-unfixed cause surfaces the same 4xx the original ingest returned.

Parâmetros

NomeTipoDetalhe
evidence_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

EvidenceRetryRequest — 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/obligations/{obligation_id}/redispatch

Re-drive a failed outbound dispatch

Re-queue a FAILED dispatch (or the enqueue-failure signature). EXCEPTION rows return to FINAL(null), `dispatch_status` becomes RETRY_REQUESTED, and a fresh `outbound_dispatch` job is enqueued for tx-worker (RFC-022 §4.2).

Parâmetros

NomeTipoDetalhe
obligation_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

ObligationRedispatchRequest — 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/obligations/{obligation_id}/resolve

Operator resolve of a stuck obligation

Clear a PENDING/EXCEPTION obligation with an operator-attested outcome + proof (D1). Exactly one Hydra tx when the obligation UTxO is live (the value is disposed and the new output resolves FINAL on confirm — `hydra_tx_id` non-null); zero when spent/absent (metadata-only resolve). Accepts `obl_*` and legacy `txhash_N` ids.

Parâmetros

NomeTipoDetalhe
obligation_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

ObligationResolveRequest — 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/operator/tenants/{tenant}/foundry/compiles

List a tenant's compile jobs

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

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
limitintegerquery

Respostas

StatusCorpoDetalhe
200FoundryCompileListResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/foundry/compiles

Submit a product bundle to the Foundry

Compile and gate one tenant-authored validator.

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

A submission that fails a static gate (the source admission scan, the manifest through `load_manifest`, the namespace check) 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.

⚠️ Compiling is not certifying and certainly not binding. A green report is evidence; conformance execution, the adversarial battery and a countersigned Certified Product Artifact are what make a product real, and nothing here writes to the bindable-template allowlist.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

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/operator/tenants/{tenant}/foundry/compiles/{compile_id}

Get one compile job 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 that showed only failures could not answer "was this checked?", which is the question a countersigner asks.

⛔ A foreign 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
tenantstringpathobrigatório
compile_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200FoundryCompileResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/foundry/compiles/{compile_id}/source

Read a submission's source (the P6 countersigner's read)

The tenant's Haskell, verbatim, for the human who has to sign off on it.

⛔ **This route exists because §4.3's countersignature is not a rubber stamp.** P6 requires a platform engineer to countersign *the report and the source*, and LaaS-88 D2 keeps the source out of the published evidence set — SSE-KMS, platform-only, referenced from the certification by hash. So there has to be exactly one way to read it, and this is it: operator-scoped, per compile, logged with the client that asked.

⚠️ **The honest cost of D2, stated where a reader meets it:** an outside auditor can verify every hash and both signatures and *cannot* check that the certified script came from the claimed source. Publishing the source would close that gap and would also publish a tenant's IP to everyone holding the evidence bucket. That trade was made deliberately.

Answers `text/plain` — the bytes as submitted, whose sha256 is the `source_hash` in the gate report.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
compile_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/operator/tenants/{tenant}/product-keys

Read a tenant's bundle-signing key enrollment

The active enrollment and the fingerprints it superseded, or 404.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Respostas

StatusCorpoDetalhe
200ProductKeyResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/product-keys

Enroll a tenant's bundle-signing public key

Record the public key whose signature proves who authored a Product Bundle.

**Why this is an operator act and not self-service.** A tenant self-enrolling would make the recorded authority only as strong as the API credential that enrolled it — and outliving that credential is the whole reason a detached signature exists. The row records the enrolling client, so *who vouched that this key is the tenant's* has an answer.

Idempotent by fingerprint: the same key answers **200** with `enrolled: false`. A *different* key is refused **409** unless `replace: true`, and a rotation files the incumbent as superseded rather than overwriting it — a certification signed under the old key must keep verifying, so its PEM stays published under its own fingerprint.

Public key only. There is no field a private key could be pasted into and no code path that would know what to do with one.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201ProductKeyResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/products

List a tenant's product bindings

This tenant's bindings, current version each, newest change first.

SUSPENDED and RETIRED products are listed. Lifecycle gates writing, never observation.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
limitintegerquery
cursorstring, opcionalquery

Respostas

StatusCorpoDetalhe
200TenantProductListResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/products/{product_id}

Get a tenant product binding

One binding: its current version, every version recorded, and its history.

⛔ A foreign tenant's `product_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: status, body, headers and the time taken to answer cannot differ.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
product_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200TenantProductResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PATCH/v1/operator/tenants/{tenant}/products/{product_id}

Move a product binding through its lifecycle

DRAFT → CERTIFIED → LIVE → SUSPENDED → RETIRED, on the shipped table.

**LIVE** requires `attestation.signed_by` — the platform countersignature of founder decision P6. Pre-Foundry that is a recorded operator sign-off written into the row's `certification` block; laas-86 replaces it with the certified artifact's own signature, in the same field.

**SUSPENDED** is unilateral and immediate: the next create or advance answers 409 `PRODUCT_NOT_ACCEPTING_WRITES` while a close still serves, because the adapter re-reads the binding on every write and exempts the close role. Suspending must stop new instances, never strand the ones an operator suspended it to look at.

**RETIRED** is terminal — there is no un-retire and no unbind verb at all. History stays resolvable: an obligation whose product no longer resolves is an audit hole.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
product_idstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200TenantProductResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/products/{product_id}

Bind a certified product artifact to one tenant

Bind one certified artifact to exactly one tenant.

The registry/bindings split (Product Plane §4.4): the artifact is content-addressed and published here, and the **row** is what activates it. Certification without binding deploys nothing.

For a parametric template this carries the whole job: resolve this tenant's binding params, apply them, derive the applied script hash and address the result produces, publish the applied bytes, and write the row with `applied.{template_hash, script_key, params, param_values}`. Two tenants binding one template get two addresses, and neither can be spent under the other's terms.

Idempotent on artifact identity: a repeat with a byte-identical manifest and the same baked-in params answers **200** with `bound: false` and appends no version. A changed manifest hashes differently and supersedes.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
product_idstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201TenantProductResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/products/{product_id}/certification

Read a product's certification envelope

The signed certification, its countersignature if it has one, and staleness.

⭐ **Stale is reported, never enforced.** A battery upgrade does not invalidate a LIVE product: an inventory-hash 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. The certification records `battery_version` and `inventory_hash`; this read compares them against what the estate ships now and says so. Re-certification is a deliberate act.

Everything needed to verify the artifact offline is in the response, and the published public keys live beside it in the store — `keys/product-platform-*.pub.pem` and `keys/product-countersigner-*.pub.pem`. Check it with `scripts/verify-product-certification.py`, which needs no platform access at all.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
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/operator/tenants/{tenant}/products/{product_id}/certification

Certify a product binding against its evidence

Assemble the **Certified Product Artifact**, sign it, and record CERTIFIED.

Staples LaaS-83's gate report, LaaS-84's conformance transcript and LaaS-85's battery report card **by reference** into one content-addressed document, captures this product's golden vectors from its own IR schemas, records which relaxation policy authorised the path, signs the body with the platform certification key and publishes the envelope to the WORM certification store.

⛔ **It verifies evidence; it does not produce evidence.** Every named document is fetched, re-hashed against the hash the request gives, and checked for an `accepted` verdict and a matching subject. A route that produced its own evidence and then judged it would be a route that certifies itself.

⛔ **Nothing is published if the evidence does not support a certification.** A refused certification is not an artifact, and the store's objects cannot be deleted.

Also the re-certification path: run against a CERTIFIED or LIVE binding it replaces the certification block and leaves the state alone, because `CERTIFIED → CERTIFIED` is not an edge in the transition table and inventing one would make the table stop describing the machine.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
product_idstringpathobrigatório

Corpo da requisição

TenantProductCertifyRequest — 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/operator/tenants/{tenant}/products/{product_id}/drain

Plan a drain: how each open instance would be closed

Per open instance, the route that closes it — or the reason there is none.

Migration between versions is **close-and-reopen** (Product Plane §4.2 step 5): hash is address, so a new version is a new address by construction and no transaction moves value between them. This plans the closing half.

The routes come from the manifest's own close actions, walked by the same planner conformance uses — a per-product drain command would be the platform re-authoring what the tenant declared. An instance in a reachable non-terminal state with **no path out** is reported as `no_route` by name: its value is stranded, that is a manifest defect rather than an operational one, and no drain will move it.

Read-only. `POST` to the same path executes, and it needs an explicit id list.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
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/operator/tenants/{tenant}/products/{product_id}/drain

Drain a product: close the named instances

Close the instances named in `instance_ids`, through the shipped close path.

⛔ Needs `consent: true` and an explicit id list. There is no close-everything shape, because the operator reaching for a drain is usually reaching for it under time pressure and a plan they did not read is not consent.

⚠️ **Best-effort per instance, and it does not stop on the first failure.** Every close is independent, so there is nothing a rollback could mean — and a drain that aborted half-way would leave an operator with no record of which closes landed. Each instance gets its own outcome in `results`.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
product_idstringpathobrigatório

Corpo da requisição

TenantProductDrainRequest — 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/operator/tenants/{tenant}/provider-accounts

List a tenant's processor accounts

Every processor account this tenant holds.

Never carries credential material — that crosses out once, on the call that opened the account, and is not recoverable from here or from the processor.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Respostas

StatusCorpoDetalhe
200ProviderAccountListResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/provider-accounts

Open a tenant's account at a processor

Open one account for this tenant at a processor, and record it.

⚠️ **The response carries the account's credential exactly once, and the platform never stores it.** A processor that mints one at creation cannot show it again — capture it from this response and provision it at the `credential.secret_ref` path, which is where the driver resolves it from. Until that is done the binding answers `credential_status: PENDING_PROVISION` and any dispatch through it fails closed with a config error rather than moving money with no credentials.

Idempotent **by the recorded account**, not by an `Idempotency-Key`: if this tenant already holds an account at this provider the processor is never called, because opening an account is *not* idempotent at the far end — a retry opens a second real account. A repeat returns the existing binding with `provisioned: false` and no credential.

A **different** account already bound for the same tenant and provider is refused with 409 rather than replaced: the first one is still open and can still receive money, so overwriting the row would orphan it silently.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201ProviderAccountResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/provider-accounts/{provider_id}/transfers

Move value between two accounts inside one processor

Move float out of this tenant's account at `provider_id`.

⛔ **The source is the binding named in the path**, and the driver resolved from it is authenticated as that account. There is deliberately no source field on the body: a cross-tenant debit would then be one mistyped value away, and such a debit reconciles to zero on both sides, which is what makes it nearly invisible.

This is a **treasury** operation, not a customer payment. A transfer between two customers is a ledger movement on the head and involves no processor — what this moves is the fiat float backing a tenant's ledger balance, so that each processor account matches the mirror that proves it.

⚠️ `authorized: false` means the processor is holding the transfer for an out-of-band human approval. The value is queued either way; do not re-send.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
provider_idstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201ProviderAccountTransferResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/qbrl-policy

Read a tenant's QBRL minting policy binding

The tenant's policy binding, or 404 when it has none.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Respostas

StatusCorpoDetalhe
200TenantQbrlPolicyResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/qbrl-policy

Bind a tenant to its own QBRL minting policy

Provision a tenant's own QBRL minting policy on a **running** head.

Under the shared-head tenancy tier a tenant's money is distinguished only by its minting policy, so this is the act of onboarding one. It generates the tenant's issuer keypair, derives the native `sig` script and its policy id, records the binding and creates the tenant's supply GL node.

Idempotent by construction — a repeat call returns the same policy id with `provisioned: false`, and no `Idempotency-Key` is required because the binding write is conditional on the policy already matching. A second, *different* policy for a tenant is refused with 409 rather than replacing the first: value already minted under the old one would still be on the head and would read as a foreign token.

This does not mint. Where the faucet's elastic supply is armed, the tenant's first funded transfer mints its opening balance under the policy bound here.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Respostas

StatusCorpoDetalhe
201TenantQbrlPolicyResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/quotas

Read a tenant's quota and current usage

The effective quota, where it came from, and how much of today is spent.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Respostas

StatusCorpoDetalhe
200TenantQuotaResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PUT/v1/operator/tenants/{tenant}/quotas

Set a tenant's quota overrides

Raise or lower what one tenant may spend on metered Foundry work.

⚠️ **Absence is the estate default, not zero.** A tenant with no row here is a tenant nobody has priced yet, which is the opposite of how an unbound QBRL policy resolves — and right for the same reason stated in reverse: there is a safe default for a compile allowance and there is none for *whose money is this*.

**The meter ships; the pricing does not.** What a compile hour is worth, and which tenants get how many, is a commercial decision owned by the founders. This route is how that decision is applied once it is made.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200TenantQuotaResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/rail-bindings

List a tenant's inbound provider routes

Every provider connection whose inbound credits belong to this tenant.

An empty list is the honest answer for a tenant with no routes, and it is the state every tenant starts in: with no rows provisioned, inbound routing answers through the incumbent chain exactly as it always has.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Respostas

StatusCorpoDetalhe
200ProviderRouteListResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/rail-bindings

Assign a provider's inbound credits to a tenant

Record which tenant receives inbound credits through a provider.

A provider-authenticated webhook carries no bearer, so the tenant a credit belongs to cannot come from a caller — it comes from the provider binding, and until this row existed a binding could only name the environment's own tenant. Writing it is what lets a non-incumbent tenant receive money.

Idempotent — a repeat call returns the same binding with `provisioned: false`, and no `Idempotency-Key` is required because the write is conditional on the owner already matching. A **second, different** tenant for one `(rail, provider_id)` pair is refused with 409 rather than replacing the first: a provider id identifies exactly one tenant, and silently rerouting it would move a live inbound stream into another ledger. Two tenants on the same processor use two provider ids.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201ProviderRouteResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/transfer-templates

List a tenant's transfer templates

This tenant's templates, current version each, newest change first.

RETIRED templates are listed: retiring gates new execution, never observation.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
limitintegerquery
cursorstring, opcionalquery

Respostas

StatusCorpoDetalhe
200TenantTemplateListResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/operator/tenants/{tenant}/transfer-templates

Author a tenant transfer template

Author, or supersede, one tenant-scoped transfer template.

The body is validated by calling the **same** `_parse_template` the committed `transfer_templates.json` is parsed by, so a tenant-authored template is held to every invariant an operator-authored one is. Versions are immutable and content-hashed: `template_version` must be strictly greater than this tenant's current version for the id, and the new version becomes current (D2). A colliding id — a platform template's name, or a version that does not supersede — is refused here, so the ambiguity never exists at execute time.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201TenantTemplateResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
GET/v1/operator/tenants/{tenant}/transfer-templates/{template_id}

Get a tenant transfer template

One template's current version plus every version ever recorded.

A retired version still resolves here, and deletion has no code path at all — an obligation whose `template_content_hash` no longer resolves is an audit hole.

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
template_idstringpathobrigatório

Respostas

StatusCorpoDetalhe
200TenantTemplateResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PATCH/v1/operator/tenants/{tenant}/transfer-templates/{template_id}

Retire a tenant transfer template

Retire the current version: no new execution, still readable.

`RETIRED` is the only accepted status — a rejected `ACTIVE` is the model's `Literal`, i.e. a 422 from FastAPI. Idempotent: a repeat answers 200 with the already-retired row. Reactivation is a new version (D2's supersede path).

Parâmetros

NomeTipoDetalhe
tenantstringpathobrigatório
template_idstringpathobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200TenantTemplateResponseResposta bem-sucedida
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 ""

CertificationEvidence

The three documents a certification staples together by reference.

CampoTipoDetalhe
batteryCertificationEvidenceRefobrigatórioLaaS-85's adversarial battery report card. Required.
conformanceCertificationEvidenceRefobrigatórioLaaS-84's conformance transcript. Required.
gate_reportCertificationEvidenceRef, opcionalLaaS-83's compile gate report. **Optional, and its absence is recorded rather than defaulted**: a catalog product was never compiled through the Foundry — its bytes are committed and byte-gated by scripts/compile-validators.sh — so there is no gate report to name, and an empty one would be a green-looking field with nothing behind it.

Disposition

Optional override of the D2 default destination for a live-value resolve (SETTLED → quadra-faucet; FAILED/CANCELED → the obligation's debtor).

CampoTipoDetalhe
destination_account_idstringobrigatório

EvidenceResolveRequest

``POST /v1/evidence/{evidence_id}/resolve`` — manual match: the operator pins the target obligation an unmatched settlement should credit.

CampoTipoDetalhe
actorstring, opcional
justificationstringobrigatório
obligation_idstringobrigatórioTarget obligation (obl_* or legacy txhash_N).
proofProofBlock, opcional

EvidenceRetryRequest

``POST /v1/evidence/{evidence_id}/retry`` — re-run a stored ``status=ERROR`` evidence row through the ingest pipeline once its cause is fixed. No payload: the source_type + raw_payload come from the persisted row.

CampoTipoDetalhe
actorstring, opcional
justificationstringobrigatório

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

HTTPValidationError

CampoTipoDetalhe
detailarray de ValidationError

ObligationRedispatchRequest

``POST /v1/obligations/{obligation_id}/redispatch`` — re-drive a FAILED outbound dispatch (RFC-022 §4.2 RETRY_REQUESTED).

CampoTipoDetalhe
actorstring, opcional
justificationstringobrigatório
reasonstring, opcional

ObligationResolveRequest

``POST /v1/obligations/{obligation_id}/resolve`` — clear a stuck PENDING/EXCEPTION obligation with an operator-attested outcome + proof.

CampoTipoDetalhe
actorstring, opcionalOperator identity. Token-authoritative in production; required in the body in local mode.
approvalsarray de não declarado
dispositionDisposition, opcional
justificationstringobrigatório
outcomestringobrigatórioSETTLED | FAILED | CANCELED
proofProofBlockobrigatório

ProductAccounting

The GL mapping the registry row refuses to be written without. ⛔ `gl_node_id` is not derivable and is never defaulted. Without it `entry_projector._attribute` books a product's value to the customer's own account, both legs net to zero and `_project_group` returns at `if not legs` — no entry set, no EXCEPTION marker, no metric (laas-74's second finding). ⛔ And for a **catalog** product it is not free either: `default_node_for` checks the row's node *before* its `product_id == "quadra-escrow"` literal, so the moment the incumbent has a row the row's node wins for both surfaces. A wrong value silently re-books every escrow leg in the estate, which is why the bind pins it against a shipped map instead of trusting the body.

CampoTipoDetalhe
custody_to_productstringPadrão "PRODUCT_COMMIT"
gl_node_idstringobrigatório
product_to_custodystringPadrão "PRODUCT_RELEASE"
product_to_productstringPadrão "PRODUCT_INTERNAL"

ProductAttestation

The human countersignature that gates LIVE (founder decision P6). ⭐ Merged into the row's **existing** `certification` block rather than a field of its own — laas-74 D6 shaped it nullable from birth precisely so laas-86 writes *into* it instead of migrating it. One data shape, two eras: the certification step fills the machine half (hashes, the platform signature's fingerprint) and this fills the human half, in the same write as the state. ⛔ **`countersignature` cannot be produced by this service, and that asymmetry is the gate.** The services hold `kms:GetPublicKey` on the countersign key and no `kms:Sign`; the signature is minted repo-side by `scripts/countersign-product-certification.py` under an IAM role a task role cannot assume. A gate the platform can forge is a field.

CampoTipoDetalhe
algorithmstring, opcionalDeclared signature algorithm; defaults to ECDSA_SHA_256
battery_versionstring, opcionalRetained for the pre-Foundry shape; see report_card_hash
countersignaturestring, opcional⟲ LaaS-86 D3. Base64 DER ECDSA-P256 over the certification's 32-byte body hash, signed **prehashed** (`ECDSA_SHA_256`, `MessageType=DIGEST`). Required for LIVE. Produce it with scripts/countersign-product-certification.py.
report_card_hashstring, opcionalRetained for the pre-Foundry shape. The certification step records the real battery report card hash, so a value here is not what the gate reads.
signed_bystringobrigatórioThe countersigning **role**, never a person — the countersigner IAM role ARN, or the reviewed role name it stands for. Recorded verbatim in the hashed countersignature document.
signing_pubkey_fprstring, opcionalsha256 of the signer's DER SubjectPublicKeyInfo. Optional, and checked when supplied: it lets a countersigner assert which key they used rather than being told which one was trusted.

ProductKeyEnrollRequest

Enroll (or rotate) one tenant's bundle-signing public key. ⛔ **Public key only, and the model cannot express a private one.** There is no field a well-meaning caller could paste a private key into and no code path that would know what to do with one — the same refusal-by-omission ``product_signing`` uses to make ``sign(countersigner)`` inexpressible.

CampoTipoDetalhe
labelstringFree-text note for whoever reads the enrollment later — which of the tenant's systems holds the private half. Recorded, never interpreted.Padrão ""
public_key_pemstringobrigatórioPEM SubjectPublicKeyInfo for an ECDSA P-256 public key. Re-serialised from the parsed key before storage, so whitespace and line endings cannot produce two byte-different publications of one key.
replacebooleanRotate: supersede the active key rather than being refused as a conflict. Required for a *different* key; a repeat of the same key is idempotent without it. ⚠️ Rotation never invalidates an existing certification — the superseded PEM stays published under its own fingerprint so old signatures keep verifying.Padrão false

ProductKeyResponse

One tenant's enrollment, as the operator surface shows it.

CampoTipoDetalhe
algorithmstringPadrão "ECDSA_SHA_256"
curvestringPadrão "P-256"
enrolledbooleanFalse when the identical key was already active and nothing was written — the laas-67 `provisioned: false` shape, answered 200.Padrão true
enrolled_atstring, opcional
enrolled_bystring, opcional
labelstring, opcional
public_key_pemstringobrigatório
published_keystring, opcionalWhere the PEM is published in the certification store, so an auditor can check an authorship claim without platform access.
signing_pubkey_fprstringobrigatóriosha256 of the DER SubjectPublicKeyInfo — what a certification records.
statusstringobrigatórioACTIVE | SUPERSEDED
supersededarray de stringFingerprints of previously enrolled keys, newest first.
tenantstringobrigatório

ProductScriptRef

Which script bytes this binding runs on. Exactly one of the two forms. ⛔ **Bytes are never accepted over the wire, and that is the design (D1).** Pre-Foundry there is no compile provenance and no adversarial battery, so an API that took a `cbor_hex` would be the thing laas-83..86 exist to gate. A template is named instead, and the name resolves only inside `shared/script_params.PARAMETRIC_TEMPLATES` — an allowlist of git-reviewed `.plutus` artifacts that `validators.yml` compiled and byte-compared. * ``template`` — a parametric template. Its params are a property of the compiled Haskell, so the allowlist carries them and the binding applies them; a ``params`` echo here must agree or the bind is refused (D2). * ``catalog`` — a **platform catalog product** (LaaS-77): an incumbent re-declared as a manifest. Address, script hash and bytes all come from the static registry, because the product already exists at an address open instances sit at. Deriving them would move it.

CampoTipoDetalhe
catalogbooleanBind an incumbent at its own unchanged static address (LaaS-77). Mutually exclusive with `template`.Padrão false
certificationstring, opcional⟲ LaaS-86 D6. The body hash of an existing certification this binding INHERITS, which is what lets it be created at CERTIFIED. Not a third source of script bytes — the script still comes from `template` or `catalog`; this names the evidence. Required for a CERTIFIED bind, and therefore required in a production estate, where DRAFT is refused at the accessor. The certification must be platform-signed and must have been produced for this manifest and this template; its battery ran against another estate's applied bytes, which is why an inherited certification cannot reach LIVE until the battery is re-run here.
paramsarray de string, opcionalOptional echo of the template's binding vocabulary, in wire order. Must equal what the template declares; it exists so a caller can assert what it thinks it is baking in, never to choose it.
templatestring, opcionalParametric template name, from the shipped allowlist

ProofBlock

Evidence backing an operator resolve. ``kind`` names the source (e.g. ``sponsor_statement``), ``evidence_ids`` links any ``ev_*`` rows, and ``rule`` records the disposition rule applied. Extra descriptive keys are preserved verbatim into ``resolution_metadata`` + the audit row.

CampoTipoDetalhe
evidence_idsarray de string
kindstringobrigatório
rulestring, opcional

ProviderAccountAddress

The address a processor's onboarding form requires. Every field here is required by at least one processor and none of them has a safe default — a postal code that cannot be resolved is a 400, not a guess.

CampoTipoDetalhe
complementstring, opcional
numberstringobrigatório
postal_codestringobrigatório
provincestringobrigatórioNeighbourhood / bairro
streetstringobrigatório

ProviderAccountCredential

⚠️ Returned exactly once, and never stored by the platform. A processor that mints an account credential at creation typically cannot show it again. It is handed over here so an operator can provision it into the secret store out of band — the platform holds a *reference* and a status, not the value. See the route's docstring.

CampoTipoDetalhe
secret_refstringobrigatórioWhere to provision it. The descriptor resolves the credential from this path.
valuestringobrigatórioThe credential. Capture it now; it is not recoverable.

ProviderAccountListResponse

CampoTipoDetalhe
accountsarray de ProviderAccountResponse
tenantstringobrigatório

ProviderAccountRequest

Open one account for this tenant at a processor.

CampoTipoDetalhe
addressProviderAccountAddressobrigatório
company_typestring, opcionalMEI | LIMITED | INDIVIDUAL | ASSOCIATION
emailstringobrigatório
income_valuenumberobrigatórioDeclared monthly revenue. Required by the processor and deliberately not defaulted — a made-up figure on a regulated onboarding form is a false statement.
legal_namestringobrigatório
mobile_phonestringobrigatório
provider_idstringobrigatórioThe provider instance id, matching `^[a-z0-9][a-z0-9-]{0,31}$`. One account per tenant per provider — two tenants on the same processor need two ids.
railstringRail family the provider serves.Padrão "PIX"
tax_idstringobrigatórioCPF or CNPJ, digits only.

ProviderAccountResponse

CampoTipoDetalhe
account_numberobject
account_statusstringobrigatórioThe processor's own status. Rarely transactable immediately — a regulated onboarding evaluation typically follows.
credentialProviderAccountCredential, opcionalPresent ONLY on the call that opened the account.
credential_refstring, opcional
credential_statusstringobrigatórioPENDING_PROVISION until an operator has stored the credential.
familystringobrigatório
provider_account_idstringobrigatório
provider_idstringobrigatório
provisionedbooleanobrigatórioFalse when this call matched an account already recorded.
tenantstringobrigatório
wallet_idstring, opcional

ProviderAccountTransferRequest

Move value between two accounts inside one processor.

CampoTipoDetalhe
amount_centsintegerobrigatórioAmount in centavos.
currencystringPadrão "BRL"
descriptionstring, opcional
destination_wallet_idstringobrigatórioThe destination account's wallet handle at the processor.

ProviderAccountTransferResponse

CampoTipoDetalhe
amount_centsintegerobrigatório
authorizedboolean, opcionalFalse when the processor is holding the transfer for an out-of-band human approval. The value is queued either way — do not re-send.
currencystringobrigatório
familystringobrigatório
provider_idstringobrigatório
provider_transfer_idstring, opcional
tenantstringobrigatório
transfer_statusstring, opcional

ProviderRoute

One `(rail, provider)` → tenant inbound routing binding.

CampoTipoDetalhe
bound_in_processbooleanWhether this deployment currently has a binding for the provider. False is legal: a route may be recorded before the driver ships.Padrão false
caller_less_inboundbooleanWhether this family can receive a credit with no authenticated caller. When false, every inbound path is bearer-authenticated and the tenant is already the caller's — the route is bookkeeping rather than the routing authority.Padrão false
familystringobrigatórioRail family, upper-cased.
kindstring`rail` for a money rail, `kyc` otherwise.Padrão "rail"
provider_idstringobrigatórioThe provider instance id.
provisionedboolean, opcionalTrue when this call created the binding, false when it already existed with the same owner. Absent on reads.
statusstringACTIVE while the route resolves.Padrão "ACTIVE"
tenantstringobrigatórioThe tenant whose ledger these credits belong to.

ProviderRouteListResponse

Every inbound route one tenant owns.

CampoTipoDetalhe
routesarray de ProviderRoute
tenantstringobrigatório

ProviderRouteRequest

Which provider connection an operator is assigning to a tenant.

CampoTipoDetalhe
provider_idstringobrigatórioThe provider instance id, matching `^[a-z0-9][a-z0-9-]{0,31}$`. This is the *driver instance*, not the payload schema — and it identifies exactly one tenant, so two tenants on the same processor need two ids.
railstringobrigatórioRail family the provider serves — `PIX`, `ACH`, `MOCK`, or `KYC` for the identity-verification namespace. Case-insensitive.

TenantProductBindRequest

Bind one certified artifact to exactly one tenant. The registry/bindings split (Product Plane §4.4, the KYC pattern): the artifact is content-addressed and published here, and the **row** is what activates it for this tenant. Certification without binding deploys nothing. ``manifest`` is a manifest document in exactly the form `products/manifest/document.load_manifest` parses — the same validator the committed `contracts/manifests/*.json` go through, so a body posted here is held to every invariant a shipped one is. It is deliberately a free-form object rather than a nested Pydantic schema, for laas-78 D1's reason: the grammar has one validator, and a second description of it is how two authoring paths come to diverge. ``product_id`` and ``tenant`` inside the manifest are **overwritten from the path** before validation. A body that could name its own tenant would be a body that could bind into another tenant's namespace.

CampoTipoDetalhe
accountingProductAccountingobrigatórioThe GL mapping for this product
acknowledge_open_instancesboolean⟲ LaaS-86 D8. A version bump that moves the script address is refused while instances are open, because migration is close-and-reopen (Product Plane §4.2 step 5) — drain them first. Set this to bind anyway: the previous version stays resolvable so its instances can still be advanced and closed, but no new ones are created under it.Padrão false
lifecycle"DRAFT" | "CERTIFIED"The state to bind at. ⟲ **LaaS-86 D5 changed the default to DRAFT**: a bind used to land at CERTIFIED, so every product was born certified with no gate report, no conformance transcript and no battery card behind it. CERTIFIED now requires `script.certification` naming an existing signed certification for this manifest and template. LIVE is never a bind — it needs the countersignature and is reached with PATCH. DRAFT is refused in a production-shaped estate at the accessor, which is why a production bind inherits a certification.Padrão "DRAFT"
manifestobjectobrigatórioThe manifest document (manifest_version, states, actions, schemas, …)
scriptProductScriptRefobrigatórioWhich script bytes to bind

TenantProductCertifyRequest

Assemble, sign and record a certification for one binding.

CampoTipoDetalhe
evidenceCertificationEvidenceobrigatórioThe documents this certification is a claim about
justificationstringobrigatórioWhy this certification is being recorded, for the operator timeline

TenantProductDrainRequest

Close the named instances of one product. ⛔ There is deliberately no close-everything shape. The operator reaching for a drain is usually reaching for it under time pressure, and a plan they did not read is not consent.

CampoTipoDetalhe
account_idstringobrigatórioThe acting account. A close pays out, and the payee comes from this account exactly as on the ordinary close route.
consentbooleanobrigatórioMust be true: a drain closes real instances and pays real value
instance_idsarray de stringobrigatórioThe instances to close. Read them off GET .../drain first.
justificationstringobrigatórioFor the operator timeline
reasonobject, opcionalExtra body fields the product's close action declares, merged into each close. The same shape the ordinary close route takes.

TenantProductLifecycleRequest

Move one binding through the lifecycle. The transition table lives in `shared/product_registry._LEGAL_TRANSITIONS` and is enforced at the accessor twice — in Python for the message and as a DynamoDB `ConditionExpression` so two concurrent transitions serialize. A kill switch that races is not one. ⛔ There is no `RETIRED -> anything`, and no unbind verb at all. History stays resolvable: an obligation whose product no longer resolves is an audit hole, and a suspended product's own instances are exactly what an operator suspended it to look at.

CampoTipoDetalhe
attestationProductAttestation, opcionalRequired for LIVE and refused for every other target — a countersignature on a suspension would record a sign-off nobody gave.
justificationstringobrigatórioWhy. Recorded on the operator timeline row (laas-24's surface).
lifecycle"CERTIFIED" | "LIVE" | "SUSPENDED" | "RETIRED"obrigatórioThe target state

TenantProductListResponse

A page of this tenant's bindings (current version each).

CampoTipoDetalhe
itemsarray de TenantProductResponsePadrão []
next_cursorstring, opcionalOpaque cursor; null when the listing is exhausted

TenantProductResponse

One binding's current version, as the public read model.

CampoTipoDetalhe
accountingobjectPadrão {}
actionsobjectPadrão {}
addressstringobrigatório
appliedobjectThe parametric binding: template_hash, script_key, params, param_values. Empty for a non-parametric product.Padrão {}
artifact_bucketstringPadrão ""
artifact_hashstringPadrão ""
artifact_keystringPadrão ""
boundboolean, opcionalBind only. False when the identical artifact was already bound and no version was appended — the laas-67 `provisioned: false` shape.
certificationobjectPadrão {}
created_atstringPadrão ""
datum_schemastringPadrão ""
gl_node_idstring, opcionalBind only: the node provisioned
ir_versionintegerPadrão 1
lifecyclestringobrigatório
lifecycle_historyarray de object, opcional
operation_idstring, opcionalThe operator-timeline row this call wrote
product_idstringobrigatório
redeemer_schemastringPadrão ""
release_targetsarray de stringPadrão []
script_hashstringobrigatório
template_hashstring, opcionalBind only: convenience echo of applied.template_hash
tenantstringobrigatório
tierstringAlways product; the custody tier is the platform'sPadrão "product"
updated_atstringPadrão ""
versionintegerobrigatório
versionsarray de object, opcionalEvery version ever recorded, newest first — the detail read

TenantQbrlPolicyResponse

A tenant's QBRL minting-policy binding.

CampoTipoDetalhe
issuer_account_idstringobrigatórioThe account owning the key whose hash defines the policy. It holds no value; it exists to sign mints and burns.
policy_idstringobrigatórioThe native `sig` script hash that is this tenant's minting policy. Under the shared-head tenancy tier this value is what distinguishes the tenant's money on-chain.
provisionedboolean, opcionalTrue only when this call created the binding. A repeat call returns false with the same policy id.
sourcestring`bootstrap` for the tenant whose policy comes from genesis, `registry` for one provisioned onto a running head.Padrão "registry"
statusstringACTIVE while the policy may mint.Padrão "ACTIVE"
supply_nodestringGL node carrying this tenant's outstanding QBRL issuance.Padrão ""
tenantstringobrigatórioThe tenant this policy issues money for.

TenantQuotaRequest

Set one tenant's metered-work allowances. ⚠️ Every field is optional and ``None`` means *leave it alone*, not *set it to zero*. A PUT that silently zeroed an unmentioned quota would make raising one cap a way to revoke another.

CampoTipoDetalhe
foundry_daily_compilesinteger, opcionalCompiles this tenant may submit per UTC day. 0 is a legal value and means *suspended*, which is a different fact from an absent row (nobody has priced this tenant yet, so the estate default applies).

TenantQuotaResponse

The effective quota, where it came from, and how much of today is spent.

CampoTipoDetalhe
quotaintegerobrigatório
quota_sourcestring`tenant_override` | `estate_default` — which decided `quota`.Padrão "estate_default"
remainingintegerobrigatório
tenantstringobrigatório
updated_atstring, opcional
updated_bystring, opcional
usedintegerobrigatório
windowstringPadrão "utc_day"
window_resets_atstring, opcional
window_started_atstring, opcional

TenantTemplateCreateRequest

Author (or supersede) one tenant-authored transfer template. ``definition`` is a template entry in **exactly** the closed form ``services/shared/transfer_templates.json`` uses — ``template_version``, ``product_id``, ``params``, ``constants``, ``source``, ``legs`` — and it is handed to ``shared.transfer_templates._parse_template`` verbatim. ⛔ Deliberately typed as a free-form object rather than a nested Pydantic schema (D1). The template grammar has exactly one validator, and every invariant that makes a template safe to execute — the four closed amount forms, exactly one residual leg, reserved leg roles, declared param types, ``MAX_BPS``, the content hash — lives inside it. A second, Pydantic-shaped description of the same grammar would be a second set of rules to keep in step, and the two authoring paths could then diverge. ``template_version`` lives inside the definition because it is one of the entry's required fields; a separate parameter would be a second source for it. It must be strictly greater than this tenant's current version for this id.

CampoTipoDetalhe
definitionobjectobrigatórioThe template entry, in the same shape transfer_templates.json uses (template_version, product_id, params, constants, source, legs).
template_idstringobrigatórioNamespaced template id, tnt.<tenant>.<name>

TenantTemplateListResponse

A page of this tenant's templates (current version each).

CampoTipoDetalhe
itemsarray de TenantTemplateResponsePadrão []
next_cursorstring, opcionalOpaque cursor; null when the listing is exhausted

TenantTemplateResponse

One tenant template's current version, as the public read model.

CampoTipoDetalhe
constantsobjectPadrão {}
content_hashstringobrigatório
created_atstringPadrão ""
descriptionstringPadrão ""
legsarray de objectPadrão []
paramsobjectPadrão {}
product_idstringobrigatório
sourceobjectPadrão {}
statusstringACTIVE or RETIREDPadrão "ACTIVE"
status_historyarray de object, opcional
template_idstringobrigatório
template_versionintegerobrigatório
tierstringplatform (static) or tenant (authored)Padrão "tenant"
updated_atstringPadrão ""
versionsarray de object, opcionalEvery version ever recorded, newest first — present on the single-template read. A retired version stays listed so an obligation's template_content_hash resolves forever.

TenantTemplateStatusPatchRequest

Retire a template's current version. ⛔ ``RETIRED`` is the only accepted value, and the restriction is the design (D2: supersede, never edit; retire, never delete). Bringing a template back is a new version through ``POST``; a ``RETIRED -> ACTIVE`` flip would make "was this template live when that obligation was written" unanswerable from the version alone.

CampoTipoDetalhe
statusstringobrigatórioOnly RETIRED is accepted; reactivate by posting a new version
template_versioninteger, opcionalOptional pin: the version expected to be current. A mismatch is 409, so a retire cannot land on a version the caller has not seen.

ValidationError

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