Skip to content

Envoyer des données par webhook

Cette page explique exactement quoi envoyer à DURUM.ai pour que l'app fonctionne à son plein potentiel. Que vous utilisiez GHL, Typeform, Calendly, Stripe, Zoho, Pipedrive ou un outil custom, les règles sont les mêmes.


Les 3 choses absolument essentielles

Sans ces 3 éléments, votre événement ne sera pas traité correctement.

1. Identifier votre compte (client_key)

Chaque webhook doit être associé à votre compte. Il y a deux façons de le faire :

Option A : Dans l'URL avec bid (recommandé) :

https://app.durum.ai/api/webhook/lead?bid=VOTRE_BUSINESS_ID

C'est le format que l'app vous donne dans Réglages -> Intégrations. Le bid est un identifiant unique impossible à deviner, donc plus sûr qu'une clé lisible. Les 8 endpoints standard l'acceptent.

Option B : Dans l'URL avec client_key :

https://app.durum.ai/api/webhook/lead?client_key=VOTRE_CLE

Toujours supporté, aucune dépréciation.

Option C : Dans le payload JSON :

json
{ "client_key": "VOTRE_CLE", "email": "..." }

Sans client_key

L'événement est mis en quarantaine. Il ne sera pas perdu, mais il devra être classé manuellement par l'agence. Vos KPIs ne seront pas à jour en temps réel.

2. Identifier le contact (email ou téléphone)

DURUM.ai doit pouvoir identifier qui est le prospect. Envoyez au minimum un de ces champs :

ChampExemplePriorité
emailjean.tremblay@email.comIdéal : sert aussi à la déduplication et à l'attribution
phone+15145551234Bon backup : format E.164 ou 10 chiffres
nameJean TremblayUtile mais insuffisant seul

Sans email ni téléphone

Pour booking, no-show et sale (envoi JSON générique), l'événement est refusé (réponse rejected: missing_contact_info) : un rendez-vous ou une vente impossible à rattacher à un contact ne sert à rien et fausserait vos KPIs. Pour lead et application, l'événement sera enregistré, mais le système ne pourra pas :

  • Détecter les doublons (risque de compter 2 fois le même lead)
  • Relier le lead à ses futures actions (booking, vente)
  • Enrichir les données avec l'historique du contact

3. Envoyer au bon endpoint

Chaque type d'événement a son propre endpoint. C'est ce qui détermine le type dans DURUM.ai.

QuandEndpointCe qui est créé
Un prospect montre de l'intérêt/api/webhook/leadLead
Un prospect remplit un formulaire détaillé/api/webhook/applicationApplication
Un rendez-vous est réservé/api/webhook/bookingBooking
Un prospect ne se présente pas/api/webhook/no-showNo-show
Une vente est conclue/api/webhook/saleVente
Un paiement est reçu/api/webhook/paymentPaiement
Un remboursement est émis/api/webhook/refundRemboursement
Un visiteur ajoute au panier/api/webhook/add-to-cartAjout au panier
Un événement à vous (hors des 8 standard)/api/webhook/eventÉvénement custom (nommé)

Événements custom (vos propres événements)

En plus des 8 événements standard, vous pouvez envoyer n'importe quel événement, sous le nom que vous voulez (« Démo complétée », « Deal déplacé en colonne X », « Webinaire regardé à 80% »...).

Le nom de l'événement se met dans l'URL, vous n'envoyez que les données du contact dans le corps :

POST https://app.durum.ai/api/webhook/event?client_key=VOTRE_CLE&event_name=demo_completee&source=custom
Content-Type: application/json

{
  "email": "client@exemple.com",
  "phone": "+15145550199",
  "value": 250,
  "occurred_at": "2026-07-07T14:00:00Z"
}

Champs reconnus : email, phone, value, occurred_at, contact_id, calendar_name, plus les 13 champs d'attribution si vous voulez rattacher l'événement à une publicité. Tout autre champ est conservé dans le payload brut.

Où créer un événement custom dans l'app

Réglages -> Événements -> « Ajouter un événement custom » : nommez-le, obtenez son URL de webhook dédiée + le cadre JSON. Il apparaît ensuite dans vos Conversions (page Conversions) et vos mappings d'intégration (ex. « ce calendrier Calendly = cet événement »).

Un événement != trois événements

Si 3 intégrations envoient toutes des leads, c'est un seul événement Lead alimenté par 3 sources, pas 3 événements. Pour distinguer par source, utilisez un filtre au niveau de la conversion, jamais un événement séparé. Un événement custom = seulement un signal qui n'existe pas dans les 8 standard.


Les 13 champs d'attribution publicitaire

Ces champs permettent à DURUM.ai de relier chaque lead, booking et vente à la publicité exacte qui l'a généré. C'est ce qui alimente le tableau Marketing, le calcul du CPA, ROAS, ROI, et toute l'attribution dans l'app.

Sans ces champs, l'app perd sa valeur principale

