Skip to main content
Esta guía es para la persona que va a conectar un sistema externo (portal, tienda, app, ERP) con Relevant. La API v1 tiene tres endpoints: uno para registrar leads, otro para avisar que pasó algo con un lead ya registrado (y, si cambió el precio, actualizar su monto) y otro para corregir los datos de un contacto. El orden natural de integración es el de este documento: obtener la llave, registrar un lead, enviar un evento y, cuando haga falta, corregir un contacto. Si buscas la explicación para quien administra la cuenta (qué es el origen, cómo armar la automatización que escucha el evento), está en Conecta tu sistema a Relevant.

Antes de empezar

  • Base URL: https://app.relevantleads.io
  • Formato: JSON en el cuerpo y en la respuesta. Envía Content-Type: application/json. El cuerpo debe ser un objeto JSON (un arreglo o un valor suelto se rechaza).
  • Autenticación: encabezado Authorization: Bearer <llave>.
  • Métodos: POST en leads y eventos, PATCH en contactos. No hay CORS: el navegador bloquea la llamada, así que llama desde tu servidor, no desde el navegador del usuario final.
  • Entorno: no existe sandbox ni llaves de prueba. Todas las llaves son rk_live_ y operan sobre la cuenta real. Para probar sin arriesgar datos, usa un embudo de pruebas y leads de prueba.

1. La llave

Una persona con rol Owner o Admin la crea en Ajustes, API, Nueva llave (grupo Admin Center). Al crearla define tres cosas que viven en la llave, no en cada envío:
  • El embudo y etapa destino por defecto de los leads que entren con ella (tu envío puede sobrescribirlos, ver abajo).
  • El origen con el que se etiquetan esos leads en Contactos, Atribución y reportes (por ejemplo “Registro web”; si no se configura, “Registro externo”).
  • Su nombre, que aparece en las notas de sistema del chat del lead: “Datos del registro (nombre)” en cada registro con custom_data que crea o reutiliza un lead, y “Evento recibido de (nombre)” en cada evento.
Formato: rk_live_ seguido de 43 caracteres, 51 en total. Se muestra completa una sola vez al crearla; Relevant solo guarda un hash. Guárdala en variables de entorno o en tu gestor de secretos. Si se pierde, el administrador la revoca y crea otra. Cada petición autenticada actualiza el Último uso de la llave (aunque después falle por validación), así que quien administra puede ver desde Relevant que tu integración ya está llamando. Una llave revocada responde 401 de inmediato.

Errores de autenticación

2. Registrar un lead

POST /api/v1/leads Crea el contacto y su lead en el embudo destino. Si la persona ya existe, la reutiliza (ver deduplicación). Es seguro reintentar el mismo envío.

Campos del cuerpo

Los campos de texto opcionales (external_id, email, country_code, company, location, website, UTMs) que exceden su máximo se recortan en silencio, no se rechazan. Solo name rechaza por longitud. Envía valores dentro de los límites para que lo que guardes coincida con lo que mandaste.

Normalización del teléfono

Relevant quita espacios, guiones, paréntesis, puntos y el +, y aplica estas reglas:
  • 10 dígitos: se antepone country_code (o 52). "5512345678" se guarda como 525512345678.
  • Empieza con 521 y tiene 13 dígitos: se quita el 1 (formato viejo de celulares mexicanos). "5215512345678" se guarda como 525512345678.
  • Empieza con 00: se quitan los dos ceros.
  • De 11 a 15 dígitos (por ejemplo 12 con lada): se guarda tal cual; se asume que ya trae código de país.
  • 8 o 9 dígitos: no se guarda. La petición responde 422 con fields.phone explicando el formato (“Debe tener 10 dígitos con lada (por ejemplo “8112345678”) o incluir el código de país (por ejemplo “+528112345678”, máximo 15 dígitos).”).
El teléfono guardado se devuelve en phone. En un contacto que ya existía, el teléfono guardado no se reemplaza.

Destino del lead

  1. Por defecto: el embudo y etapa de la llave. Si la llave tiene embudo pero no etapa, la primera etapa del embudo. Si la llave no tiene embudo y el cuerpo tampoco, se crea solo el contacto (deal_id: null).
  2. funnel_id en el cuerpo: se valida que sea de tu cuenta (404 si no). La etapa por defecto de la llave se descarta.
  3. stage_id en el cuerpo: se valida que sea de tu cuenta (404 si no). Si viene sin funnel_id, el embudo es el de esa etapa.

