{
  "components": {
    "schemas": {
      "ActiveBetweenModel": {
        "properties": {
          "end": {
            "description": "São Paulo local 'HH:MM' (exclusive); start > end wraps midnight",
            "title": "End",
            "type": "string"
          },
          "start": {
            "description": "São Paulo local 'HH:MM' (inclusive)",
            "title": "Start",
            "type": "string"
          }
        },
        "required": [
          "start",
          "end"
        ],
        "title": "ActiveBetweenModel",
        "type": "object"
      },
      "AdjustHoldRequest": {
        "properties": {
          "amount_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "New (smaller) hold amount in centavos; increases are rejected",
            "title": "Amount Cents"
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "New ISO-8601 expiry; explicit null clears the deadline (indefinite)",
            "title": "Expires At"
          }
        },
        "title": "AdjustHoldRequest",
        "type": "object"
      },
      "AmountDetail": {
        "properties": {
          "currency": {
            "description": "ISO 4217 currency code",
            "title": "Currency",
            "type": "string"
          },
          "value": {
            "description": "Amount in cents",
            "title": "Value",
            "type": "integer"
          }
        },
        "required": [
          "currency",
          "value"
        ],
        "title": "AmountDetail",
        "type": "object"
      },
      "AmountField": {
        "properties": {
          "currency": {
            "description": "ISO 4217 currency code (e.g., 'BRL')",
            "title": "Currency",
            "type": "string"
          },
          "value": {
            "description": "Amount in centavos (e.g., 2500 = R$25.00)",
            "title": "Value",
            "type": "integer"
          }
        },
        "required": [
          "currency",
          "value"
        ],
        "title": "AmountField",
        "type": "object"
      },
      "BundleSignature": {
        "additionalProperties": false,
        "description": "The detached authorship signature that rides a bundle submission.",
        "properties": {
          "signature": {
            "description": "base64 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`.",
            "title": "Signature",
            "type": "string"
          },
          "signing_pubkey_fpr": {
            "default": "",
            "description": "Optional 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.",
            "title": "Signing Pubkey Fpr",
            "type": "string"
          }
        },
        "required": [
          "signature"
        ],
        "title": "BundleSignature",
        "type": "object"
      },
      "CaptureHoldRequest": {
        "properties": {
          "amount_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Partial capture amount in centavos; omitted = full capture",
            "title": "Amount Cents"
          },
          "creditor_account_id": {
            "description": "Account receiving the captured funds",
            "title": "Creditor Account Id",
            "type": "string"
          }
        },
        "required": [
          "creditor_account_id"
        ],
        "title": "CaptureHoldRequest",
        "type": "object"
      },
      "CertificationEvidence": {
        "description": "The three documents a certification staples together by reference.",
        "properties": {
          "battery": {
            "$ref": "#/components/schemas/CertificationEvidenceRef",
            "description": "LaaS-85's adversarial battery report card. Required."
          },
          "conformance": {
            "$ref": "#/components/schemas/CertificationEvidenceRef",
            "description": "LaaS-84's conformance transcript. Required."
          },
          "gate_report": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CertificationEvidenceRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "LaaS-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."
          }
        },
        "required": [
          "conformance",
          "battery"
        ],
        "title": "CertificationEvidence",
        "type": "object"
      },
      "CertificationEvidenceRef": {
        "description": "One evidence document, named by hash and key.\n\n⛔ **Both, always.** The hash is what makes the reference checkable and the key is\nwhat makes it fetchable; the route re-hashes the bytes at the key and refuses a\ndisagreement. Trusting the pair would let a request point at a green transcript\nwhile naming a red one's hash.",
        "properties": {
          "hash": {
            "description": "sha256 of the document's canonical JSON",
            "title": "Hash",
            "type": "string"
          },
          "inherited": {
            "default": false,
            "description": "⟲ LaaS-86 D6. This document was produced against a DIFFERENT applied script than this binding's — legitimate for a conformance transcript, which needs a live head and a funded instance and so cannot be reproduced per estate. Recorded in the signed body with an explicit disclaim. It is **not** legitimate for the battery: that is hermetic, and a certification whose battery is inherited cannot reach LIVE.",
            "title": "Inherited",
            "type": "boolean"
          },
          "key": {
            "description": "Its key in the product-artifact store",
            "title": "Key",
            "type": "string"
          }
        },
        "required": [
          "hash",
          "key"
        ],
        "title": "CertificationEvidenceRef",
        "type": "object"
      },
      "ChangeMemberRoleRequest": {
        "additionalProperties": false,
        "description": "``PATCH /v1/squads/{sqd_id}/members/{member_account_id}/role`` (RFC-018).\n\n``actor_account_id`` must be an OWNER; ``role`` is the member's new role. An owner\nmay only change *other* members' roles (never their own), so self-promotion is\nimpossible. ``role`` is upper-cased before validation.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "role": {
            "title": "Role",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id",
          "role"
        ],
        "title": "ChangeMemberRoleRequest",
        "type": "object"
      },
      "CloseRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/close`` (SQ-14).\n\n``actor_account_id`` is the OWNER closing the squad (must be a current OWNER\nmember). The close is irreversible — there is no ``/reopen``. ``reason`` is\nfree-form audit text and does not affect the on-chain tx.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "CloseRequest",
        "type": "object"
      },
      "ConfirmVariableRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/recurring-expenses/{rex_id}/confirm`` — the payer sets a\nvariable conta's real amount for the current period, turning its\n``PENDING_CONFIRMATION`` placeholder into a live on-chain ACCOUNTING expense.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          }
        },
        "required": [
          "actor_account_id",
          "amount"
        ],
        "title": "ConfirmVariableRequest",
        "type": "object"
      },
      "ConformanceRunOpenRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/products/{product_id}/conformance`` (LaaS-88).\n\n⛔ **The only thing a caller supplies is a roster of accounts it owns.** No\nparams, no amounts, no deadlines: those are synthesised from the manifest by\nthe one producer both conformance drivers use, because an action driven with a\nvalue nobody chose proves nothing about the product.\n\n⭐ Account **ids**, never keys. Two catalog products need a 32-byte\ncounterparty verification key at create and no read publishes one (laas-82\nfinding 6), so the platform resolves the keys internally from ids the caller\nowns. Key material crosses this API in neither direction.",
        "properties": {
          "account_ids": {
            "description": "Distinct 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.",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "title": "Account Ids",
            "type": "array"
          }
        },
        "required": [
          "account_ids"
        ],
        "title": "ConformanceRunOpenRequest",
        "type": "object"
      },
      "ConformanceStepRequest": {
        "additionalProperties": false,
        "description": "``POST …/conformance/{run_id}/steps/{index}``. Deliberately empty.\n\n⚠️ A body exists only so the route has a schema and `extra=\"forbid\"` can refuse\none: a caller who sends params has misunderstood who chooses them, and being\ntold so beats having them silently ignored.",
        "properties": {},
        "title": "ConformanceStepRequest",
        "type": "object"
      },
      "ConsentRequest": {
        "additionalProperties": false,
        "description": "``PUT /v1/squads/{sqd_id}/auto-collect/consent`` — a member grants (or refreshes) a\nstanding, capped authorization to auto-settle their share of one conta each cycle.\n\n``caller_account_id`` is the consenting member (own-share-only — a member can only\nconsent for themselves). ``max_amount`` caps how much may be auto-collected per cycle;\na posted share above the cap SUSPENDS the consent rather than over-collecting.",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          },
          "max_amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "rex_id": {
            "title": "Rex Id",
            "type": "string"
          }
        },
        "required": [
          "caller_account_id",
          "rex_id",
          "max_amount"
        ],
        "title": "ConsentRequest",
        "type": "object"
      },
      "ConsentResponse": {
        "additionalProperties": false,
        "description": "200 body for ``PUT …/auto-collect/consent``. ``state`` is ACTIVE after a grant;\n``consent_state`` is ``null`` (cleared) — a re-grant re-activates a suspended consent.",
        "properties": {
          "consent_id": {
            "title": "Consent Id",
            "type": "string"
          },
          "consent_state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent State"
          },
          "granted_at": {
            "title": "Granted At",
            "type": "string"
          },
          "max_amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "rex_id": {
            "title": "Rex Id",
            "type": "string"
          },
          "state": {
            "default": "ACTIVE",
            "title": "State",
            "type": "string"
          }
        },
        "required": [
          "consent_id",
          "rex_id",
          "max_amount",
          "granted_at"
        ],
        "title": "ConsentResponse",
        "type": "object"
      },
      "ConsentRevokeRequest": {
        "additionalProperties": false,
        "description": "``DELETE /v1/squads/{sqd_id}/auto-collect/consent/{consent_id}`` body — the caller\nmay only revoke their own consent (own-share-only).",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          }
        },
        "required": [
          "caller_account_id"
        ],
        "title": "ConsentRevokeRequest",
        "type": "object"
      },
      "ConsentRevokeResponse": {
        "additionalProperties": false,
        "description": "200 body for a revoke — the consent row is hard-deleted; future cycles no longer\nauto-collect this member's share.",
        "properties": {
          "consent_id": {
            "title": "Consent Id",
            "type": "string"
          },
          "revoked": {
            "default": true,
            "title": "Revoked",
            "type": "boolean"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "consent_id"
        ],
        "title": "ConsentRevokeResponse",
        "type": "object"
      },
      "ContributionRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/contributions`` — ``kind`` selects FUNDED (a QBRL\ndeposit) or ACCOUNTING (a non-monetary split entry, vQBRL-minted).\n\n``kind`` is a plain ``str`` (not a ``Literal``) on purpose: the route validates\nit explicitly so an unknown kind returns a structured ``400 INVALID_KIND``\nrather than FastAPI's generic 422 body.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "kind": {
            "title": "Kind",
            "type": "string"
          },
          "members_snapshot": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Members Snapshot"
          },
          "source_tx_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Tx Ids"
          },
          "split": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SplitSpec"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "kind",
          "actor_account_id",
          "amount"
        ],
        "title": "ContributionRequest",
        "type": "object"
      },
      "CreateAccountLimitPolicyRequest": {
        "description": "POST /v1/accounts/{account_id}/limits — ACCOUNT-scope policy.",
        "properties": {
          "action": {
            "enum": [
              "WARN",
              "REJECT"
            ],
            "title": "Action",
            "type": "string"
          },
          "active_between": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ActiveBetweenModel"
              },
              {
                "type": "null"
              }
            ],
            "description": "Time-of-day applicability (e.g. a nighttime policy); requires window=DAY"
          },
          "applies_max_kyc_level": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Applies only when the funnel supplies kyc_level <= this; funnels that don't populate kyc_level skip the policy (fail-open)",
            "title": "Applies Max Kyc Level"
          },
          "dimension": {
            "description": "What the threshold bounds: summed centavos (AMOUNT), event count (COUNT), or a per-transaction cap — threshold compare only, no counter (SINGLE_AMOUNT)",
            "enum": [
              "AMOUNT",
              "COUNT",
              "SINGLE_AMOUNT"
            ],
            "title": "Dimension",
            "type": "string"
          },
          "direction": {
            "enum": [
              "DEBIT",
              "CREDIT"
            ],
            "title": "Direction",
            "type": "string"
          },
          "enforce_per": {
            "anyOf": [
              {
                "enum": [
                  "SCOPE",
                  "ACCOUNT"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ACCOUNT: this broad-scope policy gates per-account counters (default SCOPE = one shared counter per scope)",
            "title": "Enforce Per"
          },
          "policy_key": {
            "anyOf": [
              {
                "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pack identity (e.g. 'pix.night.amount'): the most-specific scope carrying a key shadows broader ones, and interval counters key on it so overrides inherit mid-window utilization. Unique per scope.",
            "title": "Policy Key"
          },
          "rail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Restrict to one rail (QUADRA/ACH/MOCK/PIX); absent = all rails",
            "title": "Rail"
          },
          "threshold": {
            "description": "Centavos for AMOUNT, count for COUNT",
            "exclusiveMinimum": 0,
            "title": "Threshold",
            "type": "integer"
          },
          "window": {
            "description": "Tumbling calendar window, América/São Paulo boundaries",
            "enum": [
              "MINUTE",
              "HOUR",
              "DAY",
              "MONTH"
            ],
            "title": "Window",
            "type": "string"
          }
        },
        "required": [
          "dimension",
          "direction",
          "window",
          "threshold",
          "action"
        ],
        "title": "CreateAccountLimitPolicyRequest",
        "type": "object"
      },
      "CreateLimitPolicyRequest": {
        "description": "POST /v1/limit-policies — GLOBAL / ACCOUNT_TYPE / RAIL / PRODUCT scope.",
        "properties": {
          "action": {
            "enum": [
              "WARN",
              "REJECT"
            ],
            "title": "Action",
            "type": "string"
          },
          "active_between": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ActiveBetweenModel"
              },
              {
                "type": "null"
              }
            ],
            "description": "Time-of-day applicability (e.g. a nighttime policy); requires window=DAY"
          },
          "applies_max_kyc_level": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Applies only when the funnel supplies kyc_level <= this; funnels that don't populate kyc_level skip the policy (fail-open)",
            "title": "Applies Max Kyc Level"
          },
          "dimension": {
            "description": "What the threshold bounds: summed centavos (AMOUNT), event count (COUNT), or a per-transaction cap — threshold compare only, no counter (SINGLE_AMOUNT)",
            "enum": [
              "AMOUNT",
              "COUNT",
              "SINGLE_AMOUNT"
            ],
            "title": "Dimension",
            "type": "string"
          },
          "direction": {
            "enum": [
              "DEBIT",
              "CREDIT"
            ],
            "title": "Direction",
            "type": "string"
          },
          "enforce_per": {
            "anyOf": [
              {
                "enum": [
                  "SCOPE",
                  "ACCOUNT"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ACCOUNT: this broad-scope policy gates per-account counters (default SCOPE = one shared counter per scope)",
            "title": "Enforce Per"
          },
          "policy_key": {
            "anyOf": [
              {
                "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pack identity (e.g. 'pix.night.amount'): the most-specific scope carrying a key shadows broader ones, and interval counters key on it so overrides inherit mid-window utilization. Unique per scope.",
            "title": "Policy Key"
          },
          "rail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Restrict to one rail (QUADRA/ACH/MOCK/PIX); absent = all rails",
            "title": "Rail"
          },
          "scope_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Type name / rail family / product id; omitted for GLOBAL",
            "title": "Scope Id"
          },
          "scope_type": {
            "enum": [
              "GLOBAL",
              "ACCOUNT_TYPE",
              "RAIL",
              "PRODUCT"
            ],
            "title": "Scope Type",
            "type": "string"
          },
          "threshold": {
            "description": "Centavos for AMOUNT, count for COUNT",
            "exclusiveMinimum": 0,
            "title": "Threshold",
            "type": "integer"
          },
          "window": {
            "description": "Tumbling calendar window, América/São Paulo boundaries",
            "enum": [
              "MINUTE",
              "HOUR",
              "DAY",
              "MONTH"
            ],
            "title": "Window",
            "type": "string"
          }
        },
        "required": [
          "dimension",
          "direction",
          "window",
          "threshold",
          "action",
          "scope_type"
        ],
        "title": "CreateLimitPolicyRequest",
        "type": "object"
      },
      "CreateObligationRequest": {
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/AmountField"
          },
          "creditor": {
            "$ref": "#/components/schemas/DebtorCreditor"
          },
          "debtor": {
            "$ref": "#/components/schemas/DebtorCreditor"
          },
          "expected_settlement": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ExpectedSettlement"
              },
              {
                "type": "null"
              }
            ],
            "description": "Expected settlement window"
          },
          "match_keys": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Keys for matching evidence to this obligation",
            "title": "Match Keys"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free-form metadata",
            "title": "Metadata"
          },
          "rail": {
            "$ref": "#/components/schemas/RailFamily"
          }
        },
        "required": [
          "rail",
          "amount",
          "debtor",
          "creditor"
        ],
        "title": "CreateObligationRequest",
        "type": "object"
      },
      "CreateScheduleRequest": {
        "properties": {
          "account_id": {
            "description": "Owning account (= debtor)",
            "minLength": 1,
            "title": "Account Id",
            "type": "string"
          },
          "action": {
            "$ref": "#/components/schemas/ScheduleAction"
          },
          "first_run_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "RECURRING anchor; defaults to creation time",
            "title": "First Run At"
          },
          "misfire_grace_seconds": {
            "default": 86400,
            "maximum": 604800,
            "minimum": 0,
            "title": "Misfire Grace Seconds",
            "type": "integer"
          },
          "recurrence": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RecurrenceRule"
              },
              {
                "type": "null"
              }
            ]
          },
          "retry_policy": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RetryPolicy"
              },
              {
                "type": "null"
              }
            ]
          },
          "run_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ONE_SHOT: the scheduled instant",
            "title": "Run At"
          },
          "schedule_type": {
            "enum": [
              "ONE_SHOT",
              "RECURRING"
            ],
            "title": "Schedule Type",
            "type": "string"
          },
          "timezone": {
            "default": "America/Sao_Paulo",
            "description": "IANA zone for wall-clock recurrence math",
            "title": "Timezone",
            "type": "string"
          }
        },
        "required": [
          "account_id",
          "schedule_type",
          "action"
        ],
        "title": "CreateScheduleRequest",
        "type": "object"
      },
      "DebtorCreditor": {
        "properties": {
          "account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Quadra account ID (e.g., 'acc_...')",
            "title": "Account Id"
          },
          "external_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "External entity identifier (for kind='external')",
            "title": "External Id"
          },
          "kind": {
            "description": "Entity kind: 'account' or 'external'",
            "title": "Kind",
            "type": "string"
          }
        },
        "required": [
          "kind"
        ],
        "title": "DebtorCreditor",
        "type": "object"
      },
      "Disposition": {
        "description": "Optional override of the D2 default destination for a live-value resolve\n(SETTLED → quadra-faucet; FAILED/CANCELED → the obligation's debtor).",
        "properties": {
          "destination_account_id": {
            "minLength": 1,
            "title": "Destination Account Id",
            "type": "string"
          }
        },
        "required": [
          "destination_account_id"
        ],
        "title": "Disposition",
        "type": "object"
      },
      "DocumentRef": {
        "additionalProperties": false,
        "description": "Provider-hosted document reference (D4 — never bytes, only refs).\n\nThe refs-only posture in ``kyc/__init__.py`` is enforced here rather than merely\nasserted (LaaS-44 D4), by two properties that must both survive any edit:\n\n* ``extra=\"forbid\"`` — a ``document_bytes`` / ``content`` / ``image_b64`` field\n  cannot be smuggled in beside the ref;\n* ``max_length`` — a ref is an **identifier**, so the bound is far below anything\n  a base64 document could fit in. A caller pasting an inline payload into\n  ``provider_ref`` gets a 422 at the schema layer, before the engine or any\n  provider sees it.\n\nWidening either of these is a change to the published BYO contract, not a tidy-up.",
        "properties": {
          "provider_ref": {
            "description": "Provider-side document id — an identifier, never content",
            "maxLength": 256,
            "minLength": 1,
            "title": "Provider Ref",
            "type": "string"
          },
          "type": {
            "description": "Document type, e.g. 'id_front', 'selfie'",
            "maxLength": 64,
            "minLength": 1,
            "title": "Type",
            "type": "string"
          }
        },
        "required": [
          "type",
          "provider_ref"
        ],
        "title": "DocumentRef",
        "type": "object"
      },
      "EntrySplitOverrideRequest": {
        "additionalProperties": false,
        "description": "``PATCH /v1/squads/{sqd_id}/entries/{entry_seq}/split`` — owner escape hatch.\n\nThe owner manually re-divides one expense's *still-open* shares using an explicit\n``split`` (EQUAL / SHARES / AMOUNTS over the open debtors). Works even on a\npartially-settled entry (only the open portion is re-issued); the entry is then\nflagged so automatic re-splits leave it alone (RFC-018).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "split": {
            "$ref": "#/components/schemas/SplitSpec"
          }
        },
        "required": [
          "actor_account_id",
          "split"
        ],
        "title": "EntrySplitOverrideRequest",
        "type": "object"
      },
      "EvidenceResolveRequest": {
        "description": "``POST /v1/evidence/{evidence_id}/resolve`` — manual match: the operator\npins the target obligation an unmatched settlement should credit.",
        "properties": {
          "actor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actor"
          },
          "justification": {
            "minLength": 1,
            "title": "Justification",
            "type": "string"
          },
          "obligation_id": {
            "description": "Target obligation (obl_* or legacy txhash_N).",
            "minLength": 1,
            "title": "Obligation Id",
            "type": "string"
          },
          "proof": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProofBlock"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "obligation_id",
          "justification"
        ],
        "title": "EvidenceResolveRequest",
        "type": "object"
      },
      "EvidenceRetryRequest": {
        "description": "``POST /v1/evidence/{evidence_id}/retry`` — re-run a stored ``status=ERROR``\nevidence row through the ingest pipeline once its cause is fixed. No payload:\nthe source_type + raw_payload come from the persisted row.",
        "properties": {
          "actor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actor"
          },
          "justification": {
            "minLength": 1,
            "title": "Justification",
            "type": "string"
          }
        },
        "required": [
          "justification"
        ],
        "title": "EvidenceRetryRequest",
        "type": "object"
      },
      "ExpectedSettlement": {
        "properties": {
          "window": {
            "description": "Expected settlement window (e.g., 'T+1', 'T+2')",
            "title": "Window",
            "type": "string"
          }
        },
        "required": [
          "window"
        ],
        "title": "ExpectedSettlement",
        "type": "object"
      },
      "FoundryCompileListResponse": {
        "properties": {
          "compiles": {
            "items": {
              "$ref": "#/components/schemas/FoundryCompileResponse"
            },
            "title": "Compiles",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          }
        },
        "required": [
          "tenant",
          "compiles"
        ],
        "title": "FoundryCompileListResponse",
        "type": "object"
      },
      "FoundryCompileRequest": {
        "description": "One Product Bundle submitted for compilation and gating.\n\n⛔ **The source travels by value and the compiled bytes never do.** That is the\ninverse of the binding API, and deliberately so: `TenantProductBindRequest`\nrefuses a `cbor_hex` because pre-Foundry there is no compile provenance\n(laas-80 D1). This endpoint is where provenance is *created*, so source is\nexactly what it must accept — and the thing it will not accept is somebody\nelse's already-compiled bytes.\n\n⚠️ Compiling does not bind. A green report is evidence; certification\n(laas-86) is what turns evidence into a bindable product, and nothing here\nwrites to `script_params.PARAMETRIC_TEMPLATES`.",
        "properties": {
          "manifest": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "The 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.",
            "title": "Manifest"
          },
          "product_id": {
            "description": "Namespaced product id, `tnt.{tenant}.{name}`",
            "examples": [
              "tnt.acme.escrow"
            ],
            "title": "Product Id",
            "type": "string"
          },
          "signature": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/BundleSignature"
              },
              {
                "type": "null"
              }
            ],
            "description": "Detached 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."
          },
          "source": {
            "description": "The tenant's `Tenant.Product` module, verbatim. Its header, its single export and its allowed imports are published in docs/product-author-contract.md.",
            "title": "Source",
            "type": "string"
          },
          "verify_determinism": {
            "default": false,
            "description": "Compile twice into different build directories and compare the bytes (laas-83 D9). Doubles the job; off by default.",
            "title": "Verify Determinism",
            "type": "boolean"
          }
        },
        "required": [
          "product_id",
          "source"
        ],
        "title": "FoundryCompileRequest",
        "type": "object"
      },
      "FoundryCompileResponse": {
        "description": "A compile job, at whatever stage it has reached.",
        "properties": {
          "applied_size_bytes": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Applied Size Bytes"
          },
          "authorship_fpr": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fingerprint 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.",
            "title": "Authorship Fpr"
          },
          "bundle_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "sha256 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.",
            "title": "Bundle Hash"
          },
          "compile_id": {
            "title": "Compile Id",
            "type": "string"
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "gate_report": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Gate Report"
          },
          "gate_report_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Gate Report Hash"
          },
          "gate_report_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where 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.",
            "title": "Gate Report Key"
          },
          "manifest_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Manifest Hash"
          },
          "product_id": {
            "title": "Product Id",
            "type": "string"
          },
          "script_size_budget_bytes": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Script Size Budget Bytes"
          },
          "script_size_bytes": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Script Size Bytes"
          },
          "source_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Hash"
          },
          "source_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where 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.",
            "title": "Source Key"
          },
          "status": {
            "description": "QUEUED | COMPILING | ACCEPTED | REFUSED | ERROR",
            "title": "Status",
            "type": "string"
          },
          "substrate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Substrate"
          },
          "template_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "sha256 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).",
            "title": "Template Hash"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          }
        },
        "required": [
          "compile_id",
          "tenant",
          "product_id",
          "status"
        ],
        "title": "FoundryCompileResponse",
        "type": "object"
      },
      "FoundryQuotaResponse": {
        "description": "The tenant-facing view of the compile meter (LaaS-88).\n\n⚠️ Narrower than the operator's ``TenantQuotaResponse`` on purpose: it carries\nno ``updated_by``, because who inside the platform set a tenant's cap is our\nbusiness and not theirs. The laas-87 D7 split, in a second place.",
        "properties": {
          "quota": {
            "title": "Quota",
            "type": "integer"
          },
          "quota_source": {
            "default": "estate_default",
            "title": "Quota Source",
            "type": "string"
          },
          "remaining": {
            "title": "Remaining",
            "type": "integer"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          },
          "used": {
            "title": "Used",
            "type": "integer"
          },
          "window": {
            "default": "utc_day",
            "title": "Window",
            "type": "string"
          },
          "window_resets_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Window Resets At"
          },
          "window_started_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Window Started At"
          }
        },
        "required": [
          "tenant",
          "quota",
          "used",
          "remaining"
        ],
        "title": "FoundryQuotaResponse",
        "type": "object"
      },
      "GLAccountPatchRequest": {
        "description": "Rename or deactivate a GL account. GL nodes are never deleted.",
        "properties": {
          "name": {
            "anyOf": [
              {
                "maxLength": 80,
                "minLength": 1,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "New display name",
            "title": "Name"
          },
          "status": {
            "anyOf": [
              {
                "enum": [
                  "ACTIVE",
                  "INACTIVE"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "INACTIVE blocks new mapping-rule targets; history is never deleted",
            "title": "Status"
          }
        },
        "title": "GLAccountPatchRequest",
        "type": "object"
      },
      "GLMappingRuleIn": {
        "description": "One ordered mapping rule: match → COA node.",
        "properties": {
          "gl_node_id": {
            "description": "Target COA node for matching legs",
            "pattern": "^gl_[a-z0-9_]{2,48}$",
            "title": "Gl Node Id",
            "type": "string"
          },
          "match": {
            "$ref": "#/components/schemas/GLMappingRuleMatchIn",
            "description": "Conditions (missing key = wildcard)"
          }
        },
        "required": [
          "match",
          "gl_node_id"
        ],
        "title": "GLMappingRuleIn",
        "type": "object"
      },
      "GLMappingRuleMatchIn": {
        "additionalProperties": false,
        "description": "Match conditions; every present key must equal exactly (missing = wildcard).",
        "properties": {
          "account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Exact account id to match",
            "title": "Account Id"
          },
          "account_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Account type to match (CUSTOMER, SQUAD, ...)",
            "title": "Account Type"
          },
          "event_kind": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Entry-set event kind to match",
            "title": "Event Kind"
          },
          "product_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Validator/product id to match (e.g. quadra-escrow)",
            "title": "Product Id"
          }
        },
        "title": "GLMappingRuleMatchIn",
        "type": "object"
      },
      "GLMappingRulesetCreateRequest": {
        "description": "Append a new ruleset version (full replacement list; prospective-only).",
        "properties": {
          "rules": {
            "description": "Ordered, first-match-wins; unmatched legs fall back to built-in per-type defaults",
            "items": {
              "$ref": "#/components/schemas/GLMappingRuleIn"
            },
            "minItems": 1,
            "title": "Rules",
            "type": "array"
          }
        },
        "required": [
          "rules"
        ],
        "title": "GLMappingRulesetCreateRequest",
        "type": "object"
      },
      "GLSubAccountCreateRequest": {
        "description": "Create a sub-GL account (derived GL row, no on-chain keys).",
        "properties": {
          "account_id": {
            "description": "Operator-chosen node id (gl_* slug; referenced by mapping rules)",
            "pattern": "^gl_[a-z0-9_]{2,48}$",
            "title": "Account Id",
            "type": "string"
          },
          "currency": {
            "default": "BRL",
            "description": "ISO 4217 currency code",
            "title": "Currency",
            "type": "string"
          },
          "name": {
            "description": "Human-readable node name",
            "maxLength": 80,
            "minLength": 1,
            "title": "Name",
            "type": "string"
          },
          "normal_balance": {
            "anyOf": [
              {
                "enum": [
                  "DR",
                  "CR"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Defaults to the parent's normal_balance, else the type default",
            "title": "Normal Balance"
          },
          "parent_account_id": {
            "description": "Must be an existing GL node",
            "title": "Parent Account Id",
            "type": "string"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "One of ASSET|LIABILITY|TRANSIT|REVENUE|EXCEPTION; defaults to the parent's type",
            "title": "Type"
          }
        },
        "required": [
          "account_id",
          "name",
          "parent_account_id"
        ],
        "title": "GLSubAccountCreateRequest",
        "type": "object"
      },
      "GenericEvidenceRequest": {
        "properties": {
          "payload": {
            "additionalProperties": true,
            "description": "Rail-specific payload",
            "title": "Payload",
            "type": "object"
          },
          "source_type": {
            "description": "Payload-schema id, not a provider id (LaaS-38 D4). Known values: ach_json_v1, pix_json_v1, MOCK. Open-ended by policy — a new driver adds a value, and a shipped value is never repurposed.",
            "minLength": 1,
            "title": "Source Type",
            "type": "string"
          }
        },
        "required": [
          "source_type",
          "payload"
        ],
        "title": "GenericEvidenceRequest",
        "type": "object"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "title": "Detail",
            "type": "array"
          }
        },
        "title": "HTTPValidationError",
        "type": "object"
      },
      "InviteAcceptRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/invitations/accept`` — the invitee accepts.\n\n``caller_account_id`` is the invitee (matching the ``/settle`` convention);\nthe squad + caller identify the pending invite. ``quota`` (cotas, RFC-018) is how\nmany people the invitee represents — default 1; a member bringing a +1 sets 2,\nmaking EQUAL-split expenses weight them accordingly. Accepting folds the invitee\n(at this quota) into every still-open prior expense (see ``retroactive`` in the\nresponse).",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          },
          "quota": {
            "default": 1,
            "maximum": 20,
            "minimum": 1,
            "title": "Quota",
            "type": "integer"
          }
        },
        "required": [
          "caller_account_id"
        ],
        "title": "InviteAcceptRequest",
        "type": "object"
      },
      "InviteCreateRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/invitations`` — an OWNER invites one or more accounts.\n\nReplaces the old direct add-member: nobody joins a squad without their own\naccept. The accepted role is always ``SPENDER`` (no role field), so inviting a\nprospective OWNER is intentionally out of scope.\n\n``invitee_account_ids`` is a list (1–50) so a client can invite several people in a\nsingle tap. The endpoint is **partial-success**: each invitee is reported as\n``invited``/``skipped``/``failed`` (see :class:`SquadInviteResultEntry`); only\nstructural errors (squad missing/closed, actor not an OWNER) fail the whole call.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "invitee_account_ids": {
            "items": {
              "type": "string"
            },
            "maxItems": 50,
            "minItems": 1,
            "title": "Invitee Account Ids",
            "type": "array"
          }
        },
        "required": [
          "actor_account_id",
          "invitee_account_ids"
        ],
        "title": "InviteCreateRequest",
        "type": "object"
      },
      "InviteDeclineRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/invitations/decline`` — the invitee declines.",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          }
        },
        "required": [
          "caller_account_id"
        ],
        "title": "InviteDeclineRequest",
        "type": "object"
      },
      "KycStatusPatchRequest": {
        "additionalProperties": false,
        "description": "Operator review resolution (Ticket 24's consumer seam).",
        "properties": {
          "reason": {
            "minLength": 1,
            "title": "Reason",
            "type": "string"
          },
          "to_state": {
            "enum": [
              "verified",
              "rejected"
            ],
            "title": "To State",
            "type": "string"
          }
        },
        "required": [
          "to_state",
          "reason"
        ],
        "title": "KycStatusPatchRequest",
        "type": "object"
      },
      "KycSubmitRequest": {
        "additionalProperties": false,
        "properties": {
          "document_refs": {
            "items": {
              "$ref": "#/components/schemas/DocumentRef"
            },
            "title": "Document Refs",
            "type": "array"
          },
          "provider_id": {
            "anyOf": [
              {
                "maxLength": 32,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "KYC provider to route to. Omit to use the tenant's default provider. Must be one this tenant is entitled to.",
            "title": "Provider Id"
          }
        },
        "title": "KycSubmitRequest",
        "type": "object"
      },
      "MedAmountModel": {
        "properties": {
          "currency": {
            "description": "ISO 4217 currency code (BRL only)",
            "title": "Currency",
            "type": "string"
          },
          "value": {
            "description": "Amount in centavos",
            "title": "Value",
            "type": "integer"
          }
        },
        "required": [
          "currency",
          "value"
        ],
        "title": "MedAmountModel",
        "type": "object"
      },
      "MedCaseCreateRequest": {
        "description": "POST /v1/pix/med/cases — file an infraction with the sponsor for our\ncustomer's claim about a payment they SENT (direction=OUTBOUND).",
        "properties": {
          "actor": {
            "description": "Operator identity",
            "title": "Actor",
            "type": "string"
          },
          "amount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/MedAmountModel"
              },
              {
                "type": "null"
              }
            ],
            "description": "Disputed amount (defaults to the original amount)"
          },
          "original_end_to_end_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "E2EID of the disputed outbound payment",
            "title": "Original End To End Id"
          },
          "original_obligation_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Logical obligation id (obl_*) of the disputed outbound payment",
            "title": "Original Obligation Id"
          },
          "reason_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Infraction reason code",
            "title": "Reason Code"
          }
        },
        "required": [
          "actor"
        ],
        "title": "MedCaseCreateRequest",
        "type": "object"
      },
      "MedCaseResolveRequest": {
        "description": "POST /v1/pix/med/cases/{case_id}/resolve.",
        "properties": {
          "action": {
            "description": "RETURN | RELEASE",
            "title": "Action",
            "type": "string"
          },
          "actor": {
            "description": "Operator identity",
            "title": "Actor",
            "type": "string"
          },
          "amount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/MedAmountModel"
              },
              {
                "type": "null"
              }
            ],
            "description": "RETURN only: partial capture amount (defaults to the full block)"
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free-text resolution reason",
            "title": "Reason"
          }
        },
        "required": [
          "action",
          "actor"
        ],
        "title": "MedCaseResolveRequest",
        "type": "object"
      },
      "ObligationException": {
        "properties": {
          "description": {
            "description": "Human-readable description of the exception",
            "title": "Description",
            "type": "string"
          },
          "evidence_amount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AmountDetail"
              },
              {
                "type": "null"
              }
            ],
            "description": "Amount from the evidence that triggered this exception"
          },
          "matched_obligation_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ID of the matched obligation (for AMOUNT_MISMATCH)",
            "title": "Matched Obligation Id"
          },
          "obligation_amount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AmountDetail"
              },
              {
                "type": "null"
              }
            ],
            "description": "Amount of the matched obligation (for AMOUNT_MISMATCH)"
          },
          "trace_number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Trace number from the evidence",
            "title": "Trace Number"
          },
          "type": {
            "description": "Exception type, e.g. AMOUNT_MISMATCH, UNMATCHED_SETTLEMENT",
            "title": "Type",
            "type": "string"
          }
        },
        "required": [
          "type",
          "description"
        ],
        "title": "ObligationException",
        "type": "object"
      },
      "ObligationListItem": {
        "properties": {
          "adapter_ref": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Adapter Ref"
          },
          "amount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Amount"
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "creditor_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Creditor Account Id"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "debtor_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Debtor Account Id"
          },
          "dispatch_attempts": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatch Attempts"
          },
          "dispatch_error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatch Error"
          },
          "dispatch_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatch Status"
          },
          "dispatched_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatched At"
          },
          "effective_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Effective At"
          },
          "obligation_id": {
            "title": "Obligation Id",
            "type": "string"
          },
          "pending_dispatch": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pending Dispatch"
          },
          "rail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rail"
          },
          "resolution_outcome": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resolution Outcome"
          },
          "state": {
            "$ref": "#/components/schemas/ObligationState"
          }
        },
        "required": [
          "obligation_id",
          "state"
        ],
        "title": "ObligationListItem",
        "type": "object"
      },
      "ObligationListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/ObligationListItem"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "ObligationListResponse",
        "type": "object"
      },
      "ObligationRedispatchRequest": {
        "description": "``POST /v1/obligations/{obligation_id}/redispatch`` — re-drive a FAILED\noutbound dispatch (RFC-022 §4.2 RETRY_REQUESTED).",
        "properties": {
          "actor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actor"
          },
          "justification": {
            "minLength": 1,
            "title": "Justification",
            "type": "string"
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason"
          }
        },
        "required": [
          "justification"
        ],
        "title": "ObligationRedispatchRequest",
        "type": "object"
      },
      "ObligationResolveRequest": {
        "description": "``POST /v1/obligations/{obligation_id}/resolve`` — clear a stuck\nPENDING/EXCEPTION obligation with an operator-attested outcome + proof.",
        "properties": {
          "actor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Operator identity. Token-authoritative in production; required in the body in local mode.",
            "title": "Actor"
          },
          "approvals": {
            "items": {},
            "title": "Approvals",
            "type": "array"
          },
          "disposition": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Disposition"
              },
              {
                "type": "null"
              }
            ]
          },
          "justification": {
            "minLength": 1,
            "title": "Justification",
            "type": "string"
          },
          "outcome": {
            "description": "SETTLED | FAILED | CANCELED",
            "title": "Outcome",
            "type": "string"
          },
          "proof": {
            "$ref": "#/components/schemas/ProofBlock"
          }
        },
        "required": [
          "outcome",
          "justification",
          "proof"
        ],
        "title": "ObligationResolveRequest",
        "type": "object"
      },
      "ObligationResponse": {
        "properties": {
          "adapter_ref": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Adapter Ref"
          },
          "amount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Amount"
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "creditor_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Creditor Account Id"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "debtor_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Debtor Account Id"
          },
          "dispatch_attempts": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatch Attempts"
          },
          "dispatch_error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatch Error"
          },
          "dispatch_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatch Status"
          },
          "dispatched_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dispatched At"
          },
          "effective_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Effective At"
          },
          "evidence_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Evidence Id"
          },
          "exception": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ObligationException"
              },
              {
                "type": "null"
              }
            ]
          },
          "expected_settlement": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expected Settlement"
          },
          "external_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "External Id"
          },
          "indexed_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Indexed At"
          },
          "match_keys": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Match Keys"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          },
          "obligation_id": {
            "title": "Obligation Id",
            "type": "string"
          },
          "pending_dispatch": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pending Dispatch"
          },
          "rail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rail"
          },
          "resolution_outcome": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resolution Outcome"
          },
          "resolution_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resolution Reason"
          },
          "resolved_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resolved At"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Role"
          },
          "state": {
            "$ref": "#/components/schemas/ObligationState"
          },
          "state_history": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "State History"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "utxo_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Utxo Id"
          }
        },
        "required": [
          "obligation_id",
          "state"
        ],
        "title": "ObligationResponse",
        "type": "object"
      },
      "ObligationState": {
        "enum": [
          "OPEN",
          "FINAL",
          "PENDING",
          "EXCEPTION"
        ],
        "title": "ObligationState",
        "type": "string"
      },
      "ObligationTimelineResponse": {
        "properties": {
          "obligation_id": {
            "title": "Obligation Id",
            "type": "string"
          },
          "timeline": {
            "items": {
              "$ref": "#/components/schemas/TimelineEvent"
            },
            "title": "Timeline",
            "type": "array"
          }
        },
        "required": [
          "obligation_id",
          "timeline"
        ],
        "title": "ObligationTimelineResponse",
        "type": "object"
      },
      "PatchScheduleRequest": {
        "description": "All-optional subset; PATCH on a mandate-owned schedule is rejected\nupstream with 422 MANDATE_MANAGED.",
        "properties": {
          "action": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ScheduleAction"
              },
              {
                "type": "null"
              }
            ]
          },
          "misfire_grace_seconds": {
            "anyOf": [
              {
                "maximum": 604800,
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Misfire Grace Seconds"
          },
          "recurrence": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RecurrenceRule"
              },
              {
                "type": "null"
              }
            ]
          },
          "retry_policy": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RetryPolicy"
              },
              {
                "type": "null"
              }
            ]
          },
          "run_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Run At"
          },
          "timezone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Timezone"
          }
        },
        "title": "PatchScheduleRequest",
        "type": "object"
      },
      "PayoutBlock": {
        "additionalProperties": false,
        "description": "External-rail payout status on a Pix squad spend (B-SQ-07). Present only on Pix\nspends. ``end_to_end_id`` is assigned by the sponsor at dispatch time, so it is\n``null`` in the 201 (``PROCESSING``) response and filled once the rail accepts.",
        "properties": {
          "end_to_end_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "End To End Id"
          },
          "rail": {
            "default": "PIX",
            "title": "Rail",
            "type": "string"
          },
          "recipient_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recipient Name"
          },
          "status": {
            "default": "PROCESSING",
            "enum": [
              "PROCESSING",
              "SETTLED",
              "FAILED"
            ],
            "title": "Status",
            "type": "string"
          }
        },
        "title": "PayoutBlock",
        "type": "object"
      },
      "PixDestination": {
        "additionalProperties": false,
        "description": "An external Pix payout target for a squad spend (B-SQ-07). Exactly one of\n``recipient_account_id`` / ``pix_destination`` is supplied on :class:`SpendRequest`.\n``key`` is the raw Pix key as typed; Core normalizes it (DICT lookup + identity-key\nnormalization) — ``key_type`` is the DICT category.",
        "properties": {
          "key": {
            "title": "Key",
            "type": "string"
          },
          "key_type": {
            "enum": [
              "CPF",
              "PHONE",
              "EMAIL",
              "EVP"
            ],
            "title": "Key Type",
            "type": "string"
          }
        },
        "required": [
          "key_type",
          "key"
        ],
        "title": "PixDestination",
        "type": "object"
      },
      "PixKeyRegisterRequest": {
        "properties": {
          "account_id": {
            "minLength": 1,
            "title": "Account Id",
            "type": "string"
          },
          "key_type": {
            "enum": [
              "EMAIL",
              "PHONE",
              "CPF",
              "CNPJ",
              "EVP"
            ],
            "title": "Key Type",
            "type": "string"
          },
          "key_value": {
            "anyOf": [
              {
                "maxLength": 120,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Required for EMAIL/PHONE/CPF/CNPJ; must be absent for EVP — the sponsor mints the value",
            "title": "Key Value"
          }
        },
        "required": [
          "account_id",
          "key_type"
        ],
        "title": "PixKeyRegisterRequest",
        "type": "object"
      },
      "PixQrDecodeRequest": {
        "properties": {
          "brcode": {
            "description": "Scanned BR Code (EMV-MPM) payload",
            "maxLength": 1000,
            "minLength": 12,
            "title": "Brcode",
            "type": "string"
          }
        },
        "required": [
          "brcode"
        ],
        "title": "PixQrDecodeRequest",
        "type": "object"
      },
      "PixQrDynamicCreateRequest": {
        "properties": {
          "amount_cents": {
            "description": "Charge amount in centavos",
            "exclusiveMinimum": 0,
            "title": "Amount Cents",
            "type": "integer"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 140,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "expires_in_seconds": {
            "default": 3600,
            "description": "Charge validity window; expiry is enforced at payment time sponsor-side (D8) — stored here as data, never a timer",
            "maximum": 2592000,
            "minimum": 60,
            "title": "Expires In Seconds",
            "type": "integer"
          },
          "key_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Receiving key (must be ACTIVE and owned by the account). Defaulted when the account has exactly one ACTIVE key; ambiguous -> 422 KEY_AMBIGUOUS",
            "title": "Key Id"
          },
          "payer_request": {
            "anyOf": [
              {
                "maxLength": 140,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional free-text prompt shown to the payer (rides the sponsor's JWS location document, not the EMV envelope)",
            "title": "Payer Request"
          }
        },
        "required": [
          "amount_cents"
        ],
        "title": "PixQrDynamicCreateRequest",
        "type": "object"
      },
      "PixReturnAmount": {
        "properties": {
          "currency": {
            "description": "ISO 4217 currency code (BRL only)",
            "title": "Currency",
            "type": "string"
          },
          "value": {
            "description": "Amount in centavos",
            "title": "Value",
            "type": "integer"
          }
        },
        "required": [
          "currency",
          "value"
        ],
        "title": "PixReturnAmount",
        "type": "object"
      },
      "PixReturnRequest": {
        "description": "POST /v1/pix/return body. One of original_obligation_id /\noriginal_end_to_end_id identifies the credit being returned.",
        "properties": {
          "account_id": {
            "description": "The account that received the original credit",
            "title": "Account Id",
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/PixReturnAmount"
          },
          "original_end_to_end_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "E2EID of the original credit",
            "title": "Original End To End Id"
          },
          "original_obligation_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Logical obligation id (obl_*) of the original credit",
            "title": "Original Obligation Id"
          },
          "reason_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pix return reason code (e.g. MD06)",
            "title": "Reason Code"
          }
        },
        "required": [
          "account_id",
          "amount"
        ],
        "title": "PixReturnRequest",
        "type": "object"
      },
      "PlaceBlockRequest": {
        "description": "Operator-class bloqueio cautelar placement (LaaS-07 D2/D4).",
        "properties": {
          "actor": {
            "description": "Operator identity (caller-injected until laas-23 authz lands)",
            "maxLength": 256,
            "minLength": 1,
            "title": "Actor",
            "type": "string"
          },
          "allow_partial": {
            "default": true,
            "description": "Block min(amount, available) — MED must block whatever is left of suspect funds",
            "title": "Allow Partial",
            "type": "boolean"
          },
          "amount_cents": {
            "description": "Amount to block, in centavos",
            "title": "Amount Cents",
            "type": "integer"
          },
          "case_ref": {
            "description": "Compliance case linkage (MED infraction id, court order, ...) — stored as the hold reference",
            "maxLength": 256,
            "minLength": 1,
            "title": "Case Ref",
            "type": "string"
          },
          "case_type": {
            "anyOf": [
              {
                "maxLength": 64,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Case classification (e.g. MED, JUDICIAL); stored in hold metadata",
            "title": "Case Type"
          },
          "currency": {
            "default": "BRL",
            "description": "ISO 4217 currency code",
            "title": "Currency",
            "type": "string"
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO-8601 expiry. ABSENT = default TTL (72h, Res. BCB 147/2021); explicit null = indefinite (judicial blocks never auto-lapse)",
            "title": "Expires At"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          }
        },
        "required": [
          "amount_cents",
          "case_ref",
          "actor"
        ],
        "title": "PlaceBlockRequest",
        "type": "object"
      },
      "PlaceHoldRequest": {
        "properties": {
          "account_id": {
            "description": "Holder account (funds never leave it)",
            "title": "Account Id",
            "type": "string"
          },
          "amount_cents": {
            "description": "Amount to encumber, in centavos",
            "title": "Amount Cents",
            "type": "integer"
          },
          "currency": {
            "default": "BRL",
            "description": "ISO 4217 currency code",
            "title": "Currency",
            "type": "string"
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO-8601 expiry; mutually exclusive with expires_in_hours. Absent = indefinite.",
            "title": "Expires At"
          },
          "expires_in_hours": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Relative expiry in hours; mutually exclusive with expires_at",
            "title": "Expires In Hours"
          },
          "hold_type": {
            "description": "Free-form hold classification (e.g. CARD_AUTH, PIX_AUTOMATICO)",
            "maxLength": 64,
            "minLength": 1,
            "title": "Hold Type",
            "type": "string"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          },
          "reference": {
            "anyOf": [
              {
                "maxLength": 256,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reference"
          }
        },
        "required": [
          "account_id",
          "amount_cents",
          "hold_type"
        ],
        "title": "PlaceHoldRequest",
        "type": "object"
      },
      "ProductAccounting": {
        "description": "The GL mapping the registry row refuses to be written without.\n\n⛔ `gl_node_id` is not derivable and is never defaulted. Without it\n`entry_projector._attribute` books a product's value to the customer's own\naccount, both legs net to zero and `_project_group` returns at `if not legs`\n— no entry set, no EXCEPTION marker, no metric (laas-74's second finding).\n\n⛔ And for a **catalog** product it is not free either: `default_node_for`\nchecks the row's node *before* its `product_id == \"quadra-escrow\"` literal,\nso the moment the incumbent has a row the row's node wins for both surfaces.\nA wrong value silently re-books every escrow leg in the estate, which is why\nthe bind pins it against a shipped map instead of trusting the body.",
        "properties": {
          "custody_to_product": {
            "default": "PRODUCT_COMMIT",
            "title": "Custody To Product",
            "type": "string"
          },
          "gl_node_id": {
            "examples": [
              "gl_product_tnt_beta_vault"
            ],
            "title": "Gl Node Id",
            "type": "string"
          },
          "product_to_custody": {
            "default": "PRODUCT_RELEASE",
            "title": "Product To Custody",
            "type": "string"
          },
          "product_to_product": {
            "default": "PRODUCT_INTERNAL",
            "title": "Product To Product",
            "type": "string"
          }
        },
        "required": [
          "gl_node_id"
        ],
        "title": "ProductAccounting",
        "type": "object"
      },
      "ProductActionRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/products/{product_id}/instances/{instance_id}/actions/{action}``.\n\nThe action is a **path segment**, never a body field: that is what makes one\nroute entry serve N actions at every edge surface.",
        "properties": {
          "account_id": {
            "description": "The account acting on the instance.",
            "title": "Account Id",
            "type": "string"
          },
          "params": {
            "additionalProperties": true,
            "title": "Params",
            "type": "object"
          }
        },
        "required": [
          "account_id"
        ],
        "title": "ProductActionRequest",
        "type": "object"
      },
      "ProductAttestation": {
        "description": "The human countersignature that gates LIVE (founder decision P6).\n\n⭐ Merged into the row's **existing** `certification` block rather than a field of\nits own — laas-74 D6 shaped it nullable from birth precisely so laas-86 writes\n*into* it instead of migrating it. One data shape, two eras: the certification step\nfills the machine half (hashes, the platform signature's fingerprint) and this fills\nthe human half, in the same write as the state.\n\n⛔ **`countersignature` cannot be produced by this service, and that asymmetry is\nthe gate.** The services hold `kms:GetPublicKey` on the countersign key and no\n`kms:Sign`; the signature is minted repo-side by\n`scripts/countersign-product-certification.py` under an IAM role a task role cannot\nassume. A gate the platform can forge is a field.",
        "properties": {
          "algorithm": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Declared signature algorithm; defaults to ECDSA_SHA_256",
            "title": "Algorithm"
          },
          "battery_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Retained for the pre-Foundry shape; see report_card_hash",
            "title": "Battery Version"
          },
          "countersignature": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "⟲ 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.",
            "title": "Countersignature"
          },
          "report_card_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Retained 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.",
            "title": "Report Card Hash"
          },
          "signed_by": {
            "description": "The 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.",
            "examples": [
              "arn:aws:iam::123456789012:role/quadra-sbx-product-countersigner"
            ],
            "title": "Signed By",
            "type": "string"
          },
          "signing_pubkey_fpr": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "sha256 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.",
            "title": "Signing Pubkey Fpr"
          }
        },
        "required": [
          "signed_by"
        ],
        "title": "ProductAttestation",
        "type": "object"
      },
      "ProductCloseRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/products/{product_id}/instances/{instance_id}/close``.\n\n``action`` may be omitted when the manifest declares exactly one close\naction; a product with several must name one, because guessing which\nterminal state to drive an instance into is not a default anything should\nhave.",
        "properties": {
          "account_id": {
            "description": "The account closing the instance.",
            "title": "Account Id",
            "type": "string"
          },
          "action": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Which declared close action to drive.",
            "title": "Action"
          },
          "params": {
            "additionalProperties": true,
            "title": "Params",
            "type": "object"
          }
        },
        "required": [
          "account_id"
        ],
        "title": "ProductCloseRequest",
        "type": "object"
      },
      "ProductInstanceCreateRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/products/{product_id}/instances``.\n\nThe manifest declares exactly one ``create`` action, so the body names no\naction — which is also why the route key needs no action segment.",
        "properties": {
          "account_id": {
            "description": "The custody account the instance's value comes from.",
            "title": "Account Id",
            "type": "string"
          },
          "params": {
            "additionalProperties": true,
            "description": "The create action's declared payload parameters, by name. One of them is the amount in centavos (the manifest's ``amount_from``).",
            "title": "Params",
            "type": "object"
          }
        },
        "required": [
          "account_id"
        ],
        "title": "ProductInstanceCreateRequest",
        "type": "object"
      },
      "ProductKeyEnrollRequest": {
        "additionalProperties": false,
        "description": "Enroll (or rotate) one tenant's bundle-signing public key.\n\n⛔ **Public key only, and the model cannot express a private one.** There is no\nfield a well-meaning caller could paste a private key into and no code path that\nwould know what to do with one — the same refusal-by-omission\n``product_signing`` uses to make ``sign(countersigner)`` inexpressible.",
        "properties": {
          "label": {
            "default": "",
            "description": "Free-text note for whoever reads the enrollment later — which of the tenant's systems holds the private half. Recorded, never interpreted.",
            "maxLength": 120,
            "title": "Label",
            "type": "string"
          },
          "public_key_pem": {
            "description": "PEM 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.",
            "examples": [
              "-----BEGIN PUBLIC KEY-----\nMFkwEw…\n-----END PUBLIC KEY-----\n"
            ],
            "title": "Public Key Pem",
            "type": "string"
          },
          "replace": {
            "default": false,
            "description": "Rotate: 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.",
            "title": "Replace",
            "type": "boolean"
          }
        },
        "required": [
          "public_key_pem"
        ],
        "title": "ProductKeyEnrollRequest",
        "type": "object"
      },
      "ProductKeyResponse": {
        "description": "One tenant's enrollment, as the operator surface shows it.",
        "properties": {
          "algorithm": {
            "default": "ECDSA_SHA_256",
            "title": "Algorithm",
            "type": "string"
          },
          "curve": {
            "default": "P-256",
            "title": "Curve",
            "type": "string"
          },
          "enrolled": {
            "default": true,
            "description": "False when the identical key was already active and nothing was written — the laas-67 `provisioned: false` shape, answered 200.",
            "title": "Enrolled",
            "type": "boolean"
          },
          "enrolled_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Enrolled At"
          },
          "enrolled_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Enrolled By"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "public_key_pem": {
            "title": "Public Key Pem",
            "type": "string"
          },
          "published_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the PEM is published in the certification store, so an auditor can check an authorship claim without platform access.",
            "title": "Published Key"
          },
          "signing_pubkey_fpr": {
            "description": "sha256 of the DER SubjectPublicKeyInfo — what a certification records.",
            "title": "Signing Pubkey Fpr",
            "type": "string"
          },
          "status": {
            "description": "ACTIVE | SUPERSEDED",
            "title": "Status",
            "type": "string"
          },
          "superseded": {
            "description": "Fingerprints of previously enrolled keys, newest first.",
            "items": {
              "type": "string"
            },
            "title": "Superseded",
            "type": "array"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          }
        },
        "required": [
          "tenant",
          "signing_pubkey_fpr",
          "public_key_pem",
          "status"
        ],
        "title": "ProductKeyResponse",
        "type": "object"
      },
      "ProductScriptRef": {
        "description": "Which script bytes this binding runs on. Exactly one of the two forms.\n\n⛔ **Bytes are never accepted over the wire, and that is the design (D1).**\nPre-Foundry there is no compile provenance and no adversarial battery, so an\nAPI that took a `cbor_hex` would be the thing laas-83..86 exist to gate. A\ntemplate is named instead, and the name resolves only inside\n`shared/script_params.PARAMETRIC_TEMPLATES` — an allowlist of git-reviewed\n`.plutus` artifacts that `validators.yml` compiled and byte-compared.\n\n* ``template`` — a parametric template. Its params are a property of the\n  compiled Haskell, so the allowlist carries them and the binding applies\n  them; a ``params`` echo here must agree or the bind is refused (D2).\n* ``catalog`` — a **platform catalog product** (LaaS-77): an incumbent\n  re-declared as a manifest. Address, script hash and bytes all come from the\n  static registry, because the product already exists at an address open\n  instances sit at. Deriving them would move it.",
        "properties": {
          "catalog": {
            "default": false,
            "description": "Bind an incumbent at its own unchanged static address (LaaS-77). Mutually exclusive with `template`.",
            "title": "Catalog",
            "type": "boolean"
          },
          "certification": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "⟲ 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.",
            "examples": [
              "9f2c…"
            ],
            "title": "Certification"
          },
          "params": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional 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.",
            "title": "Params"
          },
          "template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Parametric template name, from the shipped allowlist",
            "examples": [
              "tenant-vault"
            ],
            "title": "Template"
          }
        },
        "title": "ProductScriptRef",
        "type": "object"
      },
      "PromoteAccountRequest": {
        "additionalProperties": false,
        "description": "GUEST rows resolve the party from owner_party_id (a body party_id must\nmatch); EXTERNAL rows carry owner_party_id=None, so party_id is required.",
        "properties": {
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          },
          "party_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Party Id"
          }
        },
        "title": "PromoteAccountRequest",
        "type": "object"
      },
      "ProofBlock": {
        "additionalProperties": true,
        "description": "Evidence backing an operator resolve. ``kind`` names the source\n(e.g. ``sponsor_statement``), ``evidence_ids`` links any ``ev_*`` rows, and\n``rule`` records the disposition rule applied. Extra descriptive keys are\npreserved verbatim into ``resolution_metadata`` + the audit row.",
        "properties": {
          "evidence_ids": {
            "items": {
              "type": "string"
            },
            "title": "Evidence Ids",
            "type": "array"
          },
          "kind": {
            "minLength": 1,
            "title": "Kind",
            "type": "string"
          },
          "rule": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rule"
          }
        },
        "required": [
          "kind"
        ],
        "title": "ProofBlock",
        "type": "object"
      },
      "ProviderAccountAddress": {
        "description": "The address a processor's onboarding form requires.\n\nEvery field here is required by at least one processor and none of them has a\nsafe default — a postal code that cannot be resolved is a 400, not a guess.",
        "properties": {
          "complement": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Complement"
          },
          "number": {
            "examples": [
              "1000"
            ],
            "title": "Number",
            "type": "string"
          },
          "postal_code": {
            "examples": [
              "01310-100"
            ],
            "title": "Postal Code",
            "type": "string"
          },
          "province": {
            "description": "Neighbourhood / bairro",
            "examples": [
              "Bela Vista"
            ],
            "title": "Province",
            "type": "string"
          },
          "street": {
            "examples": [
              "Av Paulista"
            ],
            "title": "Street",
            "type": "string"
          }
        },
        "required": [
          "street",
          "number",
          "province",
          "postal_code"
        ],
        "title": "ProviderAccountAddress",
        "type": "object"
      },
      "ProviderAccountCredential": {
        "description": "⚠️ Returned exactly once, and never stored by the platform.\n\nA processor that mints an account credential at creation typically cannot show\nit again. It is handed over here so an operator can provision it into the\nsecret store out of band — the platform holds a *reference* and a status, not\nthe value. See the route's docstring.",
        "properties": {
          "secret_ref": {
            "description": "Where to provision it. The descriptor resolves the credential from this path.",
            "title": "Secret Ref",
            "type": "string"
          },
          "value": {
            "description": "The credential. Capture it now; it is not recoverable.",
            "title": "Value",
            "type": "string"
          }
        },
        "required": [
          "value",
          "secret_ref"
        ],
        "title": "ProviderAccountCredential",
        "type": "object"
      },
      "ProviderAccountListResponse": {
        "properties": {
          "accounts": {
            "items": {
              "$ref": "#/components/schemas/ProviderAccountResponse"
            },
            "title": "Accounts",
            "type": "array"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          }
        },
        "required": [
          "tenant"
        ],
        "title": "ProviderAccountListResponse",
        "type": "object"
      },
      "ProviderAccountRequest": {
        "description": "Open one account for this tenant at a processor.",
        "properties": {
          "address": {
            "$ref": "#/components/schemas/ProviderAccountAddress"
          },
          "company_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "MEI | LIMITED | INDIVIDUAL | ASSOCIATION",
            "examples": [
              "LIMITED"
            ],
            "title": "Company Type"
          },
          "email": {
            "examples": [
              "ops@acme.example"
            ],
            "title": "Email",
            "type": "string"
          },
          "income_value": {
            "description": "Declared monthly revenue. Required by the processor and deliberately not defaulted — a made-up figure on a regulated onboarding form is a false statement.",
            "examples": [
              50000
            ],
            "title": "Income Value",
            "type": "number"
          },
          "legal_name": {
            "examples": [
              "Acme Pagamentos LTDA"
            ],
            "title": "Legal Name",
            "type": "string"
          },
          "mobile_phone": {
            "examples": [
              "11999999999"
            ],
            "title": "Mobile Phone",
            "type": "string"
          },
          "provider_id": {
            "description": "The 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.",
            "examples": [
              "asaas"
            ],
            "title": "Provider Id",
            "type": "string"
          },
          "rail": {
            "default": "PIX",
            "description": "Rail family the provider serves.",
            "examples": [
              "PIX"
            ],
            "title": "Rail",
            "type": "string"
          },
          "tax_id": {
            "description": "CPF or CNPJ, digits only.",
            "examples": [
              "12345678000199"
            ],
            "title": "Tax Id",
            "type": "string"
          }
        },
        "required": [
          "provider_id",
          "legal_name",
          "tax_id",
          "email",
          "mobile_phone",
          "address",
          "income_value"
        ],
        "title": "ProviderAccountRequest",
        "type": "object"
      },
      "ProviderAccountResponse": {
        "properties": {
          "account_number": {
            "additionalProperties": true,
            "title": "Account Number",
            "type": "object"
          },
          "account_status": {
            "description": "The processor's own status. Rarely transactable immediately — a regulated onboarding evaluation typically follows.",
            "title": "Account Status",
            "type": "string"
          },
          "credential": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProviderAccountCredential"
              },
              {
                "type": "null"
              }
            ],
            "description": "Present ONLY on the call that opened the account."
          },
          "credential_ref": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Credential Ref"
          },
          "credential_status": {
            "description": "PENDING_PROVISION until an operator has stored the credential.",
            "title": "Credential Status",
            "type": "string"
          },
          "family": {
            "title": "Family",
            "type": "string"
          },
          "provider_account_id": {
            "title": "Provider Account Id",
            "type": "string"
          },
          "provider_id": {
            "title": "Provider Id",
            "type": "string"
          },
          "provisioned": {
            "description": "False when this call matched an account already recorded.",
            "title": "Provisioned",
            "type": "boolean"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          },
          "wallet_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Wallet Id"
          }
        },
        "required": [
          "tenant",
          "family",
          "provider_id",
          "provider_account_id",
          "account_status",
          "credential_status",
          "provisioned"
        ],
        "title": "ProviderAccountResponse",
        "type": "object"
      },
      "ProviderAccountTransferRequest": {
        "description": "Move value between two accounts inside one processor.",
        "properties": {
          "amount_cents": {
            "description": "Amount in centavos.",
            "exclusiveMinimum": 0,
            "title": "Amount Cents",
            "type": "integer"
          },
          "currency": {
            "default": "BRL",
            "title": "Currency",
            "type": "string"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "destination_wallet_id": {
            "description": "The destination account's wallet handle at the processor.",
            "title": "Destination Wallet Id",
            "type": "string"
          }
        },
        "required": [
          "destination_wallet_id",
          "amount_cents"
        ],
        "title": "ProviderAccountTransferRequest",
        "type": "object"
      },
      "ProviderAccountTransferResponse": {
        "properties": {
          "amount_cents": {
            "title": "Amount Cents",
            "type": "integer"
          },
          "authorized": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "False when the processor is holding the transfer for an out-of-band human approval. The value is queued either way — do not re-send.",
            "title": "Authorized"
          },
          "currency": {
            "title": "Currency",
            "type": "string"
          },
          "family": {
            "title": "Family",
            "type": "string"
          },
          "provider_id": {
            "title": "Provider Id",
            "type": "string"
          },
          "provider_transfer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Transfer Id"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          },
          "transfer_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Transfer Status"
          }
        },
        "required": [
          "tenant",
          "family",
          "provider_id",
          "amount_cents",
          "currency"
        ],
        "title": "ProviderAccountTransferResponse",
        "type": "object"
      },
      "ProviderRoute": {
        "description": "One `(rail, provider)` → tenant inbound routing binding.",
        "properties": {
          "bound_in_process": {
            "default": false,
            "description": "Whether this deployment currently has a binding for the provider. False is legal: a route may be recorded before the driver ships.",
            "title": "Bound In Process",
            "type": "boolean"
          },
          "caller_less_inbound": {
            "default": false,
            "description": "Whether 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.",
            "title": "Caller Less Inbound",
            "type": "boolean"
          },
          "family": {
            "description": "Rail family, upper-cased.",
            "title": "Family",
            "type": "string"
          },
          "kind": {
            "default": "rail",
            "description": "`rail` for a money rail, `kyc` otherwise.",
            "title": "Kind",
            "type": "string"
          },
          "provider_id": {
            "description": "The provider instance id.",
            "title": "Provider Id",
            "type": "string"
          },
          "provisioned": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when this call created the binding, false when it already existed with the same owner. Absent on reads.",
            "title": "Provisioned"
          },
          "status": {
            "default": "ACTIVE",
            "description": "ACTIVE while the route resolves.",
            "title": "Status",
            "type": "string"
          },
          "tenant": {
            "description": "The tenant whose ledger these credits belong to.",
            "title": "Tenant",
            "type": "string"
          }
        },
        "required": [
          "tenant",
          "family",
          "provider_id"
        ],
        "title": "ProviderRoute",
        "type": "object"
      },
      "ProviderRouteListResponse": {
        "description": "Every inbound route one tenant owns.",
        "properties": {
          "routes": {
            "items": {
              "$ref": "#/components/schemas/ProviderRoute"
            },
            "title": "Routes",
            "type": "array"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          }
        },
        "required": [
          "tenant"
        ],
        "title": "ProviderRouteListResponse",
        "type": "object"
      },
      "ProviderRouteRequest": {
        "description": "Which provider connection an operator is assigning to a tenant.",
        "properties": {
          "provider_id": {
            "description": "The 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.",
            "examples": [
              "celcoin-beta"
            ],
            "title": "Provider Id",
            "type": "string"
          },
          "rail": {
            "description": "Rail family the provider serves — `PIX`, `ACH`, `MOCK`, or `KYC` for the identity-verification namespace. Case-insensitive.",
            "examples": [
              "PIX"
            ],
            "title": "Rail",
            "type": "string"
          }
        },
        "required": [
          "rail",
          "provider_id"
        ],
        "title": "ProviderRouteRequest",
        "type": "object"
      },
      "PutPixLimitsRequest": {
        "properties": {
          "actor": {
            "anyOf": [
              {
                "maxLength": 256,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Caller identity (caller-injected until laas-23 authz lands)",
            "title": "Actor"
          },
          "daily_limit_minor": {
            "anyOf": [
              {
                "exclusiveMinimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Daytime cumulative Pix limit, integer centavos",
            "title": "Daily Limit Minor"
          },
          "nighttime_limit_minor": {
            "anyOf": [
              {
                "exclusiveMinimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Nighttime cumulative Pix limit, integer centavos",
            "title": "Nighttime Limit Minor"
          },
          "nighttime_start": {
            "anyOf": [
              {
                "enum": [
                  "20:00",
                  "22:00"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Nighttime window start (Res. BCB 142/2021: 20:00 default, 22:00 opt-in)",
            "title": "Nighttime Start"
          }
        },
        "title": "PutPixLimitsRequest",
        "type": "object"
      },
      "RailFamily": {
        "enum": [
          "QUADRA",
          "ACH",
          "MOCK",
          "PIX"
        ],
        "title": "RailFamily",
        "type": "string"
      },
      "ReconRunRequest": {
        "properties": {
          "business_day": {
            "anyOf": [
              {
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Only meaningful for daily_proof",
            "title": "Business Day"
          },
          "kind": {
            "description": "\"cycle\" or \"daily_proof\"",
            "title": "Kind",
            "type": "string"
          },
          "provider": {
            "anyOf": [
              {
                "maxLength": 32,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reconcile only this provider_id (default: every bound provider)",
            "title": "Provider"
          },
          "sponsor_account": {
            "anyOf": [
              {
                "maxLength": 64,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reconcile only this sponsor account (requires provider)",
            "title": "Sponsor Account"
          }
        },
        "required": [
          "kind"
        ],
        "title": "ReconRunRequest",
        "type": "object"
      },
      "RecurrenceBlock": {
        "additionalProperties": false,
        "description": "The active recurrence config echoed on writes/reads (``null`` when disabled).",
        "properties": {
          "billing_day": {
            "title": "Billing Day",
            "type": "integer"
          },
          "current_period": {
            "title": "Current Period",
            "type": "string"
          },
          "timezone": {
            "title": "Timezone",
            "type": "string"
          }
        },
        "required": [
          "billing_day",
          "timezone",
          "current_period"
        ],
        "title": "RecurrenceBlock",
        "type": "object"
      },
      "RecurrenceRequest": {
        "additionalProperties": false,
        "description": "``PUT /v1/squads/{sqd_id}/recurrence`` — OWNER enables/edits/disables monthly\ncycles. ``billing_day`` is the dia de fechamento (1–28; ``null`` disables recurrence);\nvalidated in the handler so a bad value surfaces as a discrete ``400\nINVALID_BILLING_DAY`` rather than a generic Pydantic 422. ``timezone`` is the IANA\nzone the billing day is evaluated in (billing fires at 00:00 local).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "billing_day": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Billing Day"
          },
          "timezone": {
            "default": "America/Sao_Paulo",
            "title": "Timezone",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "RecurrenceRequest",
        "type": "object"
      },
      "RecurrenceResponse": {
        "additionalProperties": false,
        "description": "200 body for ``PUT …/recurrence``. ``recurrence`` is ``null`` when the call\ndisabled cycles (``billing_day: null``).",
        "properties": {
          "recurrence": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RecurrenceBlock"
              },
              {
                "type": "null"
              }
            ]
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "updated_at": {
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "updated_at"
        ],
        "title": "RecurrenceResponse",
        "type": "object"
      },
      "RecurrenceRule": {
        "properties": {
          "by_day": {
            "anyOf": [
              {
                "items": {
                  "enum": [
                    "MO",
                    "TU",
                    "WE",
                    "TH",
                    "FR",
                    "SA",
                    "SU"
                  ],
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "WEEKLY only; defaults to the anchor's weekday",
            "title": "By Day"
          },
          "count": {
            "anyOf": [
              {
                "minimum": 1,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Count"
          },
          "day_of_month": {
            "anyOf": [
              {
                "maximum": 31,
                "minimum": 1,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "MONTHLY only; end-of-month clamp applies",
            "title": "Day Of Month"
          },
          "frequency": {
            "enum": [
              "DAILY",
              "WEEKLY",
              "MONTHLY",
              "YEARLY"
            ],
            "title": "Frequency",
            "type": "string"
          },
          "interval": {
            "default": 1,
            "maximum": 366,
            "minimum": 1,
            "title": "Interval",
            "type": "integer"
          },
          "until": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Inclusive ISO-8601 UTC instant; mutually exclusive with count",
            "title": "Until"
          }
        },
        "required": [
          "frequency"
        ],
        "title": "RecurrenceRule",
        "type": "object"
      },
      "RecurringExpenseDeleteRequest": {
        "additionalProperties": false,
        "description": "``DELETE /v1/squads/{sqd_id}/recurring-expenses/{rex_id}`` body — OWNER-only.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "RecurringExpenseDeleteRequest",
        "type": "object"
      },
      "RecurringExpenseDeleteResponse": {
        "additionalProperties": false,
        "description": "200 body for ``DELETE …/recurring-expenses/{rex_id}`` — future postings stop;\nalready-posted expenses are unaffected.",
        "properties": {
          "deleted": {
            "default": true,
            "title": "Deleted",
            "type": "boolean"
          },
          "rex_id": {
            "title": "Rex Id",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "rex_id"
        ],
        "title": "RecurringExpenseDeleteResponse",
        "type": "object"
      },
      "RecurringExpensePatchRequest": {
        "additionalProperties": false,
        "description": "``PATCH /v1/squads/{sqd_id}/recurring-expenses/{rex_id}`` — edit a conta.\n\nPartial update: only the fields present change (the route dumps with\n``exclude_unset=True``). Future cycle posts use the new values; already-posted\nexpenses are ordinary entries and stay.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "amount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SquadAmount"
              },
              {
                "type": "null"
              }
            ]
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "payer_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Payer Account Id"
          },
          "split": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SplitSpec"
              },
              {
                "type": "null"
              }
            ]
          },
          "variable": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Variable"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "RecurringExpensePatchRequest",
        "type": "object"
      },
      "RecurringExpenseRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/recurring-expenses`` — create a conta (bill template).\n\n``amount`` is the fixed charge (centavos) for ``variable=False``, or an estimate for\n``variable=True`` (the real value is set each cycle via ``/confirm``). ``payer_account_id``\nis who pays the provider (the expense's creditor when it posts). ``split`` is the same\nsealed split as a contribution (EQUAL / SHARES / AMOUNTS).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "payer_account_id": {
            "title": "Payer Account Id",
            "type": "string"
          },
          "split": {
            "$ref": "#/components/schemas/SplitSpec"
          },
          "variable": {
            "default": false,
            "title": "Variable",
            "type": "boolean"
          }
        },
        "required": [
          "actor_account_id",
          "description",
          "amount",
          "payer_account_id",
          "split"
        ],
        "title": "RecurringExpenseRequest",
        "type": "object"
      },
      "RecurringExpenseResponse": {
        "additionalProperties": false,
        "description": "201 body for create (and 200 for PATCH) of a recurring-expense.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "payer_account_id": {
            "title": "Payer Account Id",
            "type": "string"
          },
          "rex_id": {
            "title": "Rex Id",
            "type": "string"
          },
          "split": {
            "$ref": "#/components/schemas/SplitSpec"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "state": {
            "default": "ACTIVE",
            "title": "State",
            "type": "string"
          },
          "updated_at": {
            "title": "Updated At",
            "type": "string"
          },
          "variable": {
            "title": "Variable",
            "type": "boolean"
          }
        },
        "required": [
          "rex_id",
          "sqd_id",
          "description",
          "amount",
          "variable",
          "payer_account_id",
          "split",
          "created_at",
          "updated_at"
        ],
        "title": "RecurringExpenseResponse",
        "type": "object"
      },
      "ReleaseBlockRequest": {
        "properties": {
          "actor": {
            "maxLength": 256,
            "minLength": 1,
            "title": "Actor",
            "type": "string"
          },
          "case_ref": {
            "anyOf": [
              {
                "maxLength": 256,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Audit cross-reference only",
            "title": "Case Ref"
          },
          "reason": {
            "anyOf": [
              {
                "maxLength": 256,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason"
          }
        },
        "required": [
          "actor"
        ],
        "title": "ReleaseBlockRequest",
        "type": "object"
      },
      "ReleaseHoldRequest": {
        "properties": {
          "reason": {
            "anyOf": [
              {
                "maxLength": 256,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason"
          }
        },
        "title": "ReleaseHoldRequest",
        "type": "object"
      },
      "RemoveMemberRequest": {
        "additionalProperties": false,
        "description": "``DELETE /v1/squads/{sqd_id}/members/{member_account_id}`` (SQ-10).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "RemoveMemberRequest",
        "type": "object"
      },
      "RescreenSweepRequest": {
        "additionalProperties": false,
        "description": "Optional body for the internal re-screen sweep trigger (D5).",
        "properties": {
          "limit": {
            "default": 100,
            "maximum": 1000,
            "minimum": 1,
            "title": "Limit",
            "type": "integer"
          }
        },
        "title": "RescreenSweepRequest",
        "type": "object"
      },
      "RetryPolicy": {
        "description": "Local self-retry for generic schedules only (D7) — mandate charge\nretentativa is rail-side and never configured here.",
        "properties": {
          "max_attempts": {
            "maximum": 10,
            "minimum": 1,
            "title": "Max Attempts",
            "type": "integer"
          },
          "retry_interval_seconds": {
            "maximum": 86400,
            "minimum": 1,
            "title": "Retry Interval Seconds",
            "type": "integer"
          }
        },
        "required": [
          "max_attempts",
          "retry_interval_seconds"
        ],
        "title": "RetryPolicy",
        "type": "object"
      },
      "RevokeInviteRequest": {
        "additionalProperties": false,
        "description": "``DELETE /v1/squads/{sqd_id}/invitations/{invitee_account_id}`` — OWNER revokes.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "RevokeInviteRequest",
        "type": "object"
      },
      "RiskFlagCreateRequest": {
        "additionalProperties": false,
        "properties": {
          "reason": {
            "minLength": 1,
            "title": "Reason",
            "type": "string"
          },
          "source_ref": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Ref"
          }
        },
        "required": [
          "reason"
        ],
        "title": "RiskFlagCreateRequest",
        "type": "object"
      },
      "ScheduleAction": {
        "description": "Closed enum with one value — extensible without a DSL (Tier-4).",
        "properties": {
          "action_type": {
            "const": "CREATE_OBLIGATION",
            "title": "Action Type",
            "type": "string"
          },
          "amount_cents": {
            "exclusiveMinimum": 0,
            "title": "Amount Cents",
            "type": "integer"
          },
          "creditor": {
            "$ref": "#/components/schemas/ScheduleActionParty"
          },
          "currency": {
            "const": "BRL",
            "default": "BRL",
            "title": "Currency",
            "type": "string"
          },
          "debtor_account_id": {
            "minLength": 1,
            "title": "Debtor Account Id",
            "type": "string"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 140,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "rail": {
            "enum": [
              "QUADRA",
              "ACH",
              "MOCK",
              "PIX"
            ],
            "title": "Rail",
            "type": "string"
          }
        },
        "required": [
          "action_type",
          "rail",
          "debtor_account_id",
          "creditor",
          "amount_cents"
        ],
        "title": "ScheduleAction",
        "type": "object"
      },
      "ScheduleActionParty": {
        "properties": {
          "account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Account Id"
          },
          "external_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "External Id"
          },
          "kind": {
            "enum": [
              "account",
              "external"
            ],
            "title": "Kind",
            "type": "string"
          }
        },
        "required": [
          "kind"
        ],
        "title": "ScheduleActionParty",
        "type": "object"
      },
      "SettleRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/settle`` — per-debtor **self**-settle (SQ-13,\namending SQ-17). The caller discharges the shares where THEY are the debtor,\npaying each creditor from their own BancoBRL custody; the matching share vQBRL\nburns. Witness set collapses to the caller — one API call can only ever move\nthe caller's own funds (the SquadValidator's ``SettleShare`` enforces it).\n``entry_seq`` optionally narrows settlement to a single expense; omitted means\nevery OPEN share where the caller is the debtor.",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          },
          "entry_seq": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Entry Seq"
          }
        },
        "required": [
          "caller_account_id"
        ],
        "title": "SettleRequest",
        "type": "object"
      },
      "SpendApprovalPolicy": {
        "additionalProperties": false,
        "description": "The spend-approval policy body. ``threshold_amount`` gates spends *above* it;\n``approvals_required`` is the number of distinct approvers (the requester does not\ncount); ``approvers`` selects the eligible set. Values are validated in the handler so\na bad value surfaces as a discrete ``400 INVALID_THRESHOLD`` / ``INVALID_APPROVALS_REQUIRED``\n/ ``INVALID_APPROVERS`` rather than a generic Pydantic 422.",
        "properties": {
          "approvals_required": {
            "title": "Approvals Required",
            "type": "integer"
          },
          "approvers": {
            "default": "OWNERS",
            "title": "Approvers",
            "type": "string"
          },
          "threshold_amount": {
            "$ref": "#/components/schemas/SquadAmount"
          }
        },
        "required": [
          "threshold_amount",
          "approvals_required"
        ],
        "title": "SpendApprovalPolicy",
        "type": "object"
      },
      "SpendRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/spends`` — pay from squad funds (SQ-12, B-SQ-07).\n``actor_account_id`` is the OWNER/SPENDER moving the funds. Exactly one destination:\n``recipient_account_id`` (an existing account that receives QBRL at BancoBRL custody,\nmust not be the squad itself) **or** ``pix_destination`` (an external Pix key — the\npool's QBRL bridges to the deferred Pix rail). ``metadata`` is free-form and copied\nonto the spend obligation. The amount is centavos (1 QBRL = 1 centavo).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          },
          "pix_destination": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PixDestination"
              },
              {
                "type": "null"
              }
            ]
          },
          "recipient_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recipient Account Id"
          }
        },
        "required": [
          "actor_account_id",
          "amount"
        ],
        "title": "SpendRequest",
        "type": "object"
      },
      "SpendRequestApprovalEntry": {
        "additionalProperties": false,
        "properties": {
          "account_id": {
            "title": "Account Id",
            "type": "string"
          },
          "approved_at": {
            "title": "Approved At",
            "type": "string"
          }
        },
        "required": [
          "account_id",
          "approved_at"
        ],
        "title": "SpendRequestApprovalEntry",
        "type": "object"
      },
      "SpendRequestApproveRequest": {
        "additionalProperties": false,
        "description": "Body for ``POST …/spend-requests/{spr_id}/approve``. The caller identity is injected\nby the BFF/gateway from the authenticated principal.",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          }
        },
        "required": [
          "caller_account_id"
        ],
        "title": "SpendRequestApproveRequest",
        "type": "object"
      },
      "SpendRequestPendingResponse": {
        "additionalProperties": false,
        "description": "The PENDING_APPROVAL body: 202 on a gated spend-create, 200 on a recorded (non-final)\napproval. The executed (final) approval instead returns a ``SquadSpendResponse`` (201).",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "approvals": {
            "items": {
              "$ref": "#/components/schemas/SpendRequestApprovalEntry"
            },
            "title": "Approvals",
            "type": "array"
          },
          "approvals_required": {
            "title": "Approvals Required",
            "type": "integer"
          },
          "expires_at": {
            "title": "Expires At",
            "type": "string"
          },
          "recipient_account_id": {
            "title": "Recipient Account Id",
            "type": "string"
          },
          "requested_by": {
            "title": "Requested By",
            "type": "string"
          },
          "spend_request_id": {
            "title": "Spend Request Id",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "state": {
            "title": "State",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "spend_request_id",
          "state",
          "requested_by",
          "recipient_account_id",
          "amount",
          "approvals_required",
          "expires_at"
        ],
        "title": "SpendRequestPendingResponse",
        "type": "object"
      },
      "SpendRequestRejectRequest": {
        "additionalProperties": false,
        "description": "Body for ``POST …/spend-requests/{spr_id}/reject`` (optional human-readable reason).",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason"
          }
        },
        "required": [
          "caller_account_id"
        ],
        "title": "SpendRequestRejectRequest",
        "type": "object"
      },
      "SpendRequestRejectResponse": {
        "additionalProperties": false,
        "description": "200 body for ``POST …/spend-requests/{spr_id}/reject``.",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "approvals": {
            "items": {
              "$ref": "#/components/schemas/SpendRequestApprovalEntry"
            },
            "title": "Approvals",
            "type": "array"
          },
          "approvals_required": {
            "title": "Approvals Required",
            "type": "integer"
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason"
          },
          "recipient_account_id": {
            "title": "Recipient Account Id",
            "type": "string"
          },
          "rejected_by": {
            "title": "Rejected By",
            "type": "string"
          },
          "requested_by": {
            "title": "Requested By",
            "type": "string"
          },
          "spend_request_id": {
            "title": "Spend Request Id",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "state": {
            "title": "State",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "spend_request_id",
          "state",
          "rejected_by",
          "requested_by",
          "recipient_account_id",
          "amount",
          "approvals_required"
        ],
        "title": "SpendRequestRejectResponse",
        "type": "object"
      },
      "SplitSpec": {
        "additionalProperties": false,
        "description": "Allocation for an ACCOUNTING contribution. ``entries`` maps member account id ->\nrelative weight (SHARES) or exact cents (AMOUNTS); omitted/ignored for EQUAL.",
        "properties": {
          "entries": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "integer"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Entries"
          },
          "kind": {
            "enum": [
              "EQUAL",
              "SHARES",
              "AMOUNTS"
            ],
            "title": "Kind",
            "type": "string"
          }
        },
        "required": [
          "kind"
        ],
        "title": "SplitSpec",
        "type": "object"
      },
      "SquadAmount": {
        "additionalProperties": false,
        "properties": {
          "currency": {
            "title": "Currency",
            "type": "string"
          },
          "value": {
            "description": "Amount in centavos (1 QBRL = 1 centavo).",
            "title": "Value",
            "type": "integer"
          }
        },
        "required": [
          "currency",
          "value"
        ],
        "title": "SquadAmount",
        "type": "object"
      },
      "SquadBatchInviteResponse": {
        "additionalProperties": false,
        "description": "201 body for ``POST /v1/squads/{sqd_id}/invitations`` (batch, partial-success).\n\nNo ``tx_id``: an invite is a projection-only consent record, not a Cardano tx. Each\ninvitee's fate is in ``results``; ``summary`` is the per-status tally. A 201 here\nmeans the request was processed — inspect ``summary``/``results`` for what changed.",
        "properties": {
          "inviter_account_id": {
            "title": "Inviter Account Id",
            "type": "string"
          },
          "results": {
            "items": {
              "$ref": "#/components/schemas/SquadInviteResultEntry"
            },
            "title": "Results",
            "type": "array"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "summary": {
            "$ref": "#/components/schemas/SquadInviteSummary"
          }
        },
        "required": [
          "sqd_id",
          "inviter_account_id",
          "results",
          "summary"
        ],
        "title": "SquadBatchInviteResponse",
        "type": "object"
      },
      "SquadCloseFinalBalance": {
        "additionalProperties": false,
        "description": "The squad's residual pooled balance at close — always zero (the close\nprecondition requires every Balance UTxO drained).",
        "properties": {
          "currency": {
            "default": "BRL",
            "title": "Currency",
            "type": "string"
          },
          "value": {
            "default": 0,
            "title": "Value",
            "type": "integer"
          }
        },
        "title": "SquadCloseFinalBalance",
        "type": "object"
      },
      "SquadCloseResponse": {
        "additionalProperties": false,
        "description": "201 body for ``POST /v1/squads/{sqd_id}/close`` (RFC-018 §5.1, SQ-14).\n\nThe terminal lifecycle event: the tx consumes the OPEN Config UTxO and\nrecreates it with ``state=\"CLOSED\"``. After close every write referencing the\nConfig fails the validator's ``configIsOpen`` check (SI-7); reads continue\nindefinitely. ``closed_at`` is the server timestamp; ``final_member_count`` is\nthe preserved roster size; ``final_balance`` is always zero by precondition.",
        "properties": {
          "closed_at": {
            "title": "Closed At",
            "type": "string"
          },
          "closed_by": {
            "title": "Closed By",
            "type": "string"
          },
          "final_balance": {
            "$ref": "#/components/schemas/SquadCloseFinalBalance"
          },
          "final_member_count": {
            "title": "Final Member Count",
            "type": "integer"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "state": {
            "default": "CLOSED",
            "title": "State",
            "type": "string"
          },
          "tx_id": {
            "title": "Tx Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "tx_id",
          "closed_at",
          "closed_by",
          "final_member_count",
          "final_balance"
        ],
        "title": "SquadCloseResponse",
        "type": "object"
      },
      "SquadCreateRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads`` — the creator becomes the first OWNER member.\n\n``name`` is the only required display field; everything else lives under the\noptional ``metadata`` object (description, emoji, image_url, location).\n``invitee_account_ids`` is **optional**: omit it to create a bare squad, or pass a\nlist to create + invite in one atomic call. Every invitee is validated *before* the\nirreversible create tx, so a single bad invitee fails the whole request with nothing\ncreated on-chain. Invitees enter the on-chain roster only when they accept.",
        "properties": {
          "creator_account_id": {
            "title": "Creator Account Id",
            "type": "string"
          },
          "invitee_account_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "maxItems": 50,
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Invitee Account Ids"
          },
          "metadata": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SquadMetadata"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "creator_account_id",
          "name"
        ],
        "title": "SquadCreateRequest",
        "type": "object"
      },
      "SquadDebtResolution": {
        "additionalProperties": false,
        "description": "What member removal did to the leaver's open accounting debts.\n\nEvery entry the leaver owed on is redistributed proportionally across that entry's\nremaining members (no write-offs; \"creditor absorbs\" is just the degenerate\nlast-member case). ``entries_skipped`` carries any entry a transient error left\nuntouched (``RESPLIT_FAILED``) — the member is still removed, retry re-runs them.",
        "properties": {
          "entries_redistributed": {
            "items": {
              "$ref": "#/components/schemas/SquadEntryRedistribution"
            },
            "title": "Entries Redistributed",
            "type": "array"
          },
          "entries_skipped": {
            "items": {
              "$ref": "#/components/schemas/SquadResplitSkip"
            },
            "title": "Entries Skipped",
            "type": "array"
          },
          "reissue_tx_ids": {
            "items": {
              "type": "string"
            },
            "title": "Reissue Tx Ids",
            "type": "array"
          },
          "void_tx_ids": {
            "items": {
              "type": "string"
            },
            "title": "Void Tx Ids",
            "type": "array"
          },
          "vqbrl_burned": {
            "default": 0,
            "title": "Vqbrl Burned",
            "type": "integer"
          },
          "vqbrl_minted": {
            "default": 0,
            "title": "Vqbrl Minted",
            "type": "integer"
          }
        },
        "title": "SquadDebtResolution",
        "type": "object"
      },
      "SquadEntryRedistribution": {
        "additionalProperties": false,
        "description": "How one accounting entry absorbed a removed debtor's share.",
        "properties": {
          "creditor_pkh": {
            "title": "Creditor Pkh",
            "type": "string"
          },
          "deltas": {
            "items": {
              "$ref": "#/components/schemas/SquadRedistributionDelta"
            },
            "title": "Deltas",
            "type": "array"
          },
          "entry_seq": {
            "title": "Entry Seq",
            "type": "integer"
          },
          "leaver_share_cents": {
            "title": "Leaver Share Cents",
            "type": "integer"
          }
        },
        "required": [
          "entry_seq",
          "creditor_pkh",
          "leaver_share_cents"
        ],
        "title": "SquadEntryRedistribution",
        "type": "object"
      },
      "SquadEntrySplitOverrideResponse": {
        "additionalProperties": false,
        "description": "200 body for the per-entry split override (RFC-018).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "entry_seq": {
            "title": "Entry Seq",
            "type": "integer"
          },
          "open_amount_cents": {
            "title": "Open Amount Cents",
            "type": "integer"
          },
          "shares": {
            "items": {
              "$ref": "#/components/schemas/SquadShareEntry"
            },
            "title": "Shares",
            "type": "array"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "tx_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tx Id"
          }
        },
        "required": [
          "sqd_id",
          "entry_seq",
          "actor_account_id",
          "open_amount_cents"
        ],
        "title": "SquadEntrySplitOverrideResponse",
        "type": "object"
      },
      "SquadFreezeRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/freeze`` and ``.../unfreeze`` — an OWNER toggles the\nsquad's reversible wind-down state. Off-chain only (no Cardano tx): while frozen,\ndeposits/spends/accounting and all roster changes are rejected (422 SQUAD_FROZEN);\nsettlement, close, decline-invite, and metadata edits still work. Freezing is a\nprerequisite for ``simplify-debts``.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "SquadFreezeRequest",
        "type": "object"
      },
      "SquadFreezeResponse": {
        "additionalProperties": false,
        "description": "200 body for freeze/unfreeze. ``frozen`` is the resulting state; ``changed`` is\nfalse when the squad was already in that state (idempotent no-op). ``simplified`` is\nthe sticky historical marker (true once the squad has ever been simplified) and is\nsurfaced here for convenience — unfreeze never clears it.",
        "properties": {
          "changed": {
            "title": "Changed",
            "type": "boolean"
          },
          "frozen": {
            "title": "Frozen",
            "type": "boolean"
          },
          "simplified": {
            "default": false,
            "title": "Simplified",
            "type": "boolean"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "updated_at": {
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "frozen",
          "changed",
          "updated_at"
        ],
        "title": "SquadFreezeResponse",
        "type": "object"
      },
      "SquadGoalBlock": {
        "additionalProperties": false,
        "description": "The server-computed goal state echoed on writes and reads (the ``goal`` block).\n\n``funded_cents`` is the live pool balance (FUNDED in − spends − reclaims);\n``progress`` is ``funded_cents / target_amount.value`` clamped to ``[0, 1]``;\n``achieved_at`` is sticky — set the first moment the pool reaches the target and kept\neven if the balance later dips.",
        "properties": {
          "achieved_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Achieved At"
          },
          "funded_cents": {
            "title": "Funded Cents",
            "type": "integer"
          },
          "progress": {
            "title": "Progress",
            "type": "number"
          },
          "target_amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "target_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Target Date"
          }
        },
        "required": [
          "target_amount",
          "funded_cents",
          "progress"
        ],
        "title": "SquadGoalBlock",
        "type": "object"
      },
      "SquadGoalDeleteRequest": {
        "additionalProperties": false,
        "description": "``DELETE /v1/squads/{sqd_id}/goal`` — an OWNER removes the goal. Only the actor is\nneeded (there is no goal body to clear beyond the row attributes).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "SquadGoalDeleteRequest",
        "type": "object"
      },
      "SquadGoalDeleteResponse": {
        "additionalProperties": false,
        "description": "200 body for ``DELETE /v1/squads/{sqd_id}/goal`` — ``goal`` is always ``null``.",
        "properties": {
          "goal": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SquadGoalBlock"
              },
              {
                "type": "null"
              }
            ]
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id"
        ],
        "title": "SquadGoalDeleteResponse",
        "type": "object"
      },
      "SquadGoalRequest": {
        "additionalProperties": false,
        "description": "``PUT /v1/squads/{sqd_id}/goal`` — an OWNER sets or edits the savings goal.\n\nOff-chain projection only (no Cardano tx) — the goal constrains nothing, it only\nmeasures. ``target_amount`` is the finish line (BRL, centavos); ``target_date`` is\nan optional ``YYYY-MM-DD`` deadline. Both are validated in the handler so a bad value\nsurfaces as a discrete ``400 INVALID_GOAL_AMOUNT`` / ``INVALID_GOAL_DATE`` rather than\na generic Pydantic 422.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "target_amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "target_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Target Date"
          }
        },
        "required": [
          "actor_account_id",
          "target_amount"
        ],
        "title": "SquadGoalRequest",
        "type": "object"
      },
      "SquadGoalResponse": {
        "additionalProperties": false,
        "description": "200 body for ``PUT /v1/squads/{sqd_id}/goal``.",
        "properties": {
          "goal": {
            "$ref": "#/components/schemas/SquadGoalBlock"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "updated_at": {
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "goal",
          "updated_at"
        ],
        "title": "SquadGoalResponse",
        "type": "object"
      },
      "SquadInviteAcceptResponse": {
        "additionalProperties": false,
        "description": "201 body for ``POST /v1/squads/{sqd_id}/invitations/accept``.\n\nThe accept runs the on-chain ChangeMembership, so it carries ``tx_id`` and the\nnew roster. ``acted_by_owner_account_id`` is the current OWNER that custodially\nauthored the add (the invitee is not an OWNER, so cannot sign it themselves).\n``quota`` is the accepted member's cota count; ``retroactive`` reports how the\nopen prior expenses were re-split to include them (RFC-018).",
        "properties": {
          "acted_by_owner_account_id": {
            "title": "Acted By Owner Account Id",
            "type": "string"
          },
          "config_utxo_ref": {
            "title": "Config Utxo Ref",
            "type": "string"
          },
          "invitee_account_id": {
            "title": "Invitee Account Id",
            "type": "string"
          },
          "invitee_pkh": {
            "title": "Invitee Pkh",
            "type": "string"
          },
          "joined_at": {
            "title": "Joined At",
            "type": "string"
          },
          "member_count": {
            "title": "Member Count",
            "type": "integer"
          },
          "members": {
            "items": {
              "$ref": "#/components/schemas/SquadMemberRosterEntry"
            },
            "title": "Members",
            "type": "array"
          },
          "quota": {
            "default": 1,
            "title": "Quota",
            "type": "integer"
          },
          "retroactive": {
            "$ref": "#/components/schemas/SquadResplitReport"
          },
          "role": {
            "title": "Role",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "tx_id": {
            "title": "Tx Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "tx_id",
          "config_utxo_ref",
          "invitee_account_id",
          "invitee_pkh",
          "role",
          "joined_at",
          "acted_by_owner_account_id",
          "members",
          "member_count"
        ],
        "title": "SquadInviteAcceptResponse",
        "type": "object"
      },
      "SquadInviteActionResponse": {
        "additionalProperties": false,
        "description": "200 body for revoke / decline — the invite's new terminal ``state``.",
        "properties": {
          "invitee_account_id": {
            "title": "Invitee Account Id",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "state": {
            "title": "State",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "invitee_account_id",
          "state"
        ],
        "title": "SquadInviteActionResponse",
        "type": "object"
      },
      "SquadInviteResultEntry": {
        "additionalProperties": false,
        "description": "One invitee's outcome in a batch-invite report.\n\n``status`` is ``invited`` (a PENDING row was written), ``skipped`` (a benign\nno-op: self / already a member / already pending / duplicated in the request), or\n``failed`` (the invitee account does not exist or is itself a SQUAD account).\n``reason`` is the machine code (``OK``, ``CANNOT_INVITE_SELF``, ``ALREADY_A_MEMBER``,\n``INVITE_ALREADY_PENDING``, ``DUPLICATE_IN_REQUEST``, ``ACCOUNT_NOT_FOUND``,\n``SQUAD_AS_SQUAD_MEMBER_FORBIDDEN``). ``invitee_pkh``/``created_at`` are present only\nwhen the invitee resolved / was written.",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "invitee_account_id": {
            "title": "Invitee Account Id",
            "type": "string"
          },
          "invitee_pkh": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Invitee Pkh"
          },
          "reason": {
            "title": "Reason",
            "type": "string"
          },
          "state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "State"
          },
          "status": {
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "invitee_account_id",
          "status",
          "reason"
        ],
        "title": "SquadInviteResultEntry",
        "type": "object"
      },
      "SquadInviteSummary": {
        "additionalProperties": false,
        "properties": {
          "failed": {
            "title": "Failed",
            "type": "integer"
          },
          "invited": {
            "title": "Invited",
            "type": "integer"
          },
          "skipped": {
            "title": "Skipped",
            "type": "integer"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "invited",
          "skipped",
          "failed",
          "total"
        ],
        "title": "SquadInviteSummary",
        "type": "object"
      },
      "SquadLocation": {
        "additionalProperties": false,
        "description": "A map pin for a squad (both coordinates required together). Ranges are checked\nin the handler so the error surfaces as a discrete ``INVALID_LOCATION`` (400), not a\ngeneric Pydantic 422.",
        "properties": {
          "latitude": {
            "title": "Latitude",
            "type": "number"
          },
          "longitude": {
            "title": "Longitude",
            "type": "number"
          }
        },
        "required": [
          "latitude",
          "longitude"
        ],
        "title": "SquadLocation",
        "type": "object"
      },
      "SquadMemberQuotaResponse": {
        "additionalProperties": false,
        "description": "200 body for the quota edit. ``retroactive`` reports the re-split of open\nEQUAL entries under the new quota.",
        "properties": {
          "member_account_id": {
            "title": "Member Account Id",
            "type": "string"
          },
          "member_pkh": {
            "title": "Member Pkh",
            "type": "string"
          },
          "quota": {
            "title": "Quota",
            "type": "integer"
          },
          "retroactive": {
            "$ref": "#/components/schemas/SquadResplitReport"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "member_account_id",
          "member_pkh",
          "quota"
        ],
        "title": "SquadMemberQuotaResponse",
        "type": "object"
      },
      "SquadMemberRemoveResponse": {
        "additionalProperties": false,
        "description": "200 body for ``DELETE /v1/squads/{sqd_id}/members/{member_account_id}``.",
        "properties": {
          "config_utxo_ref": {
            "title": "Config Utxo Ref",
            "type": "string"
          },
          "debt_resolution": {
            "$ref": "#/components/schemas/SquadDebtResolution"
          },
          "member_count": {
            "title": "Member Count",
            "type": "integer"
          },
          "members": {
            "items": {
              "$ref": "#/components/schemas/SquadMemberRosterEntry"
            },
            "title": "Members",
            "type": "array"
          },
          "removed_member_account_id": {
            "title": "Removed Member Account Id",
            "type": "string"
          },
          "removed_member_pkh": {
            "title": "Removed Member Pkh",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "tx_id": {
            "title": "Tx Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "tx_id",
          "config_utxo_ref",
          "removed_member_account_id",
          "removed_member_pkh",
          "members",
          "member_count"
        ],
        "title": "SquadMemberRemoveResponse",
        "type": "object"
      },
      "SquadMemberRoleChangeResponse": {
        "additionalProperties": false,
        "description": "200 body for ``PATCH /v1/squads/{sqd_id}/members/{member_account_id}/role``.\n\n``changed`` is ``False`` (and ``tx_id`` ``None``) when the member already had the\nrequested role — a no-op that ran no Cardano tx. Otherwise it carries the\nChangeMembership ``tx_id`` and the post-change roster.",
        "properties": {
          "changed": {
            "title": "Changed",
            "type": "boolean"
          },
          "config_utxo_ref": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Config Utxo Ref"
          },
          "member_account_id": {
            "title": "Member Account Id",
            "type": "string"
          },
          "member_count": {
            "title": "Member Count",
            "type": "integer"
          },
          "member_pkh": {
            "title": "Member Pkh",
            "type": "string"
          },
          "members": {
            "items": {
              "$ref": "#/components/schemas/SquadMemberRosterEntry"
            },
            "title": "Members",
            "type": "array"
          },
          "role": {
            "title": "Role",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "tx_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tx Id"
          }
        },
        "required": [
          "sqd_id",
          "member_account_id",
          "member_pkh",
          "role",
          "changed",
          "members",
          "member_count"
        ],
        "title": "SquadMemberRoleChangeResponse",
        "type": "object"
      },
      "SquadMemberRosterEntry": {
        "additionalProperties": false,
        "description": "One entry of a member-mutation response roster.\n\nV1 stores members pkh-only (no pkh→account_id index; the join is the SQ-18\nread layer's job — see ``shared/squad_view``), so the roster is keyed by\n``member_pkh``. The account_id of the member touched by *this* request is\nechoed at the top level of the response instead.",
        "properties": {
          "member_pkh": {
            "title": "Member Pkh",
            "type": "string"
          },
          "role": {
            "title": "Role",
            "type": "string"
          }
        },
        "required": [
          "member_pkh",
          "role"
        ],
        "title": "SquadMemberRosterEntry",
        "type": "object"
      },
      "SquadMetadata": {
        "additionalProperties": false,
        "description": "Optional, purely-cosmetic display metadata for a squad (off-chain only — never\npart of the on-chain Config datum). Every field is optional; on a PATCH an explicit\n``null`` clears that field while an omitted field is left unchanged.",
        "properties": {
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "emoji": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Emoji"
          },
          "image_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Image Url"
          },
          "location": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SquadLocation"
              },
              {
                "type": "null"
              }
            ]
          },
          "template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Template"
          },
          "template_config": {
            "anyOf": [
              {},
              {
                "type": "null"
              }
            ],
            "title": "Template Config"
          }
        },
        "title": "SquadMetadata",
        "type": "object"
      },
      "SquadRedistributionDelta": {
        "additionalProperties": false,
        "description": "One member's slice of a leaver's redistributed portion on a single entry.\n\n``was_settled`` is ``True`` when this member had already settled their original\nshare — they keep that settled slice and now owe this fresh ``delta_cents`` top-up\n(a brand-new debtor share). ``delta_cents`` for the creditor is folded into their\nown share (no UTxO), so a creditor delta carries ``was_settled: False``.",
        "properties": {
          "delta_cents": {
            "title": "Delta Cents",
            "type": "integer"
          },
          "member_pkh": {
            "title": "Member Pkh",
            "type": "string"
          },
          "was_settled": {
            "default": false,
            "title": "Was Settled",
            "type": "boolean"
          }
        },
        "required": [
          "member_pkh",
          "delta_cents"
        ],
        "title": "SquadRedistributionDelta",
        "type": "object"
      },
      "SquadResplitReport": {
        "additionalProperties": false,
        "description": "What a retroactive re-split did across a squad's open EQUAL entries.\n\n``entries_resplit`` are the entry_seqs re-issued under the new membership/quotas;\n``entries_skipped`` are entries left untouched (already settled/voided, or a\ntransient failure) — the owner can fix those via the per-entry split override.",
        "properties": {
          "entries_resplit": {
            "items": {
              "type": "integer"
            },
            "title": "Entries Resplit",
            "type": "array"
          },
          "entries_skipped": {
            "items": {
              "$ref": "#/components/schemas/SquadResplitSkip"
            },
            "title": "Entries Skipped",
            "type": "array"
          }
        },
        "title": "SquadResplitReport",
        "type": "object"
      },
      "SquadResplitSkip": {
        "additionalProperties": false,
        "description": "One entry the retroactive re-split could not touch, with a machine reason\n(``SETTLED_NEEDS_MANUAL`` — a settle/void already realized part of it; use the\nowner per-entry override / ``RESPLIT_FAILED`` — a transient on-chain error).",
        "properties": {
          "entry_seq": {
            "title": "Entry Seq",
            "type": "integer"
          },
          "reason": {
            "title": "Reason",
            "type": "string"
          }
        },
        "required": [
          "entry_seq",
          "reason"
        ],
        "title": "SquadResplitSkip",
        "type": "object"
      },
      "SquadRulesBlock": {
        "additionalProperties": false,
        "description": "The ``rules`` block echoed on the write response and squad detail (``null`` when\nunset).",
        "properties": {
          "spend_approval": {
            "$ref": "#/components/schemas/SpendApprovalPolicy"
          }
        },
        "required": [
          "spend_approval"
        ],
        "title": "SquadRulesBlock",
        "type": "object"
      },
      "SquadRulesDeleteRequest": {
        "additionalProperties": false,
        "description": "``DELETE /v1/squads/{sqd_id}/rules`` — an OWNER removes the policy. Only the actor is\nneeded.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "SquadRulesDeleteRequest",
        "type": "object"
      },
      "SquadRulesDeleteResponse": {
        "additionalProperties": false,
        "description": "200 body for ``DELETE /v1/squads/{sqd_id}/rules`` — ``rules`` is always ``null``.",
        "properties": {
          "rules": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SquadRulesBlock"
              },
              {
                "type": "null"
              }
            ]
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id"
        ],
        "title": "SquadRulesDeleteResponse",
        "type": "object"
      },
      "SquadRulesRequest": {
        "additionalProperties": false,
        "description": "``PUT /v1/squads/{sqd_id}/rules`` — an OWNER sets/edits the spend-approval policy.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "spend_approval": {
            "$ref": "#/components/schemas/SpendApprovalPolicy"
          }
        },
        "required": [
          "actor_account_id",
          "spend_approval"
        ],
        "title": "SquadRulesRequest",
        "type": "object"
      },
      "SquadRulesResponse": {
        "additionalProperties": false,
        "description": "200 body for ``PUT /v1/squads/{sqd_id}/rules``.",
        "properties": {
          "rules": {
            "$ref": "#/components/schemas/SquadRulesBlock"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "updated_at": {
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "rules",
          "updated_at"
        ],
        "title": "SquadRulesResponse",
        "type": "object"
      },
      "SquadSettleResponse": {
        "additionalProperties": false,
        "description": "201 body for ``POST /v1/squads/{sqd_id}/settle`` (SQ-13 per-debtor self-settle).\n\nWithdraw-only success: when the caller owes nothing but had a squad deposit, the\ndeposit is returned to their personal custody and the call succeeds with\n``settled_shares == 0``, ``squad_funds_withdrawn_cents > 0``, and\n``tx_id == withdrawal_tx_id`` (no ``SettleShare`` tx ran — the withdrawal is the\nonly on-chain tx). A 404 ``ACCOUNTING_NOT_FOUND`` is returned only when the caller\nowed nothing AND had no deposit (nothing to settle).",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          },
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "settled_shares": {
            "title": "Settled Shares",
            "type": "integer"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "squad_funds_withdrawn_cents": {
            "default": 0,
            "title": "Squad Funds Withdrawn Cents",
            "type": "integer"
          },
          "state": {
            "default": "OPEN",
            "title": "State",
            "type": "string"
          },
          "transfers": {
            "items": {
              "$ref": "#/components/schemas/SquadSettleTransfer"
            },
            "title": "Transfers",
            "type": "array"
          },
          "tx_id": {
            "title": "Tx Id",
            "type": "string"
          },
          "vqbrl_burned": {
            "title": "Vqbrl Burned",
            "type": "integer"
          },
          "withdrawal_tx_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Withdrawal Tx Id"
          }
        },
        "required": [
          "sqd_id",
          "tx_id",
          "caller_account_id",
          "settled_shares",
          "vqbrl_burned",
          "created_at"
        ],
        "title": "SquadSettleResponse",
        "type": "object"
      },
      "SquadSettleTransfer": {
        "additionalProperties": false,
        "properties": {
          "amount_cents": {
            "title": "Amount Cents",
            "type": "integer"
          },
          "creditor_pkh": {
            "title": "Creditor Pkh",
            "type": "string"
          }
        },
        "required": [
          "creditor_pkh",
          "amount_cents"
        ],
        "title": "SquadSettleTransfer",
        "type": "object"
      },
      "SquadShareEntry": {
        "additionalProperties": false,
        "description": "One per-debtor share minted by an ACCOUNTING register (SQ-13).\n\npkh-keyed (V1 has no pkh→account_id index — SQ-18 owns that join);\n``share_utxo_ref`` is the new AccountingShare UTxO (``tx_hash#ix``);\n``obligation_id`` is the logical ``obl_*`` row recording this share.",
        "properties": {
          "debtor_pkh": {
            "title": "Debtor Pkh",
            "type": "string"
          },
          "obligation_id": {
            "title": "Obligation Id",
            "type": "string"
          },
          "share_cents": {
            "title": "Share Cents",
            "type": "integer"
          },
          "share_utxo_ref": {
            "title": "Share Utxo Ref",
            "type": "string"
          }
        },
        "required": [
          "debtor_pkh",
          "share_cents",
          "share_utxo_ref",
          "obligation_id"
        ],
        "title": "SquadShareEntry",
        "type": "object"
      },
      "SquadSimplifyConsolidation": {
        "additionalProperties": false,
        "description": "One synthetic net entry the simplification created: a single creditor owed by\none or more debtors, replacing the gross shares that netted to it.",
        "properties": {
          "creditor_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Creditor Account Id"
          },
          "creditor_pkh": {
            "title": "Creditor Pkh",
            "type": "string"
          },
          "debtors": {
            "items": {
              "$ref": "#/components/schemas/SquadSimplifyDebtor"
            },
            "title": "Debtors",
            "type": "array"
          },
          "entry_seq": {
            "title": "Entry Seq",
            "type": "integer"
          },
          "total_cents": {
            "title": "Total Cents",
            "type": "integer"
          }
        },
        "required": [
          "entry_seq",
          "creditor_pkh",
          "total_cents"
        ],
        "title": "SquadSimplifyConsolidation",
        "type": "object"
      },
      "SquadSimplifyDebtor": {
        "additionalProperties": false,
        "properties": {
          "cents": {
            "title": "Cents",
            "type": "integer"
          },
          "debtor_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Debtor Account Id"
          },
          "debtor_pkh": {
            "title": "Debtor Pkh",
            "type": "string"
          }
        },
        "required": [
          "debtor_pkh",
          "cents"
        ],
        "title": "SquadSimplifyDebtor",
        "type": "object"
      },
      "SquadSimplifyRequest": {
        "additionalProperties": false,
        "description": "``POST /v1/squads/{sqd_id}/simplify-debts`` — collapse the open accounting\ngraph into the minimal set of net debts. OWNER-only: it void+reissues *every*\nmember's shares, a squad-wide restructuring (unlike settle, which only ever\nmoves the caller's own funds).",
        "properties": {
          "caller_account_id": {
            "title": "Caller Account Id",
            "type": "string"
          }
        },
        "required": [
          "caller_account_id"
        ],
        "title": "SquadSimplifyRequest",
        "type": "object"
      },
      "SquadSimplifyResponse": {
        "additionalProperties": false,
        "description": "201 body for ``POST /v1/squads/{sqd_id}/simplify-debts``.\n\n``no_op`` is true (with empty void/created lists and equal before/after counts)\nwhen the graph is already minimal — no on-chain work runs. Otherwise the open\nshares were voided and the minimal net set reissued: ``vqbrl_minted`` equals\n``vqbrl_burned`` (total open debt is conserved; only the edge count shrinks).",
        "properties": {
          "consolidations": {
            "items": {
              "$ref": "#/components/schemas/SquadSimplifyConsolidation"
            },
            "title": "Consolidations",
            "type": "array"
          },
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "created_entries": {
            "items": {
              "type": "integer"
            },
            "title": "Created Entries",
            "type": "array"
          },
          "no_op": {
            "default": false,
            "title": "No Op",
            "type": "boolean"
          },
          "reissue_tx_ids": {
            "items": {
              "type": "string"
            },
            "title": "Reissue Tx Ids",
            "type": "array"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "state": {
            "default": "OPEN",
            "title": "State",
            "type": "string"
          },
          "transfers_after_count": {
            "title": "Transfers After Count",
            "type": "integer"
          },
          "transfers_before_count": {
            "title": "Transfers Before Count",
            "type": "integer"
          },
          "void_tx_ids": {
            "items": {
              "type": "string"
            },
            "title": "Void Tx Ids",
            "type": "array"
          },
          "voided_entries": {
            "items": {
              "type": "integer"
            },
            "title": "Voided Entries",
            "type": "array"
          },
          "vqbrl_burned": {
            "default": 0,
            "title": "Vqbrl Burned",
            "type": "integer"
          },
          "vqbrl_minted": {
            "default": 0,
            "title": "Vqbrl Minted",
            "type": "integer"
          }
        },
        "required": [
          "sqd_id",
          "transfers_before_count",
          "transfers_after_count",
          "created_at"
        ],
        "title": "SquadSimplifyResponse",
        "type": "object"
      },
      "SquadSpendResponse": {
        "additionalProperties": false,
        "description": "201 body for ``POST /v1/squads/{sqd_id}/spends`` (RFC-018 §5.1, SQ-12, B-SQ-07).\n\n``consumed_balance_utxos`` are the Balance UTxO refs spent at the SquadValidator;\n``residual_balance_utxo`` is the leftover Balance UTxO (``tx_hash#ix``) or ``null``\nwhen the spend is exact. ``obligation_id`` is the logical ``obl_*`` row recording the\nspend (debtor = the squad). For an **internal** spend ``state`` is ``\"OPEN\"`` and\n``recipient_account_id`` is set. For an **external Pix** spend ``recipient_account_id``\nis ``null``, ``state`` is ``\"PROCESSING\"``, and ``payout`` carries the rail status.\nThe amount is centavos (1 QBRL = 1 centavo).",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/SquadAmount"
          },
          "consumed_balance_utxos": {
            "items": {
              "type": "string"
            },
            "title": "Consumed Balance Utxos",
            "type": "array"
          },
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "event_seq": {
            "title": "Event Seq",
            "type": "integer"
          },
          "obligation_id": {
            "title": "Obligation Id",
            "type": "string"
          },
          "payout": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PayoutBlock"
              },
              {
                "type": "null"
              }
            ]
          },
          "recipient_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recipient Account Id"
          },
          "residual_balance_utxo": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Residual Balance Utxo"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "state": {
            "default": "OPEN",
            "title": "State",
            "type": "string"
          },
          "tx_id": {
            "title": "Tx Id",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "tx_id",
          "obligation_id",
          "actor_account_id",
          "amount",
          "consumed_balance_utxos",
          "event_seq",
          "created_at"
        ],
        "title": "SquadSpendResponse",
        "type": "object"
      },
      "SquadUpdateRequest": {
        "additionalProperties": false,
        "description": "``PATCH /v1/squads/{sqd_id}`` — an OWNER edits the squad's display fields.\n\nPartial update: only the fields present in the body change; an omitted field is left\nuntouched, and an explicit ``null`` on an optional metadata field clears it (``name``\nis never clearable). The route dumps this with ``exclude_unset=True`` so the handler\ncan tell \"omitted\" from \"set to null\". This is an off-chain projection write only —\nno Cardano transaction is built.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "metadata": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SquadMetadata"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "SquadUpdateRequest",
        "type": "object"
      },
      "SquadUpdateResponse": {
        "additionalProperties": false,
        "description": "200 body for ``PATCH /v1/squads/{sqd_id}`` — the squad's full current display\nmetadata after the edit.",
        "properties": {
          "metadata": {
            "$ref": "#/components/schemas/SquadMetadata"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "updated_at": {
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "sqd_id",
          "name",
          "metadata",
          "updated_at"
        ],
        "title": "SquadUpdateResponse",
        "type": "object"
      },
      "SquadVoidResponse": {
        "additionalProperties": false,
        "description": "200 body for ``DELETE /v1/squads/{sqd_id}/contributions/{entry_seq}`` (SQ-13).",
        "properties": {
          "sqd_id": {
            "title": "Sqd Id",
            "type": "string"
          },
          "tx_id": {
            "title": "Tx Id",
            "type": "string"
          },
          "voided_entry_seq": {
            "title": "Voided Entry Seq",
            "type": "integer"
          },
          "voided_shares": {
            "title": "Voided Shares",
            "type": "integer"
          },
          "vqbrl_burned": {
            "title": "Vqbrl Burned",
            "type": "integer"
          }
        },
        "required": [
          "sqd_id",
          "tx_id",
          "voided_entry_seq",
          "voided_shares",
          "vqbrl_burned"
        ],
        "title": "SquadVoidResponse",
        "type": "object"
      },
      "TemplateTransferRequest": {
        "description": "A template-transfer invocation.\n\n``params`` is a free-form object validated against the named template's\ndeclared params (typed enum: account_id | cents | bps | string) — the\nengine rejects unknown params and any attempt to supply an operator\nconstant. ``template_version`` is an optional pin: if supplied and it does\nnot match the deployed version, the engine raises 409\nTEMPLATE_VERSION_MISMATCH (there is no template-version negotiation — the\ndeployed JSON is authoritative).",
        "properties": {
          "params": {
            "additionalProperties": true,
            "description": "Caller-supplied typed parameters",
            "title": "Params",
            "type": "object"
          },
          "template_id": {
            "description": "Registered template id (e.g. 'fee_bearing_transfer')",
            "title": "Template Id",
            "type": "string"
          },
          "template_version": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional expected template version; mismatch → 409",
            "title": "Template Version"
          }
        },
        "required": [
          "template_id",
          "params"
        ],
        "title": "TemplateTransferRequest",
        "type": "object"
      },
      "TenantDraftBindRequest": {
        "additionalProperties": false,
        "description": "A tenant binds one of the shipped templates for **itself**, at DRAFT (LaaS-87).\n\nThe playground's write. Deliberately the *narrowest* body that can express a\nbinding, and every field the operator request carries and this one does not is\na decision a tenant must not make:\n\n* no ``lifecycle`` — it is forced to DRAFT. CERTIFIED costs evidence (laas-86 D5)\n  and a body that could name its own lifecycle would be the free edge that\n  ticket exists to close.\n* no ``accounting`` — the GL node is derived. A caller-chosen node would let a\n  tenant point their product's legs at ``gl_safeswap_escrow`` and silently\n  re-book somebody else's value.\n* no ``script.catalog`` and no ``script.certification`` — a tenant cannot bind an\n  incumbent at the platform's own static address, and cannot inherit evidence\n  that was produced for someone else.\n* no ``acknowledge_open_instances`` — that flag lets a version bump strand new\n  value under a superseded binding, which is an operator's call to make.\n\n``extra=\"forbid\"`` so a body that *tries* any of the above is refused by name\nrather than having the field silently ignored — a caller who thinks they set\n``lifecycle: CERTIFIED`` and got a 201 has been misled.",
        "properties": {
          "compile_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "An **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`.",
            "examples": [
              "cmp_5f3a9c1e7b0d4a628f10c3d5"
            ],
            "title": "Compile Id"
          },
          "manifest": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "The 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.",
            "title": "Manifest"
          },
          "template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Which 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`.",
            "examples": [
              "tenant-vault"
            ],
            "title": "Template"
          }
        },
        "title": "TenantDraftBindRequest",
        "type": "object"
      },
      "TenantDraftBindResponse": {
        "description": "One binding, in the **tenant-facing** projection.\n\n⛔ Not `TenantProductResponse`. That is the operator read model and it carries\n`artifact_bucket`, `artifact_key` and the `accounting` block — estate topology\nand our chart of accounts. This response goes to a browser.",
        "properties": {
          "actions": {
            "additionalProperties": {
              "type": "boolean"
            },
            "default": {},
            "title": "Actions",
            "type": "object"
          },
          "address": {
            "title": "Address",
            "type": "string"
          },
          "artifact_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Artifact Hash"
          },
          "bound": {
            "default": true,
            "description": "False when the identical artifact was already bound and no version was appended — the laas-67 `provisioned: false` shape, answered 200.",
            "title": "Bound",
            "type": "boolean"
          },
          "ir_version": {
            "default": 1,
            "title": "Ir Version",
            "type": "integer"
          },
          "lifecycle": {
            "title": "Lifecycle",
            "type": "string"
          },
          "product_id": {
            "title": "Product Id",
            "type": "string"
          },
          "release_targets": {
            "default": [],
            "items": {
              "type": "string"
            },
            "title": "Release Targets",
            "type": "array"
          },
          "script_hash": {
            "title": "Script Hash",
            "type": "string"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          },
          "version": {
            "title": "Version",
            "type": "integer"
          }
        },
        "required": [
          "product_id",
          "tenant",
          "version",
          "lifecycle",
          "address",
          "script_hash"
        ],
        "title": "TenantDraftBindResponse",
        "type": "object"
      },
      "TenantProductBindRequest": {
        "description": "Bind one certified artifact to exactly one tenant.\n\nThe registry/bindings split (Product Plane §4.4, the KYC pattern): the\nartifact is content-addressed and published here, and the **row** is what\nactivates it for this tenant. Certification without binding deploys nothing.\n\n``manifest`` is a manifest document in exactly the form\n`products/manifest/document.load_manifest` parses — the same validator the\ncommitted `contracts/manifests/*.json` go through, so a body posted here is\nheld to every invariant a shipped one is. It is deliberately a free-form\nobject rather than a nested Pydantic schema, for laas-78 D1's reason: the\ngrammar has one validator, and a second description of it is how two\nauthoring paths come to diverge.\n\n``product_id`` and ``tenant`` inside the manifest are **overwritten from the\npath** before validation. A body that could name its own tenant would be a\nbody that could bind into another tenant's namespace.",
        "properties": {
          "accounting": {
            "$ref": "#/components/schemas/ProductAccounting",
            "description": "The GL mapping for this product"
          },
          "acknowledge_open_instances": {
            "default": false,
            "description": "⟲ 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.",
            "title": "Acknowledge Open Instances",
            "type": "boolean"
          },
          "lifecycle": {
            "default": "DRAFT",
            "description": "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.",
            "enum": [
              "DRAFT",
              "CERTIFIED"
            ],
            "title": "Lifecycle",
            "type": "string"
          },
          "manifest": {
            "additionalProperties": true,
            "description": "The manifest document (manifest_version, states, actions, schemas, …)",
            "title": "Manifest",
            "type": "object"
          },
          "script": {
            "$ref": "#/components/schemas/ProductScriptRef",
            "description": "Which script bytes to bind"
          }
        },
        "required": [
          "manifest",
          "script",
          "accounting"
        ],
        "title": "TenantProductBindRequest",
        "type": "object"
      },
      "TenantProductCertifyRequest": {
        "additionalProperties": false,
        "description": "Assemble, sign and record a certification for one binding.",
        "properties": {
          "evidence": {
            "$ref": "#/components/schemas/CertificationEvidence",
            "description": "The documents this certification is a claim about"
          },
          "justification": {
            "description": "Why this certification is being recorded, for the operator timeline",
            "minLength": 1,
            "title": "Justification",
            "type": "string"
          }
        },
        "required": [
          "evidence",
          "justification"
        ],
        "title": "TenantProductCertifyRequest",
        "type": "object"
      },
      "TenantProductDrainRequest": {
        "additionalProperties": false,
        "description": "Close the named instances of one product.\n\n⛔ There is deliberately no close-everything shape. The operator reaching for a\ndrain is usually reaching for it under time pressure, and a plan they did not read\nis not consent.",
        "properties": {
          "account_id": {
            "description": "The acting account. A close pays out, and the payee comes from this account exactly as on the ordinary close route.",
            "title": "Account Id",
            "type": "string"
          },
          "consent": {
            "description": "Must be true: a drain closes real instances and pays real value",
            "title": "Consent",
            "type": "boolean"
          },
          "instance_ids": {
            "description": "The instances to close. Read them off GET .../drain first.",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "title": "Instance Ids",
            "type": "array"
          },
          "justification": {
            "description": "For the operator timeline",
            "minLength": 1,
            "title": "Justification",
            "type": "string"
          },
          "reason": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Extra body fields the product's close action declares, merged into each close. The same shape the ordinary close route takes.",
            "title": "Reason"
          }
        },
        "required": [
          "instance_ids",
          "account_id",
          "consent",
          "justification"
        ],
        "title": "TenantProductDrainRequest",
        "type": "object"
      },
      "TenantProductLifecycleRequest": {
        "description": "Move one binding through the lifecycle.\n\nThe transition table lives in `shared/product_registry._LEGAL_TRANSITIONS`\nand is enforced at the accessor twice — in Python for the message and as a\nDynamoDB `ConditionExpression` so two concurrent transitions serialize. A\nkill switch that races is not one.\n\n⛔ There is no `RETIRED -> anything`, and no unbind verb at all. History\nstays resolvable: an obligation whose product no longer resolves is an audit\nhole, and a suspended product's own instances are exactly what an operator\nsuspended it to look at.",
        "properties": {
          "attestation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProductAttestation"
              },
              {
                "type": "null"
              }
            ],
            "description": "Required for LIVE and refused for every other target — a countersignature on a suspension would record a sign-off nobody gave."
          },
          "justification": {
            "description": "Why. Recorded on the operator timeline row (laas-24's surface).",
            "minLength": 1,
            "title": "Justification",
            "type": "string"
          },
          "lifecycle": {
            "description": "The target state",
            "enum": [
              "CERTIFIED",
              "LIVE",
              "SUSPENDED",
              "RETIRED"
            ],
            "title": "Lifecycle",
            "type": "string"
          }
        },
        "required": [
          "lifecycle",
          "justification"
        ],
        "title": "TenantProductLifecycleRequest",
        "type": "object"
      },
      "TenantProductListResponse": {
        "description": "A page of this tenant's bindings (current version each).",
        "properties": {
          "items": {
            "default": [],
            "items": {
              "$ref": "#/components/schemas/TenantProductResponse"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque cursor; null when the listing is exhausted",
            "title": "Next Cursor"
          }
        },
        "title": "TenantProductListResponse",
        "type": "object"
      },
      "TenantProductResponse": {
        "description": "One binding's current version, as the public read model.",
        "properties": {
          "accounting": {
            "additionalProperties": true,
            "default": {},
            "title": "Accounting",
            "type": "object"
          },
          "actions": {
            "additionalProperties": true,
            "default": {},
            "title": "Actions",
            "type": "object"
          },
          "address": {
            "title": "Address",
            "type": "string"
          },
          "applied": {
            "additionalProperties": true,
            "default": {},
            "description": "The parametric binding: template_hash, script_key, params, param_values. Empty for a non-parametric product.",
            "title": "Applied",
            "type": "object"
          },
          "artifact_bucket": {
            "default": "",
            "title": "Artifact Bucket",
            "type": "string"
          },
          "artifact_hash": {
            "default": "",
            "title": "Artifact Hash",
            "type": "string"
          },
          "artifact_key": {
            "default": "",
            "title": "Artifact Key",
            "type": "string"
          },
          "bound": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Bind only. False when the identical artifact was already bound and no version was appended — the laas-67 `provisioned: false` shape.",
            "title": "Bound"
          },
          "certification": {
            "additionalProperties": true,
            "default": {},
            "title": "Certification",
            "type": "object"
          },
          "created_at": {
            "default": "",
            "title": "Created At",
            "type": "string"
          },
          "datum_schema": {
            "default": "",
            "title": "Datum Schema",
            "type": "string"
          },
          "gl_node_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Bind only: the node provisioned",
            "title": "Gl Node Id"
          },
          "ir_version": {
            "default": 1,
            "title": "Ir Version",
            "type": "integer"
          },
          "lifecycle": {
            "title": "Lifecycle",
            "type": "string"
          },
          "lifecycle_history": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lifecycle History"
          },
          "operation_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The operator-timeline row this call wrote",
            "title": "Operation Id"
          },
          "product_id": {
            "title": "Product Id",
            "type": "string"
          },
          "redeemer_schema": {
            "default": "",
            "title": "Redeemer Schema",
            "type": "string"
          },
          "release_targets": {
            "default": [],
            "items": {
              "type": "string"
            },
            "title": "Release Targets",
            "type": "array"
          },
          "script_hash": {
            "title": "Script Hash",
            "type": "string"
          },
          "template_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Bind only: convenience echo of applied.template_hash",
            "title": "Template Hash"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          },
          "tier": {
            "default": "product",
            "description": "Always product; the custody tier is the platform's",
            "title": "Tier",
            "type": "string"
          },
          "updated_at": {
            "default": "",
            "title": "Updated At",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "integer"
          },
          "versions": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Every version ever recorded, newest first — the detail read",
            "title": "Versions"
          }
        },
        "required": [
          "tenant",
          "product_id",
          "version",
          "lifecycle",
          "address",
          "script_hash"
        ],
        "title": "TenantProductResponse",
        "type": "object"
      },
      "TenantQbrlPolicyResponse": {
        "description": "A tenant's QBRL minting-policy binding.",
        "properties": {
          "issuer_account_id": {
            "description": "The account owning the key whose hash defines the policy. It holds no value; it exists to sign mints and burns.",
            "title": "Issuer Account Id",
            "type": "string"
          },
          "policy_id": {
            "description": "The 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.",
            "title": "Policy Id",
            "type": "string"
          },
          "provisioned": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True only when this call created the binding. A repeat call returns false with the same policy id.",
            "title": "Provisioned"
          },
          "source": {
            "default": "registry",
            "description": "`bootstrap` for the tenant whose policy comes from genesis, `registry` for one provisioned onto a running head.",
            "title": "Source",
            "type": "string"
          },
          "status": {
            "default": "ACTIVE",
            "description": "ACTIVE while the policy may mint.",
            "title": "Status",
            "type": "string"
          },
          "supply_node": {
            "default": "",
            "description": "GL node carrying this tenant's outstanding QBRL issuance.",
            "title": "Supply Node",
            "type": "string"
          },
          "tenant": {
            "description": "The tenant this policy issues money for.",
            "title": "Tenant",
            "type": "string"
          }
        },
        "required": [
          "tenant",
          "policy_id",
          "issuer_account_id"
        ],
        "title": "TenantQbrlPolicyResponse",
        "type": "object"
      },
      "TenantQuotaRequest": {
        "additionalProperties": false,
        "description": "Set one tenant's metered-work allowances.\n\n⚠️ Every field is optional and ``None`` means *leave it alone*, not *set it to\nzero*. A PUT that silently zeroed an unmentioned quota would make raising one\ncap a way to revoke another.",
        "properties": {
          "foundry_daily_compiles": {
            "anyOf": [
              {
                "maximum": 10000,
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Compiles 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).",
            "title": "Foundry Daily Compiles"
          }
        },
        "title": "TenantQuotaRequest",
        "type": "object"
      },
      "TenantQuotaResponse": {
        "description": "The effective quota, where it came from, and how much of today is spent.",
        "properties": {
          "quota": {
            "title": "Quota",
            "type": "integer"
          },
          "quota_source": {
            "default": "estate_default",
            "description": "`tenant_override` | `estate_default` — which decided `quota`.",
            "title": "Quota Source",
            "type": "string"
          },
          "remaining": {
            "title": "Remaining",
            "type": "integer"
          },
          "tenant": {
            "title": "Tenant",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          },
          "updated_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated By"
          },
          "used": {
            "title": "Used",
            "type": "integer"
          },
          "window": {
            "default": "utc_day",
            "title": "Window",
            "type": "string"
          },
          "window_resets_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Window Resets At"
          },
          "window_started_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Window Started At"
          }
        },
        "required": [
          "tenant",
          "quota",
          "used",
          "remaining"
        ],
        "title": "TenantQuotaResponse",
        "type": "object"
      },
      "TenantTemplateCreateRequest": {
        "description": "Author (or supersede) one tenant-authored transfer template.\n\n``definition`` is a template entry in **exactly** the closed form\n``services/shared/transfer_templates.json`` uses — ``template_version``,\n``product_id``, ``params``, ``constants``, ``source``, ``legs`` — and it is\nhanded to ``shared.transfer_templates._parse_template`` verbatim.\n\n⛔ Deliberately typed as a free-form object rather than a nested Pydantic\nschema (D1). The template grammar has exactly one validator, and every\ninvariant that makes a template safe to execute — the four closed amount\nforms, exactly one residual leg, reserved leg roles, declared param types,\n``MAX_BPS``, the content hash — lives inside it. A second, Pydantic-shaped\ndescription of the same grammar would be a second set of rules to keep in\nstep, and the two authoring paths could then diverge.\n\n``template_version`` lives inside the definition because it is one of the\nentry's required fields; a separate parameter would be a second source for it.\nIt must be strictly greater than this tenant's current version for this id.",
        "properties": {
          "definition": {
            "additionalProperties": true,
            "description": "The template entry, in the same shape transfer_templates.json uses (template_version, product_id, params, constants, source, legs).",
            "title": "Definition",
            "type": "object"
          },
          "template_id": {
            "description": "Namespaced template id, tnt.<tenant>.<name>",
            "examples": [
              "tnt.acme.payout-split"
            ],
            "title": "Template Id",
            "type": "string"
          }
        },
        "required": [
          "template_id",
          "definition"
        ],
        "title": "TenantTemplateCreateRequest",
        "type": "object"
      },
      "TenantTemplateListResponse": {
        "description": "A page of this tenant's templates (current version each).",
        "properties": {
          "items": {
            "default": [],
            "items": {
              "$ref": "#/components/schemas/TenantTemplateResponse"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque cursor; null when the listing is exhausted",
            "title": "Next Cursor"
          }
        },
        "title": "TenantTemplateListResponse",
        "type": "object"
      },
      "TenantTemplateResponse": {
        "description": "One tenant template's current version, as the public read model.",
        "properties": {
          "constants": {
            "additionalProperties": {
              "type": "string"
            },
            "default": {},
            "title": "Constants",
            "type": "object"
          },
          "content_hash": {
            "title": "Content Hash",
            "type": "string"
          },
          "created_at": {
            "default": "",
            "title": "Created At",
            "type": "string"
          },
          "description": {
            "default": "",
            "title": "Description",
            "type": "string"
          },
          "legs": {
            "default": [],
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "title": "Legs",
            "type": "array"
          },
          "params": {
            "additionalProperties": {
              "type": "string"
            },
            "default": {},
            "title": "Params",
            "type": "object"
          },
          "product_id": {
            "title": "Product Id",
            "type": "string"
          },
          "source": {
            "additionalProperties": {
              "type": "string"
            },
            "default": {},
            "title": "Source",
            "type": "object"
          },
          "status": {
            "default": "ACTIVE",
            "description": "ACTIVE or RETIRED",
            "title": "Status",
            "type": "string"
          },
          "status_history": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status History"
          },
          "template_id": {
            "title": "Template Id",
            "type": "string"
          },
          "template_version": {
            "title": "Template Version",
            "type": "integer"
          },
          "tier": {
            "default": "tenant",
            "description": "platform (static) or tenant (authored)",
            "title": "Tier",
            "type": "string"
          },
          "updated_at": {
            "default": "",
            "title": "Updated At",
            "type": "string"
          },
          "versions": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Every 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.",
            "title": "Versions"
          }
        },
        "required": [
          "template_id",
          "template_version",
          "product_id",
          "content_hash"
        ],
        "title": "TenantTemplateResponse",
        "type": "object"
      },
      "TenantTemplateStatusPatchRequest": {
        "description": "Retire a template's current version.\n\n⛔ ``RETIRED`` is the only accepted value, and the restriction is the design\n(D2: supersede, never edit; retire, never delete). Bringing a template back is\na new version through ``POST``; a ``RETIRED -> ACTIVE`` flip would make \"was\nthis template live when that obligation was written\" unanswerable from the\nversion alone.",
        "properties": {
          "status": {
            "const": "RETIRED",
            "description": "Only RETIRED is accepted; reactivate by posting a new version",
            "title": "Status",
            "type": "string"
          },
          "template_version": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional pin: the version expected to be current. A mismatch is 409, so a retire cannot land on a version the caller has not seen.",
            "title": "Template Version"
          }
        },
        "required": [
          "status"
        ],
        "title": "TenantTemplateStatusPatchRequest",
        "type": "object"
      },
      "TimelineEvent": {
        "properties": {
          "event": {
            "title": "Event",
            "type": "string"
          },
          "journal": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TimelineJournalRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "transaction_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Transaction Id"
          },
          "updated_at": {
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "event",
          "updated_at"
        ],
        "title": "TimelineEvent",
        "type": "object"
      },
      "TimelineJournalRef": {
        "description": "Hash-chained journal reference for a state transition (LaaS Ticket 03).\n\nPresent only for journaled obligations — pre-journal rows and REJECTED\nintents produce events without this key (additive; AC4 byte-identity).",
        "properties": {
          "journal_hash": {
            "title": "Journal Hash",
            "type": "string"
          },
          "seq_no": {
            "title": "Seq No",
            "type": "integer"
          }
        },
        "required": [
          "seq_no",
          "journal_hash"
        ],
        "title": "TimelineJournalRef",
        "type": "object"
      },
      "UpdateMatchKeysRequest": {
        "properties": {
          "match_keys": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Arbitrary key-value pairs for matching evidence to this obligation (all values must be strings)",
            "title": "Match Keys",
            "type": "object"
          }
        },
        "required": [
          "match_keys"
        ],
        "title": "UpdateMatchKeysRequest",
        "type": "object"
      },
      "UpdateMemberQuotaRequest": {
        "additionalProperties": false,
        "description": "``PATCH /v1/squads/{sqd_id}/members/{member_account_id}/quota`` (RFC-018).\n\n``actor_account_id`` is the caller: a member may change their own quota, and an\nOWNER may change anyone's. Blocked (409 QUOTA_CHANGE_LOCKED) once the squad has\nany settled/voided entry.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          },
          "quota": {
            "maximum": 20,
            "minimum": 1,
            "title": "Quota",
            "type": "integer"
          }
        },
        "required": [
          "actor_account_id",
          "quota"
        ],
        "title": "UpdateMemberQuotaRequest",
        "type": "object"
      },
      "ValidationError": {
        "properties": {
          "ctx": {
            "title": "Context",
            "type": "object"
          },
          "input": {
            "title": "Input"
          },
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "title": "Location",
            "type": "array"
          },
          "msg": {
            "title": "Message",
            "type": "string"
          },
          "type": {
            "title": "Error Type",
            "type": "string"
          }
        },
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError",
        "type": "object"
      },
      "VoidContributionRequest": {
        "additionalProperties": false,
        "description": "``DELETE /v1/squads/{sqd_id}/contributions/{entry_seq}`` body (SQ-13).\n\nThe creditor (original actor) burns the entry's still-unsettled shares.",
        "properties": {
          "actor_account_id": {
            "title": "Actor Account Id",
            "type": "string"
          }
        },
        "required": [
          "actor_account_id"
        ],
        "title": "VoidContributionRequest",
        "type": "object"
      },
      "WebhookCreateRequest": {
        "properties": {
          "description": {
            "anyOf": [
              {
                "maxLength": 500,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "event_filters": {
            "items": {
              "type": "string"
            },
            "maxItems": 50,
            "minItems": 1,
            "title": "Event Filters",
            "type": "array"
          },
          "url": {
            "maxLength": 2048,
            "title": "Url",
            "type": "string"
          }
        },
        "required": [
          "url",
          "event_filters"
        ],
        "title": "WebhookCreateRequest",
        "type": "object"
      },
      "WebhookPatchRequest": {
        "description": "url / event_filters / status only — the secret is immutable (rotation =\ndelete + re-create, webhooks-v1 §3). SUSPENDED_AUTO is dispatcher-set;\nowners can PATCH to ACTIVE (resets the failure streak) or SUSPENDED.",
        "properties": {
          "event_filters": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "maxItems": 50,
                "minItems": 1,
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Event Filters"
          },
          "status": {
            "anyOf": [
              {
                "enum": [
                  "ACTIVE",
                  "SUSPENDED"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "url": {
            "anyOf": [
              {
                "maxLength": 2048,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url"
          }
        },
        "title": "WebhookPatchRequest",
        "type": "object"
      }
    },
    "securitySchemes": {
      "oauth2_client_credentials": {
        "description": "Client credentials OAuth 2.0. Faça um POST form-encoded com grant_type=client_credentials, o seu client_id e o seu client_secret; omita scope, e o token vem carregando exatamente o que o seu cliente tem concedido. Envie o resultado como Authorization: Bearer <access_token>.",
        "flows": {
          "clientCredentials": {
            "scopes": {
              "quadra/accounts.read": "Ler partes, contas, saldos e extratos",
              "quadra/accounts.write": "Criar partes e contas, vincular meios de pagamento",
              "quadra/health": "Sondas de saúde e de versão",
              "quadra/holds": "Colocar, capturar e liberar holds",
              "quadra/obligations.write": "Criar e resolver obrigações",
              "quadra/products": "Criar, dirigir e ler instâncias dos seus produtos",
              "quadra/products.draft": "Vincular um produto seu em rascunho no ambiente de avaliação",
              "quadra/squads": "Leituras e escritas de contas em grupo"
            },
            "tokenUrl": "https://api-sbx.sonacore.com.br/auth/token"
          }
        },
        "type": "oauth2"
      }
    }
  },
  "info": {
    "description": "Command ingestion API for Quadra ledger operations",
    "title": "Quadra Command API",
    "version": "0.2.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/v1/accounts/{account_id}/blocks": {
      "post": {
        "description": "Freeze ``amount_cents`` of the account (never the whole account) as a\nCOMPLIANCE_BLOCK hold only the block routes can release. Consumes no\nvelocity budget (LaaS-07 D3). ``expires_at`` absent = 72 h default TTL;\nexplicit null = indefinite (judicial). ``allow_partial`` blocks\n``min(amount, available)`` — the 201 body carries ``requested_amount_cents``\nvs the placed ``amount_cents``.",
        "operationId": "place_block_v1_v1_accounts__account_id__blocks_post",
        "parameters": [
          {
            "in": "path",
            "name": "account_id",
            "required": true,
            "schema": {
              "title": "Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlaceBlockRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Place a Targeted Compliance Block (Bloqueio Cautelar)",
        "tags": [
          "Blocks"
        ]
      }
    },
    "/v1/accounts/{account_id}/limits": {
      "post": {
        "description": "Create an ACCOUNT-scope velocity/limit policy (WARN or REJECT) enforced\non the account's monetary writes. GL and faucet accounts are exempt.",
        "operationId": "create_account_limit_policy_v1_v1_accounts__account_id__limits_post",
        "parameters": [
          {
            "in": "path",
            "name": "account_id",
            "required": true,
            "schema": {
              "title": "Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAccountLimitPolicyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a Per-Account Limit Policy",
        "tags": [
          "Limits"
        ]
      }
    },
    "/v1/accounts/{account_id}/pix-limits": {
      "put": {
        "description": "Adjust the account's Pix limits within the pack ceilings (LaaS-07 D7/D8).\nDecreases apply immediately; increases (and the 20:00→22:00 night start)\ntake effect only after the mandated 24–48 h delay, reported per knob as\n``pending {value, activates_at}``. Above a ceiling → 422\nLIMIT_CEILING_EXCEEDED (operator path).",
        "operationId": "put_pix_limits_v1_v1_accounts__account_id__pix_limits_put",
        "parameters": [
          {
            "in": "path",
            "name": "account_id",
            "required": true,
            "schema": {
              "title": "Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutPixLimitsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Set Self-Service Pix Limits",
        "tags": [
          "Limits"
        ]
      }
    },
    "/v1/accounts/{account_id}/promote": {
      "post": {
        "description": "RFC-021 §3.4 promotion flow (LaaS-17 D7): requires the owner party to\nbe KYC-verified; stamps promoted_to_account_id on the old row.",
        "operationId": "promote_account_v1_v1_accounts__account_id__promote_post",
        "parameters": [
          {
            "in": "path",
            "name": "account_id",
            "required": true,
            "schema": {
              "title": "Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/PromoteAccountRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Payload"
              }
            }
          }
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Promote a GUEST/EXTERNAL account to CUSTOMER",
        "tags": [
          "Accounts"
        ]
      }
    },
    "/v1/blocks/{block_id}/release": {
      "post": {
        "description": "The only release path for a COMPLIANCE_BLOCK (the ordinary hold routes\n422 on reserved types). Compensates no velocity budget — the place\nconsumed none (LaaS-07 D3).",
        "operationId": "release_block_v1_v1_blocks__block_id__release_post",
        "parameters": [
          {
            "in": "path",
            "name": "block_id",
            "required": true,
            "schema": {
              "title": "Block Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReleaseBlockRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Release a Compliance Block",
        "tags": [
          "Blocks"
        ]
      }
    },
    "/v1/evidence": {
      "post": {
        "description": "Ingest external evidence through the adapter framework.\n\nAccepts a generic envelope with `source_type` (e.g. \"ach_json_v1\") and\na rail-specific `payload`. The adapter parses, validates, resolves the\naccount, and normalizes the event. Core then processes the normalized event.\n\nThe Idempotency-Key is provided as an HTTP header.",
        "operationId": "create_evidence_v1_v1_evidence_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenericEvidenceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Ingest external evidence via rail adapter",
        "tags": [
          "Evidence"
        ]
      }
    },
    "/v1/evidence/{evidence_id}/resolve": {
      "post": {
        "description": "Manual match: settle the operator-pinned obligation and unwind the\nsuspense park this evidence created (≤ 2 Hydra txs, each leg idempotent).\nThe evidences row flips to MANUALLY_MATCHED; a second call 409s.",
        "operationId": "resolve_evidence_operator_v1_v1_evidence__evidence_id__resolve_post",
        "parameters": [
          {
            "in": "path",
            "name": "evidence_id",
            "required": true,
            "schema": {
              "title": "Evidence Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvidenceResolveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Manually match an unmatched evidence to an obligation",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/evidence/{evidence_id}/retry": {
      "post": {
        "description": "Re-run a stored `status=ERROR` evidence row through the ingest pipeline\nonce its cause is fixed (zero recorded effects only). A still-unfixed cause\nsurfaces the same 4xx the original ingest returned.",
        "operationId": "retry_evidence_operator_v1_v1_evidence__evidence_id__retry_post",
        "parameters": [
          {
            "in": "path",
            "name": "evidence_id",
            "required": true,
            "schema": {
              "title": "Evidence Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvidenceRetryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Retry a failed evidence ingest",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/foundry/compiles": {
      "get": {
        "description": "Your tenant's compile jobs, newest first. Source is never echoed back.",
        "operationId": "list_own_foundry_compiles_v1_v1_foundry_compiles_get",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoundryCompileListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List your own compile jobs",
        "tags": [
          "Products"
        ]
      },
      "post": {
        "description": "Compile and gate a validator **you** wrote, under your own tenant.\n\n**202, not 201** — the job is accepted, not finished. Poll the companion `GET`.\n\nThe submission must carry an authorship `signature` over its `bundle_hash`,\nmade with the key an operator enrolled for your tenant. That signature is what\nthe Certified Product Artifact records as authorship, and it is deliberately a\ndifferent fact from the API credential that sent the request: credentials\nrotate, and a certification has to keep answering *who wrote this validator*\nyears later.\n\nA submission that fails a static gate comes back **already REFUSED** and is\nnever queued — the compile slot is the expensive thing, and source that cannot\npass a lexer will not pass a compiler. The refusal names the offending rule in\nthe gate report's own vocabulary.\n\n⚠️ Compiling is not binding and certainly not certifying. A green report is\nevidence; `POST /v1/products/{product_id}` with this `compile_id` is what\ndeploys it at DRAFT.",
        "operationId": "submit_own_foundry_compile_v1_v1_foundry_compiles_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FoundryCompileRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoundryCompileResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Submit your own Product Bundle to the Foundry",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/foundry/compiles/{compile_id}": {
      "get": {
        "description": "One compile job, at whatever stage it has reached.\n\nThe gate report lists **every** gate that ran, passes included, plus a\n`deferred` block naming what this stage deliberately did not prove. A report\nshowing only failures could not answer \"was this checked?\", which is the\nquestion a countersigner asks.\n\n⛔ Another tenant's `compile_id` and one that never existed are the same\nDynamoDB miss — the tenant is a partition-key segment, so 404-before-403 holds\nin its strongest form.",
        "operationId": "get_own_foundry_compile_v1_v1_foundry_compiles__compile_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "compile_id",
            "required": true,
            "schema": {
              "title": "Compile Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoundryCompileResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read one of your compile jobs and its gate report",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/foundry/quota": {
      "get": {
        "description": "Used, allowed, and when the window rolls.\n\n⚠️ This **raises rather than reporting zero** when the count cannot be taken. A\nquota surface answering *\"0 of 25 used\"* during an outage would be worse than\nno surface, because a caller would believe it.\n\n⚠️ Its own path rather than `/v1/products/quota`, deliberately: FastAPI matches\nin declaration order and `/v1/products/{product_id}` is declared above, so\n`quota` would be captured as a product id and answered `PRODUCT_NOT_FOUND`.",
        "operationId": "get_own_foundry_quota_v1_v1_foundry_quota_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoundryQuotaResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "How much of your daily compile allowance is left",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/gl/accounts": {
      "post": {
        "description": "Create an operator-defined sub-GL account under an existing GL parent\n(RFC-025 §6): a derived GL row (no on-chain keys) that mapping rules can\nroute entries to and that rolls up into its parent in the trial balance.\n\nRaises:\n    404: PARENT_NOT_FOUND\n    409: IDEMPOTENCY_KEY_REUSED or GL_ACCOUNT_EXISTS\n    422: PARENT_NOT_GL or PARENT_INACTIVE",
        "operationId": "create_gl_sub_account_v1_v1_gl_accounts_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GLSubAccountCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a sub-GL account (operator)",
        "tags": [
          "GL Accounts"
        ]
      }
    },
    "/v1/gl/accounts/{account_id}": {
      "patch": {
        "description": "Rename or deactivate any GL node (built-in or sub-GL). GL accounts are\nnever deleted; INACTIVE only blocks new mapping-rule targets.\n\nRaises:\n    404: NOT_FOUND (unknown id, or not a GL account)",
        "operationId": "patch_gl_account_v1_v1_gl_accounts__account_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "account_id",
            "required": true,
            "schema": {
              "title": "Account Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GLAccountPatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Rename or deactivate a GL account (operator; never delete)",
        "tags": [
          "GL Accounts"
        ]
      }
    },
    "/v1/gl/mapping-rules": {
      "post": {
        "description": "Append a new transaction-type→node mapping ruleset version (RFC-025 §7).\nRules apply prospectively only — already-projected entries keep the\nruleset_version they were stamped with (re-projection is a non-goal).\n\nRaises:\n    409: IDEMPOTENCY_KEY_REUSED or RULESET_CONFLICT (concurrent append)\n    422: UNKNOWN_GL_NODE, INACTIVE_GL_NODE, UNKNOWN_ACCOUNT_TYPE, UNKNOWN_EVENT_KIND",
        "operationId": "create_gl_mapping_ruleset_v1_v1_gl_mapping_rules_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GLMappingRulesetCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Append a mapping-ruleset version and flip CURRENT (operator)",
        "tags": [
          "GL Accounts"
        ]
      }
    },
    "/v1/holds": {
      "post": {
        "description": "Reserve funds on an account: they leave `available`, appear in `held`,\nand remain in the owner's custody until captured or released. Optional\ndeadline (`expires_at` XOR `expires_in_hours`); absent = indefinite.",
        "operationId": "place_hold_v1_v1_holds_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlaceHoldRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Place a Hold on Account Funds",
        "tags": [
          "Holds"
        ]
      }
    },
    "/v1/holds/{hold_id}": {
      "patch": {
        "description": "Decrease the hold amount (re-split; the difference is released) and/or\nchange the expiry (record-only; explicit null clears the deadline).\nAmount increases are rejected — place a second hold.",
        "operationId": "adjust_hold_v1_v1_holds__hold_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "hold_id",
            "required": true,
            "schema": {
              "title": "Hold Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdjustHoldRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Adjust a Hold's Amount or Expiry",
        "tags": [
          "Holds"
        ]
      }
    },
    "/v1/holds/{hold_id}/capture": {
      "post": {
        "description": "Convert the hold (fully or partially) into an ordinary obligation to\nthe creditor; any remainder returns to the holder's available balance.\nSingle-shot: the hold goes terminal CAPTURED.",
        "operationId": "capture_hold_v1_v1_holds__hold_id__capture_post",
        "parameters": [
          {
            "in": "path",
            "name": "hold_id",
            "required": true,
            "schema": {
              "title": "Hold Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaptureHoldRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Capture a Hold into an Obligation",
        "tags": [
          "Holds"
        ]
      }
    },
    "/v1/holds/{hold_id}/release": {
      "post": {
        "description": "Release held funds back to the holder's spendable balance (chain-free).",
        "operationId": "release_hold_v1_v1_holds__hold_id__release_post",
        "parameters": [
          {
            "in": "path",
            "name": "hold_id",
            "required": true,
            "schema": {
              "title": "Hold Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/ReleaseHoldRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Payload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Release a Hold",
        "tags": [
          "Holds"
        ]
      }
    },
    "/v1/kyc/rescreen-sweep": {
      "post": {
        "description": "Internal sweep trigger (D5): EventBridge → API destination in sandbox,\nops-invocable everywhere. Safe to re-run; returns counters.",
        "operationId": "kyc_rescreen_sweep_v1_v1_kyc_rescreen_sweep_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/RescreenSweepRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Payload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Re-screen verified parties past cadence or marked due",
        "tags": [
          "KYC"
        ]
      }
    },
    "/v1/kyc/webhooks/{provider_id}": {
      "post": {
        "description": "Async provider verdict receiver (LaaS-17 D8, per-provider auth by LaaS-44 D2).\n\nUnauthenticated at the API Gateway (authorization_type=NONE — providers cannot do\nCognito client-credentials); authenticated in-handler against **this provider's**\nverification strategy, resolved from its binding through LaaS-39's registry. The\nfixed ``timestamped_hmac_v1`` is now the default rather than the only option, so a\nvendor signing with JWT or a body-only HMAC needs a binding, not route surgery.\n\nOrdering below is load-bearing and matches the Pix receivers (``_pix_webhook_auth``):\n\n1. **unknown or unentitled provider ⇒ 404, before any signature is examined.** One\n   code for both, so the segment cannot be used to enumerate other tenants'\n   vendors (``docs/authorization-policy.md``);\n2. binding unreadable / unbuildable ⇒ 503, retryable — never 404, which would tell\n   a real provider \"this endpoint is not yours\" during an SSM blip;\n3. bad signature or stale timestamp ⇒ 401, and only the two permitted codes.\n\nMinimal ack for ALL outcomes — engine internals never leak to the provider, and\nunparseable payloads are acked-and-ignored (a provider retrying them helps nobody).",
        "operationId": "receive_kyc_webhook_v1_v1_kyc_webhooks__provider_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "provider_id",
            "required": true,
            "schema": {
              "title": "Provider Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "KYC provider webhook receiver",
        "tags": [
          "KYC"
        ]
      }
    },
    "/v1/limit-policies": {
      "post": {
        "description": "Create a GLOBAL / ACCOUNT_TYPE / RAIL / PRODUCT limit policy.",
        "operationId": "create_limit_policy_v1_v1_limit_policies_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLimitPolicyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a Shared-Scope Limit Policy",
        "tags": [
          "Limits"
        ]
      }
    },
    "/v1/limit-policies/{policy_id}": {
      "delete": {
        "description": "Soft-disable (``enabled=false``). Policy rows are never deleted — an\nauditor may need them. Idempotent: re-disabling returns 200.",
        "operationId": "disable_limit_policy_v1_v1_limit_policies__policy_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "policy_id",
            "required": true,
            "schema": {
              "title": "Policy Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Disable a Limit Policy",
        "tags": [
          "Limits"
        ]
      }
    },
    "/v1/obligations": {
      "get": {
        "description": "List obligations with optional filters and cursor-based pagination.\n\nFilters: state, resolution_outcome, rail_family, created_from, created_to,\neffective_from, effective_to (business time), match_key.client_reference,\nmatch_key.rail_ref.",
        "operationId": "list_obligations_v1_v1_obligations_get",
        "parameters": [
          {
            "in": "query",
            "name": "state",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "State"
            }
          },
          {
            "in": "query",
            "name": "resolution_outcome",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Resolution Outcome"
            }
          },
          {
            "in": "query",
            "name": "rail",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Rail"
            }
          },
          {
            "in": "query",
            "name": "created_from",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Created From"
            }
          },
          {
            "in": "query",
            "name": "created_to",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Created To"
            }
          },
          {
            "in": "query",
            "name": "effective_from",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Effective From"
            }
          },
          {
            "in": "query",
            "name": "effective_to",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Effective To"
            }
          },
          {
            "in": "query",
            "name": "match_key.client_reference",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Match Key.Client Reference"
            }
          },
          {
            "in": "query",
            "name": "match_key.rail_ref",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Match Key.Rail Ref"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObligationListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List Obligations",
        "tags": [
          "Obligations"
        ]
      },
      "post": {
        "description": "Create a transfer obligation between two Quadra accounts.\n\nFor INTERNAL / atomic transfers, the Hydra L2 transaction is submitted\nand the obligation is returned in state PENDING. Hydra confirms or rejects\ntransactions asynchronously, so the caller must poll GET /v1/obligations/{id}\nto determine the final resolution.\n\nRequires an Idempotency-Key header.",
        "operationId": "create_obligation_v1_v1_obligations_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateObligationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a Transfer Obligation",
        "tags": [
          "Obligations"
        ]
      }
    },
    "/v1/obligations/{obligation_id}": {
      "get": {
        "description": "Retrieve an obligation by its obligation ID.\n\nAccepts both logical obligation IDs (``obl_*``) and legacy UTXO-based IDs\n(``txhash_index``).\n\nState lifecycle:\n- OPEN — the obligation was created and the Hydra tx submitted, awaiting confirmation.\n- RESOLVED — the head-indexer confirmed or rejected the tx. Check resolution_outcome\n             for SETTLED, FAILED, or CANCELED.",
        "operationId": "get_obligation_v1_v1_obligations__obligation_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "obligation_id",
            "required": true,
            "schema": {
              "title": "Obligation Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObligationResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get an Obligation",
        "tags": [
          "Obligations"
        ]
      }
    },
    "/v1/obligations/{obligation_id}/match-keys": {
      "patch": {
        "description": "Add or update match_keys on an existing obligation.\n\nOnly `rail_ref` and `client_reference` are accepted keys.\nNew values are merged with existing match_keys (overriding on conflict).",
        "operationId": "update_obligation_match_keys_v1_v1_obligations__obligation_id__match_keys_patch",
        "parameters": [
          {
            "in": "path",
            "name": "obligation_id",
            "required": true,
            "schema": {
              "title": "Obligation Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMatchKeysRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Update match keys on an Obligation",
        "tags": [
          "Obligations"
        ]
      }
    },
    "/v1/obligations/{obligation_id}/redispatch": {
      "post": {
        "description": "Re-queue a FAILED dispatch (or the enqueue-failure signature). EXCEPTION\nrows return to FINAL(null), `dispatch_status` becomes RETRY_REQUESTED, and a\nfresh `outbound_dispatch` job is enqueued for tx-worker (RFC-022 §4.2).",
        "operationId": "redispatch_obligation_operator_v1_v1_obligations__obligation_id__redispatch_post",
        "parameters": [
          {
            "in": "path",
            "name": "obligation_id",
            "required": true,
            "schema": {
              "title": "Obligation Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ObligationRedispatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Re-drive a failed outbound dispatch",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/obligations/{obligation_id}/resolve": {
      "post": {
        "description": "Clear a PENDING/EXCEPTION obligation with an operator-attested outcome +\nproof (D1). Exactly one Hydra tx when the obligation UTxO is live (the value\nis disposed and the new output resolves FINAL on confirm — `hydra_tx_id`\nnon-null); zero when spent/absent (metadata-only resolve). Accepts `obl_*`\nand legacy `txhash_N` ids.",
        "operationId": "resolve_obligation_operator_v1_v1_obligations__obligation_id__resolve_post",
        "parameters": [
          {
            "in": "path",
            "name": "obligation_id",
            "required": true,
            "schema": {
              "title": "Obligation Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ObligationResolveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Operator resolve of a stuck obligation",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/obligations/{obligation_id}/timeline": {
      "get": {
        "description": "Retrieve the full lifecycle timeline of an obligation.\n\nReconstructs events from all UTXOs (including spent ones) associated\nwith the given obligation ID. Returns a chronologically-ordered list\nof state transition events.",
        "operationId": "get_obligation_timeline_v1_v1_obligations__obligation_id__timeline_get",
        "parameters": [
          {
            "in": "path",
            "name": "obligation_id",
            "required": true,
            "schema": {
              "title": "Obligation Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObligationTimelineResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Obligation Timeline",
        "tags": [
          "Obligations"
        ]
      }
    },
    "/v1/openapi": {
      "get": {
        "description": "Every action your certified products declare, as a typed API.\n\n⭐ Derived from your manifests on every read, so binding, versioning or\nsuspending a product changes the next response and nothing has to be\nregenerated. The document describes **your** products and no one else's — the\ntenant is a segment of the partition key, so another tenant's product is not\nfiltered out here, it is unaddressable.\n\n⛔ Every operation is a shipped generic route with its template filled in. The\nproduct id is in the path and the action is a path segment or a `const` in the\nbody; nothing here is a route of its own.\n\n⚠️ `servers` is absent by construction — this service sits behind a gateway and\ndoes not know its own public URL, and a caller-supplied one baked into a\ngenerated client would be a way to send credentials elsewhere. Use the host you\nfetched the document from.",
        "operationId": "tenant_openapi_v1_v1_openapi_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Your tenant's own OpenAPI document",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/openapi/sdk/{language}": {
      "get": {
        "description": "A single-file client, generated from the document above.\n\n⭐ The reason this is generated rather than left to a codegen tool is\n`wait_for_state`. Writes here are obligation-first, so an action your validator\nrefuses answers 200 and is refused a beat later; a truthful client polls the\ninstance read for the declared state **and** for `awaiting_index: false`.\nDropping that second condition is a race, and no off-the-shelf generator emits\nit.\n\nStdlib only, so it runs where you paste it. `base_url` is a constructor argument\nand is never guessed, for the reason the document gives for omitting `servers`.",
        "operationId": "tenant_sdk_v1_v1_openapi_sdk__language__get",
        "parameters": [
          {
            "in": "path",
            "name": "language",
            "required": true,
            "schema": {
              "title": "Language",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "A generated client for your own products",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/foundry/compiles": {
      "get": {
        "description": "This tenant's compile jobs, newest first. Source is never echoed back.",
        "operationId": "list_foundry_compiles_v1_v1_operator_tenants__tenant__foundry_compiles_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoundryCompileListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List a tenant's compile jobs",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Compile and gate one tenant-authored validator.\n\n**202, not 201** — the job is accepted, not finished. Poll the companion\n`GET` for its verdict.\n\nA submission that fails a static gate (the source admission scan, the\nmanifest through `load_manifest`, the namespace check) comes back **already\nREFUSED** and is never queued: the compile slot is the expensive thing, and\nsource that cannot pass a lexer will not pass a compiler.\n\n⚠️ Compiling is not certifying and certainly not binding. A green report is\nevidence; conformance execution, the adversarial battery and a countersigned\nCertified Product Artifact are what make a product real, and nothing here\nwrites to the bindable-template allowlist.",
        "operationId": "submit_foundry_compile_v1_v1_operator_tenants__tenant__foundry_compiles_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FoundryCompileRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoundryCompileResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Submit a product bundle to the Foundry",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/foundry/compiles/{compile_id}": {
      "get": {
        "description": "One compile job, at whatever stage it has reached.\n\nThe gate report lists **every** gate that ran, passes included, plus a\n`deferred` block naming what this stage deliberately did not prove. A report\nthat showed only failures could not answer \"was this checked?\", which is the\nquestion a countersigner asks.\n\n⛔ A foreign tenant's `compile_id` and one that never existed are the same\nDynamoDB miss — the tenant is a partition-key segment, so 404-before-403 holds\nin its strongest form.",
        "operationId": "get_foundry_compile_v1_v1_operator_tenants__tenant__foundry_compiles__compile_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "compile_id",
            "required": true,
            "schema": {
              "title": "Compile Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoundryCompileResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get one compile job and its gate report",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/foundry/compiles/{compile_id}/source": {
      "get": {
        "description": "The tenant's Haskell, verbatim, for the human who has to sign off on it.\n\n⛔ **This route exists because §4.3's countersignature is not a rubber stamp.**\nP6 requires a platform engineer to countersign *the report and the source*, and\nLaaS-88 D2 keeps the source out of the published evidence set — SSE-KMS,\nplatform-only, referenced from the certification by hash. So there has to be\nexactly one way to read it, and this is it: operator-scoped, per compile,\nlogged with the client that asked.\n\n⚠️ **The honest cost of D2, stated where a reader meets it:** an outside auditor\ncan verify every hash and both signatures and *cannot* check that the certified\nscript came from the claimed source. Publishing the source would close that gap\nand would also publish a tenant's IP to everyone holding the evidence bucket.\nThat trade was made deliberately.\n\nAnswers `text/plain` — the bytes as submitted, whose sha256 is the\n`source_hash` in the gate report.",
        "operationId": "get_foundry_compile_source_v1_v1_operator_tenants__tenant__foundry_compiles__compile_id__source_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "compile_id",
            "required": true,
            "schema": {
              "title": "Compile Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read a submission's source (the P6 countersigner's read)",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/product-keys": {
      "get": {
        "description": "The active enrollment and the fingerprints it superseded, or 404.",
        "operationId": "get_tenant_product_key_v1_v1_operator_tenants__tenant__product_keys_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductKeyResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read a tenant's bundle-signing key enrollment",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Record the public key whose signature proves who authored a Product Bundle.\n\n**Why this is an operator act and not self-service.** A tenant self-enrolling\nwould make the recorded authority only as strong as the API credential that\nenrolled it — and outliving that credential is the whole reason a detached\nsignature exists. The row records the enrolling client, so *who vouched that\nthis key is the tenant's* has an answer.\n\nIdempotent by fingerprint: the same key answers **200** with `enrolled: false`.\nA *different* key is refused **409** unless `replace: true`, and a rotation\nfiles the incumbent as superseded rather than overwriting it — a certification\nsigned under the old key must keep verifying, so its PEM stays published under\nits own fingerprint.\n\nPublic key only. There is no field a private key could be pasted into and no\ncode path that would know what to do with one.",
        "operationId": "enroll_tenant_product_key_v1_v1_operator_tenants__tenant__product_keys_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductKeyEnrollRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductKeyResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Enroll a tenant's bundle-signing public key",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/products": {
      "get": {
        "description": "This tenant's bindings, current version each, newest change first.\n\nSUSPENDED and RETIRED products are listed. Lifecycle gates writing, never\nobservation.",
        "operationId": "list_tenant_products_v1_v1_operator_tenants__tenant__products_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantProductListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List a tenant's product bindings",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/products/{product_id}": {
      "get": {
        "description": "One binding: its current version, every version recorded, and its history.\n\n⛔ A foreign tenant's `product_id` and one that never existed are the same\nDynamoDB miss — the tenant is a partition-key segment, so 404-before-403 holds\nin its strongest form: status, body, headers and the time taken to answer\ncannot differ.",
        "operationId": "get_tenant_product_v1_v1_operator_tenants__tenant__products__product_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantProductResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get a tenant product binding",
        "tags": [
          "Operator"
        ]
      },
      "patch": {
        "description": "DRAFT → CERTIFIED → LIVE → SUSPENDED → RETIRED, on the shipped table.\n\n**LIVE** requires `attestation.signed_by` — the platform countersignature of\nfounder decision P6. Pre-Foundry that is a recorded operator sign-off written\ninto the row's `certification` block; laas-86 replaces it with the certified\nartifact's own signature, in the same field.\n\n**SUSPENDED** is unilateral and immediate: the next create or advance answers\n409 `PRODUCT_NOT_ACCEPTING_WRITES` while a close still serves, because the\nadapter re-reads the binding on every write and exempts the close role.\nSuspending must stop new instances, never strand the ones an operator\nsuspended it to look at.\n\n**RETIRED** is terminal — there is no un-retire and no unbind verb at all.\nHistory stays resolvable: an obligation whose product no longer resolves is\nan audit hole.",
        "operationId": "transition_tenant_product_v1_v1_operator_tenants__tenant__products__product_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantProductLifecycleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantProductResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Move a product binding through its lifecycle",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Bind one certified artifact to exactly one tenant.\n\nThe registry/bindings split (Product Plane §4.4): the artifact is\ncontent-addressed and published here, and the **row** is what activates it.\nCertification without binding deploys nothing.\n\nFor a parametric template this carries the whole job: resolve this tenant's\nbinding params, apply them, derive the applied script hash and address the\nresult produces, publish the applied bytes, and write the row with\n`applied.{template_hash, script_key, params, param_values}`. Two tenants\nbinding one template get two addresses, and neither can be spent under the\nother's terms.\n\nIdempotent on artifact identity: a repeat with a byte-identical manifest and\nthe same baked-in params answers **200** with `bound: false` and appends no\nversion. A changed manifest hashes differently and supersedes.",
        "operationId": "bind_tenant_product_v1_v1_operator_tenants__tenant__products__product_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantProductBindRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantProductResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Bind a certified product artifact to one tenant",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/products/{product_id}/certification": {
      "get": {
        "description": "The signed certification, its countersignature if it has one, and staleness.\n\n⭐ **Stale is reported, never enforced.** A battery upgrade does not invalidate a\nLIVE product: an inventory-hash bump would otherwise be an estate-wide outage\ntriggered by adding an attack class, and the products it would take down are exactly\nthe ones that passed the previous inventory honestly. The certification records\n`battery_version` and `inventory_hash`; this read compares them against what the\nestate ships now and says so. Re-certification is a deliberate act.\n\nEverything needed to verify the artifact offline is in the response, and the\npublished public keys live beside it in the store — `keys/product-platform-*.pub.pem`\nand `keys/product-countersigner-*.pub.pem`. Check it with\n`scripts/verify-product-certification.py`, which needs no platform access at all.",
        "operationId": "get_tenant_product_certification_v1_v1_operator_tenants__tenant__products__product_id__certification_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read a product's certification envelope",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Assemble the **Certified Product Artifact**, sign it, and record CERTIFIED.\n\nStaples LaaS-83's gate report, LaaS-84's conformance transcript and LaaS-85's\nbattery report card **by reference** into one content-addressed document, captures\nthis product's golden vectors from its own IR schemas, records which relaxation\npolicy authorised the path, signs the body with the platform certification key and\npublishes the envelope to the WORM certification store.\n\n⛔ **It verifies evidence; it does not produce evidence.** Every named document is\nfetched, re-hashed against the hash the request gives, and checked for an\n`accepted` verdict and a matching subject. A route that produced its own evidence\nand then judged it would be a route that certifies itself.\n\n⛔ **Nothing is published if the evidence does not support a certification.** A\nrefused certification is not an artifact, and the store's objects cannot be deleted.\n\nAlso the re-certification path: run against a CERTIFIED or LIVE binding it replaces\nthe certification block and leaves the state alone, because `CERTIFIED → CERTIFIED`\nis not an edge in the transition table and inventing one would make the table stop\ndescribing the machine.",
        "operationId": "certify_tenant_product_v1_v1_operator_tenants__tenant__products__product_id__certification_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantProductCertifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Certify a product binding against its evidence",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/products/{product_id}/drain": {
      "get": {
        "description": "Per open instance, the route that closes it — or the reason there is none.\n\nMigration between versions is **close-and-reopen** (Product Plane §4.2 step 5):\nhash is address, so a new version is a new address by construction and no\ntransaction moves value between them. This plans the closing half.\n\nThe routes come from the manifest's own close actions, walked by the same planner\nconformance uses — a per-product drain command would be the platform re-authoring\nwhat the tenant declared. An instance in a reachable non-terminal state with **no\npath out** is reported as `no_route` by name: its value is stranded, that is a\nmanifest defect rather than an operational one, and no drain will move it.\n\nRead-only. `POST` to the same path executes, and it needs an explicit id list.",
        "operationId": "plan_product_drain_v1_v1_operator_tenants__tenant__products__product_id__drain_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Plan a drain: how each open instance would be closed",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Close the instances named in `instance_ids`, through the shipped close path.\n\n⛔ Needs `consent: true` and an explicit id list. There is no close-everything\nshape, because the operator reaching for a drain is usually reaching for it under\ntime pressure and a plan they did not read is not consent.\n\n⚠️ **Best-effort per instance, and it does not stop on the first failure.** Every\nclose is independent, so there is nothing a rollback could mean — and a drain that\naborted half-way would leave an operator with no record of which closes landed. Each\ninstance gets its own outcome in `results`.",
        "operationId": "execute_product_drain_v1_v1_operator_tenants__tenant__products__product_id__drain_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantProductDrainRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Drain a product: close the named instances",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/provider-accounts": {
      "get": {
        "description": "Every processor account this tenant holds.\n\nNever carries credential material — that crosses out once, on the call that\nopened the account, and is not recoverable from here or from the processor.",
        "operationId": "list_provider_accounts_v1_v1_operator_tenants__tenant__provider_accounts_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderAccountListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List a tenant's processor accounts",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Open one account for this tenant at a processor, and record it.\n\n⚠️ **The response carries the account's credential exactly once, and the\nplatform never stores it.** A processor that mints one at creation cannot show\nit again — capture it from this response and provision it at the\n`credential.secret_ref` path, which is where the driver resolves it from. Until\nthat is done the binding answers `credential_status: PENDING_PROVISION` and\nany dispatch through it fails closed with a config error rather than moving\nmoney with no credentials.\n\nIdempotent **by the recorded account**, not by an `Idempotency-Key`: if this\ntenant already holds an account at this provider the processor is never called,\nbecause opening an account is *not* idempotent at the far end — a retry opens a\nsecond real account. A repeat returns the existing binding with\n`provisioned: false` and no credential.\n\nA **different** account already bound for the same tenant and provider is\nrefused with 409 rather than replaced: the first one is still open and can\nstill receive money, so overwriting the row would orphan it silently.",
        "operationId": "provision_provider_account_v1_v1_operator_tenants__tenant__provider_accounts_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderAccountRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderAccountResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Open a tenant's account at a processor",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/provider-accounts/{provider_id}/transfers": {
      "post": {
        "description": "Move float out of this tenant's account at `provider_id`.\n\n⛔ **The source is the binding named in the path**, and the driver resolved\nfrom it is authenticated as that account. There is deliberately no source\nfield on the body: a cross-tenant debit would then be one mistyped value away,\nand such a debit reconciles to zero on both sides, which is what makes it\nnearly invisible.\n\nThis is a **treasury** operation, not a customer payment. A transfer between\ntwo customers is a ledger movement on the head and involves no processor —\nwhat this moves is the fiat float backing a tenant's ledger balance, so that\neach processor account matches the mirror that proves it.\n\n⚠️ `authorized: false` means the processor is holding the transfer for an\nout-of-band human approval. The value is queued either way; do not re-send.",
        "operationId": "transfer_between_provider_accounts_v1_v1_operator_tenants__tenant__provider_accounts__provider_id__transfers_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "provider_id",
            "required": true,
            "schema": {
              "title": "Provider Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderAccountTransferRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderAccountTransferResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Move value between two accounts inside one processor",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/qbrl-policy": {
      "get": {
        "description": "The tenant's policy binding, or 404 when it has none.",
        "operationId": "get_tenant_qbrl_policy_v1_v1_operator_tenants__tenant__qbrl_policy_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantQbrlPolicyResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read a tenant's QBRL minting policy binding",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Provision a tenant's own QBRL minting policy on a **running** head.\n\nUnder the shared-head tenancy tier a tenant's money is distinguished only by\nits minting policy, so this is the act of onboarding one. It generates the\ntenant's issuer keypair, derives the native `sig` script and its policy id,\nrecords the binding and creates the tenant's supply GL node.\n\nIdempotent by construction — a repeat call returns the same policy id with\n`provisioned: false`, and no `Idempotency-Key` is required because the binding\nwrite is conditional on the policy already matching. A second, *different*\npolicy for a tenant is refused with 409 rather than replacing the first: value\nalready minted under the old one would still be on the head and would read as\na foreign token.\n\nThis does not mint. Where the faucet's elastic supply is armed, the tenant's\nfirst funded transfer mints its opening balance under the policy bound here.",
        "operationId": "provision_tenant_qbrl_policy_v1_v1_operator_tenants__tenant__qbrl_policy_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantQbrlPolicyResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Bind a tenant to its own QBRL minting policy",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/quotas": {
      "get": {
        "description": "The effective quota, where it came from, and how much of today is spent.",
        "operationId": "get_tenant_quota_v1_v1_operator_tenants__tenant__quotas_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantQuotaResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read a tenant's quota and current usage",
        "tags": [
          "Operator"
        ]
      },
      "put": {
        "description": "Raise or lower what one tenant may spend on metered Foundry work.\n\n⚠️ **Absence is the estate default, not zero.** A tenant with no row here is a\ntenant nobody has priced yet, which is the opposite of how an unbound QBRL\npolicy resolves — and right for the same reason stated in reverse: there is a\nsafe default for a compile allowance and there is none for *whose money is\nthis*.\n\n**The meter ships; the pricing does not.** What a compile hour is worth, and\nwhich tenants get how many, is a commercial decision owned by the founders.\nThis route is how that decision is applied once it is made.",
        "operationId": "put_tenant_quota_v1_v1_operator_tenants__tenant__quotas_put",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantQuotaRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantQuotaResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Set a tenant's quota overrides",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/rail-bindings": {
      "get": {
        "description": "Every provider connection whose inbound credits belong to this tenant.\n\nAn empty list is the honest answer for a tenant with no routes, and it is the\nstate every tenant starts in: with no rows provisioned, inbound routing\nanswers through the incumbent chain exactly as it always has.",
        "operationId": "list_provider_routes_v1_v1_operator_tenants__tenant__rail_bindings_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderRouteListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List a tenant's inbound provider routes",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Record which tenant receives inbound credits through a provider.\n\nA provider-authenticated webhook carries no bearer, so the tenant a credit\nbelongs to cannot come from a caller — it comes from the provider binding,\nand until this row existed a binding could only name the environment's own\ntenant. Writing it is what lets a non-incumbent tenant receive money.\n\nIdempotent — a repeat call returns the same binding with `provisioned: false`,\nand no `Idempotency-Key` is required because the write is conditional on the\nowner already matching. A **second, different** tenant for one\n`(rail, provider_id)` pair is refused with 409 rather than replacing the\nfirst: a provider id identifies exactly one tenant, and silently rerouting it\nwould move a live inbound stream into another ledger. Two tenants on the same\nprocessor use two provider ids.",
        "operationId": "provision_provider_route_v1_v1_operator_tenants__tenant__rail_bindings_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderRouteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderRoute"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Assign a provider's inbound credits to a tenant",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/transfer-templates": {
      "get": {
        "description": "This tenant's templates, current version each, newest change first.\n\nRETIRED templates are listed: retiring gates new execution, never observation.",
        "operationId": "list_tenant_transfer_templates_v1_v1_operator_tenants__tenant__transfer_templates_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantTemplateListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List a tenant's transfer templates",
        "tags": [
          "Operator"
        ]
      },
      "post": {
        "description": "Author, or supersede, one tenant-scoped transfer template.\n\nThe body is validated by calling the **same** `_parse_template` the committed\n`transfer_templates.json` is parsed by, so a tenant-authored template is held\nto every invariant an operator-authored one is. Versions are immutable and\ncontent-hashed: `template_version` must be strictly greater than this tenant's\ncurrent version for the id, and the new version becomes current (D2). A\ncolliding id — a platform template's name, or a version that does not\nsupersede — is refused here, so the ambiguity never exists at execute time.",
        "operationId": "create_tenant_transfer_template_v1_v1_operator_tenants__tenant__transfer_templates_post",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantTemplateCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantTemplateResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Author a tenant transfer template",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/operator/tenants/{tenant}/transfer-templates/{template_id}": {
      "get": {
        "description": "One template's current version plus every version ever recorded.\n\nA retired version still resolves here, and deletion has no code path at all —\nan obligation whose `template_content_hash` no longer resolves is an audit hole.",
        "operationId": "get_tenant_transfer_template_v1_v1_operator_tenants__tenant__transfer_templates__template_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "template_id",
            "required": true,
            "schema": {
              "title": "Template Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantTemplateResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get a tenant transfer template",
        "tags": [
          "Operator"
        ]
      },
      "patch": {
        "description": "Retire the current version: no new execution, still readable.\n\n`RETIRED` is the only accepted status — a rejected `ACTIVE` is the model's\n`Literal`, i.e. a 422 from FastAPI. Idempotent: a repeat answers 200 with the\nalready-retired row. Reactivation is a new version (D2's supersede path).",
        "operationId": "retire_tenant_transfer_template_v1_v1_operator_tenants__tenant__transfer_templates__template_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "title": "Tenant",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "template_id",
            "required": true,
            "schema": {
              "title": "Template Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantTemplateStatusPatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantTemplateResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Retire a tenant transfer template",
        "tags": [
          "Operator"
        ]
      }
    },
    "/v1/parties/{party_id}/kyc": {
      "post": {
        "description": "Start verification + initial screening (D3: not_performed → pending →\nsync verdict, review on screening hit, or async pending via webhook).",
        "operationId": "submit_kyc_v1_v1_parties__party_id__kyc_post",
        "parameters": [
          {
            "in": "path",
            "name": "party_id",
            "required": true,
            "schema": {
              "title": "Party Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KycSubmitRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Submit KYC verification for a party",
        "tags": [
          "KYC"
        ]
      }
    },
    "/v1/parties/{party_id}/kyc/status": {
      "patch": {
        "description": "Operator-only review exit (Ticket 24's consumer seam): review →\nverified requires all screening-sourced flags resolved (422 otherwise).",
        "operationId": "update_kyc_status_v1_v1_parties__party_id__kyc_status_patch",
        "parameters": [
          {
            "in": "path",
            "name": "party_id",
            "required": true,
            "schema": {
              "title": "Party Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KycStatusPatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Operator KYC review resolution",
        "tags": [
          "KYC"
        ]
      }
    },
    "/v1/parties/{party_id}/risk-flags": {
      "post": {
        "operationId": "add_risk_flag_v1_v1_parties__party_id__risk_flags_post",
        "parameters": [
          {
            "in": "path",
            "name": "party_id",
            "required": true,
            "schema": {
              "title": "Party Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RiskFlagCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Add a risk flag to a party",
        "tags": [
          "KYC"
        ]
      }
    },
    "/v1/parties/{party_id}/risk-flags/{flag_id}": {
      "delete": {
        "operationId": "resolve_risk_flag_v1_v1_parties__party_id__risk_flags__flag_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "party_id",
            "required": true,
            "schema": {
              "title": "Party Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "flag_id",
            "required": true,
            "schema": {
              "title": "Flag Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Resolve a risk flag (soft-resolve; row kept for audit)",
        "tags": [
          "KYC"
        ]
      }
    },
    "/v1/pix/keys": {
      "post": {
        "description": "Register a Pix key (EMAIL/PHONE/CPF/CNPJ, or sponsor-minted EVP) for a\nCUSTOMER account. A sponsor rejection still returns 201 with the key row\nin REGISTRATION_FAILED — portability starts from that row.\n\nRequires an Idempotency-Key header.",
        "operationId": "register_pix_key_v1_v1_pix_keys_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PixKeyRegisterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Register a Pix key via the sponsor's DICT access",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/keys/events": {
      "post": {
        "deprecated": true,
        "description": "**Deprecated — use `POST /v1/pix/keys/events/{provider_id}`.**\n\nKept live through the LaaS-39 rollout; resolves the incumbent provider\n(`PIX_SPONSOR_ID`). Removed when LaaS-43 lands. Note that the *signature\nscheme* changed here even on this path. The old `X-Sim-Signature`\nheader is no longer accepted; it carried no timestamp, so it bounded\nreplay by nothing at all.",
        "operationId": "receive_pix_key_event_v1_legacy_v1_pix_keys_events_post",
        "parameters": [
          {
            "description": "Unix epoch seconds, integer string. Sent by providers bound to the `timestamped_hmac_v1` strategy (the default).",
            "in": "header",
            "name": "X-Webhook-Timestamp",
            "required": true,
            "schema": {
              "title": "X-Webhook-Timestamp",
              "type": "string"
            }
          },
          {
            "description": "`v1=<hex(HMAC_SHA256(secret, timestamp + '.' + raw_body))>`, verified inside a freshness window. This is the `timestamped_hmac_v1` strategy; a provider bound to another strategy sends that strategy's headers instead, and the binding for `{provider_id}` decides which applies.",
            "in": "header",
            "name": "X-Webhook-Signature",
            "required": true,
            "schema": {
              "title": "X-Webhook-Signature",
              "type": "string"
            }
          },
          {
            "description": "Provider delivery handle; becomes the derived idempotency key when present, else the key is derived from the body bytes.",
            "in": "header",
            "name": "X-Webhook-Delivery-Id",
            "required": false,
            "schema": {
              "title": "X-Webhook-Delivery-Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Sponsor DICT key-event ingest (deprecated alias)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/keys/events/{provider_id}": {
      "post": {
        "description": "Ingest provider key events (KEY_* / CLAIM_*). Authenticated by the\nverification strategy the `{provider_id}` binding selects, against that\nprovider's own secret (LaaS-39 D4 — this route previously used a static\nbody HMAC with no timestamp and therefore no replay bound at all).\nRedelivery-idempotent via a DEDUPE# row; out-of-order events no-op on the\nstate guards (AC4).",
        "operationId": "receive_pix_key_event_v1_v1_pix_keys_events__provider_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "provider_id",
            "required": true,
            "schema": {
              "title": "Provider Id",
              "type": "string"
            }
          },
          {
            "description": "Unix epoch seconds, integer string. Sent by providers bound to the `timestamped_hmac_v1` strategy (the default).",
            "in": "header",
            "name": "X-Webhook-Timestamp",
            "required": true,
            "schema": {
              "title": "X-Webhook-Timestamp",
              "type": "string"
            }
          },
          {
            "description": "`v1=<hex(HMAC_SHA256(secret, timestamp + '.' + raw_body))>`, verified inside a freshness window. This is the `timestamped_hmac_v1` strategy; a provider bound to another strategy sends that strategy's headers instead, and the binding for `{provider_id}` decides which applies.",
            "in": "header",
            "name": "X-Webhook-Signature",
            "required": true,
            "schema": {
              "title": "X-Webhook-Signature",
              "type": "string"
            }
          },
          {
            "description": "Provider delivery handle; becomes the derived idempotency key when present, else the key is derived from the body bytes.",
            "in": "header",
            "name": "X-Webhook-Delivery-Id",
            "required": false,
            "schema": {
              "title": "X-Webhook-Delivery-Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Sponsor DICT key-event ingest",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/keys/lookup": {
      "get": {
        "description": "Look up a Pix key in the DICT via the sponsor: recipient display name,\nmasked tax id, participant, and fraud markers (D8). Persists nothing —\nno database dependency at all; sponsor unreachable or unset → 503 (a\ndirectory read has no meaningful stub).",
        "operationId": "lookup_pix_key_v1_v1_pix_keys_lookup_get",
        "parameters": [
          {
            "in": "query",
            "name": "key",
            "required": true,
            "schema": {
              "maxLength": 120,
              "minLength": 1,
              "title": "Key",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Pre-payment DICT lookup",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/keys/{key_id}": {
      "delete": {
        "description": "Exclude an ACTIVE key (idempotent: re-DELETE of an EXCLUDED key\nreturns 200). The ledger identity row is released — the same normalized\nkey can be registered again on a fresh key row.",
        "operationId": "exclude_pix_key_v1_v1_pix_keys__key_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Exclude a Pix key from the DICT",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/keys/{key_id}/portability/cancel": {
      "post": {
        "description": "Cancel the active claim on this key (either role).",
        "operationId": "cancel_pix_claim_v1_v1_pix_keys__key_id__portability_cancel_post",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Cancel the key's active claim",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/keys/{key_id}/portability/claim": {
      "post": {
        "description": "Start portability for a key whose registration failed because the key\nis owned elsewhere (REGISTRATION_FAILED row). Requires Idempotency-Key.",
        "operationId": "open_pix_portability_claim_v1_v1_pix_keys__key_id__portability_claim_post",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Open a portability claim (we are the claimer)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/keys/{key_id}/portability/confirm": {
      "post": {
        "description": "Confirm the active claim on this key. Serves both roles — as DONOR it\nlets the claim proceed; the record's role field disambiguates.",
        "operationId": "confirm_pix_claim_v1_v1_pix_keys__key_id__portability_confirm_post",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Confirm the key's active claim",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/mandates/events": {
      "post": {
        "deprecated": true,
        "description": "**Deprecated — use `POST /v1/pix/mandates/events/{provider_id}`.**\n\nKept live through the LaaS-39 rollout; resolves the incumbent provider\n(`PIX_SPONSOR_ID`). Removed when LaaS-43 lands. As with the key-event\nreceiver, the *signature scheme* changed here too. The old\n`X-Sim-Signature` header is no longer accepted; it carried no timestamp\nand therefore no replay window.",
        "operationId": "receive_pix_mandate_event_v1_legacy_v1_pix_mandates_events_post",
        "parameters": [
          {
            "description": "Unix epoch seconds, integer string. Sent by providers bound to the `timestamped_hmac_v1` strategy (the default).",
            "in": "header",
            "name": "X-Webhook-Timestamp",
            "required": true,
            "schema": {
              "title": "X-Webhook-Timestamp",
              "type": "string"
            }
          },
          {
            "description": "`v1=<hex(HMAC_SHA256(secret, timestamp + '.' + raw_body))>`, verified inside a freshness window. This is the `timestamped_hmac_v1` strategy; a provider bound to another strategy sends that strategy's headers instead, and the binding for `{provider_id}` decides which applies.",
            "in": "header",
            "name": "X-Webhook-Signature",
            "required": true,
            "schema": {
              "title": "X-Webhook-Signature",
              "type": "string"
            }
          },
          {
            "description": "Provider delivery handle; becomes the derived idempotency key when present, else the key is derived from the body bytes.",
            "in": "header",
            "name": "X-Webhook-Delivery-Id",
            "required": false,
            "schema": {
              "title": "X-Webhook-Delivery-Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Sponsor Pix Automático event ingest (deprecated alias)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/mandates/events/{provider_id}": {
      "post": {
        "description": "Ingest provider mandate events (MANDATE_* / CHARGE_*). Authenticated by the\nverification strategy the `{provider_id}` binding selects, against that\nprovider's own secret (LaaS-39 D4 — this route previously used a static\nbody HMAC with no timestamp and therefore no replay bound at all).\nRedelivery-idempotent via a DEDUPE# row; out-of-order events no-op on the\nstate guards.",
        "operationId": "receive_pix_mandate_event_v1_v1_pix_mandates_events__provider_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "provider_id",
            "required": true,
            "schema": {
              "title": "Provider Id",
              "type": "string"
            }
          },
          {
            "description": "Unix epoch seconds, integer string. Sent by providers bound to the `timestamped_hmac_v1` strategy (the default).",
            "in": "header",
            "name": "X-Webhook-Timestamp",
            "required": true,
            "schema": {
              "title": "X-Webhook-Timestamp",
              "type": "string"
            }
          },
          {
            "description": "`v1=<hex(HMAC_SHA256(secret, timestamp + '.' + raw_body))>`, verified inside a freshness window. This is the `timestamped_hmac_v1` strategy; a provider bound to another strategy sends that strategy's headers instead, and the binding for `{provider_id}` decides which applies.",
            "in": "header",
            "name": "X-Webhook-Signature",
            "required": true,
            "schema": {
              "title": "X-Webhook-Signature",
              "type": "string"
            }
          },
          {
            "description": "Provider delivery handle; becomes the derived idempotency key when present, else the key is derived from the body bytes.",
            "in": "header",
            "name": "X-Webhook-Delivery-Id",
            "required": false,
            "schema": {
              "title": "X-Webhook-Delivery-Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Sponsor Pix Automático mandate/charge event ingest",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/mandates/{mandate_id}/authorize": {
      "post": {
        "operationId": "authorize_pix_mandate_v1_v1_pix_mandates__mandate_id__authorize_post",
        "parameters": [
          {
            "in": "path",
            "name": "mandate_id",
            "required": true,
            "schema": {
              "title": "Mandate Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Authorize a Pix Automático mandate (relayed to the sponsor)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/mandates/{mandate_id}/charges/{charge_id}/cancel": {
      "post": {
        "operationId": "cancel_pix_mandate_charge_v1_v1_pix_mandates__mandate_id__charges__charge_id__cancel_post",
        "parameters": [
          {
            "in": "path",
            "name": "mandate_id",
            "required": true,
            "schema": {
              "title": "Mandate Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "charge_id",
            "required": true,
            "schema": {
              "title": "Charge Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Cancel a pending mandate charge pre-debit (relayed to the sponsor)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/mandates/{mandate_id}/reject": {
      "post": {
        "operationId": "reject_pix_mandate_v1_v1_pix_mandates__mandate_id__reject_post",
        "parameters": [
          {
            "in": "path",
            "name": "mandate_id",
            "required": true,
            "schema": {
              "title": "Mandate Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Reject a pending Pix Automático mandate",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/mandates/{mandate_id}/revoke": {
      "post": {
        "operationId": "revoke_pix_mandate_v1_v1_pix_mandates__mandate_id__revoke_post",
        "parameters": [
          {
            "in": "path",
            "name": "mandate_id",
            "required": true,
            "schema": {
              "title": "Mandate Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Revoke an ACTIVE mandate (releases holds, cancels pending charges)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/med/cases": {
      "post": {
        "description": "Open an OUTBOUND MED case for our customer's claim and file it with the\nsponsor synchronously (LaaS-16 D10). A sponsor timeout leaves the case\nFILING and returns 503 — the Idempotency-Key retry re-files the same\ncase_id, which the sponsor dedupes.",
        "operationId": "create_pix_med_case_v1_v1_pix_med_cases_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MedCaseCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "File a MED infraction with the sponsor",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/med/cases/{case_id}/resolve": {
      "post": {
        "description": "RETURN executes the devolução: the block is captured to the clearing\naccount and the capture obligation rides the deferred-dispatch lifecycle\nto the sponsor's return API (D8). RELEASE answers the sponsor and lifts\nthe block. Single-shot per block — concurrent resolvers lose with 409.",
        "operationId": "resolve_pix_med_case_v1_v1_pix_med_cases__case_id__resolve_post",
        "parameters": [
          {
            "in": "path",
            "name": "case_id",
            "required": true,
            "schema": {
              "title": "Case Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MedCaseResolveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Resolve a MED case (RETURN or RELEASE)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/med/events": {
      "post": {
        "deprecated": true,
        "description": "**Deprecated — use `POST /v1/pix/med/events/{provider_id}`.**\n\nKept live through the LaaS-39 rollout so a provider already posting here is\nnot cut off mid-flight. It resolves the incumbent provider (`PIX_SPONSOR_ID`)\nand behaves identically in every other respect. Removed when LaaS-43 lands.",
        "operationId": "receive_pix_med_event_v1_legacy_v1_pix_med_events_post",
        "parameters": [
          {
            "description": "Unix epoch seconds, integer string. Sent by providers bound to the `timestamped_hmac_v1` strategy (the default).",
            "in": "header",
            "name": "X-Webhook-Timestamp",
            "required": true,
            "schema": {
              "title": "X-Webhook-Timestamp",
              "type": "string"
            }
          },
          {
            "description": "`v1=<hex(HMAC_SHA256(secret, timestamp + '.' + raw_body))>`, verified inside a freshness window. This is the `timestamped_hmac_v1` strategy; a provider bound to another strategy sends that strategy's headers instead, and the binding for `{provider_id}` decides which applies.",
            "in": "header",
            "name": "X-Webhook-Signature",
            "required": true,
            "schema": {
              "title": "X-Webhook-Signature",
              "type": "string"
            }
          },
          {
            "description": "Provider delivery handle; becomes the derived idempotency key when present, else the key is derived from the body bytes.",
            "in": "header",
            "name": "X-Webhook-Delivery-Id",
            "required": false,
            "schema": {
              "title": "X-Webhook-Delivery-Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Sponsor MED case-event receiver (deprecated alias)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/med/events/{provider_id}": {
      "post": {
        "description": "Authenticated receiver for provider MED infraction/case notifications\n(LaaS-16 D2; per-provider since LaaS-39). Case events are NOT evidence — an\ninfraction moves nothing at ingest — so they land here instead of the\nevidence pipe. Authenticated by the verification strategy the\n`{provider_id}` binding selects, against that provider's own secret;\n2xx-on-applied.",
        "operationId": "receive_pix_med_event_v1_v1_pix_med_events__provider_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "provider_id",
            "required": true,
            "schema": {
              "title": "Provider Id",
              "type": "string"
            }
          },
          {
            "description": "Unix epoch seconds, integer string. Sent by providers bound to the `timestamped_hmac_v1` strategy (the default).",
            "in": "header",
            "name": "X-Webhook-Timestamp",
            "required": true,
            "schema": {
              "title": "X-Webhook-Timestamp",
              "type": "string"
            }
          },
          {
            "description": "`v1=<hex(HMAC_SHA256(secret, timestamp + '.' + raw_body))>`, verified inside a freshness window. This is the `timestamped_hmac_v1` strategy; a provider bound to another strategy sends that strategy's headers instead, and the binding for `{provider_id}` decides which applies.",
            "in": "header",
            "name": "X-Webhook-Signature",
            "required": true,
            "schema": {
              "title": "X-Webhook-Signature",
              "type": "string"
            }
          },
          {
            "description": "Provider delivery handle; becomes the derived idempotency key when present, else the key is derived from the body bytes.",
            "in": "header",
            "name": "X-Webhook-Delivery-Id",
            "required": false,
            "schema": {
              "title": "X-Webhook-Delivery-Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Sponsor MED case-event receiver (infractions)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/qr/decode": {
      "post": {
        "description": "Parse + validate any scanned BR Code locally (TLV + CRC); dynamic\npayloads are resolved through the sponsor — Core never fetches scanned\nURLs (D7). Persists nothing; malformed input -> 422 INVALID_BRCODE with\na structured reason.",
        "operationId": "decode_pix_qr_v1_v1_pix_qr_decode_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PixQrDecodeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Decode a scanned BR Code payload",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/qr/{account_id}/dynamic": {
      "post": {
        "description": "Create a single-use dynamic charge: Core mints the txid, the sponsor\ncreates + hosts the JWS location document, Core persists the PIXQR# row\nand composes the EMV envelope locally (D3). Requires an ACTIVE Ticket-14\nkey owned by the account (defaulted when there is exactly one).\n\nRequires an Idempotency-Key header.",
        "operationId": "create_dynamic_pix_qr_v1_v1_pix_qr__account_id__dynamic_post",
        "parameters": [
          {
            "in": "path",
            "name": "account_id",
            "required": true,
            "schema": {
              "title": "Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PixQrDynamicCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a dynamic Pix QR (sponsor-hosted single-use charge)",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/return": {
      "post": {
        "description": "Return (part of) a Pix credit this account received (LaaS-16 D4): a new\ncounter-obligation on the deferred-dispatch lifecycle, referencing the\noriginal's E2EID. Partial and multiple returns are allowed, cumulatively\ncapped at the original amount. Requires an Idempotency-Key header.",
        "operationId": "create_pix_return_v1_v1_pix_return_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PixReturnRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Initiate a devolução of a received Pix credit",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/pix/webhooks/{provider_id}": {
      "post": {
        "description": "Authenticated receiver for provider Pix webhooks (LaaS-12; per-provider\nsince LaaS-39).\n\nUnauthenticated at the API Gateway (authorization_type=NONE — providers\ncannot do Cognito client-credentials); authenticated in-handler by the\nverification strategy the `{provider_id}` binding selects, against that\nprovider's own secret. The default strategy is `timestamped_hmac_v1` —\nLaaS-12's D6 contract, unchanged — inside a ±300 s freshness window.\nRoutes the raw provider payload through the same in-process pipeline as\n``POST /v1/evidence`` and returns a minimal ack; obligation internals never\nleak to the provider, and a rejection never says which check failed.",
        "operationId": "receive_pix_webhook_v1_v1_pix_webhooks__provider_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "provider_id",
            "required": true,
            "schema": {
              "title": "Provider Id",
              "type": "string"
            }
          },
          {
            "description": "Unix epoch seconds, integer string. Sent by providers bound to the `timestamped_hmac_v1` strategy (the default).",
            "in": "header",
            "name": "X-Webhook-Timestamp",
            "required": true,
            "schema": {
              "title": "X-Webhook-Timestamp",
              "type": "string"
            }
          },
          {
            "description": "`v1=<hex(HMAC_SHA256(secret, timestamp + '.' + raw_body))>`, verified inside a freshness window. This is the `timestamped_hmac_v1` strategy; a provider bound to another strategy sends that strategy's headers instead, and the binding for `{provider_id}` decides which applies.",
            "in": "header",
            "name": "X-Webhook-Signature",
            "required": true,
            "schema": {
              "title": "X-Webhook-Signature",
              "type": "string"
            }
          },
          {
            "description": "Provider delivery handle; becomes the derived idempotency key when present, else the key is derived from the body bytes.",
            "in": "header",
            "name": "X-Webhook-Delivery-Id",
            "required": false,
            "schema": {
              "title": "X-Webhook-Delivery-Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Sponsor Pix inbound webhook receiver",
        "tags": [
          "Pix"
        ]
      }
    },
    "/v1/products/{product_id}": {
      "post": {
        "description": "Draft-mode deploy: bind one of the shipped templates for your own tenant.\n\nBindable **only in a showcase sandbox estate** — faucet money, simulated rails,\nreset with notice — because a DRAFT artifact has passed no conformance run and no\nadversarial battery. A production binding is born CERTIFIED naming a\ncertification produced elsewhere, and that is an operator call.\n\nIdempotent on artifact identity: a repeat with a byte-identical manifest answers\n**200** with `bound: false` and appends no version.\n\n⚠️ Two preconditions that are not about your manifest, both named in the refusal\nif you meet them: a tenant with no QBRL minting-policy binding cannot resolve its\nbinding params, and a non-incumbent tenant cannot yet receive an inbound credit at\nall — so it can bind and plan its scenarios, and cannot fund an instance.",
        "operationId": "draft_bind_product_v1_v1_products__product_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantDraftBindRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantDraftBindResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Bind a shipped template as your own DRAFT product",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/battery": {
      "post": {
        "description": "Attack your applied script with the generated battery, and report a card.\n\n**202, not 201** — the engine is a bounded job, not a request. Poll the\ncompanion `GET`.\n\nThe battery evaluates your applied script's **UPLC** against contexts it\nassembles, fuel-bounded, in a networkless sandbox. It never submits a\ntransaction: most of these attacks cannot be *built* by the platform's own\ninterpreter, and of those that can, the ledger would refuse them before your\nscript ran — so a live-head battery would go green having measured the chain\nrather than your Haskell.\n\n⚠️ **Grey is not green.** A class whose positive control the script refused\nanyway proved nothing and is reported `inconclusive`, which a certification\ntreats exactly as it treats a red.\n\n⚠️ One at a time per product: a second run would spend a build slot answering a\nquestion already in flight, and two cards for one script make \"which one did\nthe certification reference\" a guess.\n\nErrors:\n  404: PRODUCT_NOT_FOUND (also for another tenant's)\n  409: BATTERY_ALREADY_RUNNING\n  422: PRODUCT_NOT_PLANNABLE, BATTERY_NOT_PLANNABLE, PRODUCT_NOT_PARAMETRIC\n  503: PRODUCT_ARTIFACT_UNAVAILABLE",
        "operationId": "start_product_battery_v1_v1_products__product_id__battery_post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Run the adversarial battery against your own product",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/battery/{battery_id}": {
      "get": {
        "description": "The run's status and, once `DONE`, where its signed card lives.\n\n⚠️ `RUNNING` for longer than the engine's own ceiling means the task was lost —\na background job does not survive a deploy — and starting a new one is then\npermitted. The row is not silently adopted.",
        "operationId": "get_product_battery_v1_v1_products__product_id__battery__battery_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "battery_id",
            "required": true,
            "schema": {
              "title": "Battery Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read a battery run and its report card",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/certification": {
      "get": {
        "description": "The signed certification for your own binding, its countersignature, staleness.\n\n⭐ **Stale is reported, never enforced.** A battery upgrade does not invalidate a\nLIVE product: an inventory bump would otherwise be an estate-wide outage triggered\nby adding an attack class, and the products it would take down are exactly the ones\nthat passed the previous inventory honestly.\n\n⚠️ **A DRAFT product answers 404 `CERTIFICATION_NOT_FOUND`, and that is the\nexpected state, not a fault.** Certification requires a conformance transcript,\nwhich needs a live head and a funded instance — and the estate stack that runs one\ndoes not exist yet, so a product you bind in the sandbox cannot be certified there\ntoday. The refusal says so.\n\nEverything needed to verify the artifact offline is in the response, and the\npublished public keys live beside it in the store. The referenced evidence is one\nhop away, at `…/certification/evidence/{kind}`.",
        "operationId": "product_certification_v1_v1_products__product_id__certification_get",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Your product's certification, and whether it has gone stale",
        "tags": [
          "Products"
        ]
      },
      "post": {
        "description": "Assemble, sign and record the Certified Product Artifact for your binding.\n\n⛔ **The body is empty and the evidence is looked up, not named.** An operator\nnaming `{hash, key}` is naming documents it has read; a tenant naming them could\nname somebody else's, and the certification's integrity checks would not catch\nit — a valid document about another product is still a valid document. So this\nroute finds what *your own* runs produced: the gate report from your compile\n(when the product came from one), the transcript from your sealed conformance\nrun, and the card from your completed battery.\n\n⚠️ **The battery card must describe your current applied script.** A card\nproduced before a version bump attests to different bytes, so it reads as absent\nrather than as evidence — the conservative direction, and the same equality\nlaas-86 puts at the LIVE gate.\n\nThis reaches **CERTIFIED**. It does not reach LIVE: that needs a human\ncountersignature the platform cannot mint, produced under a role no task role\ncan assume.\n\nErrors:\n  404: PRODUCT_NOT_FOUND\n  409: CONFORMANCE_REQUIRED, BATTERY_REQUIRED, PRODUCT_NOT_CERTIFIABLE\n  422: CERTIFICATION_EVIDENCE_REFUSED (an evidence verdict is not `accepted`)\n  503: CERTIFICATION_POLICY_UNAVAILABLE, GOLDEN_VECTOR_CAPTURE_UNAVAILABLE",
        "operationId": "certify_own_product_v1_v1_products__product_id__certification_post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Certify your own product from the evidence it produced",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/certification/evidence/{kind}": {
      "get": {
        "description": "The gate report, the conformance transcript, the battery card, or the vectors.\n\nA certification staples its evidence together **by reference**, because a hashed\ndocument cannot be rewritten and a battery card carries a whole transaction\ncontext per case. This is the dereference: the document at the key the signed body\nnames, re-hashed against the hash the signed body names.\n\n⛔ **Byte-exact, with nothing stripped.** Your recourse is to re-hash these bytes\nand compare, so a friendlier projection would break the only property that makes\nthe evidence worth reading.\n\nEach document carries its own claims and disclaims *inside* the hashed body — what\nit proves and what it explicitly does not. Read them: a renderer cannot omit what\nit does not control, and that is the point of them being there.",
        "operationId": "product_certification_evidence_v1_v1_products__product_id__certification_evidence__kind__get",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "kind",
            "required": true,
            "schema": {
              "title": "Kind",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "One evidence document a certification references",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/conformance": {
      "post": {
        "description": "Derive the plan, resolve the roster, and open a run you drive step by step.\n\nA conformance run is what turns a *declared* manifest into a *proved* one: every\naction it declares executed against the compiled script on a real head, with the\nschema IR round-tripping the datums the script accepted onto the chain.\n\n**You supply only accounts you own.** The platform resolves their verification\nkeys itself — no read publishes one, and a synthesised key produces an instance\nnobody can sign for — and it chooses every payload from the manifest, because an\naction driven with a value nobody chose proves nothing.\n\n⚠️ An incomplete plan does **not** refuse here. An uncovered action, an unreached\nterminal state or a dead-end state each becomes a failed finding and a `refused`\ntranscript, which is more useful than no document at all.\n\nErrors:\n  403: DRAFT_RUN_NOT_AVAILABLE (a DRAFT product outside a sandbox estate)\n  404: PRODUCT_NOT_FOUND, ACCOUNT_NOT_FOUND (both also for another tenant's)\n  409: PRODUCT_NOT_RUNNABLE (SUSPENDED or RETIRED)\n  422: PRODUCT_NOT_PLANNABLE, ROSTER_TOO_SMALL, ROSTER_NOT_DISTINCT,\n       ACCOUNT_NOT_USABLE\n  503: PRODUCT_ARTIFACT_UNAVAILABLE, ACCOUNT_KEY_UNAVAILABLE",
        "operationId": "open_conformance_run_v1_v1_products__product_id__conformance_post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConformanceRunOpenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Open a conformance run against your own product",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/conformance/{run_id}": {
      "get": {
        "description": "The run's plan with each step's recorded outcome merged in.\n\nOne read answers both *what is left* and *what happened*, because a client that\nhas to join two lists will eventually join them wrong. The rules a truthful\ndriver must honour travel in the response's own `driving` block.\n\n⛔ Another tenant's `run_id` and one that never existed are the same 404 — the\ntenant is a partition-key segment.",
        "operationId": "get_conformance_run_v1_v1_products__product_id__conformance__run_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "run_id",
            "required": true,
            "schema": {
              "title": "Run Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Read a conformance run, its steps and its verdict",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/conformance/{run_id}/steps/{index}": {
      "post": {
        "description": "Drive step `index`, then observe it from the head and record what happened.\n\nThe platform takes a UTxO snapshot before the step, drives it through the same\ngeneric write route you would call yourself, waits a bounded time for the\nchain's answer, snapshots again, and records the value deltas and the datum\nround-trip. **The observations are ours, taken from the head** — which is what\nmakes a run you drive usable as evidence.\n\n⛔ **A step is judged by `chain_outcome`, never by this call's status.** The\nwrite path is obligation-first: an action your validator refuses answers 200 and\nis refused a beat later.\n\nSteps run **in order**, one per request, starting at the run's `next_step`. A\nretry of the same index is safe and replays: the step's own conditional write is\nthe claim lock, and the idempotency key handed to the write is derived from\n(run, index).\n\nThe last step **seals** the run and publishes its transcript; the response\ncarries the verdict.\n\nErrors:\n  404: RUN_NOT_FOUND, STEP_NOT_FOUND\n  409: RUN_NOT_OPEN, STEP_OUT_OF_ORDER, SCENARIO_HAS_NO_INSTANCE\n  422: RUN_PRODUCT_MISMATCH\n  503: HEAD_SNAPSHOT_UNAVAILABLE, QBRL_POLICY_UNBOUND,\n       TRANSCRIPT_STORE_UNAVAILABLE",
        "operationId": "drive_conformance_step_v1_v1_products__product_id__conformance__run_id__steps__index__post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "run_id",
            "required": true,
            "schema": {
              "title": "Run Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "index",
            "required": true,
            "schema": {
              "title": "Index",
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConformanceStepRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Drive one step of a conformance run",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/instances": {
      "post": {
        "operationId": "create_product_instance_v1_v1_products__product_id__instances_post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductInstanceCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create an instance of a tenant product",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/instances/{instance_id}/actions/{action}": {
      "post": {
        "operationId": "advance_product_instance_v1_v1_products__product_id__instances__instance_id__actions__action__post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "instance_id",
            "required": true,
            "schema": {
              "title": "Instance Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "action",
            "required": true,
            "schema": {
              "title": "Action",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductActionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Drive a declared action on a product instance",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/instances/{instance_id}/close": {
      "post": {
        "operationId": "close_product_instance_v1_v1_products__product_id__instances__instance_id__close_post",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "instance_id",
            "required": true,
            "schema": {
              "title": "Instance Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductCloseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Close a product instance and release its value",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/products/{product_id}/scenarios": {
      "get": {
        "description": "Every declared action and terminal state, as a runnable plan.\n\n⭐ The plan is the one a conformance run derives — same pure function of the same\nmanifest — with the exact generic-route request per step. Run them yourself: this\nroute executes nothing.\n\n⛔ **Assert the outcome, never the HTTP status.** The write path is\nobligation-first, so an action the script refuses answers 200 and is refused on\nchain a beat later. The rules a truthful runner has to honour are in `driving`,\nin the response, because that is where somebody writing one will read them.\n\n⚠️ A step whose payload needs a real account's verification key comes back with\n`drivable: false` and `unsynthesizable` populated: no read publishes a key, so\nthe platform cannot hand you one to send. The plan is still worth reading.",
        "operationId": "product_scenarios_v1_v1_products__product_id__scenarios_get",
        "parameters": [
          {
            "in": "path",
            "name": "product_id",
            "required": true,
            "schema": {
              "title": "Product Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "The scenarios this product's manifest declares",
        "tags": [
          "Products"
        ]
      }
    },
    "/v1/recon/runs": {
      "post": {
        "description": "Run a recon cycle (statement match + classify + sweeps) or derive a\ndaily proof (LaaS-19 D3). Also driven by the in-process periodic sweep;\nthis is the operator/ops trigger.\n\nRaises:\n    400: invalid kind, or business_day supplied with kind=cycle\n    409: IDEMPOTENCY_KEY_REUSED",
        "operationId": "create_recon_run_v1_v1_recon_runs_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReconRunRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Trigger a reconciliation cycle or daily-proof derivation (operator)",
        "tags": [
          "Reconciliation"
        ]
      }
    },
    "/v1/scheduler/tick": {
      "post": {
        "description": "Idempotent by construction (every claim/transition is conditional), so\ndouble-driving against the in-process ticker is harmless. The production\nbelt calls this at rate(1 minute) via an EventBridge API destination.",
        "operationId": "scheduler_tick_v1_v1_scheduler_tick_post",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Drive one engine tick (internal — the D8 EventBridge belt)",
        "tags": [
          "Schedules"
        ]
      }
    },
    "/v1/schedules": {
      "post": {
        "description": "Create a ONE_SHOT or RECURRING schedule whose action runs through the\nordinary obligation funnel at each due instant. Requires an\nIdempotency-Key header.",
        "operationId": "create_schedule_v1_v1_schedules_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateScheduleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a scheduled action (Pix Agendado / recurring rule)",
        "tags": [
          "Schedules"
        ]
      }
    },
    "/v1/schedules/{schedule_id}": {
      "delete": {
        "operationId": "cancel_schedule_v1_v1_schedules__schedule_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "schedule_id",
            "required": true,
            "schema": {
              "title": "Schedule Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Cancel a schedule (terminal)",
        "tags": [
          "Schedules"
        ]
      },
      "patch": {
        "operationId": "patch_schedule_v1_v1_schedules__schedule_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "schedule_id",
            "required": true,
            "schema": {
              "title": "Schedule Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchScheduleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Edit a schedule (amount, creditor, rule, timezone, grace, retry)",
        "tags": [
          "Schedules"
        ]
      }
    },
    "/v1/schedules/{schedule_id}/pause": {
      "post": {
        "operationId": "pause_schedule_v1_v1_schedules__schedule_id__pause_post",
        "parameters": [
          {
            "in": "path",
            "name": "schedule_id",
            "required": true,
            "schema": {
              "title": "Schedule Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Pause an ACTIVE schedule (clears the due pointer)",
        "tags": [
          "Schedules"
        ]
      }
    },
    "/v1/schedules/{schedule_id}/resume": {
      "post": {
        "operationId": "resume_schedule_v1_v1_schedules__schedule_id__resume_post",
        "parameters": [
          {
            "in": "path",
            "name": "schedule_id",
            "required": true,
            "schema": {
              "title": "Schedule Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Resume a PAUSED schedule (next occurrence recomputed from now)",
        "tags": [
          "Schedules"
        ]
      }
    },
    "/v1/squads": {
      "post": {
        "description": "Create a Squad (RFC-018) and its Config UTxO at the SquadValidator.\n\nThin wrapper: payload validation → idempotency cache →\n``SquadAdapter.create_instance`` → response caching. The creator becomes the\nsole OWNER member; the squad account row is persisted with ``vk=null`` (the\nsquad has no key — chain enforces all authority). Caller-identity\n(ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors follow\n``adding-api-endpoints.md``. Optional ``invitee_account_ids`` creates + invites\natomically (every invitee validated before the irreversible tx). Optional ``metadata``\n(description, emoji, image_url, location) is off-chain display data only. Errors:\n  400: INVALID_NAME, INVALID_DESCRIPTION, INVALID_EMOJI, INVALID_IMAGE_URL,\n       INVALID_LOCATION, CANNOT_INVITE_SELF\n  404: ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: INVALID_CREATOR_TYPE, SQUAD_AS_SQUAD_MEMBER_FORBIDDEN, ALREADY_A_MEMBER\n  503: HYDRA_UNAVAILABLE",
        "operationId": "create_squad_v1_v1_squads_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a Squad shared account",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}": {
      "patch": {
        "description": "Edit a squad's off-chain display fields (RFC-018). OWNER-only. **No Cardano tx** —\na conditional update of the squad's display-metadata projection (name lives off-chain,\nnot in the Config datum). Partial update: omitted fields are left unchanged; an explicit\n``null`` clears an optional metadata field (``name`` is required and not clearable).\nAllowed on OPEN and CLOSED squads alike (purely cosmetic). Caller-identity\n(ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors:\n  400: INVALID_NAME, INVALID_DESCRIPTION, INVALID_EMOJI, INVALID_IMAGE_URL, INVALID_LOCATION\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED",
        "operationId": "update_squad_v1_v1_squads__sqd_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadUpdateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadUpdateResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: edit a squad's display metadata (name / emoji / image / location)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/auto-collect/consent": {
      "put": {
        "description": "Grant (or refresh) a standing, capped consent to auto-settle the caller's own share\nof ``rex_id`` each cycle (B-SQ-04 Assinatura). Own-share-only; off-chain (a projection\nwrite). ``max_amount`` caps per-cycle collection — a posted share above it SUSPENDS the\nconsent (``consent_state=REQUIRES_RECONSENT``) rather than over-collecting. A re-grant\nre-activates a suspended consent. Errors:\n  400: INVALID_AMOUNT, UNSUPPORTED_CURRENCY\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, REX_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, SQUAD_FROZEN",
        "operationId": "put_squad_auto_collect_consent_v1_v1_squads__sqd_id__auto_collect_consent_put",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsentResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Member: grant / refresh auto-collect consent for a conta",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/auto-collect/consent/{consent_id}": {
      "delete": {
        "description": "Revoke an auto-collect consent (B-SQ-04). Hard-deletes the consent row so future\ncycles no longer auto-collect this member's share. Always allowed (even when frozen /\nclosed). The caller may only revoke their own consent. Errors:\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, CONSENT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED",
        "operationId": "delete_squad_auto_collect_consent_v1_v1_squads__sqd_id__auto_collect_consent__consent_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "consent_id",
            "required": true,
            "schema": {
              "title": "Consent Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsentRevokeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsentRevokeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Member: revoke auto-collect consent (one tap)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/close": {
      "post": {
        "description": "Close the squad (RFC-018 §5.1, SQ-14). An OWNER closes once every member is\nat net-zero: the tx consumes the OPEN Config UTxO and recreates it with\n``state=\"CLOSED\"``. After close every write referencing the Config fails the\nvalidator's ``configIsOpen`` check (SI-7); reads continue indefinitely. Close\nis irreversible — there is no ``/reopen``. The net-zero preconditions\n(FUNDS_REMAINING / OPEN_ACCOUNTING_ROWS) are off-chain fast-fails and carry a\n``details.non_zero_positions`` breakdown. Errors:\n  403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_ALREADY_CLOSED, FUNDS_REMAINING, OPEN_ACCOUNTING_ROWS,\n       SETTLEMENT_IN_PROGRESS\n  503: HYDRA_UNAVAILABLE",
        "operationId": "post_squad_close_v1_v1_squads__sqd_id__close_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CloseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadCloseResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Close the squad (OWNER; terminal, irreversible)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/contributions": {
      "post": {
        "description": "Record a squad contribution (RFC-018 §5.1, SQ-11 / SQ-13).\n\n``kind=FUNDED`` moves QBRL from the actor's BancoBRL custody to a Balance UTxO\nat the SquadValidator (Config read as a reference input) and records an\nobligation. ``kind=ACCOUNTING`` records a non-monetary split: it resolves the\nsplit into per-debtor **share** UTxOs and mints the vQBRL across them (no QBRL\nmoves). Caller-identity (ACTOR_MISMATCH) is enforced at the API Gateway. Errors:\n  400: UNSUPPORTED_CURRENCY, INVALID_AMOUNT, INVALID_KIND, INVALID_SPLIT,\n       AMOUNTS_DO_NOT_SUM, UNKNOWN_MEMBER_IN_SPLIT, INVALID_DESCRIPTION,\n       INVALID_SOURCE_TX\n  403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: INSUFFICIENT_BALANCE, SQUAD_CLOSED\n  503: HYDRA_UNAVAILABLE",
        "operationId": "post_squad_contribution_v1_v1_squads__sqd_id__contributions_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContributionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Contribute to a Squad (kind=FUNDED deposits QBRL; kind=ACCOUNTING records a split)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/contributions/{entry_seq}": {
      "delete": {
        "description": "Void an accounting entry's still-unsettled shares (RFC-018 §5.1, SQ-13).\n\nImplemented via ``VoidShare``: the **creditor** (original actor) consumes and\nburns the entry's remaining share UTxOs (no QBRL moves). Already-settled shares\nare simply already-consumed UTxOs, so voiding operates on whatever remains.\nCaller-identity is enforced at the API Gateway. Errors:\n  403: NOT_THE_CREDITOR, NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, ACCOUNTING_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED\n  503: HYDRA_UNAVAILABLE",
        "operationId": "delete_squad_contribution_v1_v1_squads__sqd_id__contributions__entry_seq__delete",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "entry_seq",
            "required": true,
            "schema": {
              "title": "Entry Seq",
              "type": "integer"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoidContributionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadVoidResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Void (forgive) an accounting entry's unsettled shares (creditor only)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/entries/{entry_seq}/split": {
      "patch": {
        "description": "OWNER escape hatch (RFC-018): manually re-divide one expense's still-open shares\nwhen the general rule can't (e.g. a partially-settled entry). The entry is then\nflagged so automatic re-splits leave it alone. Errors:\n  400: INVALID_SPLIT, AMOUNTS_DO_NOT_SUM, UNKNOWN_MEMBER_IN_SPLIT\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, ACCOUNTING_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED\n  503: HYDRA_UNAVAILABLE",
        "operationId": "override_entry_split_v1_v1_squads__sqd_id__entries__entry_seq__split_patch",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "entry_seq",
            "required": true,
            "schema": {
              "title": "Entry Seq",
              "type": "integer"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EntrySplitOverrideRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadEntrySplitOverrideResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: manually re-split one expense's open shares",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/freeze": {
      "post": {
        "description": "Freeze a squad for wind-down (RFC-018). OWNER-only. **No Cardano tx** — flips an\noff-chain ``frozen`` flag on the squad's META row. The squad stays ``state=OPEN`` and\nfully readable, but deposits/spends/accounting and all roster changes are then rejected\n(422 SQUAD_FROZEN); settlement, close, decline-invite, and metadata edits keep working.\nFreezing is a prerequisite for ``simplify-debts``. Idempotent: freezing an already-frozen\nsquad is a 200 no-op with ``changed=false``. Errors:\n  403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED",
        "operationId": "post_squad_freeze_v1_v1_squads__sqd_id__freeze_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadFreezeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadFreezeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: freeze a squad (wind-down; reversible)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/goal": {
      "delete": {
        "description": "Remove a squad's savings goal (B-SQ-05). OWNER-only, off-chain. Allowed on OPEN and\nCLOSED squads alike (cleanup). Idempotent: clearing an absent goal still returns\n``goal: null``. Only ``actor_account_id`` is read from the body. Errors:\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED",
        "operationId": "delete_squad_goal_v1_v1_squads__sqd_id__goal_delete",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadGoalDeleteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadGoalDeleteResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: remove a squad's savings goal",
        "tags": [
          "Squads"
        ]
      },
      "put": {
        "description": "Set or edit a squad's savings goal (B-SQ-05). OWNER-only, **off-chain** (a projection\nwrite — no Cardano tx). The goal constrains nothing; it only measures. ``funded_cents``\n/ ``progress`` are computed from the live pool balance, and ``achieved_at`` is stamped\n(sticky) the first moment the pool reaches the target. Errors:\n  400: INVALID_GOAL_AMOUNT, INVALID_GOAL_DATE\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED",
        "operationId": "put_squad_goal_v1_v1_squads__sqd_id__goal_put",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadGoalRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadGoalResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: set or edit a squad's savings goal (target amount + optional date)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/invitations": {
      "post": {
        "description": "Invite one or more accounts (RFC-018 invite flow). OWNER-only. Writes a PENDING\ninvite projection row per invitee — **no Cardano tx**; an invitee enters the on-chain\nroster only when they accept. **Partial-success**: the 201 body reports each invitee\nas ``invited``/``skipped``/``failed`` (see ``SquadBatchInviteResponse``); per-invitee\nproblems (self, already a member/invited, not found, is a squad, duplicated) do not\nfail the call. Only the structural checks below hard-fail. Caller-identity\n(ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors:\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED",
        "operationId": "invite_squad_member_v1_v1_squads__sqd_id__invitations_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadBatchInviteResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Invite one or more accounts to a Squad",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/invitations/accept": {
      "post": {
        "description": "Accept a pending invite (RFC-018 invite flow). The invitee enters the on-chain\nroster as a SPENDER via ``build_change_membership_tx``, custodially authored by a\ncurrent OWNER (ChangeMembership is OWNER-gated). Caller-identity is enforced at the\nAPI Gateway. Errors:\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, INVITE_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, ALREADY_A_MEMBER, NO_CURRENT_OWNER\n  503: HYDRA_UNAVAILABLE",
        "operationId": "accept_squad_invite_v1_v1_squads__sqd_id__invitations_accept_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteAcceptRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadInviteAcceptResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Accept a Squad invitation",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/invitations/decline": {
      "post": {
        "description": "Decline a pending invite (RFC-018 invite flow). Projection-only state flip; no\ntx. Intentionally NOT OPEN-gated, so an invitee can tidy a stale invite. Errors:\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, INVITE_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED",
        "operationId": "decline_squad_invite_v1_v1_squads__sqd_id__invitations_decline_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteDeclineRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadInviteActionResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Decline a Squad invitation",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/invitations/{invitee_account_id}": {
      "delete": {
        "description": "Revoke a pending invite (RFC-018 invite flow). OWNER-only; projection-only state\nflip, no tx. Caller-identity is enforced at the API Gateway. Errors:\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, INVITE_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED",
        "operationId": "revoke_squad_invite_v1_v1_squads__sqd_id__invitations__invitee_account_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "invitee_account_id",
            "required": true,
            "schema": {
              "title": "Invitee Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeInviteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadInviteActionResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Revoke a pending Squad invitation",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/members/{member_account_id}": {
      "delete": {
        "description": "Remove a member (RFC-018 §5.1, SQ-10). Consumes the Config UTxO and recreates\nit with the member dropped from the ``members`` map (validator enforces \"≥1 OWNER\nremains\"). The leaver's **open accounting debts are redistributed** proportionally\nacross the entry's remaining members first (no write-offs; settled members inherit a\ntop-up) — see ``debt_resolution`` on the response. Pooled funds still block\n(``MEMBER_HAS_OUTSTANDING_BALANCE``); being **owed** money on an open share still\nblocks (``MEMBER_HAS_OUTSTANDING_ACCOUNTING`` — creditor side only). Caller-identity\n(ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors:\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, MEMBER_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, LAST_OWNER_CANNOT_BE_REMOVED,\n       MEMBER_HAS_OUTSTANDING_BALANCE, MEMBER_HAS_OUTSTANDING_ACCOUNTING\n  503: HYDRA_UNAVAILABLE",
        "operationId": "remove_squad_member_v1_v1_squads__sqd_id__members__member_account_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "member_account_id",
            "required": true,
            "schema": {
              "title": "Member Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveMemberRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadMemberRemoveResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Remove a member from a Squad",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/members/{member_account_id}/quota": {
      "patch": {
        "description": "Change how many people a member represents (RFC-018 quotas). A member may edit\ntheir own quota; an OWNER may edit anyone's. Re-divides every still-open EQUAL\nexpense at the new quota. **Locked once any entry is settled/voided.** Errors:\n  400: INVALID_QUOTA\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, MEMBER_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED, QUOTA_CHANGE_LOCKED\n  422: SQUAD_CLOSED\n  503: HYDRA_UNAVAILABLE",
        "operationId": "update_member_quota_v1_v1_squads__sqd_id__members__member_account_id__quota_patch",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "member_account_id",
            "required": true,
            "schema": {
              "title": "Member Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMemberQuotaRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadMemberQuotaResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Change a member's quota (cota) count",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/members/{member_account_id}/role": {
      "patch": {
        "description": "Change a member's role (RFC-018). OWNER-only, and an owner may only change\n**other** members' roles (never their own), so self-promotion is impossible. The\nrole lives in the on-chain Config datum, so this rewrites it via ``ChangeMembership``\n(no new redeemer); a request matching the member's current role is a no-op (no tx,\n``changed: false``). Caller-identity is enforced at the API Gateway. Errors:\n  400: INVALID_ROLE\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, MEMBER_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, CANNOT_CHANGE_OWN_ROLE, LAST_OWNER_CANNOT_BE_DEMOTED\n  503: HYDRA_UNAVAILABLE",
        "operationId": "change_member_role_v1_v1_squads__sqd_id__members__member_account_id__role_patch",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "member_account_id",
            "required": true,
            "schema": {
              "title": "Member Account Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangeMemberRoleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadMemberRoleChangeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Promote/demote a member between OWNER and SPENDER",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/recurrence": {
      "put": {
        "description": "Enable, edit, or disable monthly cycles for a squad (B-SQ-04). OWNER-only,\n**off-chain** (a projection write — no Cardano tx). ``billing_day`` (1–28) is the\ndia de fechamento; ``null`` disables. Billing fires at 00:00 in ``timezone``. Errors:\n  400: INVALID_BILLING_DAY, INVALID_TIMEZONE\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, SQUAD_FROZEN",
        "operationId": "put_squad_recurrence_v1_v1_squads__sqd_id__recurrence_put",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecurrenceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurrenceResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: enable / edit / disable a squad's monthly cycles",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/recurring-expenses": {
      "post": {
        "description": "Create a conta that auto-posts each cycle (B-SQ-04). OWNER-only, off-chain. A\nfixed conta posts at ``amount``; a ``variable`` one posts a placeholder awaiting the\npayer's ``/confirm``. ``split`` is the same sealed split as a contribution. Errors:\n  400: INVALID_AMOUNT, INVALID_DESCRIPTION, INVALID_SPLIT, AMOUNTS_DO_NOT_SUM,\n       UNKNOWN_MEMBER_IN_SPLIT, UNSUPPORTED_CURRENCY\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, SQUAD_FROZEN",
        "operationId": "post_squad_recurring_expense_v1_v1_squads__sqd_id__recurring_expenses_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecurringExpenseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringExpenseResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: create a recurring expense (conta / bill template)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/recurring-expenses/{rex_id}": {
      "delete": {
        "description": "Delete a conta (B-SQ-04). OWNER-only, off-chain. Stops future postings;\nalready-posted expenses are ordinary entries and stay. Errors:\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, REX_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED",
        "operationId": "delete_squad_recurring_expense_v1_v1_squads__sqd_id__recurring_expenses__rex_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "rex_id",
            "required": true,
            "schema": {
              "title": "Rex Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecurringExpenseDeleteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringExpenseDeleteResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: delete a recurring expense (conta)",
        "tags": [
          "Squads"
        ]
      },
      "patch": {
        "description": "Edit a conta (B-SQ-04). OWNER-only, off-chain. Partial update; future cycle posts\nuse the new values, already-posted expenses are unaffected. Errors mirror create,\nplus 404 REX_NOT_FOUND.",
        "operationId": "patch_squad_recurring_expense_v1_v1_squads__sqd_id__recurring_expenses__rex_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "rex_id",
            "required": true,
            "schema": {
              "title": "Rex Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecurringExpensePatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringExpenseResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: edit a recurring expense (conta)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/recurring-expenses/{rex_id}/confirm": {
      "post": {
        "description": "Confirm a variable conta's real amount (B-SQ-04). Payer-only. Turns the current\nperiod's PENDING_CONFIRMATION placeholder into a live on-chain ACCOUNTING expense\n(minting per-debtor shares). Errors:\n  400: INVALID_AMOUNT, UNSUPPORTED_CURRENCY\n  403: NOT_THE_PAYER\n  404: SQUAD_NOT_FOUND, REX_NOT_FOUND, PENDING_CONFIRMATION_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, SQUAD_FROZEN, ALREADY_CONFIRMED\n  503: HYDRA_UNAVAILABLE",
        "operationId": "post_squad_confirm_variable_v1_v1_squads__sqd_id__recurring_expenses__rex_id__confirm_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "rex_id",
            "required": true,
            "schema": {
              "title": "Rex Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmVariableRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Payer: confirm a variable conta's real amount for the current period",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/rules": {
      "delete": {
        "description": "Remove a squad's spend-approval policy (B-SQ-06). OWNER-only, off-chain. Allowed on\nOPEN and CLOSED alike (cleanup). Pending spend-requests are unaffected — each carries the\npolicy snapshot it was created under. Idempotent: clearing an absent policy returns\n``rules: null``. Errors:\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED",
        "operationId": "delete_squad_rules_v1_v1_squads__sqd_id__rules_delete",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadRulesDeleteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadRulesDeleteResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: remove a squad's spend-approval policy",
        "tags": [
          "Squads"
        ]
      },
      "put": {
        "description": "Set or edit a squad's spend-approval policy (B-SQ-06). OWNER-only, **off-chain** (a\nprojection write — no Cardano tx). A spend *above* ``threshold_amount`` then requires\n``approvals_required`` distinct approvers (from ``approvers`` = OWNERS | ALL_MEMBERS)\nbefore it executes. Errors:\n  400: INVALID_THRESHOLD, INVALID_APPROVALS_REQUIRED, INVALID_APPROVERS\n  403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, SQUAD_FROZEN",
        "operationId": "put_squad_rules_v1_v1_squads__sqd_id__rules_put",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadRulesRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadRulesResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: set or edit a squad's spend-approval policy (Regras)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/settle": {
      "post": {
        "description": "Per-debtor self-settle (RFC-018 §5.3, SQ-13). The caller discharges the\nshares where THEY are the debtor: one tx pays each creditor ``share_cents`` QBRL\nand burns the share vQBRL via ``SettleShare``. The settle is funded from the\ncaller's **squad deposits first** — those are drained back to their personal\ncustody in a prior ``Spend`` tx (``squad_funds_withdrawn_cents`` /\n``withdrawal_tx_id`` report it), any excess staying liquid in custody — then any\nshortfall comes from their existing custody. ``entry_seq`` optionally narrows to\none expense. A caller who owes nothing but has a squad deposit gets **201** with\n``settled_shares: 0`` and the withdrawal fields (the deposit is returned to their\npersonal custody; ``tx_id == withdrawal_tx_id``) — ``ACCOUNTING_NOT_FOUND`` is now\nreturned only when the caller owed nothing AND had no deposit. Caller-identity is\nenforced at the API Gateway. Errors:\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, ACCOUNTING_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED, INSUFFICIENT_BALANCE\n  503: HYDRA_UNAVAILABLE",
        "operationId": "post_squad_settle_v1_v1_squads__sqd_id__settle_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadSettleResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Settle the caller's own shares (per-debtor self-settle)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/simplify-debts": {
      "post": {
        "description": "Collapse the open accounting-share graph into the minimal set of net debts\n(RFC-018 netting). An OWNER triggers it; the handler computes the Splitwise-style\nminimum-cash-flow plan and rewrites the chain to match — reissuing the minimal net\nshares on fresh entries, then voiding all originals (which are kept as frozen\nhistory). Total open debt is conserved (``vqbrl_minted == vqbrl_burned``); only the\nnumber of debts shrinks. ``no_op: true`` when the graph is already minimal (no\non-chain work). The op is a resumable multi-tx sequence — a retry with the same\nIdempotency-Key continues a partial run rather than restarting. Errors:\n  403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED, SIMPLIFY_IN_PROGRESS\n  422: SQUAD_CLOSED, CREDITOR_UNRESOLVABLE, SQUAD_TOO_LARGE_TO_SIMPLIFY\n  503: HYDRA_UNAVAILABLE",
        "operationId": "post_squad_simplify_debts_v1_v1_squads__sqd_id__simplify_debts_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadSimplifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadSimplifyResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Simplify the squad's debts (OWNER; minimal multi-party netting)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/spend-requests/{spr_id}/approve": {
      "post": {
        "description": "Record one approval on a PENDING_APPROVAL spend-request (B-SQ-06).\n\nAn eligible approver (distinct from the requester and prior approvers) approves. Before\nthe Nth approval → **200** with the updated approvals list. On the Nth → the spend\nexecutes atomically and this returns **201** with the executed spend result (tx_id, …).\nInsufficient pool at execution → the request flips FAILED and 422 INSUFFICIENT_BALANCE\nis returned (no partial movement). Errors:\n  403: NOT_AN_APPROVER, NOT_A_SQUAD_MEMBER, CANNOT_APPROVE_OWN_REQUEST, INSUFFICIENT_ROLE\n  404: SPEND_REQUEST_NOT_FOUND, SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: ALREADY_APPROVED, IDEMPOTENCY_KEY_REUSED\n  422: APPROVAL_NOT_PENDING, INSUFFICIENT_BALANCE, SQUAD_FROZEN, SQUAD_CLOSED\n  503: HYDRA_UNAVAILABLE",
        "operationId": "post_squad_spend_request_approve_v1_v1_squads__sqd_id__spend_requests__spr_id__approve_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "spr_id",
            "required": true,
            "schema": {
              "title": "Spr Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpendRequestApproveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpendRequestPendingResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Approve a pending squad spend-request (the Nth approval executes it)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/spend-requests/{spr_id}/reject": {
      "post": {
        "description": "A single eligible approver rejects a PENDING_APPROVAL spend-request (B-SQ-06). Sticky:\na rejected request is terminal (a later approve → 422 APPROVAL_NOT_PENDING). Errors:\n  403: NOT_AN_APPROVER, NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SPEND_REQUEST_NOT_FOUND, SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: APPROVAL_NOT_PENDING, SQUAD_FROZEN, SQUAD_CLOSED",
        "operationId": "post_squad_spend_request_reject_v1_v1_squads__sqd_id__spend_requests__spr_id__reject_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "spr_id",
            "required": true,
            "schema": {
              "title": "Spr Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpendRequestRejectRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpendRequestRejectResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Reject (kill) a pending squad spend-request",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/spends": {
      "post": {
        "description": "Spend QBRL out of a squad (RFC-018 §5.1, SQ-12, B-SQ-07).\n\nExactly one destination. **Internal** (``recipient_account_id``): a SPENDER/OWNER\nmoves QBRL to that account's BancoBRL custody; the SquadValidator ``Spend`` redeemer\nenforces role/witness/value-conservation on-chain; returns **201** ``state:\"OPEN\"``.\n**External Pix** (``pix_destination``, B-SQ-07): the pool's QBRL bridges to the GL\nclearing account and the deferred Pix rail sends it out; the DICT key is resolved\npre-debit (recipient name in the ``payout`` block), and it returns **201**\n``state:\"PROCESSING\"`` with ``payout:{ rail, end_to_end_id, recipient_name, status }``\n— the terminal SPEND_SETTLED / SPEND_FAILED (pool auto-refunded) surface in the feed.\nCaller-identity (ACTOR_MISMATCH) is enforced at the API Gateway, not here.\n\nB-SQ-06 (Regras): if the squad has a ``spend_rules`` policy and the amount is *above*\nthe threshold, no money moves — the spend (internal or Pix) is parked as a\nPENDING_APPROVAL request and this returns **202** with ``{spend_request_id,\nstate:\"PENDING_APPROVAL\", …}``. Otherwise it executes and returns **201**. Errors:\n  400: UNSUPPORTED_CURRENCY, INVALID_AMOUNT, CANNOT_SPEND_TO_SELF,\n       MISSING_DESTINATION, AMBIGUOUS_DESTINATION, INVALID_PIX_KEY\n  403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SQUAD_NOT_FOUND, RECIPIENT_NOT_FOUND, ACCOUNT_NOT_FOUND, PIX_KEY_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: INSUFFICIENT_BALANCE, SQUAD_CLOSED, SQUAD_FROZEN, PIX_RAIL_UNAVAILABLE\n  503: HYDRA_UNAVAILABLE",
        "operationId": "post_squad_spend_v1_v1_squads__sqd_id__spends_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpendRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadSpendResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Spend from a Squad to an external recipient",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/squads/{sqd_id}/unfreeze": {
      "post": {
        "description": "Unfreeze a squad (RFC-018), re-allowing deposits/spends/accounting and roster\nchanges. OWNER-only. **No Cardano tx.** Does NOT clear the sticky ``simplified`` marker.\nIdempotent: unfreezing an already-open squad is a 200 no-op with ``changed=false``.\nErrors:\n  403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE\n  404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND\n  409: IDEMPOTENCY_KEY_REUSED\n  422: SQUAD_CLOSED",
        "operationId": "post_squad_unfreeze_v1_v1_squads__sqd_id__unfreeze_post",
        "parameters": [
          {
            "in": "path",
            "name": "sqd_id",
            "required": true,
            "schema": {
              "title": "Sqd Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SquadFreezeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SquadFreezeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Owner: unfreeze a squad (resume normal activity)",
        "tags": [
          "Squads"
        ]
      }
    },
    "/v1/template-transfers": {
      "post": {
        "description": "Execute an operator-defined transfer template as one atomic custody Hydra\ntransaction (LaaS-26).\n\nThe named template's typed params drive an ordered set of legs (fees,\nmulti-leg payouts) over the existing custody validator — no new on-chain\ncode. Yields exactly one Hydra transaction and one obligation row per leg\n(all sharing the tx hash, each carrying template attribution).\n\nRequires an Idempotency-Key header. Callers MAY pin ``template_version``;\na mismatch with the deployed version returns 409 TEMPLATE_VERSION_MISMATCH.",
        "operationId": "create_template_transfer_v1_v1_template_transfers_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateTransferRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Execute a Transfer Template",
        "tags": [
          "Templates"
        ]
      }
    },
    "/v1/webhooks": {
      "post": {
        "description": "Register an endpoint for signed event deliveries (webhooks-v1).\n\nThe plaintext ``secret`` appears ONLY in this 201 — every later read\n(including an idempotent replay of this request) returns the masked form.\nErrors:\n  409: IDEMPOTENCY_KEY_REUSED\n  422: INVALID_EVENT_FILTER, URL_SCHEME_NOT_HTTPS, URL_PRIVATE_ADDRESS,\n       URL_MALFORMED, URL_UNRESOLVABLE, WEBHOOK_LIMIT_EXCEEDED",
        "operationId": "create_webhook_v1_v1_webhooks_post",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Register a webhook endpoint",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "/v1/webhooks/{webhook_id}": {
      "delete": {
        "description": "Tombstone (status=DELETED, idempotent): delivery history remains\nreadable until its TTL. Errors: 404: WEBHOOK_NOT_FOUND.",
        "operationId": "delete_webhook_v1_v1_webhooks__webhook_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "webhook_id",
            "required": true,
            "schema": {
              "title": "Webhook Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Delete a webhook endpoint (tombstone)",
        "tags": [
          "Webhooks"
        ]
      },
      "patch": {
        "description": "Update url / event_filters / status (secret immutable). PATCHing\nstatus=ACTIVE from a suspended state resets the failure streak. Errors:\n  400: NO_UPDATABLE_FIELDS  404: WEBHOOK_NOT_FOUND  409: WEBHOOK_DELETED\n  422: INVALID_EVENT_FILTER, URL_*",
        "operationId": "patch_webhook_v1_v1_webhooks__webhook_id__patch",
        "parameters": [
          {
            "in": "path",
            "name": "webhook_id",
            "required": true,
            "schema": {
              "title": "Webhook Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Update a webhook endpoint",
        "tags": [
          "Webhooks"
        ]
      }
    },
    "/v1/webhooks/{webhook_id}/test": {
      "post": {
        "description": "Enqueue one synthetic ``webhook.test`` delivery to exactly this endpoint\n(bypasses filters; delivery row flagged test — never an EVENT# browse row).\nErrors: 404: WEBHOOK_NOT_FOUND  409: WEBHOOK_DELETED, WEBHOOK_NOT_ACTIVE\n503: DISPATCHER_UNAVAILABLE (local).",
        "operationId": "test_webhook_v1_v1_webhooks__webhook_id__test_post",
        "parameters": [
          {
            "in": "path",
            "name": "webhook_id",
            "required": true,
            "schema": {
              "title": "Webhook Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "title": "Idempotency-Key",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Send a signed webhook.test delivery",
        "tags": [
          "Webhooks"
        ]
      }
    }
  },
  "security": [
    {
      "oauth2_client_credentials": []
    }
  ],
  "servers": [
    {
      "description": "Ambiente de avaliação. Compartilhado entre avaliadores, reiniciado com aviso, sem SLA. Exige credenciais aprovadas.",
      "url": "https://api-sbx.sonacore.com.br"
    }
  ]
}
