Why two steps
Splitting a cash-out into initiate and process gives you a checkpoint between “who is the payee?” and “send the money”:
- Verify the destination first. Initiate validates and resolves the payee account without touching balances. A wrong Pix key or an invalid account fails here — before any money moves.
- Show the payer who receives the money. The initiate response returns the resolved account owner. Your app can display the real name and let the payer confirm first.
- Move funds only on confirmation. Nothing is debited until you process the transfer. If the payer abandons the flow, there’s no reversal to make — there was never any movement to undo.
Both steps are idempotent — safe to retry without creating duplicate transfers. See Retries and idempotency.
Step 1 — Initiate: confirm the destination
Initiating a transfer creates a short-lived record that validates and resolves the payee without moving funds. How the plugin finds the destination depends on what you start with:
For
KEY and QR_CODE, you never supply the destination yourself. The plugin resolves it and returns it in the response, ready to show the payer for confirmation.
Request — pick the tab for your initiation type
type values are CACC (checking), SVGS (savings), TRAN (transaction), and OTHR (other). endToEndId is optional for all types — it’s auto-generated when omitted.
Response
The response returns the initiationid (used as initiationId in step 2) and the resolved destination:
Initiations expire. The response includes an
expiresAt timestamp — process the transfer before it lapses, or initiate again. This keeps a confirmed destination from going stale between the lookup and the payment.Step 2 — Process: move the money
Processing executes the cash-out from the initiation you confirmed. It debits the source account, then routes the payment to BTG for settlement with BACEN. Settlement with the Pix network is asynchronous. The transfer comes back as
PROCESSING while BTG settles. The final result — completed or failed — arrives later through a cashout webhook. Build your flow to react to that event, not to wait on the process response. See Webhooks.
Request
Pass theid from the initiate response as initiationId, along with the amount to transfer:
amount is required. You can also pass an optional description (max 140 characters) and metadata (custom key-value attributes).
The X-Purpose header
Use the optional X-Purpose header to declare the reason for the cash-out. It defaults to TRANSFER when omitted:
Fixed-amount QR codes: the initiation can be a
QR_CODE whose EMV payload carries a fixed amount. In that case, the amount you send to process must equal that encoded amount. A mismatch is rejected before any funds move.Response
When the destination belongs to your own institution, the money never leaves for BTG — it settles internally as a P2P transfer. See Intra-PSP transfers.
Tracking a transfer
Every transfer follows a predictable lifecycle. It starts in
PENDING/PROCESSING while in flight, then reaches a terminal COMPLETED, FAILED, or CANCELLED. To check where a transfer stands, retrieve a single one by its id. You can also list transfers filtered by status, type (cash-out or cash-in), or date range.
status, type (CASHOUT/CASHIN), end_to_end, and modified_after/modified_before, plus page/limit/sort_order pagination.
How transfers land in Midaz
The plugin posts every settled movement to Midaz as a ledger transaction, with the external leg against the
@external/BRL account. Midaz records the accounting entry and correlation metadata — not the transfer’s full banking details. Counterparty branch, account number, account type, and Pix key never reach Midaz; the one exception is the payer’s identity on cash-in (sourceBank, sourceDocument, sourceName), stamped when known. The full counterparty detail lives in the plugin’s transfer record.
The metadata stamped on the Midaz transaction depends on the flow:
The Midaz transaction
code also carries the endToEndId (or the returnIdentification for refunds), so the E2E identifier is visible directly on the ledger entry.
Correlation works in both directions:
- The plugin stores the Midaz transaction and operation identifiers on its own transfer and refund records, and uses them to commit, cancel, or revert ledger entries.
- The Midaz transaction carries correlation keys in its metadata: filter by
metadata.endToEndIdfor cash-outs and cash-ins, or bymetadata.originalEndToEndId/metadata.returnIdentificationfor refunds. The transactioncodeis the common fallback — it carries the E2E ID on transfers and the return identification on refunds.
Custom
metadata you pass when processing a cash-out is stored with the plugin’s transfer record and returned by the plugin’s own API. It is not copied onto the Midaz transaction — the Midaz metadata keys above are fixed by the plugin.When a transfer gets stuck
If the settlement call to BTG times out before BTG confirms, a transfer can stay in
PROCESSING with its funds on hold. The plugin provides an unblock operation. Unblock re-checks the transfer with BTG and drives it to the correct final state. It settles the transfer if BTG confirms, or releases the hold if BTG never received it.
Unblock doesn’t apply to intra-PSP transfers — there’s no BTG transaction to re-check. For the full unblock behavior and its options, see Refund operations.
Next steps
- Intra-PSP transfers — Internal P2P settlement
- QR Codes — Generating and decoding QR codes
- Refund operations — Refunds and unblocking
- Webhooks — Cash-out and cash-in event handling
- API reference — Full request/response details, headers, and field schemas