Respuesta

201 Created cuando se creó el contacto o el lead. 200 OK cuando ambos ya existían y se reutilizaron.
  • deal_id es null cuando no hubo embudo destino: se creó solo el contacto.
  • funnel_id y stage_id son el embudo y la etapa donde quedó el lead al terminar la petición (Relevant los relee después de crear o reutilizar el lead). Si una automatización con disparador “Nuevo lead en etapa” lo movió al crearse, aquí ves la etapa final, no la de entrada.
  • Guarda contact_id y deal_id junto a tu usuario: deal_id sirve para enviar eventos con precisión, y contact_id para corregir el contacto aunque no tenga tu external_id (sección 4).

Deduplicación (idempotencia de registros)

  1. Si envías external_id y ya existe un contacto con ese valor en tu cuenta, se reutiliza.
  2. Si no envías external_id, o no coincide con ningún contacto, se busca por los últimos 10 dígitos del teléfono dentro de tu cuenta. Si más de un contacto termina en esos dígitos, se reutiliza el más antiguo (el que tiene el historial).
  3. En un contacto reutilizado se actualizan name y email si los mandas, y se rellenan los UTMs vacíos. Si el contacto no tenía external_id y ahora lo mandas, se le guarda; si ya tenía otro, conserva el que tenía (y un evento con el nuevo external_id no lo encontrará: usa deal_id o el teléfono).
  4. Si el contacto ya tiene un lead abierto en el embudo destino, se reutiliza ese lead (created_deal: false); no se tocan su título, monto ni etapa. Un segundo registro de la misma persona no es una oportunidad nueva.
  5. Si su lead anterior ya se cerró (ganado o perdido), se crea uno nuevo.
Reintentar el mismo envío no genera duplicados.

custom_data

Se escribe en el chat del lead como una nota de sistema con el formato Datos del registro (nombre de la llave): clave: valor · clave: valor, visible para el equipo. Reglas:
  • Se escribe cada vez que el registro tiene lead: cuando lo crea (created_deal: true) y también cuando reutiliza uno abierto (created_deal: false). Por eso un reintento con custom_data deja la nota otra vez (sección 7). Si no hay embudo destino (deal_id: null), custom_data se descarta sin error.
  • Máximo 20 claves (las primeras, en orden), 40 caracteres por clave, 120 por valor, 600 en total. Los valores vacíos o nulos se omiten. Un valor anidado se serializa como texto JSON y se recorta a 120.
  • Un arreglo en custom_data se rechaza con 422.

Qué pasa en Relevant al registrar

  • El contacto y el lead se crean con el origen de la llave. El lead nace con prioridad Media, estado abierto y título igual a name.
  • Sobre un lead nuevo corren las reglas de auto-asignación de la cuenta (reglas, responsable de etapa, responsable de embudo). Si asigna a alguien, esa persona recibe la notificación de lead asignado.
  • Automatizaciones al crear: un lead nuevo dispara, dentro de la misma petición, las automatizaciones cuyo disparador “Nuevo lead en etapa” vigile la etapa donde entra; por eso stage_id en la respuesta puede ser distinto del destino. Un lead reutilizado no dispara nada al registrarse de nuevo, porque no cambia de etapa. Para actuar cuando pase algo después en tu sistema, usa eventos.
  • No se envía ningún mensaje de WhatsApp al lead.

3. Avisar de un evento del lead

POST /api/v1/events Úsalo cuando en tu sistema pase algo con un lead ya registrado: un pago, una activación, una cancelación. Relevant registra el evento, lo deja como nota en el chat del lead, notifica a la persona responsable y ejecuta las automatizaciones que estén escuchando ese evento en ese embudo. Si con el evento cambió el precio, el mismo envío puede actualizar el monto del lead (amount).

Campos del cuerpo