Un lead sans UTMs arrive dans DURUM.ai mais il est impossible de savoir de quelle publicité il vient. Vos KPIs marketing (CPA, ROAS, ROI) seront faussés. Vous ne saurez pas quel ad performe et lequel gaspille votre budget.

Les 5 UTMs (noms des éléments publicitaires)

Ce sont les noms lisibles de vos campagnes, publicités et adsets. DURUM.ai les utilise pour matcher les events avec vos publicités Meta.

#ChampAlias acceptésCe que ça fait dans l'appExemplePriorité
1utm_campaignutmcampaign, UTM_Campaign, campaign_nameLie l'event à la campagne. Utilisé dans le tableau Marketing, le filtre par campagne, et le calcul du spend par campagne.bootcamp-mars-2026Non négociable
2utm_contentutmcontent, UTM_Content, ad_name, utm_ad_nameLie l'event à la publicité (ad). C'est LE champ qui connecte un lead à un ad dans Meta. Sans lui, pas d'attribution par ad.ad-temoignage-tx1-ix2Non négociable
3utm_sourceutmsource, UTM_SourceIdentifie la source du trafic. Permet de distinguer Meta vs Google vs organique dans les rapports.meta, google, tiktok, organicImportant
4utm_mediumutmmedium, UTM_MediumIdentifie le type de trafic. Distingue le paid du organique, de l'email, du social.paid, cpc, email, social, organicImportant
5utm_termutmterm, UTM_Term, utm_adset_name, adset_nameLie l'event à l'adset. Permet l'analyse de performance par audience/adset.adset-lookalike-1pct, adset-retarget-30jRecommandé

Les 3 IDs Meta (identifiants numériques)

Ce sont les IDs numériques de Meta Ads. Ils permettent un match exact au lieu de matcher par nom (plus fiable si vous renommez une campagne).

#ChampAlias acceptésCe que ça fait dans l'appExemplePriorité
6utm_campaign_idcampaign_idMatch exact avec la campagne Meta par ID au lieu du nom120210987654321Recommandé
7utm_ad_idad_idMatch exact avec la publicité Meta par ID au lieu du nom120210123456789Recommandé
8utm_adset_idadset_idMatch exact avec l'adset Meta par ID au lieu du nom120210111222333Recommandé

Noms vs IDs : pourquoi les deux?

Les noms (utm_campaign, utm_content, utm_term) sont lisibles et utiles dans les tableaux. Les IDs (utm_campaign_id, utm_ad_id, utm_adset_id) sont fiables même si vous renommez une campagne. Idéalement, envoyez les deux. Si vous ne pouvez envoyer qu'un seul, envoyez les noms.

Les 2 champs de tracking avancé

Pour l'attribution first-party et les outils tiers comme Hyros.

#ChampCe que ça fait dans l'appExemplePriorité
9fbc_idFacebook Click ID : identifiant unique du clic publicitaire Meta. Permet l'attribution même si les cookies sont bloqués. Capturé par le paramètre fbclid dans l'URL.fb.1.1612345678.abc123def456Optionnel (bonus)
10h_ad_idHyros Ad ID : si vous utilisez Hyros pour le tracking, cet ID permet le lien direct.120210123456789Optionnel (si Hyros)

Les 3 champs complémentaires

#ChampAlias acceptésCe que ça fait dans l'appExemplePriorité
11product_keyproduct, funnel_keyIdentifie le produit ou service. Alimente le funnel par produit, les revenus par produit, et les commissions.bootcamp_aiImportant
12assigned_user_nameassigned_to, Deal_Owner, rep_nameIdentifie le rep de vente assigné. Alimente le tableau Ventes Reps et les commissions par rep.Marie DupontRecommandé
13amountvalue, total, Amount, Grand_TotalMontant en dollars de la vente ou du paiement. Sans ce champ, le ROI, ROAS et les revenus sont à $0.2500Non négociable (ventes/paiements)

Produits reconnus automatiquement

bootcamp_ai, scaler_vos_ventes, propulsion, club_prive, mastermind_ai, formation_croisiere, accelerateur, acquisition_entreprises. Tout autre nom est accepté et converti en slug (ex : Mon Produit devient mon_produit).

Comment configurer les UTMs dans Meta Ads

Quand vous créez une publicité Meta, configurez les paramètres URL au niveau de la publicité (Ad) :

