---
title: codespar_pay
description: Outbound spend. Money leaves the wallet or account your agent governs, under a signed mandate. Pix, card, boleto settlement, TED and wire, plus the reads around them (status, boleto quote, DDA, DICT keys and claims, Pix devolution).
---

import { Callout } from "fumadocs-ui/components/callout";
import { Tabs, Tab } from "fumadocs-ui/components/tabs";

<MetaToolHeader tool="codespar_pay" />

Collecting FROM a buyer instead? That is [`codespar_charge`](/docs/concepts/meta-tools/charge) (sell-side). Settling in USDC or any on-chain asset? That is [`codespar_crypto_pay`](/docs/concepts/meta-tools/crypto-pay).

## Actions

<MetaToolActions tool="codespar_pay" />

## Example

`action: "pay"` over Pix, to a Pix key, from the consumer's governed wallet. Amounts are in minor units (centavos).

<Split min={380}>
<SplitPane label="Call · tools/call">

```json title="arguments"
{
  "name": "codespar_pay",
  "arguments": {
    "action": "pay",
    "amount": 2500,
    "currency": "BRL",
    "method": "pix",
    "recipient": "payee@example.com",
    "description": "Example payout",
    "consumer_id": "consumer_0000",
    "idempotency_key": "pay_0000"
  }
}
```

</SplitPane>
<SplitPane label="Result · fields the tool document names">

```json title="result"
{
  "status": "PROCESSING",
  "settled": false,
  "status_message": "Accepted by the rail and settling; the wallet is already debited.",
  "initiation_type": "DICT",
  "charge_correlation": "none",
  "end_to_end_id": "e2e_0000"
}
```

</SplitPane>
</Split>

