BIKY.ai se connecte au CRM ou au DMS de chaque marque ou distributeur. Il transmet chaque lead, quel que soit son canal d'arrivée, remonte son avancement (en temps réel ou à la clôture de la conversation, selon le CRM) et reçoit les modifications apportées par le conseiller. Tout s'articule autour de la SalesCard, la fiche BIKY.ai qui conserve le lead, son étape dans le Funnel et l'identifiant que lui attribue le CRM. Ce protocole rassemble ce que nous avons appris de plus de quinze intégrations en Amérique latine.
Comment nous nous connectons
Il existe trois voies, et un CRM peut les combiner : votre CRM nous notifie par webhook, BIKY.ai interroge son API, et les mises à jour d'avancement repartent par cette même API. Chaque identifiant renvoyé par le CRM est enregistré dans la SalesCard ou sur le contact : l'événement suivant met ainsi la fiche à jour au lieu de la dupliquer.
C'est votre CRM qui définit l'authentification : OAuth2 client_credentials avec une application connectée, OAuth2 autorisé par un utilisateur administrateur, jeton à courte durée de vie, clé d'API ou Basic Auth. Les webhooks entrants utilisent une URL unique avec un jeton par flux. Vous pouvez aussi activer le chiffrement du corps de la requête, et Flows vérifie la signature HMAC des plateformes qui en envoient une. Les formulaires web et les fournisseurs de leads passent également par ce chemin. Les formulaires Meta arrivent comme un canal supplémentaire.
Il existe trois variantes. Certaines intégrations reposent sur une plateforme d'intégration (iPaaS), avec des connecteurs OAuth2 autorisés par l'un des utilisateurs administrateurs du client. Lorsque le CRM n'a pas d'API, ou que l'API ne couvre pas un processus, un robot (RPA) utilise son portail web avec des identifiants attribués par le client. Et si votre système ne figure pas dans ce document, BIKY.ai peut envoyer chaque modification de SalesCard au webhook que vous nous indiquez.
Cela fonctionne aussi dans l'autre sens : votre CRM peut appeler l'API BIKY.ai avec la clé de votre compte. Il peut ainsi créer ou rechercher des contacts (par téléphone, e-mail ou identifiant) et créer, consulter ou déplacer des SalesCards entre les étapes d'un Funnel. Des exemples figurent dans les collections Postman de Keybe. Les champs, valeurs autorisées et exemples de cette API sont décrits dans la section Champs et structure de l'API.
Intégrations CRM
Tout transite en HTTPS. Trois éléments changent d'un CRM à l'autre : qui initie l'appel, comment il s'authentifie et quel identifiant évite les doublons. Voici les intégrations qui ont le plus d'historique.
Sale U
- Connexion et authentification : en entrée, par webhook vers une URL unique avec un jeton. En sortie, par API REST avec une clé d'API, ainsi qu'un secret et un horodatage dans le corps de la requête.
- Données échangées : en entrée, le lead attribué : nom, téléphone, e-mail, concession, modèle et identifiant du prospect. En sortie, chaque activité : statut, rendez-vous, note de suivi, verrouillage ou libération, température et clôture.
- Sens et fréquence : en temps réel. Selon la concession, dans les deux sens ou uniquement de BIKY.ai vers Sale U. Chaque concession doit obtenir l'autorisation du fournisseur.
- Prévention des doublons : le contact est recherché par téléphone et la SalesCard par l'identifiant du prospect. Si Sale U renvoie le même lead, la fiche existante est mise à jour.
Salesforce
- Connexion et authentification : API REST (objets standard ou Apex du client), parfois derrière sa propre couche d'intégration. OAuth2 client_credentials avec une application connectée, OAuth2 via un utilisateur administrateur, ou Basic Auth.
- Données échangées : en sortie, le lead avec le contact, le modèle, la source, la concession et le conseiller commercial ; puis le statut et le rendez-vous. En entrée, l'opportunité gagnée ou facturée.
- Sens et fréquence : en sortie, à la clôture de la conversation, à la prise de rendez-vous et à chaque changement de statut. En entrée, par une requête SOQL périodique (par exemple toutes les heures), filtrée sur la date de dernière modification.
- Prévention des doublons : l'identifiant du lead est enregistré sur le contact et les envois suivants le mettent à jour. Si le CRM dédoublonne aussi de son côté, sa règle est respectée.
Seekop / SICOP
- Connexion et authentification : robot (RPA) sur le portail avec l'identifiant de chaque concession. Si la concession dispose d'un accès API, API REST au format ADF avec une clé d'API.
- Données échangées : en entrée, les leads de la file d'attente du CRM. En sortie, le suivi sur la fiche du lead ; par API, le prospect (contact, modèle, source et commentaire) avec sa concession, ainsi que le rendez-vous.
- Sens et fréquence : avec le robot, dans les deux sens : il lit la file toutes les quelques minutes et consigne le suivi sur la fiche du lead. Par API, de BIKY.ai vers Seekop, à la clôture de la conversation et à la prise de rendez-vous.
- Prévention des doublons : le robot utilise l'identifiant du lead dans le CRM et une clé d'idempotence par action. Par API, le contact est marqué comme envoyé.
HubSpot
- Connexion et authentification : connecteur Flows avec OAuth2 autorisé par un utilisateur du client ; dans certains cas, webhook ou iPaaS.
- Données échangées : en sortie, le contact et, selon le cas, une transaction dans un pipeline convenu. La synchronisation entrante des transactions qui atteignent l'étape gagnée a été conçue.
- Sens et fréquence : en sortie, à la clôture de la conversation ou à chaque achat. L'entrée par interrogation périodique (polling) a été conçue.
- Prévention des doublons : upsert du contact. L'enregistrement de son identifiant dans BIKY.ai et le rapprochement sur cet identifiant ont été conçus.
Microsoft Dynamics 365
- Connexion et authentification : API OData publiée par le client ou son intégrateur derrière une passerelle d'API, avec une clé d'abonnement dans l'en-tête.
- Données échangées : en sortie, le lead avec sa campagne ; le rendez-vous est créé puis mis à jour.
- Sens et fréquence : de BIKY.ai vers Dynamics, à la clôture de la conversation et à chaque événement de rendez-vous.
- Prévention des doublons : seuls les nouveaux leads sont envoyés, pas les modifications. L'identifiant du rendez-vous est enregistré sur le contact et les changements lui sont appliqués.
CRM constructeur
- Connexion et authentification : API REST JSON avec un jeton à courte durée de vie ; multipart avec un PDF pour la commande. Pas de webhooks : un service dédié interroge l'API. Ce que l'API ne couvre pas est pris en charge par un robot sur le portail.
- Données échangées : en entrée, les leads et leurs changements de statut, par concession. En sortie, la création de nos propres leads, le suivi, l'essai routier et le bon de précommande.
- Sens et fréquence : en entrée, par interrogation chaque minute, en respectant un intervalle minimal entre deux requêtes pour un même concessionnaire ; en sortie, à chaque événement de la SalesCard.
- Prévention des doublons : le code du lead est enregistré sur la SalesCard ; la création du lead utilise l'identifiant de la SalesCard comme clé d'idempotence.
Autres intégrations réalisées
Certaines n'ont plus de comptes actifs, mais elles peuvent être remises en place.
| Système | Type | Connexion et données |
|---|---|---|
| Tecnom | CRM automobile | Lead au format ADF envoyé en POST à son connecteur web, avec identifiant et mot de passe. |
| Syonet 360 | CRM automobile | Le CRM envoie les leads par webhook ; BIKY.ai consigne appels, visites et rendez-vous via l'API REST en Basic Auth. |
| Intelisis | DMS | Le DMS consomme l'API BIKY.ai et lit les contacts et les SalesCards par leur identifiant. |
| Total Dealer | DMS après-vente | API de rendez-vous. |
| Upnify | CRM | API REST pour les prospects et les rendez-vous, avec un jeton limité à la création de fiches. |
| Odoo | CRM et ERP | Création de contacts et d'opportunités avec leurs UTM. |
| Zoho CRM | CRM | Connecteur avec OAuth2 et renouvellement du jeton ; Zoho notifie par webhook. |
| RD Station CRM | CRM | Connecteur Flows : crée des transactions et les fait avancer entre les étapes de son entonnoir. |
| Smarthome | CRM | API REST en lecture et en écriture. |
| Comunike | CRM | Webhook. |
| SICO | CRM immobilier | Sortie via API REST, avec un identifiant et un mot de passe qui génèrent un jeton valable une heure. |
| Wasi | CRM immobilier | Synchronise l'inventaire des biens avec le catalogue BIKY.ai. |
Flows comprend aussi des nœuds pour les ERP Siigo, Alegra et Defontana, ainsi que pour un DMS après-vente (prise de rendez-vous). Les boutiques en ligne (Shopify, VTEX et WooCommerce) synchronisent leur catalogue et leurs contacts avec BIKY.ai et envoient des notifications pour les paniers abandonnés, les paiements et les modifications de commande. Leurs connecteurs, comme ceux des paiements et des transporteurs, figurent sur la page des intégrations.
Correspondance des données
La correspondance est validée champ par champ avant le développement, et chaque liste fermée (sources, modèles, concessions, statuts) dispose de sa propre table d'équivalence.
| Donnée BIKY.ai | Champ CRM habituel | Règle de correspondance |
|---|---|---|
| Prénom et nom | Prénom, nom | Certaines sources envoient le nom complet dans le champ du nom de famille : il est scindé avant l'envoi. Si le CRM exige un nom de famille et que BIKY.ai n'en dispose pas, la valeur à envoyer est convenue à l'avance. |
| Téléphone mobile | Mobile | Avec l'indicatif pays (52 suivi de 10 chiffres au Mexique), sauf si le CRM ou l'objet exige le numéro national. S'il arrive réparti sur plusieurs champs, la façon de le reconstituer est convenue à l'avance. L'indicatif n'est renseigné que si la source le garantit. |
| Facultatif, sauf si l'objet l'exige. Si le CRM valide le format, un champ vide est omis ; certains CRM refusent les accents ou le ñ. | ||
| Canal et campagne (UTM) | Source, campagne | Traduits selon le catalogue de sources du CRM ; tout ce qui n'a pas d'équivalent est classé dans « Autre ». Chaque valeur va dans son propre champ, sans concaténation. |
| Produit ou modèle d'intérêt | Modèle, finition | Table d'équivalence, avec le code CRM enregistré sur le produit : le rapprochement par nom échoue. Si le champ est obligatoire, une valeur par défaut est convenue. |
| Concession | Code concessionnaire ou point de vente | Table concession → code, validée par rapport aux concessions configurées dans BIKY.ai, et non par rapport au nom commercial. |
| Conseiller commercial attribué | Propriétaire ou conseiller | L'identifiant du conseiller dans le CRM, chargé dans BIKY.ai. Si le CRM attribue selon ses propres règles, il n'est pas envoyé. |
| Étape du Funnel | Statut ou étape | Table d'équivalence bidirectionnelle (exemple ci-dessous). |
| Rendez-vous ou essai routier | Rendez-vous, événement | Dans le fuseau horaire et le format exacts exigés par le CRM, avec début et fin. L'identifiant de chaque rendez-vous est enregistré pour pouvoir le mettre à jour. |
| Identifiant de la fiche dans le CRM | Sans objet | Enregistré sur le contact ou sur la SalesCard, il sert de clé pour chaque mise à jour. |
| Longueur de chaque champ | Sans objet | La longueur maximale de chaque champ est confirmée avant le développement : un identifiant, un texte ou un numéro de téléphone plus long est rejeté. |
Les statuts sont mis en correspondance avec les étapes du Funnel. Dans un compte automobile, le Funnel de vente comprend par défaut les neuf étapes suivantes. Le nom affiché de chaque étape peut varier selon le compte ; la clé, elle, ne change pas, et c'est celle qu'utilise l'API.
| Étape du Funnel de vente | Qui fait avancer la SalesCard | Traduction dans le CRM |
|---|---|---|
Sans réponse ($step_mql$) | La SalesCard est créée ici à l'arrivée du lead, quel que soit le canal, ou depuis le CRM. | Nouveau lead, attribué ou non. |
MQL ayant répondu ($step_responded_mql$) | BIKY.ai, lorsque le client répond. | Premier contact enregistré comme suivi. |
Intéressé (SQL) ($step_sql$) | BIKY, lorsque le client est qualifié, ou le CRM, s'il passe le lead en suivi. | En suivi. |
Rendez-vous planifié ($step_scheduling$) | BIKY ou le conseiller, lorsque le rendez-vous est fixé. | Rendez-vous ou événement créé. |
Présence ($step_show$) | BIKY. Une heure après le rendez-vous, il envoie un modèle WhatsApp au client et au conseiller pour savoir si le client s'est présenté, puis fait avancer la SalesCard selon la réponse. | Visite enregistrée. |
Démo ($step_test_drive$) | BIKY, lorsque la réponse à ce modèle indique qu'un essai a eu lieu. | Essai enregistré. |
Prévente ($step_won$) | Le conseiller, avec le produit, le montant et la date, ou le CRM, s'il signale l'opportunité comme gagnée. | Reste en suivi ; avec le CRM du constructeur, le bon de prévente est envoyé. |
Facturé ($step_billed$) | Le conseiller. Avec le CRM du constructeur, c'est le CRM qui enregistre la vente. | Vente conclue. Avec le CRM du constructeur, BIKY.ai ne l'envoie pas, car l'opération y est irréversible. |
Perdu ($step_lost$) | Le conseiller, avec le motif, ou le CRM, lorsqu'il passe le lead en perdu. | Perdu, avec motif. |
Un lead que le CRM déclare invalide ne fait pas avancer la SalesCard : seul le statut est enregistré, car il ne s'agit pas d'une vente perdue. Les comptes automobiles disposent aussi d'un Funnel après-vente (qualifié, réceptionné, diagnostic, validation, en atelier, livraison, paiement, suivi et non validé), qui peut être relié au DMS d'un atelier si nécessaire.
Synchronisation et doublons
Les données sortantes sont transmises en temps réel ou à la clôture de la conversation, selon le CRM. Les données entrantes arrivent par webhook si le CRM en propose un, sinon par interrogation périodique, à une fréquence allant d'une minute à une heure. Aucune intégration CRM ne passe par SFTP ni par un échange automatique de fichiers.
Ce qui déclenche un envoi vers le CRM :
- La création d'une SalesCard : le lead est créé avec le contact, la source, le modèle et la concession.
- Un contact du conseiller ou de BIKY (appel, e-mail ou WhatsApp) : un enregistrement de suivi.
- Un changement d'étape dans le Funnel : le nouveau statut.
- Un rendez-vous planifié, déplacé ou annulé : le rendez-vous ou l'essai.
- La fin d'une conversation : le lead avec l'ensemble de ses données et son statut.
L'historique est chargé une seule fois depuis l'API du CRM, sans déclencher de messages ni de flux, en conservant la date d'origine de chaque lead.
Règles contre les doublons :
- Chaque id renvoyé par le CRM est enregistré dans BIKY.ai, et l'événement suivant met à jour cet enregistrement au lieu d'en créer un nouveau.
- Les données entrantes doivent être idempotentes : un même id de lead ou un même événement répété met à jour la SalesCard existante. Les CRM relancent leurs envois, et une relance ne doit pas ouvrir une autre SalesCard.
- Avant de créer un contact, on le recherche par numéro de téléphone normalisé. Si le CRM dédoublonne lui-même, sa règle est respectée et l'id qu'il renvoie est enregistré.
- Une personne qui a une SalesCard ouverte dans le Funnel de vente n'en ouvre pas une autre. Un intérêt différent, si, dès lors que le CRM l'enregistre comme un lead distinct.
- Le lead n'entre que par un seul chemin. Si un formulaire alimente à la fois BIKY.ai et le CRM, le même lead est créé deux fois.
- Vérifiez avec le client si son CRM crée un nouvel enregistrement à chaque envoi. Tant qu'il n'y a pas de réponse, seuls les nouveaux enregistrements sont envoyés, pas les modifications.
Ce dont nous avons besoin et combien de temps cela prend
Le développement est généralement la partie la plus rapide. Ce sont les éléments à fournir et les validations qui fixent le calendrier. Dans nos projets de 2025 et 2026, la moitié des concessions ayant rejoint un CRM déjà connecté étaient prêtes en moins de deux semaines après la demande. Une nouvelle intégration a pris cinq semaines en médiane, sans compter la phase commerciale.
Ce qui allonge le plus un projet : des identifiants qui ne fonctionnent pas, un sandbox différent de la production, des catalogues qui arrivent en retard, l'accord de confidentialité, la validation de la marque ou de l'éditeur du CRM, et la ligne WhatsApp de chaque concession. Voici la liste, phase par phase.
0. Avant de commencer
- Accord de confidentialité et tout document juridique exigé par votre entreprise.
- Revue de sécurité, le cas échéant : nous sommes certifiés ISO/IEC 27001.
- Validation de la marque ou de l'éditeur du CRM pour chaque concession, si elle est requise.
1. Découverte
- Documentation à jour de l'API : objets, champs obligatoires, valeurs autorisées pour chaque liste (picklist), codes d'erreur et limites de requêtes.
- Si le CRM envoie des notifications par webhook ou s'il faut l'interroger.
- Les objets synchronisés (lead, contact, opportunité, rendez-vous) et le responsable de chaque champ.
- Si votre CRM crée un nouvel enregistrement à chaque envoi ou met à jour l'existant.
- Si votre CRM capte aussi des leads via ses propres formulaires, et lequel des deux prévaut.
- Un référent technique côté client ou chez son intégrateur.
2. Mapping
- Catalogue des sources et des statuts avec leurs codes, en précisant les statuts finaux.
- Liste des modèles ou produits avec leur code, et la valeur par défaut si le champ est obligatoire.
- Concessions ou agences avec leur code dans le CRM.
- Identifiants des conseillers, si le CRM doit savoir qui traite le lead.
- La longueur maximale et le format de chaque champ, y compris le numéro de téléphone.
- Les règles propres au CRM : dédoublonnage, validations et attribution automatique.
3. Environnement de test
- Sandbox avec des identifiants valides, la même version, les mêmes données de référence et les mêmes concessions que la production.
- Identifiant d'intégration, un par environnement, avec des droits sur les objets dans lesquels nous écrirons : application connectée (OAuth2 client_credentials) ou utilisateur technique.
- Leads de test convenus à l'avance : un test en production crée de vrais enregistrements dans votre CRM.
4. Mise en production et supervision
- Identifiants de production transmis par le canal sécurisé que nous aurons défini, jamais par e-mail, chat ou ticket.
- Un préavis avant de renouveler ou de désactiver un identifiant.
- La ligne WhatsApp de chaque concession, les identifiants de ses conseillers et le calendrier de déploiement par groupe de concessions.
- Un contact pour les incidents.
Erreurs fréquentes et supervision
Presque tous les rejets viennent des données, pas du réseau : un champ obligatoire vide, un format que le CRM n'accepte pas ou une règle propre au CRM. Ils ne sont pas relancés, car ils échoueraient de la même façon. Nous corrigeons plutôt la donnée ou la règle, puis renvoyons l'événement.
| Erreur | Cause habituelle | Ce que nous faisons |
|---|---|---|
| Le CRM répond 200 mais rejette | Le motif figure dans le corps de la réponse ; d'autres CRM répondent 201 à un doublon. | Il faut valider le corps, pas seulement le code HTTP. Flows considère un 200 avec success: false comme un échec ; si le CRM utilise un autre indicateur d'erreur, la validation se fait dans le flux lui-même. |
| Champ obligatoire vide | Le lead arrive sans modèle d'intérêt, sans produit ou sans e-mail. | Des validations avant l'envoi et une valeur par défaut convenue. Une règle trop stricte, comme ne rien envoyer sans e-mail, peut bloquer tous les leads. |
| Champ trop long | Un id, un texte ou un numéro de téléphone qui dépasse la taille du champ dans le CRM. | La longueur de chaque champ est confirmée lors du mapping. |
| Nouvelle validation du CRM | Le CRM se met à exiger un champ ou un format sans prévenir. | Quand les rejets augmentent, nous vérifions ce qui a changé dans le CRM. |
| Concession sans code | Un lead arrive d'une concession absente de la table de correspondance. | La table est validée avant l'activation de chaque concession. |
| Numéro de téléphone invalide | Indicatif pays en double, un 1 en trop ou un numéro tronqué. | Normalisation avant l'envoi ; ce qui ne peut pas être récupéré est marqué comme invalide et n'est pas envoyé. |
| Date ou heure rejetée | Fuseau horaire, format, ou essai marqué « réalisé » avec une heure future. | Le fuseau horaire et le format exacts exigés par le CRM, validés avant l'envoi. |
| Identifiant expiré ou renouvelé | Jeton expiré, ou identifiant désactivé lors d'un renouvellement. | Le jeton est renouvelé avant son expiration grâce à son refresh token, ou demandé à nouveau. |
| Trop de requêtes (429) | Les interrogations périodiques dépassent la limite du CRM. | Un intervalle minimal entre les requêtes pour chaque distributeur. |
| CRM indisponible ou lent | Erreur 5xx ou délai dépassé. | Les services dédiés et le robot relancent avec un délai croissant. Dans Flows, les relances s'activent flux par flux, car si le CRM n'est pas idempotent, elles peuvent créer des doublons. |
| Règle propre au CRM | Une validation du client, comme l'interdiction de réattribuer le propriétaire. | L'envoi est adapté à la règle, par exemple en laissant le CRM attribuer le propriétaire. |
Comment nous le supervisons :
- Chaque exécution est enregistrée dans l'historique, avec les données envoyées dans les nœuds CRM.
- Pour les intégrations avec un service dédié et pour le robot, un moniteur effectue une vérification toutes les 5 minutes. Il classe chaque échec selon sa cause, l'affiche dans un tableau de bord et n'envoie d'alertes par e-mail que pour les problèmes critiques et récurrents.
- Nous suivons de près chaque concession pendant les premiers jours qui suivent son activation. Ensuite, à chaque réclamation, nous rapprochons les leads du CRM des SalesCards et des conversations BIKY.ai.
Leçons apprises
Presque tout ce qui a échoué se ramène à quatre règles : enregistrer l'id externe, valider le corps de chaque réponse, confirmer les champs et les catalogues avant de développer, et tester chaque concession avec un lead de test avant de l'activer.
- Sale U. Le même lead arrivait de nombreuses fois, et chaque renvoi ouvrait une nouvelle SalesCard.
- Ce que nous avons changé : nous avons supprimé les SalesCards en double, et le flux entrant recherche désormais la SalesCard par l'id du prospect avant d'en créer une.
- Ce que nous ferions autrement : lier la SalesCard à l'id du prospect.
- Sale U. Le CRM s'est mis à valider des champs qu'il acceptait auparavant, et d'anciens flux ont échoué sans aucun changement de notre côté.
- Ce que nous avons changé : nous avons corrigé les champs dans les flux concernés.
- Ce que nous ferions autrement : envoyer une alerte dès que les rejets d'une intégration augmentent.
- Sale U. Les nouvelles concessions n'avaient pas de règle d'attribution, si bien que leurs leads repartaient vers le CRM sans être traités.
- Ce que nous avons changé : une revue de la table des concessions à chaque ouverture de nouveau compte.
- Ce que nous ferions autrement : tester chaque concession avec un lead de test avant de l'activer.
- Salesforce. De nombreux leads étaient rejetés à cause d'un champ obligatoire vide : le modèle d'intérêt.
- Ce que nous avons changé : nous avons demandé la documentation complète du CRM : champs obligatoires, valeurs autorisées pour chaque liste (picklist) et catalogues.
- Ce que nous ferions autrement : convenir des valeurs par défaut avant l'activation.
- Salesforce. Une règle du CRM bloquait la réattribution du propriétaire, et le rejet n'était pas visible dans BIKY.ai.
- Ce que nous avons changé : nous avons trouvé la cause dans les journaux du connecteur.
- Ce que nous ferions autrement : journaliser chaque rejet et poser la question des règles de validation dès la découverte.
- Salesforce. La requête des ventes gagnées filtrait par date de création, si bien que presque rien ne remontait. Elle déplaçait aussi des SalesCards du Funnel après-vente vers l'étape gagnée (
$step_won$) du Funnel de vente.- Ce que nous avons changé : la requête utilise désormais la date de dernière modification de l'opportunité et filtre sur le Funnel de vente.
- Ce que nous ferions autrement : tester la requête sur six mois d'historique avant l'activation.
- Salesforce. Les formulaires Meta alimentaient à la fois BIKY.ai et le CRM, si bien que chaque lead était créé deux fois.
- Ce que nous avons changé : les leads n'arrivent désormais que par le CRM.
- Ce que nous ferions autrement : définir un point d'entrée unique dès la phase de découverte.
- Seekop. Lorsqu'un compte a été scindé en comptes distincts par concession, le routage par nom de concession a cessé de correspondre et certains leads n'ont jamais été envoyés.
- Ce que nous avons changé : un modèle unique et partagé, avec les données de chaque concession dans des variables d'environnement, et la désactivation de l'ancienne intégration au cours de la même étape.
- Ce que nous ferions autrement : ne jamais router selon des noms que le client peut modifier.
- HubSpot. Le rapprochement des affaires gagnées ne détectait que quelques cas : l'id HubSpot n'était pas enregistré sur le contact, et les recherches par e-mail produisaient des faux positifs.
- Ce que nous avons changé : nous avons conçu le rapprochement pour qu'il repose uniquement sur l'id, avec le numéro de téléphone exact en solution de repli.
- Ce que nous ferions autrement : enregistrer l'id externe dès le tout premier envoi.
- Zoho. L'accès expirait toutes les heures, faute de rafraîchissement du jeton.
- Ce que nous avons changé : nous sommes passés à un connecteur qui rafraîchit le jeton de lui-même.
- Ce que nous ferions autrement : toujours utiliser le refresh token ou un connecteur qui le gère.
- Dynamics 365. La clé d'abonnement était envoyée dans l'URL, alors que la passerelle l'exige dans l'en-tête. De plus, un champ du CRM était plus court que notre id.
- Ce que nous avons changé : la clé passe désormais dans l'en-tête, et le client a allongé le champ.
- Ce que nous ferions autrement : vérifier les en-têtes et la longueur des champs lors du mapping.
- Plusieurs CRM. Certains CRM exigent des données dont BIKY.ai ne dispose pas toujours, comme un numéro de téléphone comportant un nombre exact de chiffres, le nom de famille ou le produit. Une règle de ce type a fini par bloquer tous les leads d'un client.
- Ce que nous avons changé : nous demandons ces règles dès la phase de découverte.
- Ce que nous ferions autrement : mesurer, avec des données réelles, combien de leads respectent chaque règle avant de l'activer.
- CRM du constructeur. Marquer une vente comme conclue fige définitivement le lead dans le CRM.
- Ce que nous avons changé : BIKY.ai n'envoie jamais ce statut. Il se contente de le lire.
- Ce que nous ferions autrement : demander, lors de la découverte, quels statuts sont irréversibles.
- CRM du constructeur. Un changement des identifiants du CRM a interrompu l'arrivée des leads.
- Ce que nous avons changé : une alerte lorsque les requêtes échouent de manière répétée dans le temps.
- Ce que nous ferions autrement : convenir d'un préavis pour chaque changement et d'une transmission des nouveaux identifiants par un canal sécurisé.
- CRM du constructeur. Le sandbox ne contenait pas les données du distributeur du projet, et il acceptait des valeurs que la production rejette.
- Ce que nous avons changé : nous validons chaque champ dans le sandbox, puis le confirmons en production.
- Ce que nous ferions autrement : demander dès le départ un sandbox identique à la production.
- Plusieurs CRM. Des numéros de téléphone avec un indicatif pays en double, un 1 en trop ou sans indicatif pays créaient des contacts invalides et des SalesCards en double.
- Ce que nous avons changé : une normalisation des téléphones dans les flux entrants, avec des règles par source.
- Ce que nous ferions autrement : convenir du format de téléphone lors du mapping, objet par objet.
Champs et structure de l'API
Champs, valeurs autorisées et règles de l'API BIKY.ai pour les contacts et les SalesCards.
Accès
Chaque appel transmet la clé du compte dans l'en-tête Authorization: Bearer <key>. Keybe émet une clé par compte et la fournit avec les URL de base des services Contacts et Funnels.
{app}: l'id du compte BIKY.ai, un par marque ou par concession. Il figure dans tous les chemins, sauf celui de la validation du téléphone.{typeEntity}:people,businessouoffice. Pour les leads, utilisezpeople.- Une ressource unique est renvoyée sous forme d'objet simple. Une liste est renvoyée sous la forme
{data, paginator}.paginatorcontienttotalDocs,limit,page,totalPages,pagingCounter,hasPrevPage,hasNextPage,prevPageetnextPage. - Les erreurs sont renvoyées sous la forme
{statusCode, timestamp, path, message, error}. Dans une erreur de validation,messagecorrespond à la liste des champs en échec, par exemple["responsible should not be empty"].
Contact et SalesCard
Le contact, c'est la personne. La SalesCard, c'est chaque opportunité de vente de cette personne au sein d'un Funnel. Un CRM associe généralement son lead aux deux.
| Contact | SalesCard | |
|---|---|---|
| Ce que c'est | La personne ou l'entreprise, dans le CDP de BIKY.ai | Une opportunité, placée dans une étape d'un Funnel |
| Combien | Un par personne ; recherché par téléphone ou par e-mail | Plusieurs par personne. Tant qu'une SalesCard est ouverte dans le Sales Funnel, aucune autre n'est ouverte, sauf si le CRM enregistre un lead différent |
| Son id | uuid | _id |
| Comment ils sont liés | Sans objet | persons[] contient l'uuid du contact |
| L'id de votre CRM | externalIds[], avec systemName et value | utm.sourceCardId ou un champ extendedData |
Endpoints
| Ressource | Endpoint | Rôle |
|---|---|---|
| Contacts | POST /{app}/contacts | Crée un contact. |
| Contacts | POST /{app}/contacts/upsert-or-fallback | Crée le contact ou met à jour celui qui possède déjà ce téléphone ou cet e-mail. Répond avec {status, contact}, où status vaut created, updated ou fallback. En cas de données invalides, renvoie le contact de repli du compte et le motif dans reason. |
| Contacts | GET /{app}/contacts/{typeEntity}/phone/{phone} | Recherche par téléphone. |
| Contacts | GET /{app}/contacts/{typeEntity}/email/{email} | Recherche par e-mail. |
| Contacts | GET /{app}/contacts/{typeEntity}/{uuid} | Lit un contact. |
| Contacts | PATCH /{app}/contacts/{uuid} | Met à jour un contact ; typeEntity se place dans le corps. |
| Contacts | POST /utils/validate-phone | Valide un téléphone avec le corps {phone}. |
| Funnels | GET /{app}/funnel/with-steps | Les Funnels du compte, avec leurs étapes. |
| Funnels | GET /{app}/{funnelId}/steps | Les étapes d'un Funnel, avec leur clé (name), leur nom d'affichage (label) et leur ordre (order). |
| SalesCards | POST /{app}/funnel/{funnel}/steps/{step}/cards | Crée une SalesCard dans une étape. |
| SalesCards | POST /{app}/funnel/{funnel}/steps/{step}/cards/upsert | Si la même personne possède, dans cette étape, une SalesCard créée dans la fenêtre withinHours (1 heure par défaut), la met à jour ; sinon, en crée une nouvelle. |
| SalesCards | GET /{app}/cards-filter?person={uuid} | Les SalesCards d'un contact, de la plus récente à la plus ancienne. |
| SalesCards | GET /{app}/simple/cards/{id} | Lit une SalesCard. |
| SalesCards | PATCH /{app}/simple/cards/{id} | Met à jour une SalesCard ou la déplace vers une autre étape avec stepName. |
| SalesCards | DELETE /{app}/funnel/{funnel}/steps/{step}/cards/{id} | Supprime une SalesCard ; il s'agit d'une suppression logique (soft delete). |
Champs du contact
| Champ | Type | Obligatoire | Signification et valeurs |
|---|---|---|---|
typeEntity | texte | Oui | people, business ou office. |
name | texte | Oui | Prénom. |
surname | texte | Non | Nom de famille. |
phone[] | liste | Non | Chaque téléphone comporte value avec l'indicatif pays (525500001234), countryCode (52), country (MX), isPrimary et verify. À la création, value, countryCode et isPrimary sont obligatoires ; lors d'un PATCH, verify l'est également. |
email[] | liste | Non | Chaque e-mail comporte value, isPrimary et verify. À la création, value et isPrimary sont obligatoires ; lors d'un PATCH, verify l'est également. |
registerChannel[] | liste | Oui | channel indique la provenance du contact (api, form, import, web, chatWeb, whatsapp, instagram, facebook, tiktok, email, phone, sms, salesforce, hubspot, rdStation, shopify, vtex, other, entre autres). data est un texte libre qui précise la source. |
source | objet | Non | Attribution : utmSource, utmMedium, utmCampaign, utmTerm, utmContent, utmPartner, utmKam, utmCloser, channel et channelOther. |
externalIds[] | liste | Non | Les id du contact dans d'autres systèmes, chacun sous la forme {systemName, value}. Lors d'un PATCH, la liste entière est remplacée : nous recommandons donc de l'utiliser avec isPushData. |
extendedData[] | liste | Non | Champs propres au compte : category et field sont obligatoires, ainsi que value, valueArray ou valueMultiple. |
documentType, document | texte | Non | Type et numéro de pièce d'identité (passport, nit, curp, rut, dni, entre autres). |
responsible | objet | Non | Conseiller responsable du contact : uuid et name obligatoires, email et phone facultatifs. |
country, province, city, zone | texte | Non | Localisation. |
habeasData | objet | Non | Consentement : habeasDataStatus (Confirmed, Unconfirmed, OnlyLegals ou Blacklist), acceptation par canal, date, adresse IP, pays et preuves. |
tags | liste de textes | Non | Étiquettes libres. |
isPushData | booléen | Non | PATCH uniquement. Avec true, les téléphones et e-mails envoyés s'ajoutent à ceux existants ; avec false, ils les remplacent. |
Champs de la SalesCard
| Champ | Type | Obligatoire | Signification et valeurs |
|---|---|---|---|
name | texte | Oui | Titre de la SalesCard, généralement le nom du lead. |
persons[] | liste de textes | Oui | Le uuid du contact. |
responsible | objet | Oui | Conseiller ou BIKY en charge : uuid et name obligatoires, email et phone facultatifs. |
description | texte | Non | Texte libre visible par le conseiller. |
amount | nombre | Non | Montant de l'opportunité. S'il arrive sous forme de texte, il est enregistré comme nombre. |
productsData[] | liste | Non | Produit d'intérêt : id, sku et name obligatoires ; prix, apport, montant financé, marque et options. |
utm | objet | Non | Attribution de l'opportunité, avec sourceCardId, l'identifiant de l'opportunité dans votre CRM. sourceHistory conserve chaque source que la SalesCard reçoit via cards/upsert. |
extendedData[] | liste | Non | Champs propres au compte. |
reason | texte | Non | Motif de clôture, lorsque l'opportunité est gagnée ou perdue. |
priority | texte | Non | emergency, lowest, low, medium, high ou highest. |
schedule | objet | Non | Rendez-vous : dataTime, advisor, status et meetingUUID obligatoires ; type, location, description et entityUUID facultatifs. |
invoiceData | objet | Non | Facture : document, véhicule (vin, marque, modèle, finition, année et prix) et client. |
stepName | texte | Non | PATCH uniquement. Clé de l'étape cible, par exemple $step_sql$. |
isPushData | booléen | Non | PATCH uniquement. Avec true, extendedData est fusionné par field et productsData par id ; sans ce paramètre, les deux sont entièrement remplacés. |
Exemples
Les valeurs entre < > sont propres à chaque compte : identifiants du Funnel, de l'étape, du conseiller et du produit.
1. Créer ou mettre à jour le contact. POST /{app}/contacts/upsert-or-fallback. La réponse est {status, contact} ; contact.uuid est l'identifiant utilisé dans la SalesCard. Avec fallback, le motif figure dans reason : ne créez pas la SalesCard tant que les données n'ont pas été corrigées.
{
"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. Créer la SalesCard dans la première étape. POST /{app}/funnel/{funnel}/steps/{step}/cards. La réponse renvoie la SalesCard avec son _id.
{
"name": "Mariana Torres",
"persons": ["<contact uuid>"],
"responsible": { "uuid": "<advisor uuid>", "name": "<advisor name>" },
"description": "Lead received from MiCRM.",
"productsData": [{ "id": "<product id>", "sku": "<sku>", "name": "<model>", "price": 450000 }],
"utm": { "source": "micrm", "campaign": "lanzamiento-octubre", "sourceCardId": "OPP-000456" }
}3. Changement d'étape. PATCH /{app}/simple/cards/{id}. Fait passer la SalesCard à l'étape Intéressé (SQL) sans rien modifier d'autre.
{ "stepName": "$step_sql$" }Règles de l'API
| Cas | Ce que fait l'API | Que faire |
|---|---|---|
| Téléphone mexicain à la création | 52 + 10 chiffres, 521 + 10 et +52 55 1234 5678 avec des espaces sont enregistrés sous la forme 52 + 10. Avec 10 chiffres sans indicatif pays, upsert-or-fallback répond status: fallback et renvoie le contact de repli. | Envoyez le téléphone avec l'indicatif pays. Avec status: fallback, ne créez pas la SalesCard : corrigez les données et renvoyez-les. |
| Recherche par téléphone | 52, 521 et +52 trouvent le même contact ; 10 chiffres sans indicatif pays renvoient une erreur 404. | Recherchez toujours avec l'indicatif pays. |
| Contact existant | upsert-or-fallback avec un téléphone existant met à jour ce contact et répond status: updated. | Utilisez-le pour que la création depuis le CRM ne duplique pas les contacts. |
| Téléphones et e-mails dans un PATCH | Sans verify, l'API renvoie une erreur 400. Avec isPushData: true, ils sont ajoutés ; avec false, ils remplacent les existants. | Envoyez verify: false s'ils ne sont pas vérifiés. |
source et externalIds dans un PATCH | Les deux sont entièrement remplacés ; externalIds: [] les supprime. | Envoyez la liste externalIds complète et n'écrivez source qu'à la création. |
Création de SalesCard sans responsible | 400 responsible should not be empty. | Envoyez toujours le conseiller, ou BIKY s'il n'y a pas de conseiller. |
productsData | id, sku ou name vide : 400. price sous forme de texte : 400. | Si le produit ne figure pas au catalogue, créez la SalesCard sans productsData. |
| PATCH de SalesCard | utm est fusionné. Sans isPushData, extendedData et productsData sont entièrement remplacés. stepName déplace la SalesCard. | Utilisez isPushData: true pour ajouter sans supprimer. |
cards/upsert | Si la personne possède déjà une SalesCard dans cette étape, créée dans le délai withinHours, l'API la met à jour. | Utilisez-le lorsque le CRM est susceptible de relancer l'envoi. |
cards-filter | La pagination commence à offset=1 ; search ne filtre pas sur cet endpoint. | Filtrez par person et comparez utm.sourceCardId. |
| Suppression de SalesCard | La suppression est logique (soft delete) : la SalesCard disparaît de cards-filter, même si son GET par identifiant répond toujours. | Confirmez la suppression avec cards-filter. |