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: the Merchant API never accepts a card number, so the card is tokenized first - in the browser, or through the Vault API if your systems are PCI DSS compliant - and the transfer settles in a second call with the token.

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. See Payments vs transfers.

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 UPPROVE_SECRET_KEY and UPPROVE_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 "$UPPROVE_SIGNING_SECRET" | sed 's/^.*= //')

curl -sS -X POST "https://api.sandbox.upprove.com${REQ_PATH}" \
-H "Authorization: Bearer $UPPROVE_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.

Processing profiles​

If your account is split into processing profiles, pass the profile's code in processing_profile to send the transfer from that profile. It then routes over the profile's workflows, provider channels and cascade policy exactly as a payment addressed to it would, and it shows under the profile in every transaction search, export and transfer.* webhook. A channel_id must be a channel the profile routes over - one of its own once it has any enabled, otherwise one of the account's - and an account-scope transfer can never name a profile's channel; either mismatch is transfer_unroutable. Omit the field to operate at account scope.

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.
processing_profileThe processing profile the transfer was addressed to; absent at account scope.
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.