Skip to content

Webhooks — Notificaciones de eventos ​

Wepago notifica a tu servidor cuando ocurre un evento importante (cobro aprobado, rechazado, etc.) mediante un HTTP POST a la URL que configuraste en tu cuenta.

Configuración ​

En comercios.wepago.com → Configuración → API registra:

CampoDescripción
Webhook URLEndpoint HTTPS de tu servidor que recibirá los eventos
Webhook SecretClave aleatoria (mín. 32 chars) para verificar la firma

HTTPS obligatorio

Wepago solo envía webhooks a URLs con https://. Endpoints HTTP son rechazados.

Formato del payload ​

json
{
  "event": "subscription.charge.approved",
  "data": {
    "subscriptionTransactionId": "01JR9H0BKMCAZ6PY1GR65B91J6",
    "subscriptionPlanId": "01JR9H0BKMCAZ6PY1GR65B91J7",
    "externalReference": "tu-referencia-interna",
    "transactionId": "1200969-1775447756-67089",
    "amount": 49900,
    "status": "APPROVED",
    "chargeDate": 1712534400000
  },
  "timestamp": 1712534401234
}

Eventos disponibles ​

EventoCuándo ocurre
subscription.charge.approvedCobro procesado y aprobado por el banco
subscription.charge.declinedCobro rechazado (fondos insuficientes, tarjeta bloqueada, etc.)
subscription.charge.errorError técnico durante el cobro
subscription.charge.voidedCobro anulado

Próximamente

subscription.activated y subscription.cancelled están en roadmap.

Verificar la firma ​

Cada webhook incluye el header X-Webhook-Signature con una firma HMAC-SHA256 del cuerpo del request. Siempre verifica esta firma antes de procesar el evento.

Node.js ​

javascript
const crypto = require('crypto')

function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)           // rawBody = string sin parsear
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  )
}

// Express
app.post('/webhooks/wepago', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature']
  const isValid = verifyWebhookSignature(req.body, signature, process.env.WEPAGO_WEBHOOK_SECRET)

  if (!isValid) {
    return res.status(401).send('Invalid signature')
  }

  const event = JSON.parse(req.body)
  
  switch (event.event) {
    case 'subscription.charge.approved':
      // Activar servicio, enviar confirmación al usuario, etc.
      await activateSubscription(event.data.externalReference)
      break
    case 'subscription.charge.declined':
      // Notificar al usuario, reintentar cobro, etc.
      await handleDeclinedPayment(event.data.externalReference)
      break
  }

  res.status(200).json({ received: true })
})

Python ​

python
import hmac, hashlib

def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode('utf-8'),
        raw_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

PHP ​

php
function verifySignature(string $rawBody, string $signature, string $secret): bool {
    $expected = hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $signature);
}

No uses el body parseado

La firma se calcula sobre el body como string, antes de parsear JSON. Si usas el objeto JSON ya parseado, obtendrás una firma diferente.

Responder correctamente ​

Tu endpoint debe responder con HTTP 200 en menos de 10 segundos. Wepago no reintenta si el endpoint falla o tarda más.

javascript
// ✅ Responde rápido, procesa en background si es necesario
app.post('/webhooks/wepago', async (req, res) => {
  res.status(200).json({ received: true })  // Responde PRIMERO
  await processEvent(req.body)              // Luego procesa
})

Polling como alternativa ​

Si tu servidor no puede recibir webhooks (firewalls, desarrollo local), puedes consultar el estado de un plan directamente:

bash
GET https://merchant.api.wepago.com/merchants/plans/{subscriptionPlanId}/status
Authorization: Bearer {api_key}:{api_secret}

Ver Referencia API → Polling de estado.

Probar webhooks en desarrollo ​

Usa webhook.site o ngrok para exponer tu servidor local:

bash
# ngrok
ngrok http 3000
# → https://abc123.ngrok.io

# Registra https://abc123.ngrok.io/webhooks/wepago como tu Webhook URL

URL pública con token en la URL

En el pasado, algunas integraciones usaban una URL con token en el path (ej: /webhook/{token}) como "autenticación". No hagas esto: el token queda en logs de servidores y proxies. Usa siempre la verificación HMAC con el header X-Webhook-Signature.