Ir al contenido

API · Leads — busca y edita tus leads desde otra herramienta

Los endpoints de leads te dejan encontrar un lead, leer su ficha y modificarla desde fuera de ZeroChats: moverlo de etapa cuando reserva en tu calendario, etiquetarlo cuando paga en tu pasarela, o guardarle el email que dejó en un formulario. Es el complemento natural del Webhook personalizado: el webhook te avisa de lo que pasa en ZeroChats, y con estos endpoints reflejas en ZeroChats lo que pasa fuera.

Esta página cubre solo esos endpoints. Cómo conseguir la clave, cómo autenticarte, el límite de peticiones y los errores comunes a toda la API están en API de ZeroChats.

La URL base es:

https://app.zerochats.com/api/v1
MétodoEndpointQué hace
GET/leadsBusca leads por usuario, email o teléfono.
GET/leads/{id}Devuelve un lead por su identificador.
GET/leads/resolveDevuelve el lead al que apunta el utm_user de un enlace.
PATCH/leads/{id}Cambia la etapa, las etiquetas o el contacto de un lead.

La API no crea leads ni manda mensajes. Un lead nace cuando alguien escribe a tu negocio; desde aquí solo lo encuentras y lo editas.

Los cuatro endpoints devuelven el lead con la misma forma, y es exactamente la misma que el objeto lead que manda el Webhook personalizado. Lo que aprendas a leer en un sitio te sirve en el otro, y el id que te llega por webhook es el que usas aquí.

{
"id": "3d51f0c2-9a18-4b7e-8c56-1e2d3f4a5b6c",
"name": "Ada Lovelace",
"username": "ada",
"platform": "INSTAGRAM",
"externalId": "17841400000000000",
"email": "[email protected]",
"phone": null,
"state": "IN_PROGRESS",
"tags": ["caliente"],
"createdAt": "2026-08-11T09:12:30.000Z"
}
CampoQué es
idIdentificador del lead en ZeroChats. Estable: úsalo como clave.
nameNombre del lead.
usernameNombre de usuario en la plataforma de origen.
platformCanal de origen: INSTAGRAM, WHATSAPP, WASENDERAPI o MESSENGER.
externalIdIdentificador del lead en su plataforma: el id de Instagram, o los dígitos del teléfono en los canales de WhatsApp. null si no se conoce.
emailEmail del lead, o null si todavía no lo ha dado.
phoneTeléfono del lead, o null si todavía no lo ha dado.
stateEtapa del embudo de leads, por su nombre. La tabla de equivalencias está más abajo.
tagsLista completa de etiquetas del lead en ese momento, por su nombre.
createdAtFecha de creación del lead, en formato ISO 8601 (UTC).

En estos endpoints la respuesta no lleva meta: solo success y data.

GET /leads busca por exactamente un criterio, que va como parámetro en la URL:

ParámetroQué compara
usernameEl nombre de usuario de Instagram o WhatsApp, exacto, sin distinguir mayúsculas.
emailEl email recogido en la conversación, exacto, sin distinguir mayúsculas.
phoneEl número de WhatsApp del lead y el teléfono recogido en la conversación. Acepta cualquier formato —+34 600 111 222, 0034600111222, 34600111222—: se queda con los dígitos y compara. Mándalo con prefijo de país.
Ventana de terminal
curl -H "Authorization: Bearer zcst_tu_clave" \
"https://app.zerochats.com/api/v1/[email protected]"

data es siempre una lista, de más reciente a más antiguo y con un máximo de 20 resultados:

{
"success": true,
"data": [
{
"id": "3d51f0c2-9a18-4b7e-8c56-1e2d3f4a5b6c",
"name": "Ada Lovelace",
"username": "ada",
"platform": "INSTAGRAM",
"externalId": "17841400000000000",
"email": "[email protected]",
"phone": null,
"state": "IN_PROGRESS",
"tags": ["caliente"],
"createdAt": "2026-08-11T09:12:30.000Z"
}
]
}

Es una lista y no un único lead porque la misma persona puede ser dos leads: uno por cada canal en el que te ha escrito. Si Ada te escribió por Instagram y luego por WhatsApp y dejó el mismo email en las dos conversaciones, la búsqueda por email devuelve las dos fichas. Si nadie coincide, recibes un 200 con data a [], no un 404.

Mandar dos criterios a la vez, o ninguno, es un 400 con error.code a invalid_request y el mensaje provide exactly one of username, email or phone. Un phone sin ningún dígito también es un 400.

GET /leads/{id} devuelve un lead por su identificador de ZeroChats: el id que te da el webhook o la búsqueda.

