Asira

Webhook de ingesta de leads

El webhook de ingesta es la vía para meter leads a Asira desde afuera: tu CRM, una landing, HighLevel, Meta Ads, n8n. Recibe uno o varios leads y, por cada uno, hace el upsert del contacto, lo rutea con tus pre-procesadores hacia el agente correspondiente y lo mete en el pipeline de ese agente.

No es la API v1 con X-API-KeyEste webhook es una superficie aparte de la API pública v1. Autentica con un token por workspace (no con una key sygk_live_…) y su respuesta usa un shape propio ({ error: "…" }), no el envelope { error: { code, message } } de la API v1.

Endpoint

POST /api/webhooks/leads?wsid=<workspaceId>&token=<token>

El token también se puede mandar en el header X-API-Key en vez de la query:

POST /api/webhooks/leads?wsid=<workspaceId>
X-API-Key: <token>

Autenticación

  • wsid (query, obligatorio): el ID de tu workspace. Es la fuente de verdad del tenant, el workspace se toma siempre de acá, nunca del body.
  • token (query o header X-API-Key, obligatorio): el token de ingesta del workspace. Se compara en tiempo constante contra el token configurado; un token que no coincide devuelve 401.

El wsid y el token de ingesta se generan y ven en Configuración → Leads del panel. Si el workspace no tiene la ingesta habilitada (sin token configurado), todos los requests devuelven 401.

El token es un secreto por workspace: guárdalo en un secret manager, no lo subas a git ni lo expongas en el front.

Cuerpo del request

El body acepta cuatro formas (todas equivalentes), para encajar con lo que mande cada origen:

[
  { "name": "Ana", "phone": "+56911111111" },
  { "name": "Beto", "phone": "+56922222222" }
]

Hasta 1000 leads por request.

Campos de un lead

CampoTipoRequeridoDescripción
phonestringTeléfono del lead. Es su identidad en el workspace (UNIQUE por workspace + teléfono) y el canal por el que lo contacta el agente.
namestringNoNombre del lead.
emailstringNoEmail del lead.
sourcestringNoOrigen del lead (ej. landing_web, meta_ads). Si no viene, se usa metadata.source o lead_api.
tagsstring[]NoEtiquetas a asignar (se recortan espacios y se fusionan con las existentes).
metadataobjectNoDatos custom clave-valor.
Claves extra → metadataCualquier clave top-level que no sea name / phone / email / source / tags / metadata se pliega automáticamente dentro de metadata. Enviar { "phone": "…", "edad": 35 } equivale a { "phone": "…", "metadata": { "edad": 35 } }.

Algunas claves internas del motor (como last_recontact_at o stage_changed_at) no se pueden setear desde la ingesta: se descartan de metadata para que el emisor no controle los relojes de recontacto/timeout del pipeline.

Ejemplo

curl -X POST "https://TU-DOMINIO/api/webhooks/leads?wsid=TU_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: TU_TOKEN_DE_INGESTA" \
  -d '{
    "leads": [
      {
        "name": "Ana Pérez",
        "phone": "+56911111111",
        "email": "ana@correo.com",
        "source": "landing_web",
        "tags": ["vip"],
        "campaña": "black-friday"
      }
    ]
  }'

Qué pasa con cada lead

  1. Upsert del contacto

    Se busca por workspace_id + phone. Si existe, se actualiza (mergeando metadata y tags, sin pisar lo que ya había); si no, se crea.

  2. Ruteo por pre-procesadores

    Se corren tus reglas de pre-procesador (Processor) sobre los datos del lead para resolver a qué agente va.

  3. Entrada al pipeline

    Si el lead no estaba ya asignado a un agente, se lo mete en la etapa inicial del agente resuelto y arranca la conversación. Un lead que ya tenía agente no se secuestra: se respeta su conversación en curso (source: "already_assigned").

Respuesta

Semántica bulk tolerante a fallos: un lead inválido no tumba el batch entero. La respuesta reporta el resultado por lead.

{
  "ok": true,
  "received": 1,
  "processed": 1,
  "routed": 1,
  "failed": 0,
  "results": [
    {
      "index": 0,
      "ok": true,
      "contact_id": "c_1234",
      "agent_id": "ag_5678",
      "rule_matched": "Landing web → Ventas",
      "source": "processor"
    }
  ]
}
CampoDescripción
receivedCantidad de leads recibidos en el request.
processedCuántos se procesaron con éxito.
routedCuántos quedaron asignados a un agente.
failedCuántos fallaron (received menos processed).
results[]Detalle por lead: index, ok, contact_id, agent_id, rule_matched, source y error (si falló).

Errores

HTTPBodyCuándo
401{ "error": "Unauthorized" }Falta wsid o token; el workspace no tiene ingesta habilitada; el token no coincide.
400{ "error": "Invalid JSON body" }El body no es JSON válido.
400{ "error": "El body debe traer un lead, un array de leads o { leads: [...] }" }Forma de body no reconocida.
400{ "error": "No hay leads en el body" }El array vino vacío.
400{ "error": "Máximo 1000 leads por request…" }Se superó el tope de 1000.