BIKY.ai se conecta con el CRM o DMS de cada marca o distribuidor. Le entrega el lead que llega por cualquier canal, le reporta los avances (al momento o al cerrar la conversación, según el CRM) y recibe los cambios que hace el asesor. Todo gira alrededor de la SalesCard, el registro de BIKY.ai que guarda el lead, su step dentro del Funnel y el id que le asigna el CRM. Este protocolo recoge lo aprendido en más de quince integraciones en América Latina.
Cómo nos conectamos
Hay tres caminos y un CRM puede combinarlos: tu CRM avisa por webhook, BIKY.ai consulta su API, y los avances salen por esa misma API. Todo id que devuelve el CRM se guarda en la SalesCard o en el contacto, para que el siguiente evento actualice en vez de duplicar.
La autenticación la define tu CRM: OAuth2 client_credentials con una app conectada, OAuth2 autorizado por un usuario administrador, token de corta vida, API key o Basic Auth. Los webhooks entrantes usan una URL única con token por flujo; además, se puede activar el cifrado del cuerpo, y Flows verifica la firma HMAC de las plataformas que la envían. Por ahí también entran los formularios web y los proveedores de leads; los formularios de Meta llegan como un canal más.
Hay tres variantes. Algunas integraciones corren en una plataforma de integración (iPaaS), con conectores OAuth2 que autoriza un usuario administrador del cliente. Cuando el CRM no tiene API o la API no cubre un proceso, un robot (RPA) opera su portal web con los usuarios que asigna el cliente. Y si tu sistema no está en este documento, BIKY.ai puede enviar cada cambio de la SalesCard al webhook que nos indiques.
También funciona al revés: tu CRM puede llamar a la API de BIKY.ai con la llave de tu cuenta. Así crea o busca contactos (por teléfono, correo o id) y crea, consulta o mueve SalesCards entre los steps de un Funnel. Los ejemplos están en las colecciones de Postman de Keybe. Los campos, valores permitidos y ejemplos de esa API están en la sección Campos y estructura de la API.
Integraciones por CRM
Todo viaja por HTTPS. Entre un CRM y otro cambian tres cosas: quién inicia la llamada, cómo se autentica y qué identificador evita los duplicados. Estas son las integraciones con más recorrido.
Sale U
- Conexión y autenticación: entrada por webhook a una URL única con token. Salida por API REST con API key, más secreto y marca de tiempo en el cuerpo.
- Qué datos viajan: entra el lead asignado: nombre, teléfono, correo, agencia, modelo e id del prospecto. Sale cada actividad: estado, cita, nota de seguimiento, bloqueo o liberación, temperatura y cierre.
- Sentido y frecuencia: en tiempo real. Según la agencia, en ambos sentidos o solo de BIKY.ai a Sale U; cada agencia necesita la autorización del proveedor.
- Cómo evitamos duplicados: el contacto se busca por teléfono y la SalesCard por el id del prospecto: si Sale U reintenta el mismo lead, se actualiza la que ya existe.
Salesforce
- Conexión y autenticación: API REST (objetos estándar o Apex del cliente), a veces detrás de su capa de integración. OAuth2 client_credentials con app conectada, OAuth2 de un usuario administrador o Basic Auth.
- Qué datos viajan: sale el lead con contacto, modelo, origen, agencia y asesor; después, el estado y la cita. Entra la oportunidad ganada o facturada.
- Sentido y frecuencia: salida al cerrar la conversación, al agendar y en cada cambio de estado. Entrada por consulta SOQL periódica (por ejemplo, cada hora), filtrada por última modificación.
- Cómo evitamos duplicados: el id del lead se guarda en el contacto y los envíos siguientes lo actualizan. Si el CRM también deduplica de su lado, se respeta su regla.
Seekop / SICOP
- Conexión y autenticación: robot (RPA) sobre el portal con el usuario de cada agencia. Si la agencia tiene acceso a la API, API REST en formato ADF con API key.
- Qué datos viajan: entran los leads de la bandeja de espera del CRM. Sale el seguimiento en la ficha del lead; por API, el prospecto (contacto, modelo, fuente y comentario) con su agencia, y la cita.
- Sentido y frecuencia: con robot, en ambos sentidos: lee la bandeja cada pocos minutos y registra el seguimiento en la ficha del lead. Por API, de BIKY.ai a Seekop al cerrar la conversación y al agendar.
- Cómo evitamos duplicados: el robot usa el id del lead en el CRM y una clave de idempotencia por acción. Por API, el contacto queda marcado como enviado.
HubSpot
- Conexión y autenticación: conector de Flows con OAuth2 autorizado por un usuario del cliente; en algunos casos, webhook o iPaaS.
- Qué datos viajan: sale el contacto y, según el caso, un negocio en un pipeline acordado. La entrada de los negocios que llegan a la etapa ganada está diseñada.
- Sentido y frecuencia: salida al cerrar la conversación o en cada compra. La entrada por consulta periódica está diseñada.
- Cómo evitamos duplicados: upsert del contacto. Está diseñado guardar su id en BIKY.ai y cruzar por ese id.
Microsoft Dynamics 365
- Conexión y autenticación: API OData que el cliente o su integrador publica detrás de un API gateway, con llave de suscripción en la cabecera.
- Qué datos viajan: sale el lead con su campaña; la cita se crea y se actualiza.
- Sentido y frecuencia: de BIKY.ai a Dynamics, al cerrar la conversación y en cada evento de cita.
- Cómo evitamos duplicados: solo se envían leads nuevos, no ediciones. El id de la cita se guarda en el contacto y los cambios van sobre ella.
CRM de fabricante
- Conexión y autenticación: API REST JSON con token de corta vida; multipart con PDF para el pedido. Sin webhooks: un servicio dedicado consulta la API. Lo que la API no cubre lo hace un robot sobre el portal.
- Qué datos viajan: entran los leads y sus cambios de estado, por agencia. Salen el alta de leads propios, el seguimiento, la prueba de manejo y el pedido de preventa.
- Sentido y frecuencia: entrada por consulta cada minuto, respetando un intervalo mínimo entre consultas de un mismo distribuidor; salida en cada evento de la SalesCard.
- Cómo evitamos duplicados: el código de lead se guarda en la SalesCard; el alta usa el id de la SalesCard como clave de idempotencia.
Otras integraciones que hemos construido
Algunas ya no tienen cuentas activas, pero se pueden volver a implementar.
| Sistema | Tipo | Conexión y datos |
|---|---|---|
| Tecnom | CRM automotriz | Lead en formato ADF por POST a su conector web, con usuario y contraseña. |
| Syonet 360 | CRM automotriz | El CRM envía leads por webhook; BIKY.ai registra llamadas, visitas y citas por API REST con Basic Auth. |
| Intelisis | DMS | El DMS consume la API de BIKY.ai y lee contactos y SalesCards por su id. |
| Total Dealer | DMS de taller | API de citas. |
| Upnify | CRM | API REST de prospectos y citas, con un token que solo crea registros. |
| Odoo | CRM y ERP | Alta de contacto y oportunidad con sus UTM. |
| Zoho CRM | CRM | Conector con OAuth2 y renovación del token; Zoho avisa por webhook. |
| RD Station CRM | CRM | Conector de Flows: crea negocios y los mueve entre las etapas de su embudo. |
| Smarthome | CRM | API REST de lectura y escritura. |
| Comunike | CRM | Webhook. |
| SICO | CRM inmobiliario | Salida por API REST, con usuario y contraseña que entregan un token de una hora. |
| Wasi | CRM inmobiliario | Sincroniza el inventario de inmuebles con el catálogo de BIKY.ai. |
Flows trae además nodos para los ERP Siigo, Alegra y Defontana, y para un DMS de taller (agenda de citas). Las tiendas en línea (Shopify, VTEX y WooCommerce) sincronizan catálogo y contactos con BIKY.ai y avisan de carritos abandonados, pagos y cambios de pedido. Sus conectores, como los de pagos y transportadoras, están en la página de integraciones.
Mapeo de datos
El mapeo se acuerda campo por campo antes de construir, y cada lista cerrada (fuentes, modelos, agencias, estados) lleva su tabla de equivalencias.
| Dato de BIKY.ai | Campo típico en el CRM | Regla de mapeo |
|---|---|---|
| Nombre y apellido | Nombre, apellido | Hay orígenes que mandan el nombre completo en el apellido: se separa antes de enviar. Si el CRM exige apellido y BIKY.ai no lo tiene, se acuerda qué enviar. |
| Teléfono móvil | Móvil | Con código de país (52 y 10 dígitos en México), salvo que el CRM o el objeto pida el número nacional. Si llega partido en varios campos, se acuerda cómo se arma. El código de país se completa solo si el origen lo garantiza. |
| Correo | Correo | Opcional, salvo que el objeto lo exija. Si el CRM valida el formato, el campo vacío se omite; algunos rechazan acentos o ñ. |
| Canal y campaña (UTM) | Fuente, campaña | Se traduce al catálogo de fuentes del CRM; lo que no tiene equivalencia va a «Otro». Cada valor va en su campo, sin concatenar. |
| Producto o modelo de interés | Modelo, versión | Tabla de equivalencias, con el código del CRM guardado en el producto: casar por nombre falla. Si el campo es obligatorio, se acuerda un valor por defecto. |
| Agencia | Código de distribuidor o sucursal | Tabla agencia → código, validada contra las agencias configuradas en BIKY.ai, no contra el nombre comercial. |
| Asesor responsable | Propietario o asesor | Id del asesor en el CRM, cargado en BIKY.ai. Si el CRM asigna con sus propias reglas, no se envía. |
| Step del Funnel | Estado o etapa | Tabla de equivalencias en los dos sentidos (ejemplo abajo). |
| Cita o prueba de manejo | Cita, evento | En la zona horaria y el formato exactos que pida el CRM, con inicio y fin. El id de cada cita se guarda para actualizarla. |
| Id del registro en el CRM | No aplica | Se guarda en el contacto o en la SalesCard y es la llave de toda actualización. |
| Largo de cada campo | No aplica | Se confirma el máximo de cada campo antes de construir: un id, un texto o un teléfono más largo se rechaza. |
Los estados se mapean contra los steps del Funnel. En una cuenta automotriz, el Funnel de Ventas trae estos nueve. El nombre visible de cada step puede cambiar por cuenta; la clave no cambia y es la que usa la API.
| Step del Funnel de Ventas | Quién mueve la SalesCard | Cómo se refleja en el CRM |
|---|---|---|
No Responde ($step_mql$) | Nace aquí al llegar el lead, por cualquier canal o desde el CRM. | Lead nuevo, por asignar o asignado. |
Responde MQL ($step_responded_mql$) | BIKY.ai, cuando el cliente contesta. | Primer contacto registrado como seguimiento. |
Interesado (SQL) ($step_sql$) | BIKY, cuando el cliente califica; o el CRM, si marca el lead en seguimiento. | En seguimiento. |
Agendado ($step_scheduling$) | BIKY o el asesor, al agendar la cita. | Cita o evento creado. |
Show ($step_show$) | BIKY. Una hora después de la cita envía una plantilla de WhatsApp al cliente y al asesor para preguntar si asistió, y mueve la SalesCard con la respuesta. | Visita registrada. |
Demo ($step_test_drive$) | BIKY, cuando la respuesta a esa plantilla indica que hubo prueba de manejo. | Prueba de manejo registrada. |
Pre Venta ($step_won$) | El asesor, con producto, monto y fecha; o el CRM, si reporta la oportunidad ganada. | Sigue en seguimiento; con el CRM de fabricante, sale el pedido de preventa. |
Factura ($step_billed$) | El asesor. Con el CRM de fabricante, el CRM cuando marca la venta. | Venta cerrada. Con el CRM de fabricante, BIKY.ai no la envía, porque allí es irreversible. |
Perdido ($step_lost$) | El asesor con su motivo, o el CRM cuando lo da por perdido. | Perdido, con motivo. |
Un lead que el CRM marca como inválido no mueve la SalesCard: solo se guarda el estado, porque no es una venta perdida. Las cuentas automotrices traen además un Funnel de Posventa (calificado, recibido, diagnóstico, aprobación, en servicio, entrega, pago, seguimiento y no aprobado), disponible para mapearlo con un DMS de taller cuando se necesite.
Sincronización y duplicados
La salida viaja en tiempo real o al cerrar la conversación, según el CRM. La entrada llega por webhook si el CRM lo ofrece y, si no, por consulta periódica, de cada minuto a cada hora. Ninguna integración con CRM usa SFTP ni intercambio automático de archivos.
Lo que dispara un envío al CRM:
- Nace la SalesCard: alta del lead con contacto, origen, modelo y agencia.
- Un contacto del asesor o de BIKY (llamada, correo o WhatsApp): registro de seguimiento.
- Cambio de step en el Funnel: nuevo estado.
- Cita agendada, movida o cancelada: la cita o la prueba de manejo.
- Conversación finalizada: el lead con sus datos completos y su estado.
El histórico se carga una sola vez desde la API del CRM, sin disparar mensajes ni flujos y con la fecha original de cada lead.
Reglas contra duplicados:
- Cada id que devuelve el CRM se guarda en BIKY.ai, y el siguiente evento actualiza ese registro en vez de crear otro.
- La entrada debe ser idempotente: el mismo id de lead o el mismo evento repetido actualiza la SalesCard que ya existe. Los CRM reintentan, y un reintento no debe abrir otra SalesCard.
- Antes de crear un contacto se busca por teléfono normalizado. Si el CRM deduplica por su cuenta, se respeta su regla y se guarda el id que devuelve.
- Una persona con una SalesCard abierta en el Funnel de Ventas no abre otra; un interés distinto sí, si el CRM lo registra como otro lead.
- El lead entra por un solo camino. Si un formulario alimenta a la vez a BIKY.ai y al CRM, el mismo lead nace dos veces.
- Se confirma con el cliente si su CRM crea un registro nuevo en cada envío. Mientras no haya respuesta, solo se envían altas, no ediciones.
Qué necesitamos y cuánto toma
Construir suele ser lo rápido; el plazo lo marcan los insumos y las autorizaciones. En nuestros proyectos de 2025 y 2026, la mitad de las agencias que se sumaron a un CRM ya conectado quedaron listas en menos de dos semanas desde la solicitud. Una integración nueva tomó una mediana de cinco semanas, sin contar la etapa comercial.
Lo que más alarga un proyecto: credenciales que no funcionan, un sandbox distinto de producción, catálogos que llegan tarde, el acuerdo de confidencialidad, la autorización de la marca o del proveedor del CRM y la línea de WhatsApp de cada agencia. Esta es la lista, por fase.
0. Antes de empezar
- Acuerdo de confidencialidad y documentos legales que pida tu empresa.
- Revisión de seguridad, si aplica: contamos con certificación ISO/IEC 27001.
- Autorización de la marca o del proveedor del CRM para cada agencia, si la exige.
1. Descubrimiento
- Documentación vigente de la API: objetos, campos obligatorios, valores permitidos en cada lista (picklist), códigos de error y límites de llamadas.
- Si el CRM avisa por webhook o hay que consultarlo.
- Qué objetos se sincronizan (lead, contacto, oportunidad, cita) y quién es dueño de cada campo.
- Si tu CRM crea un registro nuevo en cada envío o actualiza el existente.
- Si tu CRM también capta leads con sus propios formularios, y cuál de los dos manda.
- Un responsable técnico del lado del cliente o de su integrador.
2. Mapeo
- Catálogo de fuentes y de estados con sus códigos, y cuáles estados son terminales.
- Lista de modelos o productos con su código, y el valor por defecto si el campo es obligatorio.
- Agencias o sucursales con su código en el CRM.
- Ids de los asesores, si el CRM debe recibir quién atiende.
- El largo máximo y el formato de cada campo, incluido el teléfono.
- Reglas propias del CRM: deduplicación, validaciones y asignación automática.
3. Ambiente de pruebas
- Sandbox con credenciales vigentes y la misma versión, los mismos datos de referencia y las mismas agencias que producción.
- Credencial de integración, una por ambiente, con permisos sobre los objetos que vamos a escribir: app conectada (OAuth2 client_credentials) o usuario técnico.
- Leads de prueba acordados: una prueba en producción crea registros reales en tu CRM.
4. Salida en vivo y monitoreo
- Credenciales de producción por el canal seguro que acordemos, nunca por correo, chat ni tickets.
- Aviso previo antes de rotar o desactivar una credencial.
- La línea de WhatsApp de cada agencia, los ids de sus asesores y el calendario de encendido por grupos de agencias.
- Un contacto para incidentes.
Errores frecuentes y monitoreo
Casi todos los rechazos son de datos, no de red: un campo obligatorio vacío, un formato que el CRM no acepta o una regla propia del CRM. Esos no se reintentan, porque se repetirían igual: se corrige el dato o la regla y se reenvía el evento.
| Error | Causa típica | Qué hacemos |
|---|---|---|
| El CRM responde 200 pero rechaza | El motivo viene en el cuerpo de la respuesta; otros CRM responden 201 a un duplicado. | Hay que validar el cuerpo, no solo el código HTTP. Flows marca como falla un 200 con success: false; si el CRM usa otro indicador de error, se valida en el propio flujo. |
| Campo obligatorio vacío | El lead llega sin modelo de interés, producto o correo. | Validaciones antes de enviar y un valor por defecto acordado. Una regla demasiado estricta, como no enviar sin correo, puede frenar todos los leads. |
| Campo más largo de lo permitido | Un id, un texto o un teléfono que excede el campo del CRM. | Se confirma el largo de cada campo en el mapeo. |
| Validación nueva del CRM | El CRM empieza a exigir un campo o un formato sin avisar. | Ante un aumento de rechazos, se revisa qué cambió en el CRM. |
| Agencia sin código | Llega un lead de una agencia que no está en la tabla de equivalencias. | La tabla se valida antes de encender cada agencia. |
| Teléfono inválido | Código de país repetido, un 1 de más o un número truncado. | Normalización antes de enviar; lo irrecuperable queda marcado como inválido y no se envía. |
| Fecha u hora rechazada | Zona horaria, formato, o una prueba de manejo «realizada» con hora futura. | La zona y el formato exactos que pida el CRM, validados antes de enviar. |
| Credencial vencida o rotada | Token expirado, o una credencial desactivada en una rotación. | El token se renueva antes de vencer con su refresh token o se pide de nuevo. |
| Demasiadas llamadas (429) | Las consultas periódicas superan el límite del CRM. | Un intervalo mínimo entre consultas por distribuidor. |
| CRM caído o lento | 5xx o tiempo de espera agotado. | Los servicios dedicados y el robot reintentan con espera creciente. En Flows el reintento se activa por flujo, porque si el CRM no es idempotente puede duplicar. |
| Regla propia del CRM | Una validación del cliente, como no permitir reasignar el propietario. | Se ajusta el envío a la regla, por ejemplo dejando que el CRM asigne el propietario. |
Cómo lo monitoreamos:
- Cada ejecución queda en el historial, con los datos enviados en los nodos de CRM.
- En las integraciones con servicio dedicado y en el robot, un monitor revisa cada 5 minutos. Clasifica cada falla por causa, la muestra en un panel y avisa por correo solo de lo crítico y de lo que se repite.
- Los primeros días después de encender cada agencia la seguimos de cerca. Después, ante cualquier reclamo, conciliamos los leads del CRM contra las SalesCards y conversaciones de BIKY.ai.
Lecciones aprendidas
Casi todo lo que falló se resume en cuatro reglas: guardar el id externo, validar el cuerpo de cada respuesta, confirmar campos y catálogos antes de construir, y probar cada agencia con un lead de prueba antes de encenderla.
- Sale U. El mismo lead llegó repetido muchas veces y cada reenvío abría otra SalesCard.
- Qué cambiamos: depuramos las SalesCards repetidas, y ahora la entrada busca la SalesCard por el id del prospecto antes de crear.
- Qué haríamos distinto: vincular la SalesCard al id del prospecto.
- Sale U. El CRM empezó a validar campos que antes aceptaba, y flujos antiguos fallaron sin cambios de nuestro lado.
- Qué cambiamos: corregimos los campos en los flujos afectados.
- Qué haríamos distinto: avisar cuando suben los rechazos de una integración.
- Sale U. Agencias nuevas sin su regla de reparto: sus leads volvían al CRM sin atender.
- Qué cambiamos: revisión de la tabla de agencias al dar de alta cada cuenta.
- Qué haríamos distinto: probar cada agencia con un lead de prueba antes de encenderla.
- Salesforce. Muchos leads se rechazaban por un campo obligatorio vacío, el modelo de interés.
- Qué cambiamos: pedimos la documentación completa del CRM: campos obligatorios, valores permitidos en cada lista (picklist) y catálogos.
- Qué haríamos distinto: acordar los valores por defecto antes de encender.
- Salesforce. Una regla del CRM impedía reasignar el propietario, y el rechazo no se veía en BIKY.ai.
- Qué cambiamos: encontramos la causa en los registros del conector.
- Qué haríamos distinto: registrar todo rechazo y preguntar por las reglas de validación en el descubrimiento.
- Salesforce. La consulta de ventas ganadas filtraba por fecha de creación y casi nada llegaba; además movía SalesCards del Funnel de Posventa al step ganado (
$step_won$) del Funnel de Ventas.- Qué cambiamos: consulta por última modificación de la oportunidad y filtro por Funnel de Ventas.
- Qué haríamos distinto: probar la consulta contra seis meses de historia antes de encender.
- Salesforce. Los formularios de Meta alimentaban a la vez a BIKY.ai y al CRM, y el lead nacía dos veces.
- Qué cambiamos: los leads entran solo por el CRM.
- Qué haríamos distinto: definir un solo camino de entrada en el descubrimiento.
- Seekop. Al dividir una cuenta en cuentas por agencia, el reparto por nombre de agencia dejó de coincidir y parte de los leads no se envió.
- Qué cambiamos: una sola plantilla compartida, con los datos de cada agencia en variables de entorno, y la integración anterior apagada en el mismo paso.
- Qué haríamos distinto: no repartir por nombres que el cliente puede cambiar.
- HubSpot. El cruce de negocios ganados alcanzaba pocos casos: el id de HubSpot no se guardaba en el contacto y la búsqueda por correo daba falsos positivos.
- Qué cambiamos: diseñamos el cruce solo por id, con el teléfono exacto como respaldo.
- Qué haríamos distinto: guardar el id externo desde el primer envío.
- Zoho. El acceso vencía cada hora porque no se renovaba el token.
- Qué cambiamos: pasamos a un conector que renueva el token solo.
- Qué haríamos distinto: usar siempre el refresh token o un conector que lo maneje.
- Dynamics 365. La llave de suscripción iba en la URL y el gateway la exige en la cabecera; además, un campo del CRM era más corto que nuestro id.
- Qué cambiamos: llave en la cabecera; el cliente amplió el campo.
- Qué haríamos distinto: revisar cabeceras y largos de campo en el mapeo.
- Varias. Algunos CRM exigen datos que BIKY.ai no siempre tiene, como un teléfono con un número exacto de dígitos, el apellido o el producto. Una regla así llegó a frenar todos los leads de un cliente.
- Qué cambiamos: pedimos esas reglas en el descubrimiento.
- Qué haríamos distinto: medir con datos reales cuántos leads cumplen cada regla antes de activarla.
- CRM de fabricante. Marcar la venta cerrada congela el lead en el CRM para siempre.
- Qué cambiamos: BIKY.ai nunca envía ese estado: solo lo lee.
- Qué haríamos distinto: preguntar en el descubrimiento qué estados son irreversibles.
- CRM de fabricante. Un cambio de credenciales del CRM cortó la entrada de leads.
- Qué cambiamos: aviso cuando las consultas fallan de forma sostenida.
- Qué haríamos distinto: acordar aviso previo de cada cambio y su entrega por un canal seguro.
- CRM de fabricante. El sandbox no tenía los datos del distribuidor del proyecto y aceptaba valores que producción rechaza.
- Qué cambiamos: validamos cada campo en el sandbox y lo confirmamos en producción.
- Qué haríamos distinto: pedir desde el inicio un sandbox igual a producción.
- Varias. Teléfonos con el código de país repetido, con un 1 de más o sin código de país hacían nacer contactos inválidos y SalesCards duplicadas.
- Qué cambiamos: normalización del teléfono en los flujos de entrada, con reglas por origen.
- Qué haríamos distinto: acordar el formato del teléfono en el mapeo, objeto por objeto.
Campos y estructura de la API
Campos, valores permitidos y reglas de la API de BIKY.ai para contactos y SalesCards.
Acceso
Cada llamada lleva la llave de la cuenta en la cabecera Authorization: Bearer <llave>. Keybe emite una llave por cuenta y la entrega junto con las URL base de los servicios de Contactos y de Funnels.
{app}: id de la cuenta de BIKY.ai, una por marca o agencia. Va en todas las rutas, salvo la de validar teléfonos.{typeEntity}:people,businessuoffice. Para leads,people.- Un recurso llega como objeto plano; un listado, como
{data, paginator}.paginatortraetotalDocs,limit,page,totalPages,pagingCounter,hasPrevPage,hasNextPage,prevPageynextPage. - Los errores llegan como
{statusCode, timestamp, path, message, error}. En una validación,messagees la lista de campos que fallaron, por ejemplo["responsible should not be empty"].
Contacto y SalesCard
El contacto es la persona; la SalesCard es cada oportunidad de venta de esa persona dentro de un Funnel. Un CRM suele mapear su lead a los dos.
| Contacto | SalesCard | |
|---|---|---|
| Qué es | La persona o empresa, en el CDP de BIKY.ai | Una oportunidad, ubicada en un step de un Funnel |
| Cuántos | Uno por persona; se busca por teléfono o correo | Varias por persona. Con una SalesCard abierta en el Funnel de Ventas no se abre otra, salvo que el CRM registre un lead distinto |
| Su id | uuid | _id |
| Cómo se ligan | No aplica | persons[] lleva el uuid del contacto |
| Id de tu CRM | externalIds[], con systemName y value | utm.sourceCardId o un campo de extendedData |
Endpoints
| Recurso | Endpoint | Qué hace |
|---|---|---|
| Contacts | POST /{app}/contacts | Crea un contacto. |
| Contacts | POST /{app}/contacts/upsert-or-fallback | Crea el contacto o actualiza el que ya tiene ese teléfono o correo. Responde {status, contact}, con status en created, updated o fallback. Con un dato inválido devuelve el contacto comodín de la cuenta y el motivo en reason. |
| Contacts | GET /{app}/contacts/{typeEntity}/phone/{phone} | Busca por teléfono. |
| Contacts | GET /{app}/contacts/{typeEntity}/email/{email} | Busca por correo. |
| Contacts | GET /{app}/contacts/{typeEntity}/{uuid} | Lee un contacto. |
| Contacts | PATCH /{app}/contacts/{uuid} | Actualiza un contacto; typeEntity va en el cuerpo. |
| Contacts | POST /utils/validate-phone | Valida un teléfono con el cuerpo {phone}. |
| Funnels | GET /{app}/funnel/with-steps | Funnels de la cuenta con sus steps. |
| Funnels | GET /{app}/{funnelId}/steps | Steps de un Funnel, con su clave (name), su nombre visible (label) y su orden (order). |
| SalesCards | POST /{app}/funnel/{funnel}/steps/{step}/cards | Crea una SalesCard en un step. |
| SalesCards | POST /{app}/funnel/{funnel}/steps/{step}/cards/upsert | Si la misma persona tiene una SalesCard en ese step creada dentro de la ventana withinHours (1 hora por defecto), la actualiza; si no, crea otra. |
| SalesCards | GET /{app}/cards-filter?person={uuid} | SalesCards de un contacto, de la más nueva a la más vieja. |
| SalesCards | GET /{app}/simple/cards/{id} | Lee una SalesCard. |
| SalesCards | PATCH /{app}/simple/cards/{id} | Actualiza una SalesCard o la mueve de step con stepName. |
| SalesCards | DELETE /{app}/funnel/{funnel}/steps/{step}/cards/{id} | Borra una SalesCard; el borrado es lógico. |
Campos del contacto
| Campo | Tipo | Obligatorio | Significado y valores |
|---|---|---|---|
typeEntity | texto | Sí | people, business u office. |
name | texto | Sí | Nombre. |
surname | texto | No | Apellido. |
phone[] | lista | No | Cada teléfono lleva value con código de país (525500001234), countryCode (52), country (MX), isPrimary y verify. En el alta son obligatorios value, countryCode e isPrimary; en un PATCH, también verify. |
email[] | lista | No | Cada correo lleva value, isPrimary y verify. En el alta son obligatorios value e isPrimary; en un PATCH, también verify. |
registerChannel[] | lista | Sí | channel dice por dónde llegó (api, form, import, web, chatWeb, whatsapp, instagram, facebook, tiktok, email, phone, sms, salesforce, hubspot, rdStation, shopify, vtex, other y otros). data es texto libre con el detalle del origen. |
source | objeto | No | Atribución: utmSource, utmMedium, utmCampaign, utmTerm, utmContent, utmPartner, utmKam, utmCloser, channel y channelOther. |
externalIds[] | lista | No | Ids del contacto en otros sistemas, cada uno como {systemName, value}. En un PATCH, la lista se reemplaza entera, por lo cual se recomienda usarlo junto a isPushData. |
extendedData[] | lista | No | Campos propios de la cuenta: category y field obligatorios, más value, valueArray o valueMultiple. |
documentType, document | texto | No | Tipo y número de documento (passport, nit, curp, rut, dni y otros). |
responsible | objeto | No | Asesor dueño del contacto: uuid y name obligatorios, email y phone opcionales. |
country, province, city, zone | texto | No | Ubicación. |
habeasData | objeto | No | Consentimiento: habeasDataStatus (Confirmed, Unconfirmed, OnlyLegals o Blacklist), aceptación por canal, fecha, IP, país y evidencia. |
tags | lista de texto | No | Etiquetas libres. |
isPushData | booleano | No | Solo en PATCH. Con true, los teléfonos y correos enviados se suman a los que ya tiene; con false, los reemplazan. |
Campos de la SalesCard
| Campo | Tipo | Obligatorio | Significado y valores |
|---|---|---|---|
name | texto | Sí | Título de la SalesCard, por lo general el nombre del lead. |
persons[] | lista de texto | Sí | uuid del contacto. |
responsible | objeto | Sí | Asesor o BIKY a cargo: uuid y name obligatorios, email y phone opcionales. |
description | texto | No | Texto libre que ve el asesor. |
amount | número | No | Monto de la oportunidad. Si llega como texto, se guarda como número. |
productsData[] | lista | No | Producto de interés: id, sku y name obligatorios; precio, enganche, monto financiado, marca y opciones. |
utm | objeto | No | Atribución de la oportunidad, con sourceCardId, el id de la oportunidad en tu CRM. sourceHistory guarda cada source que recibe la SalesCard por cards/upsert. |
extendedData[] | lista | No | Campos propios de la cuenta. |
reason | texto | No | Motivo del cierre, al ganar o perder la oportunidad. |
priority | texto | No | emergency, lowest, low, medium, high o highest. |
schedule | objeto | No | Cita: dataTime, advisor, status y meetingUUID obligatorios; type, location, description y entityUUID opcionales. |
invoiceData | objeto | No | Factura: documento, auto (vin, marca, modelo, versión, año y precio) y cliente. |
stepName | texto | No | Solo en PATCH. Clave del step destino, por ejemplo $step_sql$. |
isPushData | booleano | No | Solo en PATCH. Con true, extendedData se mezcla por field y productsData por id; sin él, los dos se reemplazan enteros. |
Ejemplos
Entre < > va lo que entrega cada cuenta: ids de Funnel, step, asesor y producto.
1. Alta o actualización del contacto. POST /{app}/contacts/upsert-or-fallback. La respuesta es {status, contact}; contact.uuid es el id que se usa en la SalesCard. Con fallback, el motivo llega en reason y conviene no crear la SalesCard hasta corregir el dato.
{
"typeEntity": "people",
"name": "Mariana",
"surname": "Torres",
"phone": [{ "value": "525500001234", "countryCode": "52", "country": "MX", "isPrimary": true }],
"email": [{ "value": "[email protected]", "isPrimary": true }],
"registerChannel": [{ "channel": "api", "data": "MiCRM" }],
"source": { "utmSource": "micrm", "utmCampaign": "lanzamiento-octubre" },
"externalIds": [{ "systemName": "MiCRM_LeadId", "value": "L-000123" }]
}2. Alta de la SalesCard en el primer step. POST /{app}/funnel/{funnel}/steps/{step}/cards. La respuesta trae la SalesCard con su _id.
{
"name": "Mariana Torres",
"persons": ["<uuid del contacto>"],
"responsible": { "uuid": "<uuid del asesor>", "name": "<nombre del asesor>" },
"description": "Lead recibido desde MiCRM.",
"productsData": [{ "id": "<id del producto>", "sku": "<sku>", "name": "<modelo>", "price": 450000 }],
"utm": { "source": "micrm", "campaign": "lanzamiento-octubre", "sourceCardId": "OPP-000456" }
}3. Cambio de step. PATCH /{app}/simple/cards/{id}. Mueve la SalesCard a Interesado (SQL) sin tocar el resto.
{ "stepName": "$step_sql$" }Reglas de la API
| Caso | Qué hace la API | Qué hacer |
|---|---|---|
| Teléfono de México en el alta | 52 + 10 dígitos, 521 + 10 y +52 55 1234 5678 con espacios se guardan como 52 + 10. Con 10 dígitos sin código de país, upsert-or-fallback responde status: fallback y el contacto comodín. | Enviar el teléfono con código de país. Con status: fallback, no crear la SalesCard: corregir el dato y reenviar. |
| Búsqueda por teléfono | 52, 521 y +52 encuentran el mismo contacto; 10 dígitos sin código de país responden 404. | Buscar siempre con el código de país. |
| Contacto que ya existe | upsert-or-fallback con un teléfono existente actualiza ese contacto y responde status: updated. | Usarlo para que el alta desde el CRM no duplique contactos. |
| Teléfonos y correos en un PATCH | Sin verify responde 400. Con isPushData: true se suman; con false, los reemplazan. | Enviar verify: false si no están verificados. |
source y externalIds en un PATCH | Los dos se reemplazan enteros; externalIds: [] los borra. | Enviar la lista completa de externalIds y escribir source solo al crear. |
Alta de SalesCard sin responsible | 400 responsible should not be empty. | Enviar siempre el asesor, o a BIKY si no hay asesor. |
productsData | id, sku o name vacíos: 400. price como texto: 400. | Si el producto no está en el catálogo, crear la SalesCard sin productsData. |
| PATCH de la SalesCard | utm se mezcla. Sin isPushData, extendedData y productsData se reemplazan enteros. stepName mueve la SalesCard. | Usar isPushData: true para agregar sin borrar. |
cards/upsert | Si la persona ya tiene una SalesCard en ese step creada dentro de withinHours, la actualiza. | Usarlo cuando el CRM puede reintentar el envío. |
cards-filter | La paginación empieza en offset=1; search no filtra en este endpoint. | Filtrar por person y comparar utm.sourceCardId. |
| Borrado de SalesCard | El borrado es lógico: sale de cards-filter, aunque su GET por id siga respondiendo. | Confirmar el borrado con cards-filter. |