Webhooks y eventos
Los webhooks de cuenta envían lo que pasa en toda tu cuenta a una URL que tú eliges, en el momento: un lead nuevo, una reunión reservada, una oportunidad que cambia de etapa. Son lo que usan por debajo las integraciones con Zapier y n8n, y también puedes dirigirlos a tu propio endpoint.
Conviven con el webhook de proyecto de la página Respuestas de un correo, que sigue funcionando igual. Un webhook de proyecto cubre las interacciones de un solo correo. Un webhook de cuenta cubre todos los correos, más los eventos de abajo, y se firma del mismo modo.
Añadir un webhook
- Ve a Desarrolladores en el panel y busca la tarjeta Webhooks.
- Escribe la URL del endpoint (una URL
https://pública) y marca los Eventos que quieras. - Haz clic en Añadir webhook y copia el secreto de firma. Solo se muestra esta vez.
Cada webhook muestra cómo se creó (Panel, API, Zapier o n8n), su estado y su última entrega. Enviar prueba envía un ejemplo del evento elegido, con "test": true en su data. Eliminar quita el webhook. Una cuenta puede tener hasta 50.
Solo el propietario de la cuenta puede añadir o eliminar webhooks, y puede que antes se le pida volver a iniciar sesión.
Eventos
| Evento | Se dispara cuando |
|---|---|
interaction.received | Un destinatario interactúa con un correo: un voto, una valoración, una respuesta de quiz, un clic con seguimiento, una compra, etc. Las repeticiones deduplicadas no lo disparan. |
form.submitted | Se envía un formulario dentro de un correo (source: "email-form") o un formulario de registro (source: "signup-form"). |
contact.created | Se añade un contacto a una lista. |
contact.updated | Cambian los campos de un contacto. Guardar datos idénticos no lo dispara. |
lead.hot | La puntuación de interacción de un contacto cruza hacia arriba tu umbral de lead caliente. |
lead.new | Llega un lead nuevo por un formulario de registro o un formulario dentro de un correo. |
booking.created | Se reserva una reunión. |
booking.cancelled | Se cancela una reserva, con cancelledBy. Reprogramar no dispara ninguno de los dos eventos de reserva. |
deal.created | Se crea una oportunidad, venga de donde venga: el tablero, una regla automática, un recorrido, una propuesta o la API. |
deal.stage_changed | Una oportunidad cambia de etapa, incluidas ganada y perdida. |
purchase.completed | Un destinatario paga con un checkout dentro del correo. |
journey.completed | Un contacto llega al final de un recorrido. Si sale antes, no cuenta. |
Los eventos de contacto se disparan con importaciones, formularios de registro, la API, sincronizaciones y conectores de IA. Una sola escritura de más de 500 contactos (una importación CSV grande, por ejemplo) no dispara ninguno, para que una importación no lance miles de flujos. Las ediciones en la cuadrícula de contactos, los pasos de recorrido Actualizar campo y las respuestas guardadas tampoco los disparan.
lead.hot y lead.new se disparan sin importar los interruptores y límites de tus alertas de leads: suscribirse equivale a aceptarlos.
Payload
Cada entrega es un POST JSON con el mismo sobre:
{
"id": "evt_8c1f…",
"type": "deal.stage_changed",
"createdAt": 1790000000000,
"data": {
"deal": {
"id": "deal_abc123",
"title": "Annual plan",
"value": 1200,
"currency": "USD",
"pipelineId": "owner_default",
"stageId": "proposal-sent",
"stage": "Proposal sent",
"status": "open",
"source": "manual",
"listId": "list_abc123",
"rowId": "3f6c1b0e2d…",
"email": "[email protected]"
},
"fromStageId": "meeting-booked"
}
}
id es el mismo en cada entrega de un mismo evento y también se envía en la cabecera X-MailInApp-Idempotency-Key, así que puedes descartar sin riesgo una nueva entrega que ya procesaste. createdAt está en milisegundos epoch.
Para ver el data de cada tipo de evento, llama a GET /api/v1/events/sample o usa Enviar prueba.
Verificar la firma
Las entregas llevan las cabeceras X-MailInApp-Timestamp y X-MailInApp-Signature, calculadas exactamente igual que en un webhook de proyecto. Compruébalas sobre el cuerpo en bruto con tu secreto de firma y rechaza las marcas de tiempo de hace más de unos minutos. La documentación del webhook de proyecto incluye una función de Node.js lista para usar.
Reintentos
Tu endpoint tiene 5 segundos para responder con un 2xx. Cualquier otra cosa (tiempo agotado, estado de error, redirección) es un fallo, y la entrega se reintenta automáticamente, con intervalos crecientes durante varias horas, con el mismo cuerpo y la misma clave de idempotencia, a la URL actual del webhook. Responde rápido y haz el trabajo lento después.
- Si tu endpoint responde
410 Gone, el webhook se desactiva. Así es como se dan de baja los clientes REST Hooks. - Revocar una clave de API desactiva los webhooks creados con ella.
- Eliminar un webhook detiene sus reintentos pendientes.
Suscribirse por la API
Zapier, n8n y tu propio código pueden gestionar webhooks con una clave de API (Authorization: Bearer mia_live_…):
curl https://mailinapp.com/api/v1/webhooks \
-H "Authorization: Bearer mia_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://hooks.example.com/mailinapp", "events": ["lead.hot", "booking.created"]}'
La respuesta 201 trae el id de la suscripción y su secret, que firma cada entrega. Guárdalo: no se vuelve a devolver. GET /api/v1/webhooks lista tus suscripciones y DELETE /api/v1/webhooks/{id} elimina una. Un solo nombre de evento desconocido hace que se rechace toda la solicitud. Estas rutas admiten 30 solicitudes por minuto y clave.
El contrato completo está en la especificación OpenAPI.