POST firmado a la URL que registres, con el detalle del pago.
Estos webhooks son salientes (1to1 → tu servidor). No los llamas tú: los
recibes. Cada entrega va firmada (estándar Standard Webhooks)
para que verifiques que vino de nosotros y no fue alterada.
Configurar un endpoint
Desde el dashboard, en Configuración → API y Conexiones, agrega la URL de tu sistema y elige los eventos que quieres recibir. Al crearlo obtienes un signing secret (whsec_…) que se muestra una sola vez — guárdalo como un
secreto: es la llave con la que verificas cada webhook. Puedes registrar hasta
10 endpoints por negocio.
Catálogo de eventos
payment.failed cubre solo los pagos manuales marcados como fallidos por tu
equipo. Los fallos de pagos online (tarjeta declinada, sesión expirada) no
emiten webhook.El payload
CadaPOST lleva un cuerpo JSON con esta forma. El ejemplo es un pago manual
acreditado:
event_at es el momento en que ocurrió el evento del pago (para payment.failed
es la hora de la falla). Es distinto del header webhook-timestamp, que es el
instante de envío usado para la firma anti-replay.provider: "manual"):
bank_account (la etiqueta de la cuenta a la que entró el dinero, p. ej.
"BANORTE 0876"), bank_datetime (fecha/hora en banca, opcional) y files
(comprobantes subidos). En pagos online quedan null / []. Para tarjeta y
SPEI online usa transaction_id y receipt_url.
Headers de cada entrega
string
Id único de la entrega. Estable entre reintentos de un mismo evento —
úsalo para deduplicar (ver Entrega).
integer
Instante de envío (segundos Unix). Se recomputa en cada reintento y entra en la
firma. Rechaza los que estén fuera de una ventana razonable (±5 min) para
protegerte de replays.
string
Una o más firmas
v1,<base64> separadas por espacio (habrá dos durante una
rotación de secret). La entrega es válida si alguna coincide.string
El tipo de evento (
payment.credited, payment.failed, …). Coincide con
type del cuerpo.string
Siempre
1to1-Webhooks/1.0.Verificar la firma
La firma es un HMAC-SHA256 del contenido{webhook-id}.{webhook-timestamp}.{body},
donde body es el cuerpo crudo exacto que recibiste (no lo re-serialices).
La clave es tu whsec_… con el prefijo removido y el resto decodificado de base64.
La forma más simple es la librería oficial de Standard Webhooks, que maneja la
rotación y la comparación en tiempo constante por ti:
Entrega y reintentos
1
Responde 2xx rápido
Contesta con cualquier
2xx en cuanto recibas el webhook. Si tardas más de
10 segundos o respondes otro código, lo tratamos como fallo y
reintentamos.2
Deduplica por webhook-id
La entrega es at-least-once: un mismo evento puede llegar más de una vez
(un reintento tras un timeout, por ejemplo). El
webhook-id es estable entre
reintentos — guárdalo y descarta los repetidos.3
No asumas orden
Los eventos no llegan garantizadamente en orden. Usa
data.payment.uuidstatuscomo la verdad, no el orden de llegada: unpayment.registeredque llegue tarde no debe pisar unpayment.creditedque ya procesaste.
4
Reintentos ~3 días
Un endpoint caído recibe reintentos con espaciado creciente durante ~3 días.
Si sigue fallando, la suscripción se deshabilita automáticamente (tras 5
fallos consecutivos agotados) — la reactivas desde el dashboard.
Rotar el secret
Desde el dashboard puedes rotar el signing secret cuando quieras. Durante una gracia de 24 horas, cada webhook se firma con el secret nuevo y el anterior a la vez (dos firmas en el header). Así actualizas tu sistema sin perder ni rechazar eventos: valida contra cualquiera de las dos; cuando vence la gracia de 24 h, el secret anterior deja de firmarse automáticamente.Comprobantes
En un pago manual,files[] lista los comprobantes subidos con referencias
estables — uuid, name y mime_type — pero sin URL de descarga: el
payload es un snapshot que se reintenta durante días y una URL firmada expiraría
en el camino. La descarga del archivo se hace con tu API key por un endpoint
autenticado (se documentará aquí cuando esté disponible); mientras tanto, el
uuid te sirve para correlacionar el comprobante en el dashboard.
Próximos pasos
Autenticación
Cómo se autentica tu integración con la API key.
Errores
El contrato de errores de la API pública.