Skip to main content

Transfers

A transfer moves funds from your provider balance to a destination you describe in the request — a bank account, a digital wallet, a real-time-payment alias, or a card. Unlike a payout, a transfer is not tied to an earlier payment: you supply the full destination instrument details yourself.

A transfer is created as a new transfer transaction and comes back with status pending; the provider is called asynchronously and the final outcome arrives by webhook.

Transfer vs payout

Use a transfer when…Use a payout when…
You are sending funds to a destination you specify — a bank account, wallet, RTP alias, or card.You want to send funds back to the instrument of a payment you already took.
There is no original payment to reference.You can identify an original settled payment.

Sending to a card

Everything on this page describes a transfer to a destination you can describe in the request — a bank account, wallet, or RTP alias. A card destination is different: you cannot send a card number to the API, so the card is collected in the browser first and the transfer settles in a second call.

See Transfers to a card for that flow.

1. Create a transfer

amount, currency, payment_method, and merchant_reference are required. The payment_method.details object describes the destination instrument — which of its fields you supply depends on the method, country, and provider (see Payment instruments). merchant_reference doubles as the idempotency key.

Bank transfers use code: "bank"

All regional bank-transfer rails (SEPA, Faster Payments, ACH, SPEI, Zengin…) share the single method code bank. The provider you route to maps it to the concrete rail based on the currency, country, and the account fields you supply.

This POST /v1/transfers call reuses the buildSignatureHeader helper from the Signing guide (the signed string for a request is timestamp + path + body). It assumes you've exported ORCHESTR_SECRET_KEY and ORCHESTR_SIGNING_SECRET as shown in Getting started.

REQ_PATH="/v1/transfers"
BODY='{"amount":"250.00","currency":"GBP","merchant_reference":"transfer-1001","reference":"ACME payout","payment_method":{"code":"bank","details":{"holder_name":"Jane Doe","iban":"GB29NWBK60161331926819","bic_swift":"NWBKGB2L","country_code":"GB"}}}'
TS=$(date +%s)
SIG=$(printf '%s' "${TS}${REQ_PATH}${BODY}" \
| openssl dgst -sha256 -hmac "$ORCHESTR_SIGNING_SECRET" | sed 's/^.*= //')

curl -sS -X POST "https://api.sandbox.upprove.com${REQ_PATH}" \
-H "Authorization: Bearer $ORCHESTR_SECRET_KEY" \
-H "X-Signature: t=${TS}, v1=${SIG}" \
-H "Content-Type: application/json" \
--data-raw "$BODY"
Routing

Omit channel_id to let the platform route the transfer through your workflows and default routing. Supply channel_id to force a specific channel. If no channel can be routed, the request is rejected with transfer_unroutable.

2. Read the response

A 201 Created returns a TransferView. The X-Signature response header signs the body — verify it before trusting the response (see Signing). The payment_instrument echoes the resolved destination.

{
"order_id": "trf_5b4a3c2d",
"merchant_reference": "transfer-1001",
"amount": 250.00,
"currency": "GBP",
"status": "pending",
"reference": "ACME payout",
"payment_instrument": {
"id": "pi_8a7b6c5d",
"type": "bank_account",
"holder_name": "Jane Doe",
"iban": "GB29NWBK60161331926819",
"bic_swift": "NWBKGB2L",
"country_code": "GB"
},
"provider_transaction_id": null,
"additional_identifiers": [],
"created_at": "2024-06-22T10:00:00Z"
}
FieldDescription
order_idThe transfer order (trf_...) — the public transfer identifier.
merchant_referenceYour reference for this transfer.
amount / currencyThe transfer amount and currency.
statusStarts at pending; moves through processing to completed, failed, or canceled. A card transfer awaiting card collection reports requires_action instead.
next_actionOnly on the card-collection leg of a card transfer — a collect_card action carrying the client secret. Absent otherwise.
referenceStatement descriptor shown to the recipient where supported.
payment_instrumentThe resolved destination instrument.
provider_transaction_idSettlement reference; null before settlement.
additional_identifiersExtra provider-side identifiers, each { "identifier": …, "type": "checkout" | "order" }.
created_atWhen the transfer was created.

Retrieving a transfer

GET /v1/transfers/{id} (where {id} is the transfer transaction id, txn_...) returns the fuller TransactionView rather than the slim TransferView above.

A transfer order can accrue more than one transaction — one per cascade attempt. GET /v1/transfers/by-order/{orderId} (where {orderId} is the transfer order, trf_...) returns every attempt, newest first, in an unpaged list:

{
"object": "list",
"data": [
{ "id": "txn_1c2b3a4d", "type": "transfer", "status": "failed", "amount": 250.00, "currency": "GBP" }
],
"total_count": 1,
"has_more": false
}

3. Handle the outcome

The create response tells you the initial state; the final outcome arrives asynchronously via the transfer.* webhooks (transfer.paid, transfer.failed, transfer.canceled, …). Alternatively, poll GET /v1/transfers/{id} until the transaction reaches a terminal status.

Next steps

  • Transfers to a card — the two-step flow for a card destination.
  • Payment instruments — the destination fields to supply per instrument type.
  • Signing — build and verify the X-Signature header.
  • Payouts — send funds back to the instrument of an existing payment.
  • Webhooks — the transfer.* events that report the final outcome.
  • The full API Reference for the transfer endpoints.