A Pix cash-out is asynchronous: `PROCESSING` means accepted and settling within seconds, with the wallet already debited. Relay `status_message` to the user; do not surface a bare `PROCESSING` and do not treat it as a failure. A static QR (the code taped to a small merchant's wall) carries no charge identifier, so its result says `charge_correlation: "none"`: `settled` means the rail moved the money, not that the merchant marked an order paid. Pass the `end_to_end_id` to the payee if they need to reconcile.

## When to use

- **Paying a store order from `codespar_shop`.** Pass the `checkout_session_id` with the same `consumer_id` used in the checkout; the backend resolves the exact Pix copia-e-cola server-side. Never re-type the long Pix code yourself (re-typing corrupts the CRC). If you already hold a copia-e-cola, pass it as `copia_e_cola`, never as `recipient`.
- **Paying a Pix key.** `recipient` is the key (email, phone, CPF/CNPJ, EVP). For a destination with no key, `recipient` is a bank-account object; pass it literally, not JSON-stringified, because the argument's runtime type is what selects the path.
- **Settling an existing boleto.** `method: "boleto"` with `linha_digitavel`. Quote first with `action: "boleto_quote"`, then settle passing `expected_amount_minor`, so a stale quote fails cleanly instead of paying a different amount. This settles an existing boleto; it does not issue one (that is `codespar_charge`).
- **A bank wire.** `method: "ted"` sends a real outbound TED to a bank account with no Pix key. It executes only under a consumer mandate whose signed `withdrawal_allowlist` names the destination; see Money and mandate.
- **Reading state.** `action: "status"` reads a payment, charge or boleto by the id a previous `codespar_pay` or `codespar_charge` result returned, and answers with that provider's status verbatim (for example `OVERDUE` for an unpaid boleto). Pin `provider` when you already know which rail holds it.
- **The consumer's own Pix account.** The `dda_*` actions register the consumer's document for national boleto visibility and list what they owe; the `dict_key_*` and `dict_claim_*` actions manage the keys on their account and the claim lifecycle. None of these moves money; the account is always resolved server-side from `consumer_id`.
- **Refunding a Pix.** `action: "pix_devolution"` returns a received Pix to its original payer; with `payment_direction: "outbound"` it asks the rail to devolve a Pix the consumer sent. Poll `pix_devolution_status`, not `status`, until `settled`.

## Arguments

The table mirrors the published schema for `codespar_pay`. `action` is required on every call.

**Common**

| Field | Type | Required | Description |
|---|---|---|---|
| `action` | `string` | Yes | One of `pay`, `status`, `boleto_quote`, `dda_subscribe`, `dda_status`, `dda_list_due`, `dda_unsubscribe`, `dict_claim_open`, `dict_claim_confirm`, `dict_claim_cancel`, `dict_claim_status`, `dict_claim_list`, `dict_claim_respond`, `dict_key_register`, `dict_key_list`, `dict_key_delete`, `pix_devolution`, `pix_devolution_status`. See the Actions table. |
| `consumer_id` | `string` | No | Whose governed wallet pays, and whose account every DDA and DICT action targets. Defaults to the session user; for a checkout-originated Pix you must pass the consumer used in the checkout. |
| `mandateId` | `string` | No | Pre-authorized mandate id |
| `idempotency_key` | `string` | For `ted`, `pix_devolution`, `dda_subscribe` | Stable per-operation key, reused verbatim on every retry of the same operation so a retry never dispatches a second payment. Strongly recommended for `method: "boleto"` (ent#783: without it every retry mints a fresh key and the provider cannot dedupe). On `pix_devolution` a new key for the same payment opens a new devolution of the remainder. |

**`action: "pay"`**

| Field | Type | Required | Description |
|---|---|---|---|
| `amount` | `number` | For `pay` | Minor units (centavos for BRL). Must match the copia-e-cola's amount when paying a QR. On `pix_devolution` it is the partial amount to return (optional inbound, required outbound). |
| `currency` | `string` | For `pay` | `BRL`, `USD`, `EUR` |
| `description` | `string` | For `pay` | Payment description |
| `method` | `string` | No | `pix`, `card`, `boleto`, `ted`, `wire`. The schema declares a free-form string with no `enum`, so an unroutable value passes validation and dies at routing with `no_eligible_providers`. With `action: "status"`, `method` (`pix`, `ted`, `boleto`) narrows which rail the status is read from. |
| `country` | `string` | No | ISO 3166-1 alpha-2 for the eligibility rail (`BR`, `US`, `MX`, `AR`, `CL`, `CO`, `INTL`). Defaults to `BR`. `US` for cross-border USD card via Stripe ACP, `INTL` for hosted-checkout flows. |
| `recipient` | `string` \| `object` | One of | A Pix key, or an object `{ bank (ISPB), account, branch, tax_id, name, account_type? }` for a destination with no key (a manual Pix cash-out, or the destination of `method: "ted"`). Pass the object literally. Do not put a copia-e-cola here. |
| `copia_e_cola` | `string` | One of | A Pix copia-e-cola / BR Code to pay. The rail decodes it (static or dynamic) and debits the governed wallet. |
| `checkout_session_id` | `string` | One of | A `codespar_shop` checkout to settle. Preferred over `copia_e_cola` for a store order. Pass with `consumer_id`. |
| `linha_digitavel` | `string` | With `boleto` | The 47/48-digit linha digitável (or barcode) of an existing boleto to pay, or to quote with `boleto_quote`. |
| `expected_amount_minor` | `number` | No | `method: "boleto"` only: the exact amount a prior `boleto_quote` returned as `true_amount`. The settle re-consults the boleto and refuses with `amount_mismatch` when the fresh amount differs; no money moves on a stale quote. |
| `client_finality` | `string` | No | `method: "ted"` only: the BaaS partner's finality code (`1` \| `3` \| `4` \| `5` \| `7` \| `9` \| `10` \| `100` \| `110` \| `99999`; defaults to `1`, a generic transfer). `99999` requires a `description`. |

**`action: "status"`**

| Field | Type | Required | Description |
|---|---|---|---|
| `payment_id` | `string` | For `status` | The id a previous `codespar_pay` or `codespar_charge` result returned: an Asaas `pay_*` id, a BaaS transaction id, or a Pix endToEndId. |
| `provider` | `string` | No | Pin which provider holds the transaction, `asaas` \| `celcoin`. Any other value is refused, not defaulted. Omit it and the read probes the rails that can answer, in order. |

**DDA (`dda_*`)**

| Field | Type | Required | Description |
|---|---|---|---|
| `document` | `string` | For `dda_subscribe`, `dda_status`, `dda_unsubscribe` | The consumer's own CPF or CNPJ (punctuation optional). For `dda_subscribe` it is registered in the national DDA register, so it must be the document verified for that consumer's account at onboarding AND be named in the signed `dda_allowlist` of an active mandate of that consumer. |
| `client_name` | `string` | No | `dda_subscribe` only: the document holder's name as it should reach the provider. Defaults to `consumer_id`. |
| `from_date` | `string` | For `dda_list_due` | `YYYY-MM-DD`; list boletos due on or after this date. |
| `to_date` | `string` | For `dda_list_due` | `YYYY-MM-DD`; list boletos due on or before this date. |

**DICT keys and claims (`dict_*`)**

| Field | Type | Required | Description |
|---|---|---|---|
| `key` | `string` | Per action | The key being claimed (`dict_claim_open`), the key value to register (`dict_key_register`, omit for `EVP`), or the key to remove (`dict_key_delete`). |
| `key_type` | `string` | For `dict_key_register` | `EMAIL` \| `PHONE` (E.164) \| `CPF` \| `CNPJ` (the account holder's own document; the alphanumeric CNPJ is accepted) \| `EVP` (the provider mints a random key; pass no `key`). Optional hint on `dict_claim_open`. |
| `claim_type` | `string` | For `dict_claim_open` | `OWNERSHIP` (contest a key resolving to another account) or `PORTABILITY` (re-point a key the consumer owns at another institution). Optional filter on `dict_claim_list`. |
| `claim_id` | `string` | For confirm, cancel, status, respond | Must be a claim this consumer opened (confirm, cancel, status) or is the donor of (respond); any other id is refused. |
| `response` | `string` | For `dict_claim_respond` | `CONFIRM` (the donor releases the key) or `REJECT` (the donor keeps it). |
| `reason` | `string` | No | For confirm, cancel, respond: `USER_REQUESTED` (default on cancel and reject) \| `ACCOUNT_CLOSURE` \| `FRAUD` \| `DEFAULT_OPERATION`. For `pix_devolution`: the Pix return code, default `MD06`. |
| `status` | `string` | No | `dict_claim_list` only: `OPEN` \| `WAITING_RESOLUTION` \| `CONFIRMED` \| `CANCELLED` \| `COMPLETED`. |
| `date_from` | `string` | No | `dict_claim_list` only: from this date (`YYYY-MM-DD`). |
| `date_to` | `string` | No | `dict_claim_list` only: up to this date (`YYYY-MM-DD`). |
| `limit_per_page` | `number` | No | `dict_claim_list` only: page size. |
| `page` | `number` | No | `dict_claim_list` only: page number. |

**Pix devolution (`pix_devolution*`)**

| Field | Type | Required | Description |
|---|---|---|---|
| `end_to_end_id` | `string` | For `pix_devolution` | The original payment's endToEndId, the only reference the rail accepts. Only a payment on the consumer's own account statement (last 7 days) can be devolved. |
| `payment_direction` | `string` | No | `inbound` (default) devolves a payment the consumer received, sending the money back to its payer; `outbound` devolves a payment the consumer sent, returning it to the consumer's account (`amount` then required, one devolution per sent payment). |
| `devolution_id` | `string` | For `pix_devolution_status` | The devolution to read, as returned by `pix_devolution`. |

## Errors and what to do

| Error | Cause | What to do |
|---|---|---|
| `invalid_args` | A required argument for the action is missing, `recipient` and `copia_e_cola` are both absent on `pay`, or an unknown `action`. Nothing is dispatched. | Fix the call against the Arguments table. |
| `no_eligible_providers` | The `method` × `currency` × `country` intent has no catalog line, or none of its providers is connected on this project. Nothing is dispatched. | Check the rail in Notes, or connect the provider via [`codespar_manage_connections`](/docs/concepts/meta-tools/manage-connections). |
| `amount_mismatch` | `method: "boleto"` with `expected_amount_minor`, and the boleto's fresh true amount differs from the quote. No money moved. | Re-quote with `boleto_quote` and show the new amount before settling. |
| `dda_document_not_owned` | `dda_subscribe` for a document that is not the one verified for this consumer's account (including an account with no verified document). Nothing sent; the refusal never says which document was expected. | Onboard the consumer whose document it is ([`codespar_kyc`](/docs/concepts/meta-tools/kyc) `onboarding`). Fixing the mandate does not clear this. |
| `dda_document_unauthorized` | The document is not named in the signed `dda_allowlist` of an active mandate of this consumer. Nothing sent. | The consumer names it at `POST /v1/consents/init`, field `intent.dda_allowlist`; there is no wildcard. |
| Refused TED with a consent next-step | `method: "ted"` to a destination the mandate's signed `withdrawal_allowlist` does not name. Nothing sent; the result reports `dispatch: "unsent"`. | Have the consumer sign a mandate naming `ted:<ispb>:<branch>:<account>`. A merchant `"*"` wildcard never authorizes it. |
| `PROCESSING` on a Pix cash-out | Not an error: accepted and settling in seconds, wallet already debited. | Relay `status_message`; poll `action: "status"` if you need the terminal state. |
| A devolution refused by the rail (outbound) | The receiver is out of the rail's reach. | It comes back as-is and is not a retry case. |

## Money and mandate

`action: "pay"` and `action: "pix_devolution"` move real money. Every spend leaves the consumer's governed wallet under a signed [mandate](/docs/concepts/directed-pay): per-currency caps, per-transaction caps, allowlists and expiry are checked server-side before dispatch. Two destinations are pinned by the mandate text itself:

- **TED** executes only when the mandate's signed `withdrawal_allowlist` names `ted:<ispb>:<branch>:<account>` (digits only). `idempotency_key` is required and checked before any money step, because the default correlation would make a second TED silently attach to the first. Every gate here is pre-dispatch and reports `dispatch: "unsent"`; an ambiguous provider outcome is never reported as unsent.
- **DDA registration** exposes the titular's boletos, so it needs the document both verified at onboarding and named in the mandate's signed `dda_allowlist`. Neither condition substitutes for the other. `dda_unsubscribe` needs no mandate, so withdrawing a document from a national register stays possible after the consumer revokes consent.

Every other action (`status`, `boleto_quote`, `dda_status`, `dda_list_due`, all `dict_*`, `pix_devolution_status`) is a read or an account-management call: no money moves. A devolution always goes back to the original payer (inbound) or to the consumer's own account (outbound); it cannot be redirected.

## Related

- [`codespar_charge`](/docs/concepts/meta-tools/charge): the inbound counterpart, and the tool that issues boletos
- [`codespar_wallet`](/docs/concepts/meta-tools/wallet): the balance this tool spends from; `receive` to fund it
- [`codespar_shop`](/docs/concepts/meta-tools/shop): the checkout whose `checkout_session_id` this tool settles
- [Directed pay and mandates](/docs/concepts/directed-pay): what the signed mandate authorizes
- [Async settlement](/docs/api/sessions#async-settlement): correlation chain and webhook flow
- [Pix Payment Agent cookbook](/docs/cookbooks/pix-payment-agent): simplest end-to-end example
- [Marketplace Payout cookbook](/docs/cookbooks/marketplace-payout): split fee and seller payout

## Notes

**Rails and providers**

| Rail | Currency | Country | Providers |
|---|---|---|---|
| Pix | BRL | BR | Outbound: **Asaas** (default) and a licensed Brazilian BaaS provider. Mercado Pago and **9 banks direct via mTLS** (Banco do Brasil, Itaú, Bradesco, Santander, Caixa, Sicoob, Sicredi, C6, Original) sit on this surface as inbound charge lines and are refused for `codespar_pay` |
| Card | BRL | BR | Cielo (+ 3DS), Pagar.me |
| Boleto (settle an existing boleto) | BRL | BR | Licensed Brazilian BaaS partner. Not a catalog line: this action bypasses the router and settles directly on the BaaS rail |
| TED | BRL | BR | Licensed Brazilian BaaS partner. Not a catalog line either: it bypasses the router and runs through the governed mandate lifecycle |
| Card | MXN | MX | Conekta |
| Card | PEN | PE | Culqi |
| Card | CLP | CL | Transbank |
| Card | COP | CO | Wompi |
| Bank transfer | COP | CO | Cobre |
| Wire | CLP | CL | Khipu |
| Wire | USD | INTL | Airwallex |
| Card | USD | US | Stripe ACP |
| Card · hosted checkout | USD / EUR | INTL | Stripe ACP, Adyen, Airwallex, dLocal, Rapyd |

The catalog carries 29 `codespar_pay` lines over 25 providers, but 10 of them (Mercado Pago and the nine bank `/cob` lines) are inbound charge lines the router refuses for a payout: 15 providers actually route outbound, across six countries (BR, MX, PE, CL, CO, US) plus the international corridors. The router fails over within a rail when the primary provider degrades (Pix BRL walks Asaas → the BaaS provider) and drops every line whose catalog entry declares `money_in` before scoring, so inbound lines are never picked and never reached by failover. Lines that declare no direction still pass; only Pix × BRL × BR has been adjudicated so far. See `/dashboard/router` for live failover telemetry, and [cert auth](/docs/concepts/authentication#provider-auth-schemes) for the banks' mTLS.

**Operator setup.** Each rail needs operator-stamped credentials in `/dashboard/auth-configs`: Asaas (API key; sandbox key for test, production key for live), Mercado Pago (access token, tied to a single seller account), Wompi / Conekta / Khipu / Transbank (per-provider API key and sandbox toggle). The dashboard wizard renders the right inputs from each server's `auth_type` in the catalog.

**Async settlement.** After `codespar_pay` returns, settlement happens via the provider webhook: the provider settles (seconds for Pix, hours-to-days for SPEI or wallet rails), POSTs a webhook, the backend correlates `external_reference` with `idempotency_key`, and `session.paymentStatus(tool_call_id)` reports `succeeded` with `final_amount_minor` and `settled_at`. See [async settlement](/docs/api/sessions#async-settlement) for per-provider idempotency-key shapes and [SSE streaming](/docs/api/sessions#streaming-status) for the streaming variant.

**From the SDK.** There is no typed wrapper for `codespar_pay`; call `session.execute()` with the same arguments as the MCP call. The executor output lives under `data`.

<Tabs items={["TypeScript", "Python"]}>

```ts tab="TypeScript"
const result = await session.execute("codespar_pay", {
  action: "pay",
  amount: 2500,
  currency: "BRL",
  method: "pix",
  recipient: "payee@example.com",
  description: "Example payout",
  consumer_id: "consumer_0000",
  idempotency_key: "pay_0000",
});
console.log(result.tool_call_id, result.data);
```

```python tab="Python"
result = session.execute("codespar_pay", {
    "action": "pay",
    "amount": 2500,
    "currency": "BRL",
    "method": "pix",
    "recipient": "payee@example.com",
    "description": "Example payout",
    "consumer_id": "consumer_0000",
    "idempotency_key": "pay_0000",
})
print(result["tool_call_id"], result["data"])
```

</Tabs>

**Result envelope (SDK), as previously documented.** `session.execute` returns `{ success, data, error, tool_call_id, server }`; for `action: "pay"` the page used to document `data` as `{ id, status, settled?, status_message?, amount?, currency?, method? }` plus rail-specific extras (`end_to_end_id` on Pix; `linha_digitavel`, `beneficiary`, `due_date` on boleto), and `action: "status"` as `{ id, status, billing_type, value, due_date }`. This revision did not re-verify those field lists against the runtime; the fields the tool document itself names are the ones in the Example above.

**`@codespar/types` drifts.** The package's copy of this schema (`SHARED_META_TOOL_DEFINITIONS.codespar_pay`) lags the API in both directions (ent#933): it still names `usdc` and `sepa` as methods, neither of which routes, and it lacks fields the API publishes. This page follows the API, which is what decides.
