SonaCORE

Referência / Quadra Command API

Squads

31 operações em Quadra Command API 0.2.0.

POST/v1/squads

Create a Squad shared account

Create a Squad (RFC-018) and its Config UTxO at the SquadValidator.

Thin wrapper: payload validation → idempotency cache → ``SquadAdapter.create_instance`` → response caching. The creator becomes the sole OWNER member; the squad account row is persisted with ``vk=null`` (the squad has no key — chain enforces all authority). Caller-identity (ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors follow ``adding-api-endpoints.md``. Optional ``invitee_account_ids`` creates + invites atomically (every invitee validated before the irreversible tx). Optional ``metadata`` (description, emoji, image_url, location) is off-chain display data only. Errors: 400: INVALID_NAME, INVALID_DESCRIPTION, INVALID_EMOJI, INVALID_IMAGE_URL, INVALID_LOCATION, CANNOT_INVITE_SELF 404: ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: INVALID_CREATOR_TYPE, SQUAD_AS_SQUAD_MEMBER_FORBIDDEN, ALREADY_A_MEMBER 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

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

Owner: edit a squad's display metadata (name / emoji / image / location)

Edit a squad's off-chain display fields (RFC-018). OWNER-only. **No Cardano tx** — a conditional update of the squad's display-metadata projection (name lives off-chain, not in the Config datum). Partial update: omitted fields are left unchanged; an explicit ``null`` clears an optional metadata field (``name`` is required and not clearable). Allowed on OPEN and CLOSED squads alike (purely cosmetic). Caller-identity (ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors: 400: INVALID_NAME, INVALID_DESCRIPTION, INVALID_EMOJI, INVALID_IMAGE_URL, INVALID_LOCATION 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadUpdateResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/close

Close the squad (OWNER; terminal, irreversible)

Close the squad (RFC-018 §5.1, SQ-14). An OWNER closes once every member is at net-zero: the tx consumes the OPEN Config UTxO and recreates it with ``state="CLOSED"``. After close every write referencing the Config fails the validator's ``configIsOpen`` check (SI-7); reads continue indefinitely. Close is irreversible — there is no ``/reopen``. The net-zero preconditions (FUNDS_REMAINING / OPEN_ACCOUNTING_ROWS) are off-chain fast-fails and carry a ``details.non_zero_positions`` breakdown. Errors: 403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_ALREADY_CLOSED, FUNDS_REMAINING, OPEN_ACCOUNTING_ROWS, SETTLEMENT_IN_PROGRESS 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201SquadCloseResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/contributions

Contribute to a Squad (kind=FUNDED deposits QBRL; kind=ACCOUNTING records a split)

Record a squad contribution (RFC-018 §5.1, SQ-11 / SQ-13).

``kind=FUNDED`` moves QBRL from the actor's BancoBRL custody to a Balance UTxO at the SquadValidator (Config read as a reference input) and records an obligation. ``kind=ACCOUNTING`` records a non-monetary split: it resolves the split into per-debtor **share** UTxOs and mints the vQBRL across them (no QBRL moves). Caller-identity (ACTOR_MISMATCH) is enforced at the API Gateway. Errors: 400: UNSUPPORTED_CURRENCY, INVALID_AMOUNT, INVALID_KIND, INVALID_SPLIT, AMOUNTS_DO_NOT_SUM, UNKNOWN_MEMBER_IN_SPLIT, INVALID_DESCRIPTION, INVALID_SOURCE_TX 403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: INSUFFICIENT_BALANCE, SQUAD_CLOSED 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

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

Void (forgive) an accounting entry's unsettled shares (creditor only)

Void an accounting entry's still-unsettled shares (RFC-018 §5.1, SQ-13).

Implemented via ``VoidShare``: the **creditor** (original actor) consumes and burns the entry's remaining share UTxOs (no QBRL moves). Already-settled shares are simply already-consumed UTxOs, so voiding operates on whatever remains. Caller-identity is enforced at the API Gateway. Errors: 403: NOT_THE_CREDITOR, NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, ACCOUNTING_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
entry_seqintegerpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadVoidResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PATCH/v1/squads/{sqd_id}/entries/{entry_seq}/split

Owner: manually re-split one expense's open shares

OWNER escape hatch (RFC-018): manually re-divide one expense's still-open shares when the general rule can't (e.g. a partially-settled entry). The entry is then flagged so automatic re-splits leave it alone. Errors: 400: INVALID_SPLIT, AMOUNTS_DO_NOT_SUM, UNKNOWN_MEMBER_IN_SPLIT 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, ACCOUNTING_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
entry_seqintegerpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadEntrySplitOverrideResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/freeze

Owner: freeze a squad (wind-down; reversible)

Freeze a squad for wind-down (RFC-018). OWNER-only. **No Cardano tx** — flips an off-chain ``frozen`` flag on the squad's META row. The squad stays ``state=OPEN`` and fully readable, but deposits/spends/accounting and all roster changes are then rejected (422 SQUAD_FROZEN); settlement, close, decline-invite, and metadata edits keep working. Freezing is a prerequisite for ``simplify-debts``. Idempotent: freezing an already-frozen squad is a 200 no-op with ``changed=false``. Errors: 403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadFreezeResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
DELETE/v1/squads/{sqd_id}/goal

Owner: remove a squad's savings goal

Remove a squad's savings goal (B-SQ-05). OWNER-only, off-chain. Allowed on OPEN and CLOSED squads alike (cleanup). Idempotent: clearing an absent goal still returns ``goal: null``. Only ``actor_account_id`` is read from the body. Errors: 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadGoalDeleteResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PUT/v1/squads/{sqd_id}/goal

Owner: set or edit a squad's savings goal (target amount + optional date)

Set or edit a squad's savings goal (B-SQ-05). OWNER-only, **off-chain** (a projection write — no Cardano tx). The goal constrains nothing; it only measures. ``funded_cents`` / ``progress`` are computed from the live pool balance, and ``achieved_at`` is stamped (sticky) the first moment the pool reaches the target. Errors: 400: INVALID_GOAL_AMOUNT, INVALID_GOAL_DATE 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadGoalResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/invitations

Invite one or more accounts to a Squad

Invite one or more accounts (RFC-018 invite flow). OWNER-only. Writes a PENDING invite projection row per invitee — **no Cardano tx**; an invitee enters the on-chain roster only when they accept. **Partial-success**: the 201 body reports each invitee as ``invited``/``skipped``/``failed`` (see ``SquadBatchInviteResponse``); per-invitee problems (self, already a member/invited, not found, is a squad, duplicated) do not fail the call. Only the structural checks below hard-fail. Caller-identity (ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors: 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201SquadBatchInviteResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
DELETE/v1/squads/{sqd_id}/invitations/{invitee_account_id}

Revoke a pending Squad invitation

Revoke a pending invite (RFC-018 invite flow). OWNER-only; projection-only state flip, no tx. Caller-identity is enforced at the API Gateway. Errors: 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, INVITE_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
invitee_account_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadInviteActionResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/invitations/accept

Accept a Squad invitation

Accept a pending invite (RFC-018 invite flow). The invitee enters the on-chain roster as a SPENDER via ``build_change_membership_tx``, custodially authored by a current OWNER (ChangeMembership is OWNER-gated). Caller-identity is enforced at the API Gateway. Errors: 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, INVITE_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, ALREADY_A_MEMBER, NO_CURRENT_OWNER 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201SquadInviteAcceptResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/invitations/decline

Decline a Squad invitation

Decline a pending invite (RFC-018 invite flow). Projection-only state flip; no tx. Intentionally NOT OPEN-gated, so an invitee can tidy a stale invite. Errors: 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, INVITE_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadInviteActionResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
DELETE/v1/squads/{sqd_id}/members/{member_account_id}

Remove a member from a Squad

Remove a member (RFC-018 §5.1, SQ-10). Consumes the Config UTxO and recreates it with the member dropped from the ``members`` map (validator enforces "≥1 OWNER remains"). The leaver's **open accounting debts are redistributed** proportionally across the entry's remaining members first (no write-offs; settled members inherit a top-up) — see ``debt_resolution`` on the response. Pooled funds still block (``MEMBER_HAS_OUTSTANDING_BALANCE``); being **owed** money on an open share still blocks (``MEMBER_HAS_OUTSTANDING_ACCOUNTING`` — creditor side only). Caller-identity (ACTOR_MISMATCH) is enforced at the API Gateway, not here. Errors: 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, MEMBER_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, LAST_OWNER_CANNOT_BE_REMOVED, MEMBER_HAS_OUTSTANDING_BALANCE, MEMBER_HAS_OUTSTANDING_ACCOUNTING 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
member_account_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadMemberRemoveResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PATCH/v1/squads/{sqd_id}/members/{member_account_id}/quota

Change a member's quota (cota) count

Change how many people a member represents (RFC-018 quotas). A member may edit their own quota; an OWNER may edit anyone's. Re-divides every still-open EQUAL expense at the new quota. **Locked once any entry is settled/voided.** Errors: 400: INVALID_QUOTA 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, MEMBER_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED, QUOTA_CHANGE_LOCKED 422: SQUAD_CLOSED 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
member_account_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadMemberQuotaResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PATCH/v1/squads/{sqd_id}/members/{member_account_id}/role

Promote/demote a member between OWNER and SPENDER

Change a member's role (RFC-018). OWNER-only, and an owner may only change **other** members' roles (never their own), so self-promotion is impossible. The role lives in the on-chain Config datum, so this rewrites it via ``ChangeMembership`` (no new redeemer); a request matching the member's current role is a no-op (no tx, ``changed: false``). Caller-identity is enforced at the API Gateway. Errors: 400: INVALID_ROLE 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, MEMBER_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, CANNOT_CHANGE_OWN_ROLE, LAST_OWNER_CANNOT_BE_DEMOTED 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
member_account_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadMemberRoleChangeResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PUT/v1/squads/{sqd_id}/recurrence

Owner: enable / edit / disable a squad's monthly cycles

Enable, edit, or disable monthly cycles for a squad (B-SQ-04). OWNER-only, **off-chain** (a projection write — no Cardano tx). ``billing_day`` (1–28) is the dia de fechamento; ``null`` disables. Billing fires at 00:00 in ``timezone``. Errors: 400: INVALID_BILLING_DAY, INVALID_TIMEZONE 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, SQUAD_FROZEN

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200RecurrenceResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/recurring-expenses

Owner: create a recurring expense (conta / bill template)

Create a conta that auto-posts each cycle (B-SQ-04). OWNER-only, off-chain. A fixed conta posts at ``amount``; a ``variable`` one posts a placeholder awaiting the payer's ``/confirm``. ``split`` is the same sealed split as a contribution. Errors: 400: INVALID_AMOUNT, INVALID_DESCRIPTION, INVALID_SPLIT, AMOUNTS_DO_NOT_SUM, UNKNOWN_MEMBER_IN_SPLIT, UNSUPPORTED_CURRENCY 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, SQUAD_FROZEN

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201RecurringExpenseResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
DELETE/v1/squads/{sqd_id}/recurring-expenses/{rex_id}

Owner: delete a recurring expense (conta)

Delete a conta (B-SQ-04). OWNER-only, off-chain. Stops future postings; already-posted expenses are ordinary entries and stay. Errors: 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, REX_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
rex_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200RecurringExpenseDeleteResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PATCH/v1/squads/{sqd_id}/recurring-expenses/{rex_id}

Owner: edit a recurring expense (conta)

Edit a conta (B-SQ-04). OWNER-only, off-chain. Partial update; future cycle posts use the new values, already-posted expenses are unaffected. Errors mirror create, plus 404 REX_NOT_FOUND.

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
rex_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200RecurringExpenseResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/recurring-expenses/{rex_id}/confirm

Payer: confirm a variable conta's real amount for the current period

Confirm a variable conta's real amount (B-SQ-04). Payer-only. Turns the current period's PENDING_CONFIRMATION placeholder into a live on-chain ACCOUNTING expense (minting per-debtor shares). Errors: 400: INVALID_AMOUNT, UNSUPPORTED_CURRENCY 403: NOT_THE_PAYER 404: SQUAD_NOT_FOUND, REX_NOT_FOUND, PENDING_CONFIRMATION_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, SQUAD_FROZEN, ALREADY_CONFIRMED 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
rex_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

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

Owner: remove a squad's spend-approval policy

Remove a squad's spend-approval policy (B-SQ-06). OWNER-only, off-chain. Allowed on OPEN and CLOSED alike (cleanup). Pending spend-requests are unaffected — each carries the policy snapshot it was created under. Idempotent: clearing an absent policy returns ``rules: null``. Errors: 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadRulesDeleteResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
PUT/v1/squads/{sqd_id}/rules

Owner: set or edit a squad's spend-approval policy (Regras)

Set or edit a squad's spend-approval policy (B-SQ-06). OWNER-only, **off-chain** (a projection write — no Cardano tx). A spend *above* ``threshold_amount`` then requires ``approvals_required`` distinct approvers (from ``approvers`` = OWNERS | ALL_MEMBERS) before it executes. Errors: 400: INVALID_THRESHOLD, INVALID_APPROVALS_REQUIRED, INVALID_APPROVERS 403: INSUFFICIENT_ROLE, NOT_A_SQUAD_MEMBER 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, SQUAD_FROZEN

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadRulesResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/settle

Settle the caller's own shares (per-debtor self-settle)

Per-debtor self-settle (RFC-018 §5.3, SQ-13). The caller discharges the shares where THEY are the debtor: one tx pays each creditor ``share_cents`` QBRL and burns the share vQBRL via ``SettleShare``. The settle is funded from the caller's **squad deposits first** — those are drained back to their personal custody in a prior ``Spend`` tx (``squad_funds_withdrawn_cents`` / ``withdrawal_tx_id`` report it), any excess staying liquid in custody — then any shortfall comes from their existing custody. ``entry_seq`` optionally narrows to one expense. A caller who owes nothing but has a squad deposit gets **201** with ``settled_shares: 0`` and the withdrawal fields (the deposit is returned to their personal custody; ``tx_id == withdrawal_tx_id``) — ``ACCOUNTING_NOT_FOUND`` is now returned only when the caller owed nothing AND had no deposit. Caller-identity is enforced at the API Gateway. Errors: 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND, ACCOUNTING_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED, INSUFFICIENT_BALANCE 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201SquadSettleResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/simplify-debts

Simplify the squad's debts (OWNER; minimal multi-party netting)

Collapse the open accounting-share graph into the minimal set of net debts (RFC-018 netting). An OWNER triggers it; the handler computes the Splitwise-style minimum-cash-flow plan and rewrites the chain to match — reissuing the minimal net shares on fresh entries, then voiding all originals (which are kept as frozen history). Total open debt is conserved (``vqbrl_minted == vqbrl_burned``); only the number of debts shrinks. ``no_op: true`` when the graph is already minimal (no on-chain work). The op is a resumable multi-tx sequence — a retry with the same Idempotency-Key continues a partial run rather than restarting. Errors: 403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED, SIMPLIFY_IN_PROGRESS 422: SQUAD_CLOSED, CREDITOR_UNRESOLVABLE, SQUAD_TOO_LARGE_TO_SIMPLIFY 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201SquadSimplifyResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/spend-requests/{spr_id}/approve

Approve a pending squad spend-request (the Nth approval executes it)

Record one approval on a PENDING_APPROVAL spend-request (B-SQ-06).

An eligible approver (distinct from the requester and prior approvers) approves. Before the Nth approval → **200** with the updated approvals list. On the Nth → the spend executes atomically and this returns **201** with the executed spend result (tx_id, …). Insufficient pool at execution → the request flips FAILED and 422 INSUFFICIENT_BALANCE is returned (no partial movement). Errors: 403: NOT_AN_APPROVER, NOT_A_SQUAD_MEMBER, CANNOT_APPROVE_OWN_REQUEST, INSUFFICIENT_ROLE 404: SPEND_REQUEST_NOT_FOUND, SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: ALREADY_APPROVED, IDEMPOTENCY_KEY_REUSED 422: APPROVAL_NOT_PENDING, INSUFFICIENT_BALANCE, SQUAD_FROZEN, SQUAD_CLOSED 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
spr_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SpendRequestPendingResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/spend-requests/{spr_id}/reject

Reject (kill) a pending squad spend-request

A single eligible approver rejects a PENDING_APPROVAL spend-request (B-SQ-06). Sticky: a rejected request is terminal (a later approve → 422 APPROVAL_NOT_PENDING). Errors: 403: NOT_AN_APPROVER, NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SPEND_REQUEST_NOT_FOUND, SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: APPROVAL_NOT_PENDING, SQUAD_FROZEN, SQUAD_CLOSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
spr_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SpendRequestRejectResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/spends

Spend from a Squad to an external recipient

Spend QBRL out of a squad (RFC-018 §5.1, SQ-12, B-SQ-07).

Exactly one destination. **Internal** (``recipient_account_id``): a SPENDER/OWNER moves QBRL to that account's BancoBRL custody; the SquadValidator ``Spend`` redeemer enforces role/witness/value-conservation on-chain; returns **201** ``state:"OPEN"``. **External Pix** (``pix_destination``, B-SQ-07): the pool's QBRL bridges to the GL clearing account and the deferred Pix rail sends it out; the DICT key is resolved pre-debit (recipient name in the ``payout`` block), and it returns **201** ``state:"PROCESSING"`` with ``payout:{ rail, end_to_end_id, recipient_name, status }`` — the terminal SPEND_SETTLED / SPEND_FAILED (pool auto-refunded) surface in the feed. Caller-identity (ACTOR_MISMATCH) is enforced at the API Gateway, not here.

B-SQ-06 (Regras): if the squad has a ``spend_rules`` policy and the amount is *above* the threshold, no money moves — the spend (internal or Pix) is parked as a PENDING_APPROVAL request and this returns **202** with ``{spend_request_id, state:"PENDING_APPROVAL", …}``. Otherwise it executes and returns **201**. Errors: 400: UNSUPPORTED_CURRENCY, INVALID_AMOUNT, CANNOT_SPEND_TO_SELF, MISSING_DESTINATION, AMBIGUOUS_DESTINATION, INVALID_PIX_KEY 403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SQUAD_NOT_FOUND, RECIPIENT_NOT_FOUND, ACCOUNT_NOT_FOUND, PIX_KEY_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: INSUFFICIENT_BALANCE, SQUAD_CLOSED, SQUAD_FROZEN, PIX_RAIL_UNAVAILABLE 503: HYDRA_UNAVAILABLE

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
201SquadSpendResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação
POST/v1/squads/{sqd_id}/unfreeze

Owner: unfreeze a squad (resume normal activity)

Unfreeze a squad (RFC-018), re-allowing deposits/spends/accounting and roster changes. OWNER-only. **No Cardano tx.** Does NOT clear the sticky ``simplified`` marker. Idempotent: unfreezing an already-open squad is a 200 no-op with ``changed=false``. Errors: 403: NOT_A_SQUAD_MEMBER, INSUFFICIENT_ROLE 404: SQUAD_NOT_FOUND, ACCOUNT_NOT_FOUND 409: IDEMPOTENCY_KEY_REUSED 422: SQUAD_CLOSED

Parâmetros

NomeTipoDetalhe
sqd_idstringpathobrigatório
Idempotency-Keystringheaderobrigatório

Corpo da requisição

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

Respostas

StatusCorpoDetalhe
200SquadFreezeResponseResposta bem-sucedida
422HTTPValidationErrorErro de validação

Esquemas

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

ChangeMemberRoleRequest

``PATCH /v1/squads/{sqd_id}/members/{member_account_id}/role`` (RFC-018). ``actor_account_id`` must be an OWNER; ``role`` is the member's new role. An owner may only change *other* members' roles (never their own), so self-promotion is impossible. ``role`` is upper-cased before validation.

CampoTipoDetalhe
actor_account_idstringobrigatório
rolestringobrigatório

CloseRequest

``POST /v1/squads/{sqd_id}/close`` (SQ-14). ``actor_account_id`` is the OWNER closing the squad (must be a current OWNER member). The close is irreversible — there is no ``/reopen``. ``reason`` is free-form audit text and does not affect the on-chain tx.

CampoTipoDetalhe
actor_account_idstringobrigatório
reasonstring, opcional

ConfirmVariableRequest

``POST /v1/squads/{sqd_id}/recurring-expenses/{rex_id}/confirm`` — the payer sets a variable conta's real amount for the current period, turning its ``PENDING_CONFIRMATION`` placeholder into a live on-chain ACCOUNTING expense.

CampoTipoDetalhe
actor_account_idstringobrigatório
amountSquadAmountobrigatório

ConsentRequest

``PUT /v1/squads/{sqd_id}/auto-collect/consent`` — a member grants (or refreshes) a standing, capped authorization to auto-settle their share of one conta each cycle. ``caller_account_id`` is the consenting member (own-share-only — a member can only consent for themselves). ``max_amount`` caps how much may be auto-collected per cycle; a posted share above the cap SUSPENDS the consent rather than over-collecting.

CampoTipoDetalhe
caller_account_idstringobrigatório
max_amountSquadAmountobrigatório
rex_idstringobrigatório

ConsentResponse

200 body for ``PUT …/auto-collect/consent``. ``state`` is ACTIVE after a grant; ``consent_state`` is ``null`` (cleared) — a re-grant re-activates a suspended consent.

CampoTipoDetalhe
consent_idstringobrigatório
consent_statestring, opcional
granted_atstringobrigatório
max_amountSquadAmountobrigatório
rex_idstringobrigatório
statestringPadrão "ACTIVE"

ConsentRevokeRequest

``DELETE /v1/squads/{sqd_id}/auto-collect/consent/{consent_id}`` body — the caller may only revoke their own consent (own-share-only).

CampoTipoDetalhe
caller_account_idstringobrigatório

ConsentRevokeResponse

200 body for a revoke — the consent row is hard-deleted; future cycles no longer auto-collect this member's share.

CampoTipoDetalhe
consent_idstringobrigatório
revokedbooleanPadrão true
sqd_idstringobrigatório

ContributionRequest

``POST /v1/squads/{sqd_id}/contributions`` — ``kind`` selects FUNDED (a QBRL deposit) or ACCOUNTING (a non-monetary split entry, vQBRL-minted). ``kind`` is a plain ``str`` (not a ``Literal``) on purpose: the route validates it explicitly so an unknown kind returns a structured ``400 INVALID_KIND`` rather than FastAPI's generic 422 body.

CampoTipoDetalhe
actor_account_idstringobrigatório
amountSquadAmountobrigatório
descriptionstring, opcional
kindstringobrigatório
members_snapshotarray de string, opcional
source_tx_idsarray de string, opcional
splitSplitSpec, opcional

EntrySplitOverrideRequest

``PATCH /v1/squads/{sqd_id}/entries/{entry_seq}/split`` — owner escape hatch. The owner manually re-divides one expense's *still-open* shares using an explicit ``split`` (EQUAL / SHARES / AMOUNTS over the open debtors). Works even on a partially-settled entry (only the open portion is re-issued); the entry is then flagged so automatic re-splits leave it alone (RFC-018).

CampoTipoDetalhe
actor_account_idstringobrigatório
splitSplitSpecobrigatório

HTTPValidationError

CampoTipoDetalhe
detailarray de ValidationError

InviteAcceptRequest

``POST /v1/squads/{sqd_id}/invitations/accept`` — the invitee accepts. ``caller_account_id`` is the invitee (matching the ``/settle`` convention); the squad + caller identify the pending invite. ``quota`` (cotas, RFC-018) is how many people the invitee represents — default 1; a member bringing a +1 sets 2, making EQUAL-split expenses weight them accordingly. Accepting folds the invitee (at this quota) into every still-open prior expense (see ``retroactive`` in the response).

CampoTipoDetalhe
caller_account_idstringobrigatório
quotaintegerPadrão 1

InviteCreateRequest

``POST /v1/squads/{sqd_id}/invitations`` — an OWNER invites one or more accounts. Replaces the old direct add-member: nobody joins a squad without their own accept. The accepted role is always ``SPENDER`` (no role field), so inviting a prospective OWNER is intentionally out of scope. ``invitee_account_ids`` is a list (1–50) so a client can invite several people in a single tap. The endpoint is **partial-success**: each invitee is reported as ``invited``/``skipped``/``failed`` (see :class:`SquadInviteResultEntry`); only structural errors (squad missing/closed, actor not an OWNER) fail the whole call.

CampoTipoDetalhe
actor_account_idstringobrigatório
invitee_account_idsarray de stringobrigatório

InviteDeclineRequest

``POST /v1/squads/{sqd_id}/invitations/decline`` — the invitee declines.

CampoTipoDetalhe
caller_account_idstringobrigatório

PayoutBlock

External-rail payout status on a Pix squad spend (B-SQ-07). Present only on Pix spends. ``end_to_end_id`` is assigned by the sponsor at dispatch time, so it is ``null`` in the 201 (``PROCESSING``) response and filled once the rail accepts.

CampoTipoDetalhe
end_to_end_idstring, opcional
railstringPadrão "PIX"
recipient_namestring, opcional
status"PROCESSING" | "SETTLED" | "FAILED"Padrão "PROCESSING"

PixDestination

An external Pix payout target for a squad spend (B-SQ-07). Exactly one of ``recipient_account_id`` / ``pix_destination`` is supplied on :class:`SpendRequest`. ``key`` is the raw Pix key as typed; Core normalizes it (DICT lookup + identity-key normalization) — ``key_type`` is the DICT category.

CampoTipoDetalhe
keystringobrigatório
key_type"CPF" | "PHONE" | "EMAIL" | "EVP"obrigatório

RecurrenceBlock

The active recurrence config echoed on writes/reads (``null`` when disabled).

CampoTipoDetalhe
billing_dayintegerobrigatório
current_periodstringobrigatório
timezonestringobrigatório

RecurrenceRequest

``PUT /v1/squads/{sqd_id}/recurrence`` — OWNER enables/edits/disables monthly cycles. ``billing_day`` is the dia de fechamento (1–28; ``null`` disables recurrence); validated in the handler so a bad value surfaces as a discrete ``400 INVALID_BILLING_DAY`` rather than a generic Pydantic 422. ``timezone`` is the IANA zone the billing day is evaluated in (billing fires at 00:00 local).

CampoTipoDetalhe
actor_account_idstringobrigatório
billing_dayinteger, opcional
timezonestringPadrão "America/Sao_Paulo"

RecurrenceResponse

200 body for ``PUT …/recurrence``. ``recurrence`` is ``null`` when the call disabled cycles (``billing_day: null``).

CampoTipoDetalhe
recurrenceRecurrenceBlock, opcional
sqd_idstringobrigatório
updated_atstringobrigatório

RecurringExpenseDeleteRequest

``DELETE /v1/squads/{sqd_id}/recurring-expenses/{rex_id}`` body — OWNER-only.

CampoTipoDetalhe
actor_account_idstringobrigatório

RecurringExpenseDeleteResponse

200 body for ``DELETE …/recurring-expenses/{rex_id}`` — future postings stop; already-posted expenses are unaffected.

CampoTipoDetalhe
deletedbooleanPadrão true
rex_idstringobrigatório
sqd_idstringobrigatório

RecurringExpensePatchRequest

``PATCH /v1/squads/{sqd_id}/recurring-expenses/{rex_id}`` — edit a conta. Partial update: only the fields present change (the route dumps with ``exclude_unset=True``). Future cycle posts use the new values; already-posted expenses are ordinary entries and stay.

CampoTipoDetalhe
actor_account_idstringobrigatório
amountSquadAmount, opcional
descriptionstring, opcional
payer_account_idstring, opcional
splitSplitSpec, opcional
variableboolean, opcional

RecurringExpenseRequest

``POST /v1/squads/{sqd_id}/recurring-expenses`` — create a conta (bill template). ``amount`` is the fixed charge (centavos) for ``variable=False``, or an estimate for ``variable=True`` (the real value is set each cycle via ``/confirm``). ``payer_account_id`` is who pays the provider (the expense's creditor when it posts). ``split`` is the same sealed split as a contribution (EQUAL / SHARES / AMOUNTS).

CampoTipoDetalhe
actor_account_idstringobrigatório
amountSquadAmountobrigatório
descriptionstringobrigatório
payer_account_idstringobrigatório
splitSplitSpecobrigatório
variablebooleanPadrão false

RecurringExpenseResponse

201 body for create (and 200 for PATCH) of a recurring-expense.

CampoTipoDetalhe
amountSquadAmountobrigatório
created_atstringobrigatório
descriptionstringobrigatório
payer_account_idstringobrigatório
rex_idstringobrigatório
splitSplitSpecobrigatório
sqd_idstringobrigatório
statestringPadrão "ACTIVE"
updated_atstringobrigatório
variablebooleanobrigatório

RemoveMemberRequest

``DELETE /v1/squads/{sqd_id}/members/{member_account_id}`` (SQ-10).

CampoTipoDetalhe
actor_account_idstringobrigatório

RevokeInviteRequest

``DELETE /v1/squads/{sqd_id}/invitations/{invitee_account_id}`` — OWNER revokes.

CampoTipoDetalhe
actor_account_idstringobrigatório

SettleRequest

``POST /v1/squads/{sqd_id}/settle`` — per-debtor **self**-settle (SQ-13, amending SQ-17). The caller discharges the shares where THEY are the debtor, paying each creditor from their own BancoBRL custody; the matching share vQBRL burns. Witness set collapses to the caller — one API call can only ever move the caller's own funds (the SquadValidator's ``SettleShare`` enforces it). ``entry_seq`` optionally narrows settlement to a single expense; omitted means every OPEN share where the caller is the debtor.

CampoTipoDetalhe
caller_account_idstringobrigatório
entry_seqinteger, opcional

SpendApprovalPolicy

The spend-approval policy body. ``threshold_amount`` gates spends *above* it; ``approvals_required`` is the number of distinct approvers (the requester does not count); ``approvers`` selects the eligible set. Values are validated in the handler so a bad value surfaces as a discrete ``400 INVALID_THRESHOLD`` / ``INVALID_APPROVALS_REQUIRED`` / ``INVALID_APPROVERS`` rather than a generic Pydantic 422.

CampoTipoDetalhe
approvals_requiredintegerobrigatório
approversstringPadrão "OWNERS"
threshold_amountSquadAmountobrigatório

SpendRequest

``POST /v1/squads/{sqd_id}/spends`` — pay from squad funds (SQ-12, B-SQ-07). ``actor_account_id`` is the OWNER/SPENDER moving the funds. Exactly one destination: ``recipient_account_id`` (an existing account that receives QBRL at BancoBRL custody, must not be the squad itself) **or** ``pix_destination`` (an external Pix key — the pool's QBRL bridges to the deferred Pix rail). ``metadata`` is free-form and copied onto the spend obligation. The amount is centavos (1 QBRL = 1 centavo).

CampoTipoDetalhe
actor_account_idstringobrigatório
amountSquadAmountobrigatório
metadataobject, opcional
pix_destinationPixDestination, opcional
recipient_account_idstring, opcional

SpendRequestApprovalEntry

CampoTipoDetalhe
account_idstringobrigatório
approved_atstringobrigatório

SpendRequestApproveRequest

Body for ``POST …/spend-requests/{spr_id}/approve``. The caller identity is injected by the BFF/gateway from the authenticated principal.

CampoTipoDetalhe
caller_account_idstringobrigatório

SpendRequestPendingResponse

The PENDING_APPROVAL body: 202 on a gated spend-create, 200 on a recorded (non-final) approval. The executed (final) approval instead returns a ``SquadSpendResponse`` (201).

CampoTipoDetalhe
amountSquadAmountobrigatório
approvalsarray de SpendRequestApprovalEntry
approvals_requiredintegerobrigatório
expires_atstringobrigatório
recipient_account_idstringobrigatório
requested_bystringobrigatório
spend_request_idstringobrigatório
sqd_idstringobrigatório
statestringobrigatório

SpendRequestRejectRequest

Body for ``POST …/spend-requests/{spr_id}/reject`` (optional human-readable reason).

CampoTipoDetalhe
caller_account_idstringobrigatório
reasonstring, opcional

SpendRequestRejectResponse

200 body for ``POST …/spend-requests/{spr_id}/reject``.

CampoTipoDetalhe
amountSquadAmountobrigatório
approvalsarray de SpendRequestApprovalEntry
approvals_requiredintegerobrigatório
reasonstring, opcional
recipient_account_idstringobrigatório
rejected_bystringobrigatório
requested_bystringobrigatório
spend_request_idstringobrigatório
sqd_idstringobrigatório
statestringobrigatório

SplitSpec

Allocation for an ACCOUNTING contribution. ``entries`` maps member account id -> relative weight (SHARES) or exact cents (AMOUNTS); omitted/ignored for EQUAL.

CampoTipoDetalhe
entriesobject, opcional
kind"EQUAL" | "SHARES" | "AMOUNTS"obrigatório

SquadAmount

CampoTipoDetalhe
currencystringobrigatório
valueintegerobrigatórioAmount in centavos (1 QBRL = 1 centavo).

SquadBatchInviteResponse

201 body for ``POST /v1/squads/{sqd_id}/invitations`` (batch, partial-success). No ``tx_id``: an invite is a projection-only consent record, not a Cardano tx. Each invitee's fate is in ``results``; ``summary`` is the per-status tally. A 201 here means the request was processed — inspect ``summary``/``results`` for what changed.

CampoTipoDetalhe
inviter_account_idstringobrigatório
resultsarray de SquadInviteResultEntryobrigatório
sqd_idstringobrigatório
summarySquadInviteSummaryobrigatório

SquadCloseFinalBalance

The squad's residual pooled balance at close — always zero (the close precondition requires every Balance UTxO drained).

CampoTipoDetalhe
currencystringPadrão "BRL"
valueintegerPadrão 0

SquadCloseResponse

201 body for ``POST /v1/squads/{sqd_id}/close`` (RFC-018 §5.1, SQ-14). The terminal lifecycle event: the tx consumes the OPEN Config UTxO and recreates it with ``state="CLOSED"``. After close every write referencing the Config fails the validator's ``configIsOpen`` check (SI-7); reads continue indefinitely. ``closed_at`` is the server timestamp; ``final_member_count`` is the preserved roster size; ``final_balance`` is always zero by precondition.

CampoTipoDetalhe
closed_atstringobrigatório
closed_bystringobrigatório
final_balanceSquadCloseFinalBalanceobrigatório
final_member_countintegerobrigatório
sqd_idstringobrigatório
statestringPadrão "CLOSED"
tx_idstringobrigatório

SquadCreateRequest

``POST /v1/squads`` — the creator becomes the first OWNER member. ``name`` is the only required display field; everything else lives under the optional ``metadata`` object (description, emoji, image_url, location). ``invitee_account_ids`` is **optional**: omit it to create a bare squad, or pass a list to create + invite in one atomic call. Every invitee is validated *before* the irreversible create tx, so a single bad invitee fails the whole request with nothing created on-chain. Invitees enter the on-chain roster only when they accept.

CampoTipoDetalhe
creator_account_idstringobrigatório
invitee_account_idsarray de string, opcional
metadataSquadMetadata, opcional
namestringobrigatório

SquadDebtResolution

What member removal did to the leaver's open accounting debts. Every entry the leaver owed on is redistributed proportionally across that entry's remaining members (no write-offs; "creditor absorbs" is just the degenerate last-member case). ``entries_skipped`` carries any entry a transient error left untouched (``RESPLIT_FAILED``) — the member is still removed, retry re-runs them.

CampoTipoDetalhe
entries_redistributedarray de SquadEntryRedistribution
entries_skippedarray de SquadResplitSkip
reissue_tx_idsarray de string
void_tx_idsarray de string
vqbrl_burnedintegerPadrão 0
vqbrl_mintedintegerPadrão 0

SquadEntrySplitOverrideResponse

200 body for the per-entry split override (RFC-018).

CampoTipoDetalhe
actor_account_idstringobrigatório
entry_seqintegerobrigatório
open_amount_centsintegerobrigatório
sharesarray de SquadShareEntry
sqd_idstringobrigatório
tx_idstring, opcional

SquadFreezeRequest

``POST /v1/squads/{sqd_id}/freeze`` and ``.../unfreeze`` — an OWNER toggles the squad's reversible wind-down state. Off-chain only (no Cardano tx): while frozen, deposits/spends/accounting and all roster changes are rejected (422 SQUAD_FROZEN); settlement, close, decline-invite, and metadata edits still work. Freezing is a prerequisite for ``simplify-debts``.

CampoTipoDetalhe
actor_account_idstringobrigatório

SquadFreezeResponse

200 body for freeze/unfreeze. ``frozen`` is the resulting state; ``changed`` is false when the squad was already in that state (idempotent no-op). ``simplified`` is the sticky historical marker (true once the squad has ever been simplified) and is surfaced here for convenience — unfreeze never clears it.

CampoTipoDetalhe
changedbooleanobrigatório
frozenbooleanobrigatório
simplifiedbooleanPadrão false
sqd_idstringobrigatório
updated_atstringobrigatório

SquadGoalBlock

The server-computed goal state echoed on writes and reads (the ``goal`` block). ``funded_cents`` is the live pool balance (FUNDED in − spends − reclaims); ``progress`` is ``funded_cents / target_amount.value`` clamped to ``[0, 1]``; ``achieved_at`` is sticky — set the first moment the pool reaches the target and kept even if the balance later dips.

CampoTipoDetalhe
achieved_atstring, opcional
funded_centsintegerobrigatório
progressnumberobrigatório
target_amountSquadAmountobrigatório
target_datestring, opcional

SquadGoalDeleteRequest

``DELETE /v1/squads/{sqd_id}/goal`` — an OWNER removes the goal. Only the actor is needed (there is no goal body to clear beyond the row attributes).

CampoTipoDetalhe
actor_account_idstringobrigatório

SquadGoalDeleteResponse

200 body for ``DELETE /v1/squads/{sqd_id}/goal`` — ``goal`` is always ``null``.

CampoTipoDetalhe
goalSquadGoalBlock, opcional
sqd_idstringobrigatório

SquadGoalRequest

``PUT /v1/squads/{sqd_id}/goal`` — an OWNER sets or edits the savings goal. Off-chain projection only (no Cardano tx) — the goal constrains nothing, it only measures. ``target_amount`` is the finish line (BRL, centavos); ``target_date`` is an optional ``YYYY-MM-DD`` deadline. Both are validated in the handler so a bad value surfaces as a discrete ``400 INVALID_GOAL_AMOUNT`` / ``INVALID_GOAL_DATE`` rather than a generic Pydantic 422.

CampoTipoDetalhe
actor_account_idstringobrigatório
target_amountSquadAmountobrigatório
target_datestring, opcional

SquadGoalResponse

200 body for ``PUT /v1/squads/{sqd_id}/goal``.

CampoTipoDetalhe
goalSquadGoalBlockobrigatório
sqd_idstringobrigatório
updated_atstringobrigatório

SquadInviteAcceptResponse

201 body for ``POST /v1/squads/{sqd_id}/invitations/accept``. The accept runs the on-chain ChangeMembership, so it carries ``tx_id`` and the new roster. ``acted_by_owner_account_id`` is the current OWNER that custodially authored the add (the invitee is not an OWNER, so cannot sign it themselves). ``quota`` is the accepted member's cota count; ``retroactive`` reports how the open prior expenses were re-split to include them (RFC-018).

CampoTipoDetalhe
acted_by_owner_account_idstringobrigatório
config_utxo_refstringobrigatório
invitee_account_idstringobrigatório
invitee_pkhstringobrigatório
joined_atstringobrigatório
member_countintegerobrigatório
membersarray de SquadMemberRosterEntryobrigatório
quotaintegerPadrão 1
retroactiveSquadResplitReport
rolestringobrigatório
sqd_idstringobrigatório
tx_idstringobrigatório

SquadInviteActionResponse

200 body for revoke / decline — the invite's new terminal ``state``.

CampoTipoDetalhe
invitee_account_idstringobrigatório
sqd_idstringobrigatório
statestringobrigatório

SquadInviteResultEntry

One invitee's outcome in a batch-invite report. ``status`` is ``invited`` (a PENDING row was written), ``skipped`` (a benign no-op: self / already a member / already pending / duplicated in the request), or ``failed`` (the invitee account does not exist or is itself a SQUAD account). ``reason`` is the machine code (``OK``, ``CANNOT_INVITE_SELF``, ``ALREADY_A_MEMBER``, ``INVITE_ALREADY_PENDING``, ``DUPLICATE_IN_REQUEST``, ``ACCOUNT_NOT_FOUND``, ``SQUAD_AS_SQUAD_MEMBER_FORBIDDEN``). ``invitee_pkh``/``created_at`` are present only when the invitee resolved / was written.

CampoTipoDetalhe
created_atstring, opcional
invitee_account_idstringobrigatório
invitee_pkhstring, opcional
reasonstringobrigatório
statestring, opcional
statusstringobrigatório

SquadInviteSummary

CampoTipoDetalhe
failedintegerobrigatório
invitedintegerobrigatório
skippedintegerobrigatório
totalintegerobrigatório

SquadMemberQuotaResponse

200 body for the quota edit. ``retroactive`` reports the re-split of open EQUAL entries under the new quota.

CampoTipoDetalhe
member_account_idstringobrigatório
member_pkhstringobrigatório
quotaintegerobrigatório
retroactiveSquadResplitReport
sqd_idstringobrigatório

SquadMemberRemoveResponse

200 body for ``DELETE /v1/squads/{sqd_id}/members/{member_account_id}``.

CampoTipoDetalhe
config_utxo_refstringobrigatório
debt_resolutionSquadDebtResolution
member_countintegerobrigatório
membersarray de SquadMemberRosterEntryobrigatório
removed_member_account_idstringobrigatório
removed_member_pkhstringobrigatório
sqd_idstringobrigatório
tx_idstringobrigatório

SquadMemberRoleChangeResponse

200 body for ``PATCH /v1/squads/{sqd_id}/members/{member_account_id}/role``. ``changed`` is ``False`` (and ``tx_id`` ``None``) when the member already had the requested role — a no-op that ran no Cardano tx. Otherwise it carries the ChangeMembership ``tx_id`` and the post-change roster.

CampoTipoDetalhe
changedbooleanobrigatório
config_utxo_refstring, opcional
member_account_idstringobrigatório
member_countintegerobrigatório
member_pkhstringobrigatório
membersarray de SquadMemberRosterEntryobrigatório
rolestringobrigatório
sqd_idstringobrigatório
tx_idstring, opcional

SquadMemberRosterEntry

One entry of a member-mutation response roster. V1 stores members pkh-only (no pkh→account_id index; the join is the SQ-18 read layer's job — see ``shared/squad_view``), so the roster is keyed by ``member_pkh``. The account_id of the member touched by *this* request is echoed at the top level of the response instead.

CampoTipoDetalhe
member_pkhstringobrigatório
rolestringobrigatório

SquadMetadata

Optional, purely-cosmetic display metadata for a squad (off-chain only — never part of the on-chain Config datum). Every field is optional; on a PATCH an explicit ``null`` clears that field while an omitted field is left unchanged.

CampoTipoDetalhe
descriptionstring, opcional
emojistring, opcional
image_urlstring, opcional
locationSquadLocation, opcional
templatestring, opcional
template_confignão declarado, opcional

SquadResplitReport

What a retroactive re-split did across a squad's open EQUAL entries. ``entries_resplit`` are the entry_seqs re-issued under the new membership/quotas; ``entries_skipped`` are entries left untouched (already settled/voided, or a transient failure) — the owner can fix those via the per-entry split override.

CampoTipoDetalhe
entries_resplitarray de integer
entries_skippedarray de SquadResplitSkip

SquadRulesBlock

The ``rules`` block echoed on the write response and squad detail (``null`` when unset).

CampoTipoDetalhe
spend_approvalSpendApprovalPolicyobrigatório

SquadRulesDeleteRequest

``DELETE /v1/squads/{sqd_id}/rules`` — an OWNER removes the policy. Only the actor is needed.

CampoTipoDetalhe
actor_account_idstringobrigatório

SquadRulesDeleteResponse

200 body for ``DELETE /v1/squads/{sqd_id}/rules`` — ``rules`` is always ``null``.

CampoTipoDetalhe
rulesSquadRulesBlock, opcional
sqd_idstringobrigatório

SquadRulesRequest

``PUT /v1/squads/{sqd_id}/rules`` — an OWNER sets/edits the spend-approval policy.

CampoTipoDetalhe
actor_account_idstringobrigatório
spend_approvalSpendApprovalPolicyobrigatório

SquadRulesResponse

200 body for ``PUT /v1/squads/{sqd_id}/rules``.

CampoTipoDetalhe
rulesSquadRulesBlockobrigatório
sqd_idstringobrigatório
updated_atstringobrigatório

SquadSettleResponse

201 body for ``POST /v1/squads/{sqd_id}/settle`` (SQ-13 per-debtor self-settle). Withdraw-only success: when the caller owes nothing but had a squad deposit, the deposit is returned to their personal custody and the call succeeds with ``settled_shares == 0``, ``squad_funds_withdrawn_cents > 0``, and ``tx_id == withdrawal_tx_id`` (no ``SettleShare`` tx ran — the withdrawal is the only on-chain tx). A 404 ``ACCOUNTING_NOT_FOUND`` is returned only when the caller owed nothing AND had no deposit (nothing to settle).

CampoTipoDetalhe
caller_account_idstringobrigatório
created_atstringobrigatório
settled_sharesintegerobrigatório
sqd_idstringobrigatório
squad_funds_withdrawn_centsintegerPadrão 0
statestringPadrão "OPEN"
transfersarray de SquadSettleTransfer
tx_idstringobrigatório
vqbrl_burnedintegerobrigatório
withdrawal_tx_idstring, opcional

SquadSettleTransfer

CampoTipoDetalhe
amount_centsintegerobrigatório
creditor_pkhstringobrigatório

SquadShareEntry

One per-debtor share minted by an ACCOUNTING register (SQ-13). pkh-keyed (V1 has no pkh→account_id index — SQ-18 owns that join); ``share_utxo_ref`` is the new AccountingShare UTxO (``tx_hash#ix``); ``obligation_id`` is the logical ``obl_*`` row recording this share.

CampoTipoDetalhe
debtor_pkhstringobrigatório
obligation_idstringobrigatório
share_centsintegerobrigatório
share_utxo_refstringobrigatório

SquadSimplifyConsolidation

One synthetic net entry the simplification created: a single creditor owed by one or more debtors, replacing the gross shares that netted to it.

CampoTipoDetalhe
creditor_account_idstring, opcional
creditor_pkhstringobrigatório
debtorsarray de SquadSimplifyDebtor
entry_seqintegerobrigatório
total_centsintegerobrigatório

SquadSimplifyRequest

``POST /v1/squads/{sqd_id}/simplify-debts`` — collapse the open accounting graph into the minimal set of net debts. OWNER-only: it void+reissues *every* member's shares, a squad-wide restructuring (unlike settle, which only ever moves the caller's own funds).

CampoTipoDetalhe
caller_account_idstringobrigatório

SquadSimplifyResponse

201 body for ``POST /v1/squads/{sqd_id}/simplify-debts``. ``no_op`` is true (with empty void/created lists and equal before/after counts) when the graph is already minimal — no on-chain work runs. Otherwise the open shares were voided and the minimal net set reissued: ``vqbrl_minted`` equals ``vqbrl_burned`` (total open debt is conserved; only the edge count shrinks).

CampoTipoDetalhe
consolidationsarray de SquadSimplifyConsolidation
created_atstringobrigatório
created_entriesarray de integer
no_opbooleanPadrão false
reissue_tx_idsarray de string
sqd_idstringobrigatório
statestringPadrão "OPEN"
transfers_after_countintegerobrigatório
transfers_before_countintegerobrigatório
void_tx_idsarray de string
voided_entriesarray de integer
vqbrl_burnedintegerPadrão 0
vqbrl_mintedintegerPadrão 0

SquadSpendResponse

201 body for ``POST /v1/squads/{sqd_id}/spends`` (RFC-018 §5.1, SQ-12, B-SQ-07). ``consumed_balance_utxos`` are the Balance UTxO refs spent at the SquadValidator; ``residual_balance_utxo`` is the leftover Balance UTxO (``tx_hash#ix``) or ``null`` when the spend is exact. ``obligation_id`` is the logical ``obl_*`` row recording the spend (debtor = the squad). For an **internal** spend ``state`` is ``"OPEN"`` and ``recipient_account_id`` is set. For an **external Pix** spend ``recipient_account_id`` is ``null``, ``state`` is ``"PROCESSING"``, and ``payout`` carries the rail status. The amount is centavos (1 QBRL = 1 centavo).

CampoTipoDetalhe
actor_account_idstringobrigatório
amountSquadAmountobrigatório
consumed_balance_utxosarray de stringobrigatório
created_atstringobrigatório
event_seqintegerobrigatório
obligation_idstringobrigatório
payoutPayoutBlock, opcional
recipient_account_idstring, opcional
residual_balance_utxostring, opcional
sqd_idstringobrigatório
statestringPadrão "OPEN"
tx_idstringobrigatório

SquadUpdateRequest

``PATCH /v1/squads/{sqd_id}`` — an OWNER edits the squad's display fields. Partial update: only the fields present in the body change; an omitted field is left untouched, and an explicit ``null`` on an optional metadata field clears it (``name`` is never clearable). The route dumps this with ``exclude_unset=True`` so the handler can tell "omitted" from "set to null". This is an off-chain projection write only — no Cardano transaction is built.

CampoTipoDetalhe
actor_account_idstringobrigatório
metadataSquadMetadata, opcional
namestring, opcional

SquadUpdateResponse

200 body for ``PATCH /v1/squads/{sqd_id}`` — the squad's full current display metadata after the edit.

CampoTipoDetalhe
metadataSquadMetadataobrigatório
namestringobrigatório
sqd_idstringobrigatório
updated_atstringobrigatório

SquadVoidResponse

200 body for ``DELETE /v1/squads/{sqd_id}/contributions/{entry_seq}`` (SQ-13).

CampoTipoDetalhe
sqd_idstringobrigatório
tx_idstringobrigatório
voided_entry_seqintegerobrigatório
voided_sharesintegerobrigatório
vqbrl_burnedintegerobrigatório

UpdateMemberQuotaRequest

``PATCH /v1/squads/{sqd_id}/members/{member_account_id}/quota`` (RFC-018). ``actor_account_id`` is the caller: a member may change their own quota, and an OWNER may change anyone's. Blocked (409 QUOTA_CHANGE_LOCKED) once the squad has any settled/voided entry.

CampoTipoDetalhe
actor_account_idstringobrigatório
quotaintegerobrigatório

ValidationError

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

VoidContributionRequest

``DELETE /v1/squads/{sqd_id}/contributions/{entry_seq}`` body (SQ-13). The creditor (original actor) burns the entry's still-unsettled shares.

CampoTipoDetalhe
actor_account_idstringobrigatório