URL Parameters (dans le champ "URL Parameters" de l'ad) :

txt
utm_source=meta&utm_medium=paid&utm_campaign={campaign.name}&utm_content={ad.name}&utm_term={adset.name}&utm_campaign_id={campaign.id}&utm_ad_id={ad.id}&utm_adset_id={adset.id}

Dans Meta Ads, les variables dynamiques entre accolades ({campaign.name}, {ad.name}, etc.) sont remplacées automatiquement par les vraies valeurs. Vos outils (GHL, Typeform, Calendly) capturent ensuite ces paramètres.

Où placer les UTMs selon votre outil

OutilOù les mettreDétail
GHLCustom fields du contactutm_source, utm_campaign, utm_content, utm_term, utm_ad_id, utm_campaign_id, utm_adset_id dans le tableau customFields
TypeformHidden fields du formulaireInjectés via l'URL du formulaire (#utm_source=meta&utm_campaign=...)
CalendlyParamètres UTM de la pageCalendly capture automatiquement les UTMs de la page où le lien est affiché
StripeMetadata du checkoutclient_key, product_key, utm_campaign, utm_content dans l'objet metadata
Zoho CRMChamps du dealUTM_Source, UTM_Campaign, UTM_Content, UTM_Term, utm_ad_id, utm_campaign_id
Zoho BooksCustom fields (cf_*)cf_product_key, cf_source, cf_referent
Générique / Make / ZapierChamps directs dans le JSONTous les champs au premier niveau du payload

Exemple complet avec TOUS les champs d'attribution

json
{
  "email": "jean.tremblay@email.com",
  "phone": "+15145551234",
  "name": "Jean Tremblay",
  "product_key": "bootcamp_ai",
  "amount": 2500,
  "assigned_user_name": "Marie Dupont",

  "utm_source": "meta",
  "utm_medium": "paid",
  "utm_campaign": "bootcamp-mars-2026",
  "utm_content": "ad-temoignage-tx1-ix2",
  "utm_term": "adset-lookalike-1pct",

  "utm_campaign_id": "120210987654321",
  "utm_ad_id": "120210123456789",
  "utm_adset_id": "120210111222333",

  "fbc_id": "fb.1.1612345678.abc123def456",
  "h_ad_id": "120210123456789"
}

Les réponses aux questions de vos formulaires

Chaque client pose des questions différentes dans ses formulaires (GHL, Typeform, Calendly). Toutes les réponses sont capturées et stockées, même si elles ne correspondent pas à des champs standard. Rien n'est perdu.

Ce qui est stocké

Toutes les réponses arrivent dans le champ raw_payload de l'événement (format JSONB). C'est un stockage complet du payload original : chaque question, chaque réponse, chaque champ custom.

En plus du stockage brut, certains champs sont extraits automatiquement vers des colonnes dédiées (email, téléphone, nom, UTMs). Les autres restent dans raw_payload et sont accessibles pour des analyses, des exports ou des filtres avancés.

Typeform : toutes les réponses du formulaire

Chaque réponse est capturée avec la question posée (le titre du champ) et la réponse donnée, quel que soit le type.

Exemples de questions custom que vos clients posent dans leurs formulaires Typeform :

Question dans le formulaireTypeExemple de réponseStocké dans
Quel est votre chiffre d'affaires annuel?number500000raw_payload
Quel est votre secteur d'activité?choiceE-commerceraw_payload
Quelles plateformes publicitaires utilisez-vous?choices["Facebook Ads", "Google Ads"]raw_payload
Quel est votre objectif principal?textDoubler mes ventes en 6 moisraw_payload
Combien d'employés avez-vous?number15raw_payload
Avez-vous un site web?urlhttps://mon-entreprise.comraw_payload
Date souhaitée pour commencer?date2026-04-15raw_payload
Acceptez-vous d'être contacté?booleantrueraw_payload
Votre courrielemailjean@email.comraw_payload + contact_email
Votre téléphonephone_number+15145551234raw_payload + contact_phone
Votre nom complettext (si le titre contient "nom")Jean Tremblayraw_payload + contact_name

Structure dans le payload : chaque réponse est stockée comme ceci :

json
{
  "field_ref": {
    "label": "Quel est votre chiffre d'affaires annuel?",
    "type": "number",
    "value": 500000
  }
}

Vous pouvez ajouter autant de questions que vous voulez dans votre Typeform. Elles seront toutes là.

GHL : tous les custom fields du contact

GHL envoie les custom fields dans un tableau customFields. Tout le tableau est lu et stocké.

Les champs UTM et produit sont extraits vers des colonnes dédiées (voir section précédente). Tous les autres custom fields sont conservés dans raw_payload.

Exemples de custom fields que vos clients configurent dans GHL :

Custom Field GHLDescriptionExemple
villeVille du prospectMontreal
entrepriseNom de l'entrepriseTremblay Inc.
chiffre_affairesCA annuel500000
nb_employesTaille de l'équipe15
budget_mensuelBudget marketing5000
secteur_activiteSecteurE-commerce
objectif_principalObjectifAugmenter mes ventes de 50%
comment_avez_vous_entenduSource déclaréePublicite Facebook
qualification_scoreScore attribué par le rep8
revenue_attenduRevenue estimé de la vente2500
type_entrepriseB2B, B2C, D2CB2C
experience_pubExpérience publicitaireDebutant
outil_crm_actuelCRM utiliséHubSpot
delai_decisionUrgenceCe mois-ci

Comment les envoyer :

json
{
  "contact": {
    "email": "jean@email.com",
    "customFields": [
      { "field_name": "ville", "value": "Montreal" },
      { "field_name": "entreprise", "value": "Tremblay Inc." },
      { "field_name": "chiffre_affaires", "value": "500000" },
      { "field_name": "nb_employes", "value": "15" },
      { "field_name": "objectif_principal", "value": "Augmenter mes ventes" },
      { "field_name": "budget_mensuel", "value": "5000" },
      { "field_name": "qualification_score", "value": "8" }
    ]
  }
}

Pas de limite

Vous pouvez ajouter autant de custom fields que nécessaire. Il n'y a pas de liste prédéterminée : tout ce que vous envoyez dans customFields est stocké et accessible.

Calendly : les questions de réservation

Calendly permet de poser des questions custom quand quelqu'un réserve un rendez-vous. Elles arrivent dans le tableau questions_and_answers.

Exemples de questions configurées dans Calendly :

Question CalendlyRéponse type
Quel est le nom de votre entreprise?Tremblay Inc.
Quel est votre chiffre d'affaires annuel?500 000$
Quel est votre objectif principal pour cet appel?Valider si le bootcamp est pour moi
Comment avez-vous entendu parler de nous?Publicite Facebook
Nombre d'employés?15
Avez-vous déjà fait de la publicité en ligne?Oui, Facebook Ads depuis 6 mois
Quel est votre budget mensuel en publicité?3000-5000$

Structure dans le payload Calendly :

json
{
  "questions_and_answers": [
    {
      "question": "Quel est le nom de votre entreprise?",
      "answer": "Tremblay Inc."
    },
    {
      "question": "Quel est votre chiffre d'affaires annuel?",
      "answer": "500 000$"
    },
    {
      "question": "Objectif principal pour cet appel?",
      "answer": "Valider si le bootcamp est pour moi"
    }
  ]
}

Zoho Books : custom fields et line items

Zoho Books envoie les custom fields (préfixés cf_) et les line items (produits facturés).

Custom Field ZohoDescription
cf_product_keyIdentifiant du produit
cf_sourceSource de la vente (DURUM, ORGANIC)
cf_referentVendeur/référent
cf_af_contact_idID GHL du contact (via ActiveFunnel)
Tout autre cf_*Stocké dans raw_payload

Les line items (produits facturés) sont aussi capturés :

json
{
  "line_items": [
    {
      "name": "Bootcamp IA - Session Mars 2026",
      "rate": 2500,
      "quantity": 1,
      "item_total": 2500
    },
    {
      "name": "Materiel supplementaire",
      "rate": 200,
      "quantity": 1,
      "item_total": 200
    }
  ]
}

Le système identifie automatiquement le produit principal (item avec le plus gros montant, en excluant les frais bancaires comme Stripe Processing Fees ou Compte Stripe).

Générique / Make / Zapier : champs libres

Si vous construisez le JSON vous-même, ajoutez vos champs custom directement dans le payload. Ils seront tous stockés :

json
{
  "email": "jean@email.com",
  "client_key": "avego",
  "utm_campaign": "bootcamp-mars-2026",

  "entreprise": "Tremblay Inc.",
  "chiffre_affaires": 500000,
  "nb_employes": 15,
  "secteur": "E-commerce",
  "objectif": "Augmenter mes ventes de 50%",
  "budget_pub": 5000,
  "source_declaree": "Publicite Facebook",
  "questions_custom": {
    "experience_pub": "Facebook Ads depuis 6 mois",
    "outil_actuel": "HubSpot",
    "delai": "Ce mois-ci"
  }
}

Tout est conservé dans raw_payload. Les champs standard (email, utm_campaign, etc.) sont en plus extraits vers des colonnes dédiées.


Par type d'événement : quoi envoyer

Lead ou Application

Un prospect montre de l'intérêt ou remplit un formulaire.

POST /api/webhook/lead?client_key=VOTRE_CLE
Content-Type: application/json
json
{
  "email": "jean.tremblay@email.com",
  "phone": "+15145551234",
  "name": "Jean Tremblay",
  "product_key": "bootcamp_ai",
  "utm_source": "meta",
  "utm_campaign": "bootcamp-mars-2026",
  "utm_content": "ad-temoignage-tx1"
}
ChampStatutPourquoi
emailEssentielIdentifie le contact et permet la déduplication
utm_campaignEssentielAttribution à la campagne
utm_contentEssentielAttribution à la publicité
phoneRecommandéBackup d'identification + enrichissement
nameRecommandéAffichage dans les tableaux
product_keyRecommandéClassification par produit/funnel
utm_sourceRecommandéSource du trafic
utm_ad_idOptionnelLien direct avec Meta

Booking (rendez-vous)

Un prospect réserve un rendez-vous.

POST /api/webhook/booking?client_key=VOTRE_CLE
json
{
  "email": "jean.tremblay@email.com",
  "name": "Jean Tremblay",
  "calendar_name": "Appel Decouverte",
  "booking_date": "2026-04-05",
  "booking_time": "14:00",
  "assigned_user_name": "Marie Dupont",
  "utm_campaign": "bootcamp-mars-2026",
  "utm_content": "ad-temoignage-tx1"
}
ChampStatutPourquoi
emailEssentielRelie le booking au lead original
booking_dateEssentielDistingue "date de création" vs "date du RDV"
booking_timeRecommandéAnalyse des créneaux no-show
calendar_nameRecommandéType de rendez-vous dans les tableaux
assigned_user_nameRecommandéAssocie au rep pour le suivi de performance
UTMsImportantSi pas déjà sur le lead, c'est la dernière chance de les capturer

Booking date vs event date

DURUM.ai distingue la date de création du booking (quand le prospect a réservé) de la date du rendez-vous (quand le meeting aura lieu). C'est critique pour calculer correctement les taux de no-show et le pipeline.

No-show

Un prospect ne se présente pas à son rendez-vous.

POST /api/webhook/no-show?client_key=VOTRE_CLE
json
{
  "email": "jean.tremblay@email.com",
  "name": "Jean Tremblay",
  "calendar_name": "Appel Decouverte",
  "booking_date": "2026-04-05",
  "booking_time": "14:00"
}

Vente

Un deal est conclu (gagné ou perdu).

POST /api/webhook/sale?client_key=VOTRE_CLE
json
{
  "email": "jean.tremblay@email.com",
  "name": "Jean Tremblay",
  "amount": 2500,
  "product_key": "bootcamp_ai",
  "status": "won",
  "assigned_user_name": "Marie Dupont",
  "utm_campaign": "bootcamp-mars-2026",
  "utm_content": "ad-temoignage-tx1"
}
ChampStatutPourquoi
emailEssentielRelie la vente au lead et au booking
amountEssentielCalcul du revenu, ROI, ticket moyen
statusImportantwon = vente, lost = perdue. Par défaut : vente.
product_keyRecommandéRevenu par produit, commissions
assigned_user_nameRecommandéPerformance par rep
UTMsImportantAttribution de la vente à la publicité

Sans montant

La vente apparaît dans le funnel mais avec $0. Le ROI, le ROAS et les revenus seront faussés.

Paiement

Un paiement est reçu (facture payée).

POST /api/webhook/payment?client_key=VOTRE_CLE
json
{
  "email": "jean.tremblay@email.com",
  "name": "Jean Tremblay",
  "amount": 2500,
  "product_key": "bootcamp_ai",
  "invoice_number": "INV-001234",
  "payment_status": "paid"
}
ChampStatutPourquoi
emailEssentielRelie le paiement au client
amountEssentielMontant encaissé
invoice_numberRecommandéDéduplication (évite de compter 2 fois si le webhook est renvoyé)
payment_statusRecommandépaid = encaissé, overdue = en retard
product_keyRecommandéRevenu par produit

Remboursement

POST /api/webhook/refund?client_key=VOTRE_CLE
json
{
  "email": "jean.tremblay@email.com",
  "amount": 2500
}

Ajout au panier

Un panier abandonné, c'est un ajout au panier qui n'est pas suivi d'une vente. Envoyez donc l'ajout au panier ici, et la vente sur /api/webhook/sale comme d'habitude : DURUM.ai fait la différence, et peut pousser la conversion AddToCart aux régies (Meta, TikTok, Google, Snapchat, LinkedIn) depuis Réglages > Conversions.

POST /api/webhook/add-to-cart?client_key=VOTRE_CLE
json
{
  "email": "jean.tremblay@email.com",
  "value": 97,
  "currency": "CAD",
  "product_key": "formation-impots",
  "product_name": "Formation Impôts",
  "utm_source": "facebook",
  "utm_campaign": "Impots-Sept",
  "utm_content": "Ad-Temoignage-12"
}
ChampStatutPourquoi
email ou phoneRequis (sauf pixel, voir ci-dessous)Identifier la personne et relier au lead, à la vente
value + currencyRecommandéValeur du panier, envoyée telle quelle à la régie
product_key (ou content_ids, sku)RecommandéProduit ajouté (content_ids côté Meta)
product_name (ou content_name)OptionnelNom lisible du produit
utm_*, fbc_id, gclidRecommandéAttribution à la publicité (sinon, DURUM.ai reprend celle du lead)

Depuis une page avec le pixel DURUM.ai installé, aucun webhook à brancher : appelez durum.track('AddToCart', { value: 97, currency: 'CAD', content_ids: ['formation-impots'] }) au clic sur le bouton, ou posez data-durum-event="AddToCart" (avec data-durum-value, data-durum-currency, data-durum-content-id) sur le bouton. Le pixel envoie l'événement au serveur avec le visiteur, ses UTM et ses identifiants de clic ; l'email est retrouvé si ce visiteur est déjà connu (formulaire rempli plus tôt). La conversion part aux régies depuis le serveur, une seule fois, jamais depuis le navigateur.


Récapitulatif : hiérarchie d'importance

NiveauChampsImpact si absent
Non négociableclient_key (URL ou payload)Événement en quarantaine, pas dans vos KPIs
Non négociableemail ou phonePas de déduplication, pas de lien entre les étapes du funnel
Non négociableutm_campaign + utm_contentPas d'attribution. Impossible de savoir quel ad a généré le lead/vente. CPA, ROAS et ROI non calculables.
Non négociableamount (ventes et paiements)Revenus à $0, ROI et ROAS faussés
Importantutm_source + utm_mediumImpossible de distinguer Meta vs Google vs organique
Importantproduct_keyPas de funnel par produit, pas de commissions par produit
Recommandéutm_termPas d'analyse par adset/audience
Recommandéutm_campaign_id + utm_ad_id + utm_adset_idMatch par nom au lieu d'ID exact (fragile si vous renommez)
Recommandéname, assigned_user_nameMoins de détails dans les tableaux, pas de perf par rep
Bonusfbc_id, h_ad_idAttribution avancée first-party et Hyros

Ce que DURUM.ai fait automatiquement

Vous n'avez pas besoin d'envoyer toutes les données dans chaque webhook. Le système fait un travail important en arrière-plan.

Enrichissement UTM automatique

Si un webhook arrive sans UTMs (par exemple un paiement Zoho Books), DURUM.ai cherche automatiquement les UTMs dans cet ordre :

  1. Custom fields GHL : si le contact existe dans GHL avec des champs UTM configurés, ils sont récupérés
  2. Tracker navigateur : si le prospect a visité votre site avec le tracker DURUM.ai installé, ses UTMs ont été capturés automatiquement (premier clic)
  3. Events précédents : si le même email a déjà un lead ou un booking avec des UTMs, ils sont hérités

Concrètement : si un prospect remplit un formulaire avec les bons UTMs, puis réserve un booking, puis paie via Stripe, même si Stripe n'envoie aucun UTM, la vente sera attribuée à la bonne publicité grâce au lead original.

TIP

C'est pourquoi les UTMs sur le premier point de contact (lead ou application) sont si importants. Même si les étapes suivantes n'en ont pas, l'attribution fonctionnera.

Déduplication intelligente

DURUM.ai empêche automatiquement les doublons. Vous n'avez pas à vous en soucier si un webhook est envoyé 2 fois.

SourceMéthode de dedupCe qui est vérifié
TypeformToken de soumissionChaque soumission a un token unique
CalendlyURI de l'invitéChaque invité a une URI unique
Zoho BooksNuméro de factureMême invoice_number = même événement
GHL / GénériqueEmail + type + fenêtre tempsMême email + même type dans les 24h (leads) ou 2 min (autres)

Rep assigné automatiquement

Si vous n'envoyez pas le nom du rep (assigned_user_name), le système le cherche automatiquement :

  1. Dans le contact GHL (champ assigned_to)
  2. Dans les events précédents du même contact
  3. Via le ID utilisateur GHL mappé à un rep dans DURUM.ai

Client identifié automatiquement

Si le client_key n'est pas dans l'URL, le système tente de l'identifier via :

  • L'email du contact (s'il existe déjà dans un compte)
  • Le numéro de téléphone
  • L'ID de contact GHL
  • Le numéro de facture
  • L'ID client Zoho ou Stripe Connect

