Guía para desarrolladores
Sitio de VEXPayReferencia de API
Explorar documentación

Recibe y envía USDT y USDC

Asigna a cada cliente una dirección de depósito de stablecoins, cobra en USDT o USDC en el checkout y envíalos a billeteras externas. Cada moneda se liquida en sí misma: nunca se convierte a bolívares ni a la otra moneda.

Cómo funciona USDT

  • USDT tiene su propio saldo (GET /v1/crypto/balance), separado de tu saldo en VES. 1 USDT se trata como 1 USD.
  • Los USDT que recibes quedan retenidos 24 horas antes de poder enviarlos en un payout: el saldo los reporta como held (heldUsdt) con nextReleaseAt, y available los excluye. Ver Saldos, retenciones y payouts.
  • Recibe con una dirección de depósito fija por cliente, o con el método usdt en sesiones de checkout y enlaces de pago.
  • Envía con POST /v1/crypto/payouts. Los payouts dentro de tus límites salen automáticamente; los más grandes se revisan primero.
  • Cada movimiento se notifica con webhooks firmados: payment.completed al recibir, payout.completed / payout.failed al enviar.
  • ¿Quieres USDT a partir de los bolívares que cobras? Convierte tu saldo en VES con POST /v1/conversions: ver Convertir VES a USDT.

Precios

MovimientoComisión
USDT recibido (depósitos y checkout)2,5% + 0,50 USDT, descontado del monto recibido (nunca más que el monto)
Payout de USDT a una dirección externaLa comisión de red de la red elegida + 0,25 USDT (p. ej. 1,00 USDT en BEP20, Polygon y Solana; ver GET /v1/crypto/networks)
Payout de USDT a una de tus propias direcciones de depósitoGratis: se liquida dentro de VEXPay, no se envía nada en la cadena

Ejemplo: un cliente envía 40,00 USDT → comisión 1,50 → se acreditan 38,50 USDT.

Redes

Lista las redes habilitadas, su comisión de payout y si un payout de cierto monto se puede enviar ahora. Prefiere las redes más baratas (BEP20, Polygon) cuando tu cliente pueda usarlas; TRC20 es la más cara para enviar.

curlbash
curl "${API_URL}/v1/crypto/networks?amountUsdt=50.00" \
  --header "x-api-key: ${VEXPAY_API_KEY}"
networkCadena
TRC20Tron
BEP20BNB Smart Chain
POLYGONPolygon
SOLSolana
TONTON (requiere tag / memo)
ARB1Arbitrum One

Paso 01

Direcciones de depósito

customerRef es tu id del cliente. Llamar de nuevo para el mismo cliente y red devuelve la misma dirección, así que puedes llamarlo cada vez que muestres la pantalla de depósito.

curlbash
curl -X POST "${API_URL}/v1/crypto/deposit-addresses" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --header "content-type: application/json" \
  --data '{ "customerRef": "user_123", "network": "BEP20" }'
Node SDKjavascript
const address = await vexpay.crypto.depositAddresses.create({
  customerRef: 'user_123',
  network: 'BEP20',
});
// address.address, address.tag (solo TON)
Python SDKpython
address = vexpay.crypto.deposit_addresses.create({"customerRef": "user_123", "network": "BEP20"})

Cuando llega USDT recibes payment.completed con method: "USDT", customerRef, amountUsdt, feeUsdt, network y txHashes. Acredita a tu cliente amountUsdt − feeUsdt, una sola vez por paymentId.

Paso 02

USDT en el checkout

Agrega usdt a methods al crear una sesión de checkout (o deja methods vacío para ofrecer todo lo que acepta tu cuenta). El comprador elige una red en la página alojada y paga el monto exacto; la sesión pasa a paid cuando llega el pago.

curlbash
curl -X POST "${API_URL}/v1/checkout/sessions" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --header "content-type: application/json" \
  --data '{ "amountUsd": 25.00, "methods": ["usdt", "c2p"], "reference": "order-1042" }'

El webhook payment.completed de un pago de sesión incluye checkoutSession: { id, reference, metadata }: identifica tu pedido con checkoutSession.reference (el externalRef del pago pertenece a la sesión). El plugin de WooCommerce de VEXPay ya ofrece USDT así cuando está habilitado en tu cuenta.

Paso 03

Payouts de USDT

El monto + la comisión se reservan de tu saldo USDT disponible de inmediato (los USDT que siguen en la retención de 24 h no se pueden enviar). idempotencyKey es obligatorio: repetir la misma solicitud devuelve el mismo payout (200); reutilizar la clave con otros datos responde 409 idempotency_key_reused.

curlbash
curl -X POST "${API_URL}/v1/crypto/payouts" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --header "content-type: application/json" \
  --data '{
    "network": "POLYGON",
    "address": "0x9f3c4e1b2a7d6c5e4f3a2b1c0d9e8f7a6b5c4d3e",
    "amountUsdt": "50.00",
    "customerRef": "user_123",
    "idempotencyKey": "withdrawal_8812"
  }'
