Lectico

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 de type.
  • workspace_id — workspace que originó el evento.
  • api_version — versión del contrato (v1 durante toda la beta).

Eventos disponibles

TipoCuándo se disparadata incluye
agent.createdSe crea un asistente (API o panel).agent
agent.updatedSe edita un asistente.agent, changes
agent.deletedSe borra un asistente (soft delete).agent_id
conversation.startedUn visitante abre el widget y envía primer mensaje.conversation
conversation.endedLa conversación se cierra (timeout o usuario sale).conversation
lead.capturedUn visitante deja sus datos en el widget.lead, conversation_id
knowledge.source.indexedUna fuente de conocimiento termina de procesarse.source
knowledge.source.failedFalla la indexación de una fuente.source, error
qa.regeneratedTermina POST /v1/agents/{id}/qa/regenerate (REQ-092.4).agent_id, qa_count
course.lesson.source.indexedUna fuente de lección (training) termina de procesarse.lesson, source
course.lesson.source.failedFalla la indexación de una fuente de lección.lesson, source, error
ticket.createdSe crea un ticket (widget, AI escalation o API).ticket, first_message
ticket.message.createdSe añade un mensaje al hilo de un ticket.ticket_public_id, message
ticket.status.changedCambia el estado de un ticket.ticket_public_id, from, to, actor, changed_at
ticket.resolvedUn ticket se marca como resuelto.ticket
webhook.testSe 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 recibe 2xx a tiempo. Guarda los id procesados para ignorarlos la segunda vez.
  • Responde rápido: si necesitas trabajo pesado, encola y responde 200 primero. Si tu endpoint tarda más de 10s, consideramos la entrega como fallida.
  • Ignora eventos desconocidos: puede que publiquemos tipos nuevos. Un switch con default: return 200 te mantiene compatible con versiones futuras.