Pay in bolívars, send USDT to a wallet
Add an onward payout to a Pago Móvil or C2P pay-in: when it completes, VEXPay converts its net VES to USDT and sends it to the wallet you gave — no further API calls.
How it works
Send onwardPayout with POST /v1/payments/pago-movil/verify, POST /v1/payments/c2p/request or POST /v1/payments/c2p. When the payment completes, VEXPay chains two things you could also do yourself: a VES → USDT conversion of the payment's net VES (see Convert VES or COP to USDT), then a USDT payout of that USDT minus the network fee to the address (see USDT & USDC).
- Collect with an instruction
Add
"onwardPayout": { "network": "BEP20", "address": "0x…" }to the pay-in request. VEXPay checks it before calling the bank: USDT and conversions must be enabled for your account, the network's payouts must be on, and the address must match the network's format. A bad instruction is answered with 400 and no money moves. - Payment completes
Exactly as without the instruction:
payment.completed, your VES balance credited, fees as usual. - Convert
VEXPay converts the payment's
netVes(amount minus VEXPay and application fees) at your usual conversion price: the market rate when the payment completes plus your spread. The rate is not shown in advance; the conversion object carries it. - Send
When the conversion completes, VEXPay sends its USDT minus the network's payout fee to the address, as a normal USDT payout (
payout.completedwithtxHash).
Statuses and the webhook
The payment (GET /v1/payments/:id and every payment.* webhook) carries onwardPayout: status, network, address, conversionId, payoutId, amountUsdt, feeUsdt, txHash, reason and updatedAt. Every status change also sends onward_payout.updated with paymentId, customerRef and the same object — subscribe to it under "Onward payout".
| status | Meaning | Your money |
|---|---|---|
| pending | The payment has not completed yet | Nothing moved |
| converting | The conversion exists and is not completed | VES debited, USDT not yet credited |
| waiting_release | Converted; the USDT is under the 24h balance hold until sendAfter | USDT in your balance, held |
| sending | The USDT payout exists and is not final | USDT reserved for the payout |
| completed | The payout completed (txHash set) | Sent to the address |
| held | Stopped before a step it could not take (reason) | Stays in your VES or USDT balance |
| failed | The payout failed (reason: payout_failed) | USDT and fee back in your USDT balance |
| canceled | Payment failed or reversed, or the conversion was canceled (reason) | VES back in (or never left) your VES balance |
completed, held, failed and canceled are final: VEXPay never continues after them. Funds left in your balance are yours to convert or pay out as usual.
Minimums and holds
| reason | When | Where the money is |
|---|---|---|
| below_conversion_minimum | The net VES is worth less than your conversion minimum | VES balance |
| below_payout_minimum | The USDT minus the network fee is below the network's payout minimum | USDT balance |
| daily_limit_exceeded | Your daily conversion cap is reached | VES balance |
| insufficient_balance | Your available balance no longer covers the step | VES or USDT balance |
| onward_payout_unavailable | USDT or conversions were turned off for your account | VES balance |
Minimums and fees are the same as for any conversion and USDT payout: see GET /v1/conversions/settings and GET /v1/crypto/networks.
Reversals
A C2P payment can be reversed while its onward payout is still pending (the instruction is canceled). Once its conversion exists, POST /v1/payments/:id/reverse answers 409 onward_payout_in_progress.
Example
curl --request POST "${API_URL}/v1/payments/pago-movil/verify" \
--header "content-type: application/json" \
--header "x-api-key: ${VEXPAY_API_KEY}" \
--data '{
"usdAmount": 20,
"reference": "40010003",
"externalRef": "topup-user-42",
"onwardPayout": { "network": "BEP20", "address": "0x2f5c0000000000000000000000000000000000aa" }
}'{
"event": "onward_payout.updated",
"data": {
"paymentId": "6f1c…",
"externalRef": "topup-user-42",
"onwardPayout": {
"status": "completed",
"network": "BEP20",
"address": "0x2f5c0000000000000000000000000000000000aa",
"conversionId": "c1a2…",
"payoutId": "9b7e…",
"amountUsdt": "18.94",
"feeUsdt": "0.75",
"txHash": "0x8e1d…",
"updatedAt": "2026-10-15T14:03:11.000Z"
}
}
}Testing
With a test key the whole chain runs on the sandbox: the conversion and the payout complete at once and nothing is sent on-chain, so you receive converting, sending and completed within seconds of the payment.