Documentación
EnglishWebhooks
Recibe eventos firmados de Mico cuando un resumen está listo o cuando se crea o se completa un compromiso.
Los webhooks permiten que tu propio servidor reaccione a tus reuniones: publicar un resumen en un canal, abrir un ticket por cada compromiso o actualizar un CRM. Los envían los servidores de Mico, así que llegan aunque la app de escritorio esté cerrada.
Los webhooks forman parte del plan Flow. Configúralos en Ajustes → Desarrolladores → Webhooks.
Configurar un endpoint
- Abre Ajustes → Desarrolladores → Webhooks.
- Escribe una URL
https://de un dominio público, elige los eventos y decide si quieres incluir el contenido. - Selecciona Añadir endpoint y copia el secreto de firma. Empieza por
whsec_y solo se muestra una vez. - Selecciona Enviar un evento de prueba para comprobar que tu servidor recibe y verifica un evento
webhook.test.
Desde la misma página puedes pausar un endpoint, editarlo, rotar su secreto o eliminarlo. Cada endpoint muestra sus entregas recientes y su resultado.
Eventos
| Evento | Se dispara cuando |
|---|---|
meeting.summary_ready | El resumen de una reunión recibe contenido por primera vez, o Mico lo regenera. |
action_item.created | Aparece un compromiso nuevo en una reunión o una nota. |
action_item.completed | Un compromiso se marca como hecho. |
webhook.test | Seleccionas Enviar un evento de prueba. Se entrega siempre, sean cuales sean los eventos que elegiste. |
Mico detecta los eventos en sus servidores, a partir de lo que sincronizan tus dispositivos. Volver a sincronizar la misma nota no repite un evento. Editar un resumen o el texto de un compromiso tampoco envía ninguno.
Los eventos esperan un minuto (resúmenes) o dos minutos (compromisos) antes de enviarse, para que un compromiso que aún estás escribiendo llegue completo. Si en ese tiempo se elimina el resumen o el compromiso, o el compromiso deja de estar hecho, el evento no se envía.
Los resúmenes escritos en tu dispositivo con tu propio proveedor de IA envían meeting.summary_ready solo la primera vez. Un resumen o compromiso que se sincroniza por primera vez más de siete días después de crearse no envía meeting.summary_ready ni action_item.created.
Payload
Cada petición es un POST JSON con este envoltorio:
{
"type": "action_item.completed",
"timestamp": "2026-10-06T10:02:00.000Z",
"data": { ... }
}
timestamp es el momento en que ocurrió el evento. Por defecto, data lleva IDs, títulos y horas, nunca el texto de tus notas.
meeting.summary_ready
{
"type": "meeting.summary_ready",
"timestamp": "2026-10-06T10:00:00.000Z",
"data": {
"meeting": {
"id": "3f2b0c1e-...",
"title": "Kickoff with Acme",
"started_at": "2026-10-06T09:00:00.000Z",
"ended_at": "2026-10-06T09:45:00.000Z"
},
"summary": {
"id": "3f2b0c1e-...-ai-notes",
"kind": "summary",
"template_id": null,
"title": "Kickoff with Acme",
"updated_at": "2026-10-06T09:59:41.000Z"
}
}
}
kind es summary, o template_output cuando el resumen usó una plantilla; en ese caso, template_id la identifica.
action_item.created and action_item.completed
{
"type": "action_item.created",
"timestamp": "2026-10-06T10:00:00.000Z",
"data": {
"action_item": {
"id": "3f2b0c1e-...-ai-item-0",
"status": "todo",
"due_at": "2026-10-10T00:00:00.000Z",
"completed_at": null,
"created_at": "2026-10-06T09:59:41.000Z",
"updated_at": "2026-10-06T09:59:41.000Z"
},
"meeting": {
"id": "3f2b0c1e-...",
"title": "Kickoff with Acme",
"started_at": "2026-10-06T09:00:00.000Z",
"ended_at": "2026-10-06T09:45:00.000Z"
}
}
}
status es todo, in_progress o done. meeting es null para un compromiso que no pertenece a una reunión. completed_at puede ser null aunque el estado sea done.
Con contenido
Activa Incluir el contenido en un endpoint para añadir el texto:
data.summary.content.markdown: el resumen en Markdown. Se conservan los encabezados, las listas y las casillas; el formato en línea, como la negrita y los enlaces, no. Con un máximo de 100.000 caracteres.data.action_item.textydata.action_item.assignee: el compromiso y la persona a la que está asignado, onull.
Actívalo solo para un servidor de confianza: el contenido de tus reuniones sale de Mico.
webhook.test
{
"type": "webhook.test",
"timestamp": "2026-10-06T10:00:00.000Z",
"data": {
"endpoint_id": "6a1f...",
"message": "This is a test event from Mico."
}
}
Cabeceras
Mico sigue la especificación Standard Webhooks.
| Cabecera | Contenido |
|---|---|
webhook-id | ID único del evento, como msg_0f6b2a5e1c2d4e5f8a9b0c1d2e3f4a5b. Es el mismo en cada reintento. |
webhook-timestamp | Hora Unix en segundos en que se firmó este intento. |
webhook-signature | v1,<base64>, una lista separada por espacios. Dos firmas durante una rotación del secreto. |
content-type | application/json |
user-agent | Mico-Webhooks/1.0 (+https://www.meetmico.ai/docs/reference/webhooks/) |
Verificar las firmas
La firma es un HMAC-SHA256 de {webhook-id}.{webhook-timestamp}.{raw body}. La clave es la parte del secreto que va después de whsec_, decodificada de base64, no el secreto como texto.
Lo más sencillo es usar una biblioteca oficial de Standard Webhooks:
import { Webhook } from "standardwebhooks";
const wh = new Webhook(process.env.MICO_WEBHOOK_SECRET); // "whsec_..."
// rawBody deben ser los bytes exactos recibidos, antes de parsear el JSON.
const event = wh.verify(rawBody, {
"webhook-id": request.headers["webhook-id"],
"webhook-timestamp": request.headers["webhook-timestamp"],
"webhook-signature": request.headers["webhook-signature"],
});
Sin biblioteca, en Node.js:
import crypto from "node:crypto";
function verifyMicoWebhook(secret, headers, rawBody) {
const id = headers["webhook-id"];
const timestamp = headers["webhook-timestamp"];
const signatures = String(headers["webhook-signature"] ?? "").split(" ");
// Rechaza marcas de tiempo antiguas o futuras para frenar los replays.
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(age) || age > 5 * 60) return false;
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = crypto
.createHmac("sha256", key)
.update(`${id}.${timestamp}.${rawBody}`)
.digest();
return signatures.some((entry) => {
const [version, signature] = entry.split(",");
if (version !== "v1" || !signature) return false;
const received = Buffer.from(signature, "base64");
return (
received.length === expected.length &&
crypto.timingSafeEqual(received, expected)
);
});
}
Guarda cada webhook-id que proceses e ignora los repetidos: una entrega puede llegar más de una vez.
Respuesta y reintentos
Responde con cualquier estado 2xx en menos de 10 segundos. Haz el trabajo lento después de responder. Mico no lee el cuerpo de la respuesta y no sigue redirecciones: un 3xx cuenta como fallo.
Una entrega fallida se reintenta al cabo de 1 minuto, 5 minutos, 30 minutos, 2 horas, 5 horas, 10 horas y 10 horas: ocho intentos en unas 27 horas. Los reintentos llevan el mismo webhook-id y el mismo cuerpo, con una marca de tiempo y una firma nuevas. Un evento de prueba se intenta una sola vez.
Un endpoint que falla 15 veces seguidas y lleva más de 24 horas sin una entrega correcta se desactiva, y sus entregas pendientes se descartan. Ajustes muestra el motivo. Arregla tu servidor, envía un evento de prueba y vuelve a activar el endpoint.
Rotar el secreto
Selecciona Rotar el secreto en un endpoint para obtener uno nuevo, que se muestra una sola vez. Durante las 24 horas siguientes, Mico firma cada petición con el secreto nuevo y con el anterior, para que puedas actualizar tu servidor sin perder eventos.
Seguridad y límites
- Los endpoints deben usar
https://y un nombre de dominio público. Se rechazan las direcciones IP,localhosty nombres como*.localo*.internal. - Antes de cada entrega, Mico resuelve el dominio y no envía nada si alguna dirección es privada, de loopback, de enlace local o, en general, no está en internet pública.
- Hasta 10 endpoints por cuenta y 10 eventos de prueba por endpoint y hora.
- El historial de entregas se conserva 30 días.
- Los webhooks se detienen cuando la cuenta deja de tener el plan Flow y se reanudan cuando vuelve a tenerlo. Los eventos ocurridos entre medias no se envían.