Alias acceptés par champ

DURUM.ai accepte plusieurs noms pour le même champ. Utilisez celui qui correspond à votre outil.

Ce que DURUM.ai stockeNoms acceptés
contact_emailemail, contact_email, customer_email
contact_phonephone, contact_phone, customer_phone
contact_namename, contact_name, customer_name
client_keyclient_key, clientKey
product_keyproduct_key, product, funnel_key
utm_sourceutm_source, utmsource, UTM_Source
utm_campaignutm_campaign, utmcampaign, UTM_Campaign
utm_contentutm_content, utmcontent, UTM_Content
utm_termutm_term, utmterm, UTM_Term, utm_adset_name
meta_ad_idutm_ad_id, ad_id
meta_campaign_idutm_campaign_id, campaign_id
meta_adset_idutm_adset_id, adset_id
value (montant)amount, value, total, Amount, Grand_Total
assigned_user_nameassigned_user_name, assigned_to, Deal_Owner, rep_name

Spécificités par plateforme

Chaque outil envoie les données dans un format différent. Voici où placer les champs importants selon votre outil.

GHL (GoHighLevel)

Les UTMs et le produit vont dans les custom fields du contact :

json
{
  "contact": {
    "email": "jean@email.com",
    "customFields": [
      { "field_name": "utm_campaign", "value": "bootcamp-mars-2026" },
      { "field_name": "utm_content", "value": "ad-temoignage-tx1" },
      { "field_name": "product_key", "value": "bootcamp_ai" }
    ]
  }
}

