GoHighLevel
Capture des leads depuis les formulaires GHL, opportunités et événements de calendrier via un webhook workflow — pas-à-pas avec captures d'écran.
Configuration
Crée un workflow GHL avec un trigger (Form Submitted, Contact Created, Calendar Booked) et l'action Webhook native.
Créer un workflow GHL
Dans GoHighLevel, va dans Automation > Workflows et clique Create Workflow. Choisis le trigger (Form Submitted, Contact Created, Calendar Booked — selon ce qui doit pousser le lead vers Capturia).

Ajouter l'action Webhook
Comme action, choisis Webhook. C'est l'action native qui permet d'appeler une URL externe avec un payload custom. Ne pas confondre avec Make HTTP Request (action plus restreinte).

Configurer URL et méthode
URL : https://app.capturia.io/api/v1/leads/capture
Method : POST
Encoding : JSON (option en haut du modal)
Custom Headers : ajoute une ligne Authorization avec valeur Bearer cap_live_xxxxxxxx.

Construire le payload
Dans Custom Data, ajoute des paires clé/valeur (GHL serialise en JSON automatiquement quand Encoding=JSON). Utilise les Custom Values GHL ({{contact.phone}}, {{contact.first_name}}, etc.) pour les valeurs.
Exemple :
phone→{{contact.phone}}first_name→{{contact.first_name}}last_name→{{contact.last_name}}email→{{contact.email}}sms_consent→true(valeur fixe — voir l'étape 5)source_label→ghl_workflow

Capturer le consentement SMS
Recommandé : crée un Custom Field GHL de type "Checkbox" intitulé SMS Consent, ajoute-le au formulaire de capture, puis ajoute une condition If/Else dans le workflow (« SMS Consent is checked »). Dans la branche cochée seulement, place l'action Webhook avec sms_consent → true (valeur fixe).
Si le client a déjà un Custom Field différent (ex. Marketing Opt-in), utiliser celui-ci dans la condition. Hardcoder sms_consent: true sans condition n'est acceptable que si le formulaire en amont a une attestation explicite documentée.

Tester et publier
Sélectionne d'abord un contact de test portant ton propre cellulaire et un courriel de test, puis clique Test Webhook dans le modal d'action : GHL envoie le payload à Capturia avec les valeurs de ce contact. Une réponse 200 = un vrai lead créé dans Capturia — il n'existe pas de mode d'essai : la fiche apparaît dans Leads et l'agent SMS texte le numéro envoyé si le consentement est en ordre. Archive la fiche de test une fois la vérification faite, puis sauvegarde le workflow et bascule-le sur Publish.

Mapping des champs
Le mapping ci-dessous utilise les Custom Values GHL pour les valeurs dynamiques. Adapter selon les Custom Fields disponibles côté client.
| Champ Capturia | Obligatoire | Champ source | Notes |
|---|---|---|---|
| phone | Oui | {{contact.phone}} | E.164 (+15145551234), NANP 10 ou 11 chiffres, ou formattés (514) 555-1234 / 514-555-1234. Les 10 chiffres sont auto-préfixés +1. |
| sms_consent | Oui | true (valeur fixe, derrière la condition de l'étape 5) | Boolean true OU string 'true' / 'yes' / 'oui' / 'vrai' / '1' / 'on' / 'checked' (insensible à la casse). Accepté à la racine du body ou dans l'objet `customData` (webhooks GoHighLevel). |
| first_name | Non | {{contact.first_name}} | Prénom du lead |
| last_name | Non | {{contact.last_name}} | Nom de famille |
| Non | {{contact.email}} | Email valide RFC 5322 | |
| source_label | Non | "ghl_workflow" | Étiquette libre (ex. 'webflow_form', 'fb_lead_ads') |
| utm.source | Non | (non supporté nativement) | Objet utm imbriqué (pas flat) |
| utm.medium | Non | (non supporté nativement) | Objet utm imbriqué |
| utm.campaign | Non | (non supporté nativement) | Objet utm imbriqué |
| tags | Non | "tag1, tag2" ou [] | Tableau de strings |
| pipeline.id | Non | (optionnel) | UUID du pipeline cible |
| pipeline.stage_id | Non | (optionnel) | UUID du stage cible |
Consentement SMS — LCAP / Loi 25
Le champ sms_consent est obligatoire. La loi canadienne anti-pourriel (LCAP/CASL) et la Loi 25 québécoise exigent un consentement explicite avant tout SMS commercial. Capturia conserve une trace horodatée de cette attestation pour ta protection légale.
Pattern recommandé — consentement capturé à la source
Ajoute une question custom de consentement directement dans le formulaire source (FB Lead Form custom question, champ Typeform, case GHL form). Mappe ce champ vers sms_consent. Le consentement est explicite, daté, et lié au lead qui l'a donné.
Pattern alternatif — case sur la landing page
Si le formulaire source ne permet pas de question custom, ajoute une case à cocher de consentement sur la landing page qui précède la pub. Conserve une copie de la page (Wayback Machine, screenshot daté) en preuve.
Zone grise légale
Hardcoder sms_consent: true sans attestation réelle du lead = risque légal. En cas de plainte, Capturia peut être tenue de fournir la preuve du consentement. Sans preuve, la responsabilité revient au PO de la PME.
Test step-by-step
Sélectionne d'abord un contact de test portant ton propre cellulaire et un courriel de test, puis clique Test Webhook dans le modal d'action : GHL envoie le payload à Capturia avec les valeurs de ce contact. Une réponse 200 = un vrai lead créé dans Capturia (aucun mode d'essai) : la fiche apparaît dans Leads et l'agent SMS texte le numéro envoyé si le consentement est en ordre. Ne teste jamais avec la fiche d'un vrai client. Archive la fiche de test, puis sauvegarde le workflow et bascule-le sur Publish.
Catalogue d'erreurs
| Code | Erreur | Cause | Fix |
|---|---|---|---|
| 401 | missing_api_key | Header Authorization absent ou mal formé | Ajouter le header Authorization: Bearer cap_live_... |
| 401 | invalid_api_key | Clé révoquée, expirée ou typo | Vérifier la clé dans le dashboard, en générer une nouvelle si nécessaire |
| 403 | terms_acceptance_required | CGU pas acceptées (ou bump de version forcant un ré-consent) | Le PO de la PME doit re-accepter les CGU dans le dashboard |
| 403 | insufficient_scope | La clé n'a pas le scope leads:capture | Créer une nouvelle clé avec le preset 'Capture de leads' |
| 422 | invalid_phone | Format téléphone non reconnu | Utiliser E.164 (+15145551234) ou NANP 10 chiffres (5145551234) |
| 422 | missing_consent | sms_consent absent, false, ou valeur non reconnue — le champ est cherché à la racine du body ET dans l'objet customData (GHL) | Mapper le champ de consentement vers sms_consent (true / yes / oui). Depuis GHL : valeur fixe true derrière une condition sur la checkbox de consentement |
| 422 | invalid_payload | Autre champ mal formé (email, utm objet vs flat, etc.) | Vérifier le format du body — voir la doc API leads:capture |
| 429 | rate_limited_key | Quota par clé dépassé (souvent 100 req/min) | Throttler côté source, ou demander un upgrade de tier au support |
| 429 | rate_limited_ip | Quota par IP dépassé | Réduire le débit ou contacter le support |
| 400 | invalid_payload | Body n'est pas du JSON valide (Form ou form-urlencoded à la place) | Configurer Payload Type = JSON / Content-Type = application/json |
FAQ — pièges récurrents
| Symptôme | Cause |
|---|---|
| Test plateforme vert (200 OK) mais le lead n'apparaît pas dans le pipeline | Téléphone identique à un contact existant — réponse status: idempotent_replay. Le lead existe déjà mais n'est pas dupliqué. Le mode test sandbox réutilise souvent le même numéro. |
| 400 "Body is not valid JSON" | Payload Type configuré sur Form au lieu de JSON, ou body envoyé en x-www-form-urlencoded au lieu d'application/json. |
| Réponse 200 OK mais pas de SMS envoyé au lead | sms_consent: true mais agent IA non configuré, ou agent IA SMS désactivé, ou pas de numéro Twilio provisionné côté client. |
| Lead créé sans tracking UTM | Champ utm envoyé en flat (utm_source) au lieu d'objet imbriqué (utm.source). Le serveur attend un objet. |
| 403 terms_acceptance_required après une mise à jour qui marchait avant | Bump de version CGU côté Capturia force le PO de la PME à re-accepter dans le dashboard avant que la clé refonctionne. |
| 422 missing_consent alors que sms_consent est bien dans Custom Data | GHL enveloppe Custom Data dans un objet customData, que Capturia déplie automatiquement (aucune configuration requise). Si l'erreur survient quand même, vérifier que la valeur envoyée est true (fixe), pas une interpolation {{contact...}} de checkbox. |
422 missing_consent avec sms_consent → {{contact.ma_checkbox}} | GHL interpole le libellé de l'option cochée (ex. « SMS Consent »), jamais true. Utiliser une condition If/Else sur la checkbox et envoyer la valeur fixe true dans la branche cochée (étape 5). |
Le contact a un champ personnalisé « SMS Consent » — conflit avec le sms_consent du Custom Data ? | Aucun. Le webhook GHL envoie de lui-même tous les champs personnalisés du contact sous leur nom d'affichage, en plus de tes paires Custom Data. Capturia donne toujours préséance au champ que tu as mappé toi-même (sms_consent en Custom Data) sur ces champs automatiques — c'est le montage exact prescrit à l'étape 5, aucun renommage de champ requis. |