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.

1POST /api/transfers
2{
3 "amount_in_cents": 50000,
4 "currency": "GTQ",
5 "destination": "ba_abc123"
6}

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:

destinationWhere the money goesRecord created
"ba_abc123"Payout to that bank account of yourswi_
"ac_xyz789"Instant transfer to that Recurrente accounttr_
"@mystore"Transfer to the account with that handletr_
"co_maria123"Transfer to that saved contact’s phonetr_
"+50255667788"Send to that phone numbertr_
1{ "amount_in_cents": 50000, "destination": "ba_abc123" }
2{ "amount_in_cents": 10000, "currency": "GTQ", "destination": "@mystore", "note": "Service payment" }
3{ "amount_in_cents": 5000, "currency": "GTQ", "destination": "+50255667788" }

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:

1{
2 "amount_in_cents": 10000,
3 "currency": "USD",
4 "destination": { "type": "crypto_address", "address": "0x1234…", "chain": "base", "currency": "USDC" }
5}

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 accept is_instant (instant payout, subject to eligibility and a fee) and should_perform_currency_conversion (converts your balance into the destination account’s currency). If you omit currency, the bank account’s currency is used.
  • Accounts (ac_ / @handle) — the transfer is instant and free.
  • Phones and contacts — the movement stays unclaimed until 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.currency and the network in destination.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.

statusMeaning
pendingCreated, awaiting processing or review
in_reviewUnder manual or risk review
processingApproved, being prepared for sending
sentMoney is on its way through the bank rail or network
unclaimedPhone send waiting for the recipient to claim it
completedMoney arrived at its destination
failedRejected or failed; the balance is restored
cancelledCancelled before sending; the balance is restored

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.

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.

$curl -X POST https://app.recurrente.com/api/transfers \
> -H "X-SECRET-KEY: sk_live_…" \
> -H "Idempotency-Key: payroll-2026-07" \
> -H "Content-Type: application/json" \
> -d '{"amount_in_cents": 50000, "currency": "GTQ", "destination": "ba_abc123"}'

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?types[]=bank_account&types[]=crypto_address

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:

1POST /api/transfers
2{
3 "account_id": "ac_child123",
4 "amount_in_cents": 50000,
5 "destination": "ba_childbank"
6}

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.

Requirements

To move money through the API you need:

  1. An API key with money movement enabled (Settings → API Keys).
  2. A verified account (KYC completed).
  3. 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.