L'URL doit inclure ?client_key=VOTRE_CLE&source=ghl.

Vous pouvez ajouter n'importe quel custom field supplémentaire (ville, entreprise, chiffre_affaires, etc.). Ils seront tous conservés dans les données brutes.

Voir le payload GHL complet (lead)
json
{
  "contact": {
    "id": "abc123",
    "firstName": "Jean",
    "lastName": "Tremblay",
    "email": "jean.tremblay@email.com",
    "phone": "+15145551234",
    "dateAdded": "2026-03-30T14:30:00.000Z",
    "tags": ["lead", "bootcamp-ai"],
    "assignedTo": "rep-user-id",
    "customFields": [
      { "field_name": "utm_source", "value": "meta" },
      { "field_name": "utm_campaign", "value": "bootcamp-mars-2026" },
      { "field_name": "utm_content", "value": "ad-temoignage-tx1" },
      { "field_name": "utm_term", "value": "adset-lookalike-1pct" },
      { "field_name": "utm_ad_id", "value": "120210123456789" },
      { "field_name": "utm_campaign_id", "value": "120210987654321" },
      { "field_name": "product_key", "value": "bootcamp_ai" },
      { "field_name": "ville", "value": "Montreal" },
      { "field_name": "entreprise", "value": "Tremblay Inc." }
    ]
  },
  "locationId": "ghl-location-abc123",
  "form": {
    "id": "form-xyz-789",
    "name": "Formulaire Bootcamp IA"
  }
}
Voir le payload GHL complet (booking)
json
{
  "id": "appt-abc123",
  "contactId": "contact-xyz789",
  "contact": {
    "email": "jean.tremblay@email.com",
    "name": "Jean Tremblay",
    "customFields": [
      { "field_name": "utm_campaign", "value": "bootcamp-mars-2026" }
    ]
  },
  "calendarName": "Appel Decouverte",
  "startTime": "2026-04-05T14:00:00.000Z",
  "appointmentStatus": "scheduled",
  "assignedUserId": "user-rep-123",
  "locationId": "ghl-location-abc123"
}
Voir le payload GHL complet (vente)
json
{
  "opportunity": {
    "id": "opp-abc123",
    "status": "won",
    "monetaryValue": 2500
  },
  "contact": {
    "id": "contact-xyz789",
    "email": "jean.tremblay@email.com",
    "name": "Jean Tremblay",
    "customFields": [
      { "field_name": "product_key", "value": "bootcamp_ai" }
    ]
  },
  "locationId": "ghl-location-abc123"
}