Cómo se resuelve el evento

  1. Relevant localiza al lead: por deal_id si viene; si no, por external_id; si no coincide, por los últimos 10 dígitos de phone.
  2. Toma sus leads abiertos (todos, o solo los del funnel_id indicado). Los leads cerrados no se tocan.
  3. Si mandaste amount, lo escribe en el lead abierto antes de ejecutar nada (ver “Monto del lead” abajo).
  4. Para cada lead abierto, ejecuta cada automatización activa que tenga un disparador Evento externo con ese nombre exacto y con el embudo del lead. En el editor, cada disparador de este tipo está ligado a un embudo; si la persona tiene leads abiertos en dos embudos y mandas el evento sin funnel_id, ambos leads reciben la nota y la notificación, pero solo se ejecuta la automatización del embudo que coincide.
  5. Deja rastro: registro del evento, nota de sistema Evento recibido de <nombre de la llave>: <event> (<resumen del payload>) en el chat de cada lead abierto alcanzado (si el evento cambió el monto, la nota termina con · Monto: <anterior> → <nuevo>), y notificación dentro de la app a la persona asignada a cada uno.
  6. Si la automatización tiene la acción Enviar plantilla, el lead recibe un Mensaje de WhatsApp aprobado en cuanto llega el evento, con sus variables tomadas del payload (por ejemplo {{2}} = clave monto), de los datos del contacto o del lead, o de texto fijo; si a una variable le falta el valor, no se envía y el chat lo dice. Cada mensaje entregado se cobra como difusión. Cómo se configura, en Automatizaciones.

Monto del lead (amount)

  • El monto se escribe antes de ejecutar las automatizaciones: si una de ellas marca el lead como ganado o manda una plantilla con Monto del lead, ya ve el nuevo.
  • Solo cambia leads abiertos. Si el evento no alcanza ninguno (outcome: "no_open_deals"), el monto se ignora.
  • El monto es de un lead. Si el contacto tiene varios leads abiertos y el evento los alcanza a todos, la respuesta es 422 validation_error con fields.amount (“El evento alcanza N leads abiertos de este contacto. Envía deal_id o funnel_id para indicar a cuál aplicar el monto.”) y no se registra ni se ejecuta nada: la idempotency_key queda libre. Reenvía con deal_id, o con funnel_id si el contacto tiene un solo lead abierto en ese embudo.
  • Si el monto cambió, la nota del evento en el chat lo dice al final: · Monto: $4,640 → $4,176.50 (si el lead no tenía monto, sin monto → $4,176.50). Si era el mismo, no se escribe nada.
  • Un reintento con la misma idempotency_key no vuelve a escribir el monto: devuelve el amount_update del envío original.
  • Si la respuesta es 500, el lead se queda con el monto que tenía antes del envío (salvo que alguien lo haya cambiado mientras tanto) y la clave queda libre: el reintento con la misma idempotency_key lo escribe.

Límites del payload

Relevant rechaza el evento completo (422 validation_error) cuando el payload:
  • tiene más de 20 claves (“Máximo 20 claves.”);
  • trae una clave vacía o de más de 40 caracteres (“Cada clave debe tener entre 1 y 40 caracteres.”);
  • trae un valor que es objeto o lista (“La clave “x” debe ser texto, número, booleano o null, no un objeto ni una lista.”);
  • trae un texto de más de 500 caracteres (“El valor de “x” supera 500 caracteres.”);
  • pesa más de 4 KB en total (“El payload completo supera 4096 bytes.”).
Manda solo lo que la automatización va a usar (un monto, un plan, un folio). Lo que necesites conservar completo guárdalo en tu sistema y manda la referencia.

Respuesta

200 OK siempre que el lead exista, aunque no tenga leads abiertos o ninguna automatización lo escuche.
amount_update es null cuando no mandaste amount o el evento no alcanzó ningún lead abierto. Si no, trae el lead (deal_id), el monto que tenía (previous, puede ser null), el que mandaste (amount) y si de verdad cambió (changed). changed: false significa que ya tenía ese monto o que el lead se cerró justo antes de escribirlo. Si el lead no existe: 404 not_found, con field igual a deal_id, external_id o phone según lo que mandaste. Regístralo primero con POST /api/v1/leads.

