Cómo se da de alta
Los webhooks no se autogestionan: se dan de alta desde el panel de administración interno de Mozart, a pedido de tu organización. Pedile a tu contacto en Mozart que registre tu URL y los eventos que querés recibir — queda registrado bajo Organización → Webhooks del cliente correspondiente. La URL tiene que serhttps://; Mozart no entrega eventos a
endpoints http://.
El secret tiene el formato whsec_<43 caracteres>. Lo vas a necesitar para
verificar la firma de cada evento (ver abajo).
Eventos disponibles
Los pagos que llegan dentro de un archivo de carga de cartera (por la
plataforma o por el flujo de Carga de cartera
de la API) no generan
payment.registered: son una carga masiva de
histórico, no un pago puntual. Sólo los pagos registrados
individualmente —por POST /v1/payments, desde el panel, por un link de
cobro, o al marcar una promesa de pago como cumplida— disparan el evento.Forma del evento
Cada entrega es unPOST a tu URL con este body:
data tiene exactamente la misma forma que el recurso equivalente en la API
pública: un payment.registered trae el mismo objeto que devuelve
GET /v1/payments/:id, un promise.created el mismo que lista
GET /v1/promises, y un call.completed el mismo que GET /v1/calls
(sin el bloque analysis, que sólo trae el detalle por id). id identifica
la entrega — usalo para idempotencia (ver abajo) —, no la confundas con el
id del recurso dentro de data.
Verificar la firma
Cada entrega trae dos headers:X-Mozart-Signature tiene dos partes separadas por coma: t es un timestamp
Unix (segundos) y v1 es un HMAC-SHA256 en hexadecimal, calculado sobre el
string "<t>.<body crudo>" con tu secret (whsec_...).
1
Recuperá el body crudo
Calculá la firma sobre los bytes exactos que llegaron, antes de
parsear el JSON — cualquier framework que reformatee el body (indentación,
orden de claves) invalida la comparación.
2
Recalculá el HMAC
Con tu secret, sobre
"<t>." + body, y comparalo contra v1 en tiempo
constante (nunca con ===/==, que corta apenas encuentra la primera
diferencia y filtra información por temporización).3
Chequeá la tolerancia de reloj
Rechazá la entrega si
t está a más de ~5 minutos del momento actual —
protege contra un replay de una entrega vieja capturada por un tercero.Reintentos e idempotencia
Una entrega se considera exitosa con cualquier respuesta2xx. Cualquier
otra cosa —un error, un timeout— cuenta como fallo:
- Cada intento tiene un timeout de 10 segundos.
- Mozart reintenta hasta 5 veces en total. Después del quinto intento fallido, la entrega se da por perdida (queda en una cola de mensajes fallidos para diagnóstico interno, no se vuelve a reintentar).
- Un reintento manda el mismo
idde entrega. Usalo para no procesar dos veces el mismo evento si tu endpoint llega a recibirlo más de una vez.