Typeform

Les UTMs et le client_key vont dans les hidden fields du formulaire :

https://form.typeform.com/to/XXXXX#client_key=VOTRE_CLE&utm_source=meta&utm_campaign=bootcamp-mars-2026&utm_content=ad-temoignage-tx1&product_key=bootcamp_ai

Les réponses du formulaire (email, téléphone, nom, questions custom) sont extraites automatiquement depuis le tableau answers.

Voir le payload Typeform complet
json
{
  "form_response": {
    "form_id": "sJ5lztlq",
    "token": "unique-submission-token",
    "definition": { "title": "Formulaire Bootcamp IA" },
    "hidden": {
      "client_key": "VOTRE_CLE",
      "utm_source": "meta",
      "utm_campaign": "bootcamp-mars-2026",
      "utm_content": "ad-temoignage-tx1",
      "utm_ad_id": "120210123456789",
      "product_key": "bootcamp_ai"
    },
    "answers": [
      { "type": "email", "email": "jean@email.com", "field": { "title": "Votre courriel" } },
      { "type": "phone_number", "phone_number": "+15145551234", "field": { "title": "Telephone" } },
      { "type": "text", "text": "Jean Tremblay", "field": { "title": "Votre nom" } },
      { "type": "choice", "choice": { "label": "E-commerce" }, "field": { "title": "Secteur" } },
      { "type": "number", "number": 500000, "field": { "title": "Chiffre d'affaires" } }
    ]
  }
}

