Move money
All money leaving your balance moves through a single endpoint: POST /api/transfers. You say where the money goes with the destination object, and Recurrente creates the right movement — a bank payout, a transfer to another Recurrente account, a send to a phone number, or an on-chain stablecoin send.
Destinations
In most cases destination is simply the destination’s identifier as a string — paste whichever one you hold, and its format tells us where the money goes:
The only destination that needs the object form is stablecoin, because a raw address alone doesn’t say which token or network to send on:
The object form also exists for the other types if you prefer being explicit: { "type": "bank_account", "id": "ba_..." }, { "type": "account", "id": "ac_... | @handle" }, { "type": "phone_number", "number": "..." }.
Per-destination notes:
- Payouts (
ba_) — also acceptis_instant(instant payout, subject to eligibility and a fee) andshould_perform_currency_conversion(converts your balance into the destination account’s currency). If you omitcurrency, the bank account’s currency is used. - Accounts (
ac_/@handle) — the transfer is instant and free. - Phones and contacts — the movement stays
unclaimeduntil the recipient signs up and completes KYC. You can cancel it while unclaimed. - Stablecoin — requires completing stablecoin verification in the app. Set the stablecoin in
destination.currencyand the network indestination.chain.
States
Every movement has a canonical status — the same vocabulary regardless of destination — plus a status_detail with the underlying record’s raw state.
Transfers between Recurrente accounts complete immediately. Bank payouts and stablecoin sends are asynchronous: the POST response carries the initial state, and you can follow progress with GET /api/transfers/{id} or webhooks.
Bank payouts: when to finish your flow
For a bank payout, treat sent as terminal success. Some historical payouts or rails with an additional confirmation may expose completed, but your flow must not block waiting for it after receiving sent.
Idempotency
Send an Idempotency-Key header with every POST. Retrying with the same key and body returns the original response without creating a second movement.
Listing and filtering
GET /api/transfers returns all your movements — payouts, p2p, and stablecoin — newest first. Filter by destination type with types[]:
GET /api/transfers/{id} and POST /api/transfers/{id}/cancel accept any movement ID (tr_, wi_, sw_).
Connected accounts
If you run a platform with connected accounts, pass account_id to move money for a verified child account. Child accounts support bank_account destinations, plus transfers within their own platform family — to the parent account (commission sweeps) or to sibling accounts (marketplace settlements). Out-of-family accounts, phone sends, and crypto are not available to children:
Webhooks
Every movement type emits webhooks as it progresses: transfer.sent/transfer.received (p2p), withdrawal.create/withdrawal.update (payouts), and swap.create/swap.update (stablecoin). Payout and stablecoin events include a transfer key carrying the same unified shape the API returns, alongside their historical key (withdrawal/swap). If you integrate against the unified endpoint, always read payload.transfer. For a payout, use the payload’s status and finish your flow on sent; do not wait for a later completed event.
Requirements
To move money through the API you need:
- An API key with money movement enabled (Settings → API Keys).
- A verified account (KYC completed).
- For stablecoin: completed stablecoin verification in the app.
What about the withdrawals endpoints?
/api/withdrawals and the nested connected-account withdrawals keep working indefinitely for existing integrations, but they are marked deprecated: new integrations should always use /api/transfers.

