Webhooks
Convenciones de webhooks entre productos para la API de Mono.
Un webhook es una notificación automática que Mono envía a tu sistema en el momento en que algo ocurre — una transferencia se aprueba, una tarjeta se carga, un recaudo se acredita. En vez de preguntarle a Mono repetidamente si algo cambió, tu servidor recibe una sola solicitud HTTPS apenas ocurre el evento.
Estas convenciones aplican a cada producto de Mono: Banking, Core y Bre-B Participant. Cada producto tiene su propio catálogo de eventos; esta página documenta la mecánica compartida que los rige a todos.
Antes de empezar
Vas a necesitar:
- Un endpoint HTTPS accesible públicamente (no
localhost, no127.0.0.1). - La capacidad de verificar una firma HMAC-SHA256 en cada solicitud entrante.
- Un handler de eventos idempotente — Mono reintenta en fallas, así que el mismo evento puede llegar más de una vez.
Envelope
Cada cuerpo de solicitud de webhook sigue el mismo envelope JSON:
{
"event": {
"data": { ... },
"type": "event_type_or_name"
},
"timestamp": "2022-12-29T15:42:08.325158Z"
}event.type— el nombre estable del evento (p. ej.bank_transfer_approved).event.data— el payload del evento; su esquema depende del tipo de evento.timestamp— timestamp ISO 8601 UTC de cuándo se generó el evento.
Firma
Cada solicitud está firmada con un webhook secret que obtienes desde el Dashboard. La firma y el timestamp viajan juntos en un header personalizado llamado Mono-Signature:
Mono-Signature: t=1672328528,v1=662255ca79c4b21914894d32da10189a1482cd0fee56b2765a8b472662ce55act— timestamp Unix. Úsalo para protegerte contra ataques de repetición rechazando solicitudes cuyo timestamp caiga fuera de tu ventana de tolerancia.v1— la firma HMAC-SHA256. Mono actualmente solo usa la versiónv1.
Verificación de firma
Paso 1: extraer timestamp y firma
Divide Mono-Signature por , para obtener:
t=1672328528
v1=662255ca79c4b21914894d32da10189a1482cd0fee56b2765a8b472662ce55acPaso 2: construir el string del payload firmado
Concatena el timestamp, un . literal, y el cuerpo crudo de la solicitud:
<timestamp>.<payload_rawbody>Paso 3: calcular la firma esperada
Usa HMAC-SHA256 con tu webhook secret como llave y el string del payload firmado como mensaje:
require 'openssl'
timestamp = 1672774221
raw_payload = '{"respose_body": "example"}'
signed_payload = "#{timestamp}.#{raw_payload}"
secret = "whsec_example"
hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, signed_payload)
# => 652fdc1742906b4b23ce2a5f4ac417b52c264fea0207920a5e76330a87239924Paso 4: comparar y validar
Compara el HMAC calculado contra el valor v1 usando una comparación de tiempo constante para prevenir ataques de temporización. Luego verifica que la diferencia entre el tiempo actual y t esté dentro de tu ventana aceptable (típicamente 5 minutos).
Política de reintentos
Mono reintenta solicitudes fallidas (cualquier respuesta que no sea 2xx) hasta diez veces con backoff exponencial. Tras el décimo intento, el evento no se reintenta más.
| Intento | Delay desde el anterior |
|---|---|
| 1 | inmediato |
| 2 | 30 segundos |
| 3 | 1.5 minutos |
| 4 | 3.5 minutos |
| 5 | 7.5 minutos |
| 6 | 15.5 minutos |
| 7 | 31.5 minutos |
| 8 | 1.06 horas |
| 9 | 2.13 horas |
| 10 | 4.26 horas |
Los diez intentos se completan en aproximadamente 8.4 horas.
Campos de dinero
Los montos monetarios siempre se representan en la unidad menor de la moneda (centavos para COP y USD):
240000= 2,400.00160= 1.60
La excepción es fx_rates, que lleva la tasa de cambio decimal directamente: "4002.24" = 4002.24.
Restricciones de URL
Tu endpoint de webhook debe:
- Empezar con
httpohttps. - No usar
localhostni127.0.0.1como host. - Ser una URL HTTP/HTTPS válida y alcanzable.
Siguientes pasos
- Webhooks de Banking — catálogo de eventos para transferencias bancarias y enlaces de recaudo.
- Webhooks de Core — catálogo de eventos para transacciones de tarjeta y transacciones de cuenta de ledger.
- Webhooks de Bre-B Participant — catálogo de eventos para transferencias salientes y recaudos Bre-B.