Create an internal transfer (v.3)
This is a new Internal Transfers flow, which is recommended for all new integrations.
If you already have an existing integration with the previous Transfers API, you can continue using it. For the Transfers v.2 guide, see Create an internal transfer.
Use this guide to facilitate internal transfers between wallets, with optional currency conversion. You can transfer both fiat and crypto funds.
The transfer can be initiated according to the following scenarios:
- Between you and your customer
- Between your customers
- Between wallets with different currencies (conversion transfer)
This capability is only available as part of the Virtual Account use cases and cannot be used separately.
Same-asset transfer
For transfers where the originator and beneficiary wallets hold the same currency, omit the conversion object.
Create a transfer by sending the POST /payment/v3/transfers request:
{
"reference": "treasury-789",
"originator": {
"amount": 100.00,
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:1"
},
"beneficiary": {
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:2"
},
"metadata": {
"memberId": "987654321"
}
}
The transfer completes immediately. You receive a response with status COMPLETED:
{
"id": "d4a904e0-b040-4132-a6d3-ed7d03cdfce7",
"reference": "treasury-789",
"type": "payment:transfer",
"status": "COMPLETED",
"metadata": {
"memberId": "987654321"
},
"fees": {
"processingFee": {
"amount": 0,
"currency": "USD"
}
},
"originator": {
"amount": 100.00,
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:1",
"entity": {
"legalName": "Acme Corp",
"type": "COMPANY"
}
},
"beneficiary": {
"amount": 100.00,
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:2",
"entity": {
"legalName": "Globex Trading",
"type": "COMPANY"
}
},
"expiresAt": "2025-07-31T10:00:00Z",
"createdAt": "2025-07-30T10:00:00Z",
"updatedAt": "2025-07-30T10:00:00Z",
"trackingDetails": [],
"method": "BOOK"
}
Conversion transfer with quote
Use conversion type QUOTE when you want to present a firm rate to your customer for acceptance before the transfer settles.
Create the transfer
Send the POST /payment/v3/transfers request with the conversion object:
{
"reference": "treasury-123",
"originator": {
"amount": 10.5,
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:1"
},
"beneficiary": {
"currency": "EUR",
"walletId": "a:25072267284363:kd3mRMO:2"
},
"conversion": {
"type": "QUOTE",
"validityDuration": "PT20S"
},
"metadata": {}
}
The validityDuration field accepts PT20S (20 seconds) or PT60M (60 minutes).
The transfer is created in PENDING_QUOTE_ACCEPTANCE status with the quoted rate:
{
"id": "d4a904e0-b040-4132-a6d3-ed7d03cdfce7",
"reference": "treasury-123",
"type": "payment:transfer",
"status": "PENDING_QUOTE_ACCEPTANCE",
"metadata": {},
"fees": {
"processingFee": {
"amount": 0.1,
"currency": "USD"
}
},
"originator": {
"amount": 10.5,
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:1",
"entity": {
"legalName": "Acme Corp",
"type": "COMPANY"
}
},
"beneficiary": {
"amount": 9.52,
"currency": "EUR",
"walletId": "a:25072267284363:kd3mRMO:2",
"entity": {
"legalName": "Globex Trading",
"type": "COMPANY"
}
},
"conversion": {
"type": "QUOTE",
"spread": {
"percentage": 0.01,
"amount": 0.105,
"currency": "USD"
},
"allInRate": 0.9066,
"baseRate": 0.8976,
"validityDuration": "PT20S",
"expiresAt": "2025-07-30T10:30:20Z",
"digest": "a1b2c3d4e5f6"
},
"expiresAt": "2025-07-31T10:00:00Z",
"createdAt": "2025-07-30T10:00:00Z",
"updatedAt": "2025-07-30T10:00:00Z",
"trackingDetails": [],
"method": "BOOK"
}
Accept the quote
Before the quote expires, accept it by sending the POST /payment/v3/transfers/{transferId}/actions request with the digest value from the response:
{
"type": "ACCEPT_QUOTE",
"digest": "a1b2c3d4e5f6"
}
After acceptance, the transfer moves to PROCESSING and settles the beneficiary amount without trading the originator's funds on a venue first.
Refresh an expired quote
If the quote expires before acceptance, you can refresh it:
{
"type": "REFRESH_QUOTE"
}
This returns the transfer with a new quote, updated expiresAt, and a new digest value.
All unaccepted quote transfers expire 24 hours after creation (the transfer's expiresAt field), regardless of individual quote expiration times.
Conversion transfer with auto conversion
Use conversion type AUTO_CONVERSION when you want the transfer to execute automatically at the market rate without requiring quote acceptance.
Send the POST /payment/v3/transfers request:
{
"reference": "treasury-456",
"originator": {
"amount": 10.5,
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:1"
},
"beneficiary": {
"currency": "EUR",
"walletId": "a:25072267284363:kd3mRMO:2"
},
"conversion": {
"type": "AUTO_CONVERSION"
},
"metadata": {}
}
The transfer moves to PROCESSING immediately. The beneficiary amount is settled after the originator's amount is traded on venue:
{
"id": "d4a904e0-b040-4132-a6d3-ed7d03cdfce7",
"reference": "treasury-456",
"type": "payment:transfer",
"status": "PROCESSING",
"metadata": {},
"fees": {
"processingFee": {
"amount": 0.1,
"currency": "USD"
}
},
"originator": {
"amount": 10.5,
"currency": "USD",
"walletId": "a:25072267284363:kd3mRMO:1",
"entity": {
"legalName": "Acme Corp",
"type": "COMPANY"
}
},
"beneficiary": {
"amount": 9.52,
"currency": "EUR",
"walletId": "a:25072267284363:kd3mRMO:2",
"entity": {
"legalName": "Globex Trading",
"type": "COMPANY"
}
},
"conversion": {
"type": "AUTO_CONVERSION",
"spread": {
"percentage": 0.01,
"amount": 0.105,
"currency": "USD"
},
"allInRate": 0.9066,
"baseRate": 0.8976
},
"expiresAt": "2025-07-31T10:00:00Z",
"createdAt": "2025-07-30T10:00:00Z",
"updatedAt": "2025-07-30T10:00:00Z",
"trackingDetails": [],
"method": "BOOK"
}
Only fixed debit (amount specified on the originator side) is supported for AUTO_CONVERSION transfers.
Check transfer status
To check the status of a transfer, send the GET /payment/v3/transfers/{transferId} request.
A transfer can have following statuses:
| Status | Description |
|---|---|
PROCESSING | Transfer is being processed |
PENDING_QUOTE_ACCEPTANCE | Awaiting quote acceptance (QUOTE type only) |
COMPLETED | Transfer completed successfully |
EXPIRED | Transfer expired before quote was accepted |
FAILED | Transfer failed |
Transfer webhook
You can listen to the transfer webhook to get notified when the status of the transfer changes. See the Transfer webhook documentation for more details.