Ventana de terminal
curl -H "Authorization: Bearer zcst_tu_clave" \
https://app.zerochats.com/api/v1/leads/3d51f0c2-9a18-4b7e-8c56-1e2d3f4a5b6c

Si el lead no existe o no es de tu negocio, la respuesta es un 404 con error.code a not_found. Los dos casos se ven igual a propósito: la clave no puede ni siquiera confirmar que un lead ajeno existe.

PATCH /leads/{id} recibe un JSON con los campos que quieras cambiar. Solo se escriben los que mandas; el resto queda como está.

Ventana de terminal
curl -X PATCH \
-H "Authorization: Bearer zcst_tu_clave" \
-H "Content-Type: application/json" \
-d '{ "state": "BOOKED", "addTags": ["caliente"] }' \
https://app.zerochats.com/api/v1/leads/3d51f0c2-9a18-4b7e-8c56-1e2d3f4a5b6c

El cuerpo admite estos campos, y solo estos:

{
"state": "BOOKED",
"addTags": ["caliente", "9f1c8a4e-2b77-4d0a-9d1c-3f2b6a5c7e10"],
"removeTags": ["frío"],
"email": "[email protected]",
"phone": "+34 600 111 222"
}

La respuesta es el lead tal como queda después del cambio, con la misma forma que GET /leads/{id}.

La etapa del embudo, por su nombre:

Etapa en la appstate
AbiertaOPEN_CONVERSATION
DescubriendoIN_PROGRESS
CualificandoQUALIFYING
PropuestaLEAD
AgendadoBOOKED
PagadoCLIENT
PospuestoPOSTPONED
No cualificadoNO_QUALIFY
PerdidoLOST

Cambiar la etapa desde la API se comporta exactamente igual que cambiarla a mano desde el dashboard:

  • Queda registrado en el historial de estados del lead, con el motivo «El estado se cambió a través de la API de ZeroChats».
  • Los Follow-Ups reaccionan a la nueva etapa como a cualquier otro cambio.
  • Los CRMs conectados reciben su etiqueta de estado, y el Webhook personalizado recibe lead.state_changed.

Mandar la etapa que el lead ya tiene no hace nada: no se registra ningún cambio ni se avisa a nadie.

Listas de etiquetas que añadir o quitar, con un máximo de 50 en cada una. Cada elemento puede ser el id de la etiqueta o su nombre, sin distinguir mayúsculas.

Las etiquetas tienen que existir ya en tu negocio: la API nunca crea etiquetas. Si alguna referencia no se reconoce, la petición entera falla con un 400 que te dice cuáles, y no se cambia nada; ni siquiera las que sí existían. Crea la etiqueta desde la app y repite la llamada.

Las etiquetas que añades se comportan como las que asigna la IA: si la etiqueta tiene activada la notificación, se envía; los CRMs conectados y el Webhook personalizado reciben lead.tagged. Quitar una etiqueta es silencioso. Si mandas los dos campos, primero se añaden y después se quitan.

Texto para escribir el dato, o null para borrarlo. Un email con un formato que no es un email es un 400.

Códigoerror.codeCuándo
404not_foundEl lead no existe o no es de tu negocio.
400invalid_requestCuerpo vacío, JSON mal formado, un campo que no existe, una etapa que no está en la tabla, una etiqueta desconocida o un email inválido.

Mientras el Script de seguimiento de conversiones está activo, todos los enlaces que ZeroChats envía a un lead llevan un parámetro utm_user con un identificador cifrado del lead: un valor opaco de 22 caracteres que solo ZeroChats puede descifrar. GET /leads/resolve convierte ese valor en el lead, para que puedas reconocerlo desde tu propio servidor sin instalar el script.

Ventana de terminal
curl -H "Authorization: Bearer zcst_tu_clave" \
"https://app.zerochats.com/api/v1/leads/resolve?utm_user=qdfomARk3BiETYsZgmtDbg"

data es el lead, con la misma forma que GET /leads/{id}:

{
"success": true,
"data": {
"id": "3d51f0c2-9a18-4b7e-8c56-1e2d3f4a5b6c",
"name": "Ada Lovelace",
"username": "ada",
"platform": "INSTAGRAM",
"externalId": "17841400000000000",
"email": "[email protected]",
"phone": null,
"state": "IN_PROGRESS",
"tags": ["caliente"],
"createdAt": "2026-08-11T09:12:30.000Z"
}
}

Si el valor llega con una @ delante —utm_user=@qdfomARk3BiETYsZgmtDbg— se acepta igual. Y desactivar el seguimiento de conversiones no invalida nada: los valores de los enlaces enviados antes siguen resolviéndose.

