Connecter Swimlane à votre CRM avec les webhooks et l’API
Le contrat webhook exact de Swimlane, sa signature, ses tentatives, et comment le recevoir dans HubSpot, Salesforce ou Pipedrive via n8n, Make ou votre code.
Par Swimlane Mis à jour le 14 septembre 2026 10 min de lecture
Une intégration webhook CRM ne vaut que par ce que vous savez de ce que l’expéditeur envoie vraiment. Swimlane n’a pas de synchronisation native avec HubSpot, Salesforce ou Pipedrive. Il vous donne trois webhooks contact signés, une API REST publique, et fonctionne avec n8n et Make. Ce guide documente le contrat exact, puis montre comment le recevoir dans chaque CRM sans créer de doublons.
Ce qu’il faut synchroniser, et ce qui reste dans Swimlane
Tranchez ce point avant d’écrire la moindre ligne de code. La conversation LinkedIn, ses notes et ses rappels restent dans Swimlane, à côté de la messagerie. Votre CRM a besoin de connaître une personne, puis plus tard une opportunité. Deux mécanismes couvrent ce besoin :
- Les webhooks (push) vous signalent qu’un contact a été créé, modifié ou supprimé, en une minute environ.
- L’API (pull) vous donne tout le reste sur ce contact : titre, entreprise, tags, étape de pipeline.
Les intégrations les plus solides utilisent les deux : le webhook comme déclencheur, l’API comme source du détail.
Les trois événements webhook
Swimlane envoie exactement trois événements, plus un test.
contact.created: un contact est ajouté à votre espace de travail, qu’il soit importé, créé à partir d’une conversation ou ajouté à la main.contact.updated: les champs propres d’un contact changent, par une modification dans l’application ou quand un import ou la synchronisation des conversations apporte de nouvelles valeurs pour un contact existant. Il ne se déclenche pas sur les modifications en masse, les actualisations de profil LinkedIn, les tags, les listes, les changements d’étape, les messages, les réponses ni les changements de connexion.contact.deleted: un contact est supprimé individuellement. Les suppressions en masse n’envoient rien.test: envoyé à la création d’un webhook ou quand vous cliquez sur « Tester le webhook ».
Il n’existe aucun événement pour une réponse, un tag, un changement d’étape ou une invitation acceptée, et un webhook ne se filtre pas par liste ou par tag : il reçoit tous les événements cochés de l’espace de travail.
Deux faits de livraison déterminent votre récepteur :
- Délai. Les événements sont mis en file et un processus les livre une fois par minute. Comptez jusqu’à une minute environ.
- Une livraison par webhook de membre. Un événement part vers chaque membre de l’organisation à laquelle appartient le contact, et chaque webhook actif de chaque membre reçoit sa propre copie. Si trois collègues pointent chacun un webhook vers la même URL, vous recevez trois livraisons. Confiez le webhook CRM à une seule personne.
Le contenu envoyé
Chaque livraison est un POST avec un corps JSON et ces en-têtes :
Content-Type: application/jsonX-Webhook-Event: le nom de l’événementX-Webhook-Timestamp: une date ISO 8601X-Webhook-Signature: présent seulement si le webhook a une clé secrète
{
"event": "contact.updated",
"timestamp": "2026-09-14T09:12:03.412+00:00",
"data": {
"contactId": 4821,
"uuid": "3f0c5b1e-8d2a-4c1e-9f5b-2a7d6e1c9b40",
"firstName": "Jeanne",
"lastName": "Martin",
"email": null,
"linkedinId": "jeanne-martin-42",
"changes": ["headline", "email"]
}
}
uuidest l’identifiant stable, celui qu’utilise l’API publique. Indexez votre CRM dessus.contactIdest interne. Ignorez-le.linkedinIdest l’identifiant public du profil : construisezhttps://www.linkedin.com/in/<linkedinId>.firstName,lastNameetemailpeuvent valoirnull. La plupart des contacts LinkedIn n’ont pas d’e-mail.changesn’existe que surcontact.updated. Il liste les noms des champs soumis, pas les anciennes et nouvelles valeurs, et peut citer des champs dont la valeur n’a pas changé.
Absents du contenu : entreprise, titre, localisation, niveau d’ICP, tags, listes, étape de pipeline, messages.
Configurer un webhook dans Swimlane
Allez dans Paramètres > Webhooks et cliquez sur « Ajouter un webhook ».
- URL du webhook. Un point d’accès HTTPS que vous contrôlez, ou l’URL de webhook d’un workflow n8n ou Make.
- Événements. Cochez-en au moins un.
- Nombre maximum de tentatives. De 1 à 5, 1 par défaut. C’est le nombre total d’essais : 1 signifie aucune nouvelle tentative. Mettez 5 pour un CRM.
- Générer une clé secrète. Désactivé par défaut : cochez-le. La clé n’est affichée qu’une fois, enregistrez-la tout de suite. La modification du webhook propose « Régénérer la clé secrète ».
La création du webhook envoie immédiatement un événement test. La liste propose ensuite « Tester le webhook » et un interrupteur d’activation. Swimlane n’affiche aucun historique de livraison : journalisez ce que vous recevez de votre côté.
Vérifier la signature
La signature est un HMAC-SHA256 du corps exact de la requête, calculé avec votre clé secrète, envoyé en hexadécimal minuscule sans préfixe sha256=. L’horodatage fait partie du corps signé, vous pouvez donc aussi rejeter les livraisons trop anciennes. Chaque nouvelle tentative est resignée avec un horodatage neuf : les tentatives légitimes passent.
import crypto from 'node:crypto'
import express from 'express'
const app = express()
app.post('/swimlane', express.raw({type: 'application/json'}), async (req, res) => {
const expected = crypto
.createHmac('sha256', process.env.SWIMLANE_WEBHOOK_SECRET)
.update(req.body)
.digest('hex')
const received = req.get('X-Webhook-Signature') ?? ''
const valid =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))
if (!valid) return res.status(401).end()
const event = JSON.parse(req.body.toString('utf8'))
if (Date.now() - Date.parse(event.timestamp) > 5 * 60 * 1000) return res.status(401).end()
if (event.event === 'test') return res.status(200).end()
await saveForProcessing(event) // une file ou une table : l'appel au CRM se fait ensuite
res.status(202).end()
})
Vérifiez sur les octets bruts partout où votre outil le permet. Dans n8n, où le nœud Webhook vous remet du JSON déjà analysé, recalculez le HMAC sur JSON.stringify du corps : Swimlane signe la sortie compacte de JSON.stringify, ce qui reproduit les mêmes octets. Si un outil ne peut pas vérifier la signature du tout, traitez son URL de webhook comme un secret et relisez le contact via l’API avant d’écrire quoi que ce soit. Un faux événement ne fait alors que chercher un contact qui n’existe pas.
Swimlane ne publie pas de liste d’adresses IP d’envoi : une liste blanche d’IP n’est pas une option. La signature est le contrôle.
Tentatives, ordre et idempotence
- Un succès est toute réponse 2xx en moins de 30 secondes. Tout le reste, ou un dépassement de délai, est un échec.
- Les nouvelles tentatives suivent un délai de 15 s, 30 s, 60 s puis 120 s, jusqu’à votre « Nombre maximum de tentatives ». Comme le processus tourne une fois par minute, les écarts réels s’arrondissent à la minute. Après le dernier essai, la livraison est marquée en échec et abandonnée.
- Les doublons arrivent : une nouvelle tentative après un dépassement de délai en plein traitement, ou plusieurs webhooks de membres sur la même URL. Le corps change d’un essai à l’autre, vous ne pouvez donc pas dédoublonner sur son empreinte.
- L’ordre n’est pas garanti. Ne supposez pas que
createdarrive avantupdated.
Rendez donc chaque écriture idempotente :
contact.created: cherchez l’uuid Swimlane dans le CRM, créez seulement si rien n’est trouvé.contact.updated: mettez à jour si la fiche existe, créez-la sinon. Vous avez peut-être manqué la création.contact.deleted: archivez ou marquez la fiche CRM. Ne supprimez pas un historique commercial parce que quelqu’un a nettoyé une liste.
Enrichir les événements avec l’API publique
Créez un jeton dans Paramètres > API. La même page affiche l’hôte de l’API et renvoie vers la documentation Swagger. Envoyez-le en Authorization: Bearer wpa_… ; chaque jeton dispose de 100 requêtes par minute.
GET /v1/contacts/:uuidrenvoie le contact avecheadline,location,linkedinId,companyUuids,listUuids,tagIdsetpipelineStageUuid.GET /v1/companies/:uuiddonne le nom de l’entreprise pour le champ société de votre CRM.GET /v1/tagsfait correspondre les identifiants de tags à leurs noms ;GET /v1/pipelinesetGET /v1/pipelines/:uuid/stagesfont de même pour les étapes.
Tirer plutôt que pousser : synchroniser sur un tag
Comme aucun webhook ne se déclenche sur les tags, les étapes ou les réponses, « envoyer cette personne au CRM » s’exprime au mieux par un tag qu’un workflow planifié vient lire :
- Taguez le contact « to-crm », à la main depuis la conversation ou avec une étape « Ajouter un tag » placée sous une condition « A répondu au message » dans une campagne.
- Toutes les 15 minutes, n8n ou Make appelle
GET /v1/contacts?tag_id=<id>&per_page=100. - Créez ou mettez à jour chaque contact dans le CRM.
- Seulement une fois l’appel au CRM réussi, appelez
POST /v1/contacts/:uuid/tagsavec les tags à conserver. L’appel remplace l’ensemble des tags : envoyez lestagIdsactuels sans « to-crm », plus « in-crm » si vous l’utilisez.
L’API fonctionne aussi dans l’autre sens : quand le CRM marque une affaire gagnée, POST /v1/pipelines/stages/:stageUuid/contacts place le contact dans votre étape Terminé sur Swimlane, sur tout pipeline visible par le propriétaire du jeton. Le flow qui transmet les réponses à votre CRM avec n8n construit tout cela de bout en bout, et les guides de configuration de n8n et de configuration de Make couvrent la connexion elle-même.
HubSpot
Le déclencheur de workflow « When a webhook is received » de HubSpot est réservé à Data Hub Professional et Enterprise, et il n’inscrit que des fiches qui existent déjà, retrouvées par une propriété à valeurs uniques. Il peut mettre à jour des contacts déjà synchronisés ; il ne peut pas en créer. Pour contact.created, passez par n8n ou Make, qui ont tous deux des modules HubSpot, ou par votre propre point d’accès qui appelle l’API HubSpot.
- Créez une propriété personnalisée pour l’uuid Swimlane, avec valeurs uniques obligatoires, et cherchez dessus avant de créer.
firstName→firstname,lastName→lastname.email→emailseulement s’il ne vaut pasnull.- L’URL LinkedIn va dans une propriété personnalisée.
- Le titre et le nom de l’entreprise viennent de l’appel à l’API, pas du contenu du webhook.
Salesforce
Salesforce n’accepte pas de POST non authentifié dans ses objets, et Swimlane n’envoie aucun jeton OAuth. Utilisez un intermédiaire (n8n et Make se connectent tous deux à Salesforce), ou exposez une classe Apex REST via un Salesforce Site public qui vérifie la signature avant d’écrire.
- Ajoutez un champ texte
Swimlane_UUID__cmarqué External ID et unique sur Lead ou Contact, et faites un upsert dessus pour qu’aucun doublon ne puisse se former. - Un Lead exige
LastNameetCompany, et le contenu ne garantit ni l’un ni l’autre. Rabattez-vous sur lelinkedinIdpour le nom et récupérez l’entreprise via l’API, avec une valeur par défaut si elle est inconnue.
Pipedrive
Les webhooks de Pipedrive partent de Pipedrive ; rien à l’intérieur ne peut recevoir les appels de Swimlane. Passez par n8n, Make ou votre propre point d’accès qui appelle l’API Pipedrive.
- Stockez l’uuid dans un champ personnalisé texte de la personne et recherchez les personnes sur ce champ avant de créer.
- Une personne a besoin d’un nom : assemblez prénom et nom, ou rabattez-vous sur le
linkedinId. - Rattachez l’organisation à partir du nom d’entreprise renvoyé par l’API.
- Créez les affaires depuis le workflow par tag ou par étape décrit plus haut, pas sur
contact.created, sinon chaque commentateur importé devient une affaire.
Liste de vérification
- L’événement
testreçoit une réponse 2xx et ne touche jamais le CRM. - Une mauvaise clé secrète reçoit une 401.
- Le même événement livré deux fois laisse une seule fiche CRM.
- Un
contact.updatedpour un uuid inconnu crée la fiche. - Un
contact.deletedarchive au lieu de supprimer. - Avec un « Nombre maximum de tentatives » à 5, un point d’accès indisponible pendant une minute reçoit quand même l’événement.
La page équipe et API résume tout ce que l’espace de travail expose aux autres outils.