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

Recibe webhooks firmados

Verifica las firmas HMAC antes de aplicar cambios al estado de los pagos.

Registra un endpoint

curlbash
curl --request POST "${API_URL}/v1/webhooks" \
  --header "content-type: application/json" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --data '{
    "url": "https://merchant.example.com/webhooks/vexpay",
    "events": ["payment.pending", "payment.completed", "payment.failed", "merchant.verified", "merchant.rejected", "merchant.deactivated", "merchant.reactivated", "payout.completed", "payout.failed"]
  }'
Envoltoriojson
{
  "event": "payout.completed",
  "data": {
    "payoutId": "00000000-0000-4000-8000-000000000000",
    "externalRef": "po_a1",
    "reference": "16142941",
    "livemode": true
  },
  "timestamp": "2026-07-20T15:00:00.000Z"
}
merchant.rejectedjson
{
  "event": "merchant.rejected",
  "data": {
    "merchantId": "292d478b-a1fb-4d27-ab5c-8701ed14da88",
    "externalRef": "seller_47",
    "payoutMethodId": "0064456b-7a6a-4b7e-b0b5-d9b27b0dfa5c",
    "failureCode": "BE01",
    "reason": "Datos del cliente no corresponden a la cuenta",
    "action": "payout_method_deleted",
    "livemode": true
  },
  "timestamp": "2026-07-23T18:12:05.000Z"
}

Actualiza los eventos suscritos después con PATCH /v1/webhooks/:id — al enviar events se reemplaza la lista completa. También puedes cambiar url o isActive; el secreto de firma no se puede rotar vía PATCH.

curlbash
curl --request PATCH "${API_URL}/v1/webhooks/ENDPOINT_ID" \
  --header "content-type: application/json" \
  --header "x-api-key: ${VEXPAY_API_KEY}" \
  --data '{
    "events": ["payment.completed", "payment.failed", "payout.completed", "payout.failed"]
  }'

Usa POST /v1/notifications/test después de registrar un endpoint. Las entregas incluyen los encabezados X-Webhook-Event y X-Webhook-Signature.

Catálogo de eventos

EventoCuándoCampos clave en data
payment.pendingSe creó un pago y espera completarsepaymentId, method, externalRef
payment.completedEl pago se confirmó y se acreditó a tu saldopaymentId, method, vesAmount / amountCop / amountUsdt, fee
payment.failedEl cobro falló o venciópaymentId, failureCode
payment.canceledSe canceló una intención (reemplazada, vencida o por ti)paymentId, cancelReason
payment.reversedSe reversó un pago completado: reverso C2P, reembolso COP, contracargo total de tarjeta o dinero que nunca llegó al bancopaymentId, reversalType (reversal | chargeback | bank_not_received), reversalRef. Un reembolso COP lleva method "COP", status "refunded", amountCop y feeCop, sin reversalType.
payment.chargebackEl banco aplicó un contracargo a un pago con tarjeta (VPOS); se debitó tu saldo VESchargebackId, paymentId, amountVes, feeVes, reason, ledgerEntryIds
payment.chargeback_closedSe resolvió un contracargo: ganado (se devuelve el dinero) o perdidochargebackId, paymentId, outcome, ledgerEntryIds
payout.completed / payout.failedUn retiro se pagó o falló (los fallidos devuelven el dinero)payoutId, currency, failureReason
conversion.createdEmpezó una conversión VES o COP→USDT (incluida la conversión automática de un pago COP)conversionId
conversion.completed / conversion.canceledUna conversión VES o COP→USDT terminó o se cancelóconversionId
merchant.*Ciclo de vida y saldos de comercios (marketplaces)merchantId, externalRef
tenant.*Estado de tu cuenta, activación live y llaves API—
customer.* · customer.subscription.* · invoice.* · payment_method.*Suscripciones y cobros recurrentes: ver Suscripciones y facturaciónEl cliente, la suscripción, la factura o el método de pago
notification.testPOST /v1/notifications/test—

Cada movimiento de tu saldo VES — incluidos contracargos y ajustes que no son un pago o retiro normal — aparece en GET /v1/balance/transactions. Ver Concilia tu saldo.

Comportamiento de las entregas

  • Cada evento se intenta entregar una sola vez. Las entregas fallidas no se reintentan.
  • Tu endpoint tiene 10 segundos para responder.
  • No se garantiza el orden de los eventos; compara el estado del pago en lugar del orden de llegada.
  • Devuelve una respuesta 2xx solo después de que el evento sea aceptado para su procesamiento persistente.
  • Concilia los eventos perdidos o inciertos mediante los endpoints de consulta de pagos.

Verifica la firma

Prefiere el encabezado VexPay-Signature (t=<unix>,v1=<hex>). El valor v1 es HMAC-SHA256 de <t>.<rawBody> con el secreto del endpoint. Rechaza entregas cuyo t esté fuera de tu tolerancia (los SDKs oficiales usan 300 segundos por defecto). Usa VexPay-Event-Id para deduplicar.

Node (@vexpay/node)javascript
import VexPay from '@vexpay/node';

const vexpay = new VexPay(process.env.VEXPAY_API_KEY);

app.post('/webhooks/vexpay', express.raw({ type: 'application/json' }), (req, res) => {
  const event = vexpay.webhooks.constructEvent(
    req.body,
    req.headers['vexpay-signature'],
    process.env.VEXPAY_WEBHOOK_SECRET,
  );
  // cumple desde event.data — luego res.sendStatus(200)
});
Python (vexpay)python
from vexpay import Webhook

event = Webhook.construct_event(
    request.body,  # bytes crudos
    request.headers["VexPay-Signature"],
    os.environ["VEXPAY_WEBHOOK_SECRET"],
)