Códigoerror.codeCuándo
400invalid_requestFalta utm_user, o el valor no es uno que ZeroChats produzca. El mensaje es utm_user: not a value produced by ZeroChats.
404not_foundEl seguimiento de conversiones nunca se ha activado en tu negocio —el mensaje te lo dice—, o el valor no corresponde a ningún lead tuyo: viene de los enlaces de otro negocio o está alterado. Este último caso se ve igual que un lead desconocido, a propósito.

El flujo completo, sin el script:

  1. Captura el utm_user en tu página. Léelo de la URL con la que aterriza el visitante y guárdalo en un campo oculto del formulario, o pásaselo a tu herramienta de reservas o de pago como dato extra.

  2. Mándalo a tu servidor. Con el envío del formulario, o dentro del aviso que tu herramienta emite cuando alguien reserva o paga.

  3. Resuelve el lead. Desde el servidor, GET /leads/resolve?utm_user=... con tu clave. Si recibes un 404, el visitante no llegó desde un enlace de ZeroChats; registra el caso y termina el flujo.

  4. Edita el lead. PATCH /leads/{id} con el id que acabas de recibir: la etapa, las etiquetas, el email o el teléfono que quieras guardar.

Ejemplo práctico: mover al lead cuando reserva

Sección titulada «Ejemplo práctico: mover al lead cuando reserva»

Un caso completo en n8n o Make: tu herramienta de reservas —o tu pasarela de pago— avisa por webhook cada vez que alguien reserva, y quieres que ese lead pase a Agendado en ZeroChats con la etiqueta reservó puesta, sin que nadie entre en el dashboard.

  1. Recibe el aviso de tu herramienta. Casi todas incluyen el email con el que la persona reservó; es lo que vas a usar para encontrarla.

  2. Busca el lead por email. Un nodo HTTP Request con método GET y URL:

    https://app.zerochats.com/api/v1/leads?email={{ $json.email }}

    Con la misma credencial de cabecera que usas para el resto de la API.

  3. Comprueba que hay resultado. Si data viene vacío, la persona reservó con un email que no dejó en la conversación; registra el caso y termina el flujo. Si vienen varios, quédate con el primero: es el más reciente.

  4. Edita el lead. Otro HTTP Request, esta vez PATCH, contra https://app.zerochats.com/api/v1/leads/{{ $json.data[0].id }}, con cabecera Content-Type: application/json y este cuerpo:

    { "state": "BOOKED", "addTags": ["reservó"] }
  5. Listo. El lead aparece en Agendado, con la etiqueta puesta y el cambio en su historial. Si tienes un CRM conectado o el Webhook personalizado activo, reciben el cambio igual que si lo hubieras hecho a mano.

Para una pasarela de pago, el flujo es el mismo cambiando BOOKED por CLIENT. Y si tu herramienta te da el teléfono en vez del email, busca con phone en lugar de email.

  • Guarda el id, no el usuario. El nombre de usuario de Instagram puede cambiar; el id no. Si tu flujo recibe el lead por webhook, ya tienes el id y te ahorras la búsqueda.
  • Trata la lista de búsqueda como lista. Aunque casi siempre traiga un resultado, decide qué hacer cuando traiga cero o varios antes de que pase en producción.
  • Manda solo lo que cambia. Un PATCH con la etapa que el lead ya tiene no rompe nada, pero tampoco aporta; y un PATCH con el email actual reescribe lo mismo.
  • Deja la etapa a la IA salvo que tengas mejor información. La API es para reflejar hechos que pasan fuera —una reserva, un pago—, no para mover leads por rutina desde un flujo.

O el id es de otro negocio —una clave solo ve sus propios leads— o el lead se ha eliminado desde la app. En ambos casos la respuesta es la misma a propósito. Comprueba que estás usando la clave del negocio correcto.

La búsqueda devuelve [] y sé que el lead existe

Sección titulada «La búsqueda devuelve [] y sé que el lead existe»

Repasa el criterio:

  • Con username, el nombre de usuario tiene que ser exacto: sin @, sin espacios y con la ortografía de la plataforma.
  • Con email, tiene que ser el email tal como lo escribió el lead en la conversación. Si lo dio con una errata, la búsqueda necesita la misma errata.
  • Con phone, incluye el prefijo de país. 600111222 no encuentra a un lead guardado como 34600111222.

El mensaje te dice qué referencias no se han reconocido. La API no crea etiquetas: créala primero desde la app, con el mismo nombre que usas en el flujo, y vuelve a lanzar la llamada. Hasta entonces no se cambia nada en el lead, ni siquiera el resto de campos del mismo PATCH.