Idempotencia de eventos

  • La idempotency_key es única por cuenta y no caduca: la misma clave meses después sigue devolviendo el resultado original.
  • Un reintento con una clave ya recibida responde 200 con duplicate: true, el outcome y el amount_update originales, y sin el arreglo deals. No se ejecuta nada ni se vuelve a escribir el monto.
  • Si dos envíos con la misma clave llegan al mismo tiempo, solo uno ejecuta: la clave se reserva antes de ejecutar las automatizaciones. El otro recibe el resultado del primero con duplicate: true; si el primero sigue en proceso, Relevant espera hasta 2 segundos y, si aún no termina, responde con outcome: "pending".
  • En el caso raro de que ese resultado original no se pueda leer, el segundo envío recibe 409 conflict. Reintenta una vez: obtendrás el resultado original con duplicate: true.
  • Un 422 por amount o un 500 no gastan la clave: reenvía con la misma idempotency_key.

4. Corregir un contacto

PATCH /api/v1/contacts Úsalo cuando en tu sistema se corrija un dato de un contacto que ya registraste: el nombre, el teléfono, el correo, la empresa. Reenviar POST /api/v1/leads no sirve para eso: no cambia el teléfono, no borra datos y, si el lead ya se cerró, abre uno nuevo.

Cómo se identifica el contacto

Exactamente uno de estos dos: Si mandas los dos, o ninguno: 422 validation_error. Solo se buscan contactos de tu cuenta: si no existe, 404 not_found con field igual a external_id o contact_id.

Campos que se pueden cambiar

Un campo que no mandas no se toca. Un campo con null o "" se borra, salvo name y phone, que no se pueden borrar (mandarlos vacíos o con null da 422). A diferencia del registro, un texto que pasa del máximo se rechaza con 422 en vez de recortarse: es una corrección y tiene que quedar exactamente lo que mandaste. Cualquier otro campo también da 422 con el detalle en fields: los del registro que aquí no van (funnel_id, stage_id, amount, custom_data, UTMs y referrer_url) y uno mal escrito. Para cambiar el monto del lead, usa amount en eventos (sección 3).

Cambio de teléfono

  • El mismo número en otro formato (+52 81 1234 5678, 5218112345678 o los 10 dígitos) no cuenta como cambio.
  • Si el número está bloqueado en tu cuenta: 422 blocked con field: "phone".
  • Si el número ya es de otro contacto de tu cuenta (se comparan los últimos 10 dígitos): 409 conflict con field: "phone" y conflict_contact_id. Los contactos nunca se fusionan: corrige el otro contacto o usa otro número.
  • El historial de WhatsApp se queda en el contacto. Si la persona vuelve a escribir desde el número viejo, entra como un contacto nuevo.
  • La ventana de 24 horas que contaba Relevant era del número viejo: Relevant la da por cerrada en los leads abiertos del contacto. Limitación conocida: en el chat la ventana todavía puede verse abierta por los mensajes del número viejo. Si un mensaje de texto libre al número nuevo falla, manda una plantilla aprobada.

Lo que no hace

No crea, mueve, cierra ni reabre leads, y no cambia su título, monto ni etapa. No asigna ni cambia el external_id del contacto: solo sirve para encontrarlo. No dispara automatizaciones, reglas de asignación ni notificaciones, no escribe en el chat y no manda WhatsApp.

Respuesta

200 OK, también cuando no cambió nada: repetir el mismo cuerpo devuelve changed: [].
changed lista solo los campos que de verdad cambiaron. contact es cómo quedó el contacto; phone es el teléfono guardado (dígitos con lada, sin +).

5. Errores

Todas las respuestas de error tienen esta forma:
Orden de evaluación en los tres endpoints: autenticación (401), cuerpo (413, 400), formato de los campos (422), existencia de identificadores (404), proceso (500). Después del 404 todavía pueden llegar estas respuestas: en leads, el 422 de stage_id que no pertenece al embudo y el 422 blocked; en eventos, el 422 por amount con varios leads abiertos; en contactos, el 422 blocked y el 409 conflict por el teléfono. Un evento con una idempotency_key ya recibida se contesta como duplicado justo después de revisar el formato, antes de validar funnel_id.