Calendly

Les UTMs sont capturés automatiquement dans l'objet tracking si l'URL de la page de réservation contient les paramètres UTM. Les questions personnalisées sont dans questions_and_answers.

L'URL doit inclure ?client_key=VOTRE_CLE.

Voir le payload Calendly complet
json
{
  "event": "invitee.created",
  "payload": {
    "event_type": { "name": "Appel Decouverte" },
    "invitee": {
      "email": "jean.tremblay@email.com",
      "name": "Jean Tremblay",
      "text_reminder_number": "+15145551234",
      "uri": "https://api.calendly.com/scheduled_events/xxx/invitees/yyy"
    },
    "scheduled_event": {
      "start_time": "2026-04-05T14:00:00.000Z",
      "event_memberships": [{ "user_name": "Marie Dupont" }]
    },
    "tracking": {
      "utm_source": "meta",
      "utm_campaign": "bootcamp-mars-2026",
      "utm_content": "ad-temoignage-tx1"
    },
    "questions_and_answers": [
      { "question": "Votre entreprise?", "answer": "Tremblay Inc." },
      { "question": "Chiffre d'affaires?", "answer": "500 000$" }
    ]
  }
}

Stripe

Le client_key et le product_key vont dans les metadata du checkout session ou de la facture. Les montants sont en cents (divisés automatiquement par 100).

