Documentation Index
Fetch the complete documentation index at: https://docs.ledger.so/llms.txt
Use this file to discover all available pages before exploring further.
Create a transfer
Every transfer requires a walletId — the wallet you’re sending funds from. This can be a crypto wallet or a virtual account’s wallet.
From a crypto wallet
curl -X POST https://api.ledger.so/v1/transfers \
-H "Authorization: Bearer $LEDGER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: transfer-1" \
-d '{
"customerId": "cus_...",
"walletId": "wal_...",
"amount": "10.00",
"destinationCurrency": "usdc",
"destinationPaymentRail": "solana",
"destinationAddress": "7nwiVgP8..."
}'
Response:
{
"ok": true,
"data": {
"id": "txn_...",
"customerId": "cus_...",
"type": "transfer",
"status": "in_review",
"amount": "10.00",
"fee": "0.03",
"netAmount": "9.97",
"sourceCurrency": "usdc",
"destinationCurrency": "usdc",
"destinationAddress": "7nwiVgP8...",
"finalAmount": null,
"destinationTxHash": null,
"gasFee": null,
"exchangeFee": null,
"createdAt": 1710000000000,
"updatedAt": 1710000000000
}
}
From a virtual account wallet
When you create a virtual account, the response includes a walletId. Fiat deposited into the virtual account converts to stablecoins in that wallet. Use that walletId to transfer funds out.
curl -X POST https://api.ledger.so/v1/transfers \
-H "Authorization: Bearer $LEDGER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: transfer-2" \
-d '{
"customerId": "cus_...",
"walletId": "wal_...",
"amount": "5.00",
"destinationCurrency": "gbp",
"destinationPaymentRail": "faster_payments",
"destinationAddress": "pa_..."
}'
Response:
{
"ok": true,
"data": {
"id": "txn_...",
"customerId": "cus_...",
"type": "transfer",
"status": "funds_received",
"amount": "5.00",
"fee": "0.15",
"netAmount": "4.85",
"sourceCurrency": "usdc",
"destinationCurrency": "gbp",
"payoutAccountId": "pa_...",
"finalAmount": null,
"exchangeFee": null,
"createdAt": 1710000000000,
"updatedAt": 1710000000000
}
}
Virtual account wallets support both crypto and fiat destinations.
Request fields
| Field | Type | Required | Description |
|---|
customerId | string | Yes | Ledger customer ID (cus_...) |
walletId | string | Yes | Wallet to transfer from (wal_...) |
amount | string or number | Yes | Amount to send |
destinationCurrency | string | Yes | Currency to deliver (e.g. usdc, gbp, eur, usd) |
destinationPaymentRail | string | Yes | Delivery rail (e.g. solana, ach, faster_payments, sepa) |
destinationAddress | string | Yes | Onchain address or payout account ID (pa_...) |
reference | string | No | Payment reference included with the fiat transfer (see limits below) |
clientReferenceId | string | No | Your own reference ID (not sent to the recipient) |
Reference limits by rail
The reference field is sent to the recipient’s bank. Character limits vary by rail:
| Rail | Max Length | Allowed Characters |
|---|
ach | 10 | A-Z, a-z, 0-9, spaces |
wire | 140 | — |
sepa | 140 | — |
faster_payments | — | — |
spei | — | — |
pix | — | — |
Response fields
Every transfer response includes:
| Field | Description |
|---|
amount | Original amount requested |
fee | Ledger fee deducted |
netAmount | Amount sent to destination after fee |
Additional fields vary by transfer type:
| Field | Crypto | Fiat | Description |
|---|
destinationAddress | Yes | No | Onchain recipient address |
payoutAccountId | No | Yes | Payout account receiving funds |
destinationTxHash | Yes | No | Onchain settlement transaction hash |
gasFee | Yes | No | Network gas fee |
finalAmount | Yes | Yes | Final amount delivered after fees/conversion |
exchangeFee | Yes | Yes | Exchange or conversion fee |
Fees
Ledger charges a flat fee on all transfers, deducted from the source amount before sending:
| Transfer type | Fee |
|---|
| FX transfers (e.g. USDC → GBP, USDC → EUR) | 3% |
| Stablecoin / same-currency (e.g. USDC → USD, USDC → USDC) | 0.3% |
Onchain vs fiat transfers
| Destination Rail | Type | KYC Required |
|---|
solana, ethereum, polygon, arbitrum, base, optimism, tron | Onchain transfer | No |
ach, wire, sepa, faster_payments, spei, pix | Fiat transfer | Yes |
For fiat transfers, the customer must have completed KYC verification and have a payout account created first.
Tracking transfers
After creating a transfer, track its progress via:
GET /v1/transactions/{id} to poll the status
- Subscribe to
transaction.updated webhooks for real-time updates
For crypto transfers, the destinationTxHash field populates once settled onchain.