6. Límites y comportamiento

  • Tamaño del cuerpo: 16 KB.
  • Límite de tasa: no hay. La llave registra su último uso y puede revocarse al instante; ese es el mecanismo para detectar y cortar un abuso. Si vas a enviar volúmenes altos (miles por hora), avísanos antes a soporte@relevantleads.io.
  • Recortes silenciosos (leads y eventos): external_id e idempotency_key a 128, email a 254, UTMs a 500, country_code a 4 caracteres. En contactos no se recorta nada: un texto más largo que su máximo da 422.
  • Plan: el registro de leads, los eventos y la corrección de contactos funcionan en todos los planes. No hay validación de plan en estos endpoints.
  • Sin sandbox. Métodos: POST en leads y eventos, PATCH en contactos. No hay CORS: el navegador bloquea la llamada, así que llama desde tu servidor, no desde el navegador del usuario final.
  • Edición de llaves: quien administra la cuenta (Owner o Admin) puede editar una llave sin revocarla: nombre, embudo destino, etapa destino, origen y color. La llave sigue siendo la misma, así que tu sistema no cambia nada. Los leads que ya entraron con ella conservan su origen y lo muestran con el nombre y el color nuevos. La revocación no borra el historial de los leads que entraron con ella.

7. Tiempos de respuesta, timeouts y reintentos

Tiempos medidos el 31 de octubre de 2026, con la API en Oregón (EE. UU.), desde que el cliente envía la petición hasta que recibe la respuesta, una petición a la vez:
  • POST /api/v1/leads: ~0.9 s típico. La primera llamada en frío, después de un rato sin tráfico, puede tardar hasta ~2 s.
  • POST /api/v1/events: ~0.75 s típico.
Tu tiempo real depende de tu red y de dónde esté tu servidor. Timeout. Configura 15 s por petición: deja margen para una llamada en frío o un pico sin cortar envíos que sí iban a completarse. Reintento. Ante un timeout, un error de red o una respuesta 5xx, reintenta una vez con el mismo cuerpo:
  • En leads es seguro: el reintento no crea otro contacto ni otro lead (ver deduplicación en la sección 2). Si mandaste custom_data, su nota puede aparecer dos veces en el chat del lead.
  • En eventos, reintenta con la misma idempotency_key. Si el primer envío sí llegó, recibes su resultado con duplicate: true y las automatizaciones no se ejecutan otra vez. Sin idempotency_key, un reintento puede ejecutarlas dos veces.
  • En contactos es seguro: repetir el mismo cuerpo no cambia nada más (changed: []).
Un 4xx no se arregla reintentando el mismo cuerpo (salvo el 409 conflict de eventos, ver la sección 5): revisa code y message. Si el reintento también falla, no lo repitas en bucle: guárdalo y vuelve a intentarlo más tarde desde tu sistema. Conexión. Si mandas varias peticiones seguidas (por ejemplo, una carga de leads), reutiliza la conexión HTTP (keep-alive) en vez de abrir una nueva por petición: te ahorras establecer la conexión (TCP y TLS) en cada una. Los tiempos de arriba se midieron abriendo una conexión nueva por petición.

8. Buenas prácticas

  • Manda siempre external_id: hace seguros los reintentos y es lo que identifica al lead cuando envías eventos.
  • Guarda el deal_id que te devuelve el registro y úsalo en los eventos: es la forma más precisa, evita ambigüedades si la persona tiene varios leads y, si mandas amount, evita el 422 por varios leads abiertos.
  • Guarda también el contact_id: con él puedes corregir el contacto aunque no tenga tu external_id.
  • En eventos, manda siempre idempotency_key; construye la clave con algo que identifique la acción de negocio (por ejemplo pago-<id de tu pago>), no con la fecha y hora del envío.
  • Configura un timeout de 15 s y un solo reintento (sección 7).
  • Manda country_code explícito si tus usuarios no son solo de México, y el teléfono con exactamente 10 dígitos o ya con lada.
  • Usa una llave por sistema. Si necesitas que dos sistemas cuenten como el mismo origen en reportes, dales el mismo texto de origen al crearlas.
  • Antes de conectar, pide a quien administra Relevant que pruebe la automatización con el botón Probar con un lead y que te pase el nombre exacto del evento.

¿Necesitas ayuda? Escríbenos a soporte@relevantleads.io y con gusto te apoyamos.