Eventos
Webhooks
Los webhooks te avisan en tiempo real de lo que pasa en tu cuenta. Configura una dirección HTTPS y recibe actualizaciones automáticas.
Tipos de eventos
Pagos
payment.createdpayment.succeededpayment.failedpayment.refunded
Ligas de pago
payment_link.createdpayment_link.paidpayment_link.expired
Suscripciones
subscription.createdsubscription.updatedsubscription.canceledsubscription.pausedsubscription.resumedsubscription.trial_ending
Facturas
invoice.createdinvoice.paidinvoice.payment_failedinvoice.upcoming
Formato de los datos
{
"id": "evt_1a2b3c4d5e6f",
"object": "event",
"type": "payment.succeeded",
"api_version": "2024-01-01",
"created": 1705312200,
"data": {
"object": {
"id": "pi_abc123xyz",
"object": "payment_intent",
"amount": 500.00,
"currency": "MXN",
"status": "succeeded",
"customer_id": "8e250c25-9d84-4892-98ec-d71fc1fcd3c7",
...
}
}
}
Verificación de firma (HMAC)
Cada webhook incluye un encabezado X-Recaudo-Signature que debes verificar para asegurar que el mensaje viene de Recaudo.
<?php
// Obtener el payload y la firma
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_RECAUDO_SIGNATURE'];
$secret = 'whsec_tu_webhook_secret';
// Extraer timestamp y firma del header
// Formato: t=timestamp,v1=signature
$parts = explode(',', $signature);
$timestamp = substr($parts[0], 2);
$receivedSignature = substr($parts[1], 3);
// Calcular la firma esperada
$signedPayload = $timestamp . '.' . $payload;
$expectedSignature = hash_hmac('sha256', $signedPayload, $secret);
// Verificar
if (hash_equals($expectedSignature, $receivedSignature)) {
// Firma valida - procesar el evento
$event = json_decode($payload, true);
switch ($event['type']) {
case 'payment.succeeded':
// Manejar pago exitoso
break;
case 'subscription.canceled':
// Manejar cancelacion
break;
}
http_response_code(200);
} else {
// Firma invalida
http_response_code(400);
}
const crypto = require('crypto');
app.post('/webhooks/recaudo', express.raw({type: 'application/json'}), (req, res) => {
const payload = req.body;
const signature = req.headers['x-recaudo-signature'];
const secret = 'whsec_tu_webhook_secret';
// Extraer timestamp y firma
const parts = signature.split(',');
const timestamp = parts[0].split('=')[1];
const receivedSignature = parts[1].split('=')[1];
// Calcular firma esperada
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Verificar
if (crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(receivedSignature)
)) {
const event = JSON.parse(payload);
switch (event.type) {
case 'payment.succeeded':
// Manejar pago exitoso
break;
case 'subscription.canceled':
// Manejar cancelacion
break;
}
res.status(200).send('OK');
} else {
res.status(400).send('Invalid signature');
}
});
import hmac
import hashlib
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhooks/recaudo', methods=['POST'])
def webhook():
payload = request.data
signature = request.headers.get('X-Recaudo-Signature')
secret = 'whsec_tu_webhook_secret'
# Extraer timestamp y firma
parts = signature.split(',')
timestamp = parts[0].split('=')[1]
received_signature = parts[1].split('=')[1]
# Calcular firma esperada
signed_payload = f"{timestamp}.{payload.decode()}"
expected_signature = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
# Verificar
if hmac.compare_digest(expected_signature, received_signature):
event = request.json
if event['type'] == 'payment.succeeded':
# Manejar pago exitoso
pass
elif event['type'] == 'subscription.canceled':
# Manejar cancelacion
pass
return 'OK', 200
else:
return 'Invalid signature', 400
Buenas prácticas
- Siempre verifica la firma HMAC antes de procesar el evento
- Responde con 200 rápido y procesa de forma asíncrona
- Implementa idempotencia usando el ID del evento
- Usa HTTPS con un certificado válido
- Los webhooks se reintentan automáticamente si fallan (hasta 3 veces)
API de Webhook Endpoints
Administra tus webhook endpoints programáticamente.
/v1/webhook-endpoints
Crear un nuevo webhook endpoint.
{
"url": "https://tu-servidor.com/webhooks/recaudo",
"events": ["payment.succeeded", "invoice.paid", "customer.created"],
"description": "Webhook principal de producción",
"is_active": true
}
/v1/webhook-endpoints
Listar todos los webhook endpoints configurados.
/v1/webhook-endpoints/{'{id}'}
Ver detalle del endpoint incluyendo el secret para verificar firmas.
{
"id": "we_abc123",
"url": "https://tu-servidor.com/webhooks/recaudo",
"events": ["payment.succeeded", "invoice.paid"],
"secret": "whsec_tu_webhook_secret",
"is_active": true,
"description": "Webhook principal",
"created_at": "2026-04-01T00:00:00Z"
}
/v1/webhook-endpoints/{'{id}'}
Actualizar URL, eventos o estado del endpoint.
{
"url": "https://nueva-url.com/webhooks",
"events": ["payment.succeeded", "payment.failed"],
"is_active": false
}
/v1/webhook-endpoints/{'{id}'}
Eliminar un webhook endpoint.
/v1/webhook-endpoints/{'{id}'}/test
Enviar un evento de prueba al endpoint para verificar la conectividad.
/v1/webhook-endpoints/{'{id}'}/rotate-secret
Generar un nuevo secret para el endpoint. El secret anterior dejará de ser válido inmediatamente.
/v1/webhook-endpoints/{'{id}'}/deliveries
Ver el historial de entregas del endpoint con status y response codes.
/v1/webhook-endpoints/{'{id}'}/deliveries/{'{delivery_id}'}/resend
Reenviar una entrega fallida.