Formato común
Todos los eventos comparten el mismo envoltorio:
{
"id": "evt_01HZ...",
"type": "lead.captured",
"created": 1744550460,
"data": { /* especifico del tipo */ },
"workspace_id": "ws_01HZ...",
"api_version": "v1"
}id— identificador único del evento. Úsalo para deduplicar.type— nombre del evento (ver tabla).created— Unix timestamp en segundos.data— payload específico. El tipo exacto depende detype.workspace_id— workspace que originó el evento.api_version— versión del contrato (v1durante toda la beta).
Eventos disponibles
| Tipo | Cuándo se dispara | data incluye |
|---|---|---|
agent.created | Se crea un asistente (API o panel). | agent |
agent.updated | Se edita un asistente. | agent, changes |
agent.deleted | Se borra un asistente (soft delete). | agent_id |
conversation.started | Un visitante abre el widget y envía primer mensaje. | conversation |
conversation.ended | La conversación se cierra (timeout o usuario sale). | conversation |
lead.captured | Un visitante deja sus datos en el widget. | lead, conversation_id |
knowledge.source.indexed | Una fuente de conocimiento termina de procesarse. | source |
knowledge.source.failed | Falla la indexación de una fuente. | source, error |
qa.regenerated | Termina POST /v1/agents/{id}/qa/regenerate (REQ-092.4). | agent_id, qa_count |
course.lesson.source.indexed | Una fuente de lección (training) termina de procesarse. | lesson, source |
course.lesson.source.failed | Falla la indexación de una fuente de lección. | lesson, source, error |
ticket.created | Se crea un ticket (widget, AI escalation o API). | ticket, first_message |
ticket.message.created | Se añade un mensaje al hilo de un ticket. | ticket_public_id, message |
ticket.status.changed | Cambia el estado de un ticket. | ticket_public_id, from, to, actor, changed_at |
ticket.resolved | Un ticket se marca como resuelto. | ticket |
webhook.test | Se dispara POST /v1/webhooks/{id}/test. | { "message": "test" } |
Ejemplos
lead.captured
{
"id": "evt_01HZ...",
"type": "lead.captured",
"created": 1744550460,
"data": {
"lead": {
"id": "ldx_01HZ...",
"email": "ana@example.com",
"name": "Ana Torres",
"phone": "+34 600 000 000",
"agent_id": "agt_01HZ...",
"metadata": { "source": "widget", "page": "/precios" }
},
"conversation_id": "cnv_01HZ..."
},
"workspace_id": "ws_01HZ...",
"api_version": "v1"
}agent.created
{
"id": "evt_01HZ...",
"type": "agent.created",
"created": 1744550460,
"data": {
"agent": {
"id": "agt_01HZ...",
"type": "support",
"name": "Soporte Demo",
"slug": "soporte-demo"
}
},
"workspace_id": "ws_01HZ...",
"api_version": "v1"
}ticket.created
{
"id": "evt_01HZ...",
"type": "ticket.created",
"created": 1744550460,
"data": {
"ticket": {
"id": "3a3dbf20-f739-4354-9503-9671877de302",
"public_id": "tck_b7d2a1c4f8e9",
"agent_id": "assistant-ventas-demo",
"status": "open",
"priority": "normal",
"origin": "widget_button",
"visitor_name": "Ana Torres",
"visitor_email": "ana@example.com",
"subject": "Consulta sobre precios",
"created_at": "2026-04-20T09:59:52.062493+00:00"
},
"first_message": {
"id": "...",
"ticket_public_id": "tck_b7d2a1c4f8e9",
"author_type": "visitor",
"body": "Hola, quisiera saber si el plan Pro...",
"created_at": "2026-04-20T09:59:52.062493+00:00"
}
},
"workspace_id": "ws_01HZ...",
"api_version": "v1"
}Cuando el ticket se crea sin un primer mensaje (p. ej. vía API minimalista), first_message viene como null.
ticket.status.changed
{
"id": "evt_01HZ...",
"type": "ticket.status.changed",
"created": 1744550800,
"data": {
"ticket_public_id": "tck_b7d2a1c4f8e9",
"from": "open",
"to": "pending_user",
"actor": {
"type": "member",
"id": "miembro-uid-firebase"
},
"changed_at": "2026-04-20T10:05:00.000Z"
},
"workspace_id": "ws_01HZ...",
"api_version": "v1"
}actor.type puede ser member (acción manual del dashboard o API), api (integración externa con API key) o system (transición automática, p. ej. cuando un miembro responde y el estado pasa a pending_user implícitamente).
Buenas prácticas
- Deduplica con
id: Lectico puede reenviar el mismo evento si no recibe2xxa tiempo. Guarda losidprocesados para ignorarlos la segunda vez. - Responde rápido: si necesitas trabajo pesado, encola y responde
200primero. Si tu endpoint tarda más de 10s, consideramos la entrega como fallida. - Ignora eventos desconocidos: puede que publiquemos tipos nuevos. Un
switchcondefault: return 200te mantiene compatible con versiones futuras.