Pas besoin de client_key dans l'URL : Stripe est détecté par sa signature.

Voir le payload Stripe complet
json
{
  "type": "checkout.session.completed",
  "data": {
    "object": {
      "customer_email": "jean.tremblay@email.com",
      "amount_total": 250000,
      "payment_status": "paid",
      "customer_details": {
        "name": "Jean Tremblay",
        "email": "jean.tremblay@email.com"
      },
      "metadata": {
        "client_key": "VOTRE_CLE",
        "product_key": "bootcamp_ai",
        "utm_campaign": "bootcamp-mars-2026"
      }
    }
  }
}

Zoho CRM

Les UTMs sont dans des champs du deal (UTM_Source, UTM_Campaign, UTM_Content). Le client_key doit être dans l'URL.

Voir le payload Zoho CRM complet
json
{
  "data": [{
    "Deal_Name": "Jean Tremblay - Bootcamp AI",
    "Stage": "Closed Won",
    "Amount": 2500,
    "Email": "jean.tremblay@email.com",
    "Contact_Name": "Jean Tremblay",
    "Owner": { "name": "Marie Dupont" },
    "Product": "bootcamp_ai",
    "UTM_Source": "meta",
    "UTM_Campaign": "bootcamp-mars-2026",
    "UTM_Content": "ad-temoignage-tx1"
  }]
}

Zoho Books

Le client_key doit être dans l'URL (Zoho Books ne l'envoie pas dans le payload). Les custom fields Zoho sont préfixés par cf_.

Voir le payload Zoho Books complet
json
{
  "payment": {
    "amount": 2500,
    "payment_status": "paid",
    "customer_name": "Jean Tremblay",
    "customer_email": "jean.tremblay@email.com",
    "invoices": [{ "invoice_number": "INV-001234", "amount_applied": 2500 }],
    "custom_fields": [
      { "api_name": "cf_client_key", "value": "VOTRE_CLE" },
      { "api_name": "cf_product_key", "value": "bootcamp_ai" },
      { "api_name": "cf_source", "value": "DURUM" },
      { "api_name": "cf_referent", "value": "Marie Dupont" }
    ]
  }
}

Pipedrive

L'URL doit inclure ?client_key=VOTRE_CLE&source=pipedrive. Les emails et téléphones sont des tableaux avec primary: true.

Voir le payload Pipedrive complet (deal gagné)
json
{
  "meta": { "action": "updated", "object": "deal", "company_id": 12345 },
  "current": {
    "title": "Jean Tremblay - Bootcamp IA",
    "status": "won",
    "value": 2500,
    "person_id": {
      "name": "Jean Tremblay",
      "email": [{ "value": "jean@email.com", "primary": true }],
      "phone": [{ "value": "+15145551234", "primary": true }]
    },
    "user_id": { "name": "Marie Dupont" },
    "won_time": "2026-03-30T15:00:00Z"
  },
  "previous": { "status": "open" }
}

Tester votre webhook

Copiez-collez cette commande dans votre terminal pour envoyer un lead de test :

bash
curl -X POST "https://app.durum.ai/api/webhook/lead?client_key=VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "test-webhook@votredomaine.com",
    "name": "Test Webhook",
    "utm_source": "test",
    "utm_campaign": "test-webhook",
    "utm_content": "test-ad"
  }'

Puis vérifiez dans DURUM.ai > Logs Data que l'événement apparaît.


Dépannage rapide

SymptômeCauseSolution
Événement absent de l'appclient_key manquant ou invalideAjoutez ?client_key=VOTRE_CLE à l'URL
Statut quarantinedFormulaire ou client non reconnuNormal pour un nouveau formulaire. L'agence le catégorise.
Réponse deduped: trueÉvénement déjà reçuNormal. Le doublon a été détecté.
UTMs vides dans le dashboardPas d'UTMs dans le webhookConfigurez les hidden fields (Typeform), custom fields (GHL) ou tracking (Calendly)
Montant à $0 sur une venteChamp amount absentAjoutez le montant dans le payload
Réponse 401Authentification échouéePour GHL : ajoutez &source=ghl. Pour Stripe : vérifiez la signature.
Réponse 429Trop de requêtesMaximum 60 par minute par IP
Réponse 202Serveur temporairement occupéL'événement est en file d'attente et sera traité sous quelques minutes

Propulsé par DURUM.ai : attribution publicitaire et intelligence opérationnelle