Node SDKjavascript
const payout = await vexpay.crypto.payouts.create({
  network: 'POLYGON',
  address: '0x9f3c…',
  amountUsdt: '50.00',
  idempotencyKey: 'withdrawal_8812',
});
statusSignificado
pendingReservado; en revisión (sobre tus límites) o esperando capacidad en la red
processingEnviado a la red
completedEntregado: txHash está presente (internal: true si se liquidó dentro de VEXPay)
failedNo se envió: el monto + la comisión vuelven a tu saldo; ver failureReason

Errores: 422 insufficient_balance (con held, heldUsdt y nextReleaseAt cuando parte de tu saldo sigue retenido), 422 amount_below_minimum, 400 invalid_address, 400 unsupported_network.

Paso 04

USDC

USDC funciona exactamente igual que USDT: mismos endpoints, comisiones, webhooks y revisión de payouts. Envía currency: "USDC" (en el body) o ?currency=USDC (en la query); sin ese parámetro, todos los endpoints siguen trabajando en USDT, sin cambios.

  • Redes: solo POLYGON y BASE. BASE solo admite USDC; una solicitud de USDT en BASE responde 400 unsupported_network.
  • Saldo separado: USDC tiene su propio saldo (GET /v1/crypto/balance?currency=USDC). Los payouts de USDC nunca descuentan de USDT, ni los de USDT de USDC. GET /v1/crypto/balances devuelve ambos.
  • Se habilita por separado: USDC debe activarse en tu cuenta por su cuenta. Tener USDT no habilita USDC; mientras no esté activo, las solicitudes de USDC responden 403 method_not_allowed.
  • Misma comisión de cobro que USDT (2,5% + 0,50, cobrada en USDC). Los payouts de USDC cuestan 0,75 USDC en BASE y Polygon (0,50 de comisión de red + 0,25); GET /v1/crypto/networks?currency=USDC los lista.
  • Los límites de payout son compartidos: los payouts de USDT y USDC cuentan juntos, 1:1 en USD, contra los mismos límites por payout y diarios.
  • Cualquier otro valor de currency responde 400 unsupported_currency.
Dirección de depósitobash
curl -X POST "${API_URL}/v1/crypto/deposit-addresses" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --header "content-type: application/json" \
  --data '{ "customerRef": "user_123", "network": "POLYGON", "currency": "USDC" }'
Payoutbash
curl -X POST "${API_URL}/v1/crypto/payouts" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --header "content-type: application/json" \
  --data '{
    "currency": "USDC",
    "network": "BASE",
    "address": "0x9f3c4e1b2a7d6c5e4f3a2b1c0d9e8f7a6b5c4d3e",
    "amount": "50.00",
    "idempotencyKey": "withdrawal_8813"
  }'
Node SDKjavascript
const usdc = await vexpay.crypto.balance.retrieve({ currency: 'USDC' });
const all = await vexpay.crypto.balances.list();

await vexpay.crypto.payouts.create({
  currency: 'USDC',
  network: 'BASE',
  address: '0x9f3c…',
  amount: '50.00',
  idempotencyKey: 'withdrawal_8813',
});

Usa amount para los payouts de USDC. amountUsdt solo se acepta como alias en payouts de USDT; enviar ambos con valores distintos responde 400 invalid_data. Todas las respuestas cripto incluyen ahora currency, amount y fee para ambas monedas; los campos *Usdt solo se devuelven para USDT, con su significado de siempre. La currency de un payout forma parte de la verificación de idempotencia: reutilizar un idempotencyKey con otra moneda responde 409 idempotency_key_reused.

En el checkout, agrega usdc a methods (o deja methods vacío). Cuando ambas stablecoins están disponibles, el comprador elige la moneda y luego la red. Un link o sesión limitado a ["usdt"] nunca ofrece USDC.

Webhooks

EventoCuándoCampos clave
payment.completedUSDT o USDC recibido (dirección de depósito o checkout)method y currency ("USDT" / "USDC"), amount, fee, network, txHashes, customerRef, underpaid; USDT además amountUsdt, feeUsdt
payout.completedPayout entregadopayoutId, currency, amount, fee, txHash, internal, idempotencyKey; USDT además amountUsdt, feeUsdt
payout.failedPayout no enviado; reembolsadopayoutId, currency, failureReason, idempotencyKey

Pruebas

Con una clave de prueba, la página alojada de USDT muestra botones de prueba (confirmar / cancelar / incompleto) para simular cada resultado sin fondos reales. Los pagos de prueba nunca acreditan una cuenta en vivo. Los retiros de prueba se completan al instante con payout.completed (sin txHash): no se envía nada on-chain y no aplican límites ni aprobación.