Receta: acepta pagos en una tienda en línea
Vende a compradores venezolanos con un solo checkout alojado: bolívares, stablecoins y pesos, confirmados por webhook y retirados a tu banco.
Lo que vas a construir
Una tienda donde cada pedido abre un checkout alojado, el pedido se marca como pagado a partir de un webhook verificado y el dinero se retira a tu propia cuenta bancaria. Sin pantallas de pago que construir ni certificar.
- El comprador pulsa Pagar
Tu servidor crea una sesión de checkout para el pedido y redirige al comprador.
- El comprador paga en VEXPay
El comprador elige Pago Móvil, C2P, tarjeta, USDT/USDC o pesos y completa el pago allí.
- Entregas el pedido
payment.completed llega a tu webhook; marcas el pedido como pagado.
- Recibes tu dinero
Después de la retención de 24 h, retiras tus bolívares a tu cuenta bancaria.
Paso 01
Crea una sesión por pedido
app.post('/checkout/:orderId', async (req, res) => {
const order = await orders.get(req.params.orderId);
const session = await vexpay.checkout.sessions.create(
{
amountUsd: order.totalUsd,
description: `Pedido #${order.number}`,
reference: order.id,
metadata: { orderNumber: String(order.number) },
successUrl: `https://shop.example/orders/${order.id}/thanks`,
cancelUrl: 'https://shop.example/cart',
},
{ idempotencyKey: `checkout-${order.id}` },
);
await orders.update(order.id, { checkoutSessionId: session.id });
res.redirect(303, session.url);
});- Fija el precio en USD. Los métodos en bolívares convierten a tu tasa del bolívar; los pesos, a la tasa USDT/COP de VEX Pay.
- Omite
methodspara ofrecer todo lo que acepta tu cuenta, o envía por ejemplo["pago_movil", "usdt"]. - La clave de idempotencia hace que un doble clic abra la misma sesión, no dos.
Paso 02
Marca el pedido como pagado desde el webhook
app.post('/webhooks/vexpay', express.raw({ type: 'application/json' }), async (req, res) => {
const event = vexpay.webhooks.constructEvent(req.body, req.headers['vexpay-signature'], process.env.VEXPAY_WEBHOOK_SECRET);
if (await seen(req.headers['vexpay-event-id'])) return res.sendStatus(200);
const ref = event.data.checkoutSession?.reference;
if (event.event === 'payment.completed' && ref) await orders.markPaid(ref, event.data.paymentId);
if (event.event === 'payment.reversed' && ref) await orders.flagReversed(ref);
res.sendStatus(200);
});Paso 03
Detecta lo que se te haya escapado
Los webhooks se entregan una vez. Cada pocos minutos, consulta las sesiones que siguen esperando en tu lado y resuélvelas según su estado real.
for (const order of await orders.awaitingPayment({ olderThanMinutes: 5 })) {
const s = await vexpay.checkout.sessions.retrieve(order.checkoutSessionId);
if (s.status === 'paid') await orders.markPaid(order.id, s.paymentId);
if (s.status === 'expired' || s.status === 'canceled') await orders.release(order.id);
}Paso 04
Retira a tu banco
- Verifica tu cuenta de payouts una vez
Guarda tu banco, cédula/RIF y teléfono con PUT /v1/tenant/payout-account y luego confirma los dos microdepósitos (Portal → Payouts hace ambas cosas).
- Espera la retención
Cada venta pasa a disponible 24 horas después de completarse. GET /v1/balance muestra availableVes y nextReleaseAt.
- Retira
POST /v1/payouts/instant con el monto, o pulsa Withdraw en el portal. El porcentaje en bolívares aplica sobre el monto retirado.
Las ventas en cripto quedan en tu saldo USDT hasta que las envíes con POST /v1/crypto/payouts. Las ventas en pesos quedan en tu saldo COP.