Webhook genérico: eventos, payload y firma
Recibe en tu servidor un POST en JSON por cada evento elegido, firmado con un secreto que solo tú y VSL Max conocen.
El webhook genérico envía a tu servidor un POST en JSON cada vez que ocurre uno de los eventos que elegiste. Es el camino para conectar VSL Max con un ERP, un área de miembros o cualquier sistema propio.
Cómo registrar un endpoint
- Abre Configuración › Integraciones y, en la tarjeta Webhook genérico, haz clic en Conectar.
- En Agregar endpoint, indica la URL del endpoint. Tiene que ser
https, sin usuario ni contraseña en la URL, en el puerto estándar, 443 u 8443, y apuntar a una dirección pública. Las direcciones locales o de red privada se rechazan. - Elige los eventos y haz clic en Agregar endpoint.
- Copia el secreto de firma que aparece en ese momento. Empieza con
whsec_y no vuelve a aparecer: después la pantalla muestra solo los últimos caracteres. Si lo pierdes, genera otro.
Solo los administradores crean y modifican endpoints. La cuenta acepta hasta 10 endpoints.
Eventos disponibles
sale.approved: venta aprobada.sale.refunded: reembolso.sale.chargeback: contracargo.sale.canceled: venta cancelada.video.ready: un video terminó de procesarse y está listo.balance.low: se disparó el aviso de saldo de plays bajo (el mismo disparador del correo).organization.suspended: la cuenta fue suspendida.
Si no eliges nada, el endpoint recibe los cuatro eventos de venta. El botón Probar envía un test.ping.
Formato de la solicitud
Cada entrega lleva estos encabezados:
Content-Type: application/jsonyUser-Agent: VSLMax-Webhooks/1.0.X-VSLMax-Event: el tipo de evento, el mismo del campotypedel cuerpo.X-VSLMax-Delivery: el id de la entrega, igual en todos los intentos.X-VSLMax-Signature: con el formatot=<hora unix>,v1=<firma>.
Ejemplo de cuerpo de una venta aprobada:
{
"id": "evt_3f2a9c1e-8b7d-4e21-9a55-0c1d2e3f4a5b",
"type": "sale.approved",
"createdAt": "2026-09-23T15:04:05.000Z",
"data": {
"sale": {
"id": "3f2a9c1e-8b7d-4e21-9a55-0c1d2e3f4a5b",
"externalId": "HP123456",
"status": "approved",
"amount": 197,
"amountCents": 19700,
"currency": "USD",
"occurredAt": "2026-09-23T15:03:58.000Z"
},
"conversion": { "id": "…", "name": "Hotmart principal", "platform": "hotmart" },
"video": { "id": "…", "title": "VSL v3" },
"attribution": "key",
"visitorId": "…"
}
}
En reembolso y contracargo, amount y amountCents vienen negativos. video es null cuando la venta no se atribuyó a ningún video, y attribution indica cómo se asoció al video (none cuando no se asoció).
En los demás eventos, data trae:
video.ready:videoconid,titleydurationSeconds.balance.low:balancecon el aviso, los plays incluidos, usados, restantes y el inicio y fin del ciclo.organization.suspended:organizationconid,statusy el motivo.test.ping: un mensaje de prueba.
Cómo verificar la firma
Verifica la firma antes de confiar en el cuerpo:
- Separa
tyv1del encabezadoX-VSLMax-Signature. - Calcula el HMAC-SHA256, con tu secreto, del texto formado por
t, un punto y el cuerpo sin procesar de la solicitud (antes de convertir el JSON). - Compara el resultado en hexadecimal con
v1, en tiempo constante. - Rechaza si
testá a más de 5 minutos de tu reloj. Así evitas el reenvío de una solicitud capturada. - Usa el
iddel evento para ignorar repeticiones: el reintento envía el mismo id.
Ejemplo en Node.js:
import crypto from 'node:crypto'
function firmaValida(rawBody, header, secreto) {
const partes = Object.fromEntries(header.split(',').map((p) => p.split('=')))
const t = Number(partes.t)
if (Math.abs(Date.now() / 1000 - t) > 300) return false
const esperado = crypto.createHmac('sha256', secreto).update(`${t}.${rawBody}`).digest('hex')
const a = Buffer.from(esperado)
const b = Buffer.from(partes.v1 ?? '')
return a.length === b.length && crypto.timingSafeEqual(a, b)
}
Respuestas y reintentos
Responde con cualquier estado 2xx en hasta 10 segundos. Cualquier otra respuesta, o la falta de respuesta, cuenta como fallo. Las redirecciones no se siguen.
Después de un fallo, volvemos a intentar en 1 minuto, 5 minutos y luego cada 15 minutos, hasta 6 intentos en total. Si todos fallan, la entrega queda como fallida en el historial del endpoint y la tarjeta muestra cuántos fallos seguidos hubo.
Pausar, probar y cambiar el secreto
- Probar envía un
test.pingen el momento y muestra si se entregó, el estado HTTP y el tiempo de respuesta. - Últimas entregas lista las entregas recientes del endpoint, con estado y número de intentos.
- Pausar suspende los envíos sin borrar el endpoint. Reanudar vuelve a enviar los eventos nuevos.
- Generar nuevo secreto cambia el secreto en el acto: las próximas entregas ya salen firmadas con el nuevo. Actualiza tu servidor enseguida.
- Eliminar endpoint pide tu contraseña y detiene las entregas de inmediato. No se puede deshacer.