Aller au contenu
FantomHunt
Se connecter

29 webhooks, signés et filtrables.

Chaque événement coché part vers votre adresse dès qu’il arrive, signé pour que vous sachiez qu’il vient de FantomHunt, et relancé si votre serveur ne répond pas.

Jusqu’à 10 webhooks par compte Signature vérifiable Relances progressives

Webhooks

FantomHunt envoie un POST JSON à votre URL à chaque événement coché. Jusqu’à 10 webhooks par compte, chacun avec ses événements (29, rangés par famille) et ses filtres, dans Réglages → API & Intégrations.

La livraison

  1. 1Votre URL doit être en https, sur le port 443, et pointer vers une adresse publique. Elle est revérifiée à chaque envoi ; les redirections ne sont jamais suivies.
  2. 2Répondez un code 2xx en moins de 10 secondes, puis traitez l’événement de votre côté. Tout autre code, une redirection ou un délai dépassé compte comme un échec.
  3. 3Un échec est relancé en recul progressif : 30 secondes, 2 minutes, 10 minutes, 30 minutes puis 2 heures. Après la dernière relance, la livraison est en échec définitif.
  4. 4Après trois échecs définitifs d’affilée, le webhook passe en pause : les livraisons en attente sont abandonnées, vous êtes prévenu par email et Réglages l’affiche en rouge. Réactivez-le quand votre URL répond de nouveau.
  5. 5Réglages montre les 50 dernières livraisons de chaque webhook (statut, code HTTP, erreur) ; le journal est conservé 14 jours.

Un événement fait dans l’application part en quelques secondes ; un changement fait par une campagne ou par l’extension part en moins d’une minute. L’ordre d’arrivée n’est pas garanti, et une livraison peut exceptionnellement arriver deux fois (si notre serveur redémarre pendant l’envoi) : traitez vos événements de façon idempotente, par exemple en vous appuyant sur l’identifiant de la fiche et sur cree_le.

Les événements

Prospects

ÉvénementQuand il partCe que contient donnees
prospect.ajouteUne fiche entre, quelle que soit la source : extraction, import, ajout par son lien LinkedIn (une fois la fiche lue), nouveau contact WhatsApp ou email. Un contact déjà rattaché à un prospect LinkedIn n’en est pas un : sa nouvelle coordonnée passe par coordonnee.trouvee.canal, et prospect (LinkedIn) ou contact (WhatsApp, email)
prospect.extraitUn prospect entre par une extraction ou un import de l’extension.prospect
statut.changeLe statut d’une fiche change réellement, quel que soit le chemin : à la main, par une campagne, par l’extension ou par une action groupée.statut, statut_precedent, canal, et prospect (LinkedIn) ou contact (WhatsApp, email)
coordonnee.trouveeUn email ou un téléphone est trouvé pour un prospect.type (email ou telephone), valeur, prospect
poste.changeUn changement de poste est détecté sur un prospect suivi.changement (type : promotion ou nouveau_poste, ancien_poste, ancienne_entreprise, nouveau_poste, nouvelle_entreprise, detecte_le), prospect

Échanges

ÉvénementQuand il partCe que contient donnees
message.envoyeUn message part : LinkedIn quand l’extension l’a réellement envoyé, WhatsApp et email à l’envoi. Un historique resynchronisé ne déclenche rien.message (texte, objet pour un email, envoye_le), canal, et prospect (LinkedIn) ou contact (WhatsApp, email)
invitation.envoyeeL’extension a envoyé l’invitation LinkedIn.invitation (note, envoyee_le), prospect
invitation.accepteeLe prospect accepte l’invitation LinkedIn.prospect
reponse.recueUne vraie réponse arrive. Les réponses automatiques (absence, congés) sont filtrées, ainsi que les emails dont l’expéditeur n’a pas pu être authentifié.canal, et prospect (LinkedIn) ou contact (WhatsApp, email) ; plus message (texte, objet, recu_le) si le webhook joint le texte des réponses
reponse_ia.a_validerL’IA propose une réponse LinkedIn qui attend votre validation.suggestion (texte, campagne ou null), prospect

Rendez-vous

ÉvénementQuand il partCe que contient donnees
rdv.prisUn rendez-vous est posé sur une fiche qui n’en avait pas à venir.rdv_le, canal, et prospect (LinkedIn) ou contact (WhatsApp, email)
rdv.deplaceUn rendez-vous à venir change de date.rdv_le, ancien_rdv_le, canal, et prospect (LinkedIn) ou contact (WhatsApp, email)
rdv.debriefeLe débrief du rendez-vous est enregistré.rdv_le, canal, et prospect (LinkedIn) ou contact (WhatsApp, email)

Campagnes et recherches

ÉvénementQuand il partCe que contient donnees
campagne.prospect_inscritUn prospect entre dans une campagne.campagne (id, nom), prospect
campagne.prospect_sortiUn prospect quitte une campagne.campagne (id, nom), raison (termine, a_repondu, ou la raison de l’arrêt), prospect
recherche.termineeUne recherche de prospects se termine.recherche (id, cible, pays, volume, statut, prospects_trouves, secteurs, offre_id, dates)
recherche.echoueeUne recherche s’arrête sur une erreur.recherche, avec erreur

Tâches et affaires

ÉvénementQuand il partCe que contient donnees
tache.creeeUne tâche est créée.tache (id, titre, echeance_le, faite_le, en_retard, canal, personne et ses identifiants)
tache.echueL’échéance d’une tâche non faite est passée. Une seule fois par tâche, dans les minutes qui suivent.tache
tache.faiteUne tâche est marquée faite.tache
affaire.creeeUne affaire est créée.affaire (id, nom, statut, montant_centimes, dates, colonne, personnes)
affaire.gagneeUne affaire passe en gagnée.affaire
affaire.perdueUne affaire passe en perdue.affaire, avec motif_de_perte

Compte

ÉvénementQuand il partCe que contient donnees
canal.deconnecteLinkedIn se déconnecte, ou une boîte email est à reconnecter.canal (linkedin ou email), etat, etat_precedent ; raison (LinkedIn) ou adresse (email)
canal.reconnecteLe canal refonctionne.canal, etat, etat_precedent ; adresse pour un email
prospection.en_pauseVous mettez la prospection en pause.en_pause_depuis
prospection.repriseLa prospection reprend.etait_en_pause_depuis
linkedin.freineeFantomHunt ralentit LinkedIn après plusieurs échecs d’affilée, pour protéger votre compte.jusqua, refus_d_affilee, raison
credits.basVos crédits IA passent sous 10 % de votre forfait mensuel.credits_ia (restants, par_mois)

Test

ÉvénementQuand il partCe que contient donnees
test.pingLe bouton « Envoyer un test » de Réglages.message (un texte de bienvenue, pas de fiche)

Filtrer : « Seulement pour »

Chaque webhook peut se limiter à un ou plusieurs canaux (LinkedIn, WhatsApp, email), à une campagne, à une offre ou à une étiquette. Vide, un filtre laisse tout passer. Un filtre ne trie que les événements qui portent sa donnée : le canal sur tout événement qui en a un (une recherche compte pour LinkedIn), la campagne, l’offre et l’étiquette sur les événements qui concernent une personne, l’offre aussi sur les recherches. Les autres (crédits bas, affaire créée…) partent toujours, puisque vous les avez cochés. La campagne d’un contact WhatsApp ou email est celle de sa fiche LinkedIn liée. Un webhook se modifie (événements, filtres, texte des réponses) sans changer d’adresse ni de secret.

Le corps d’une livraison

Toujours evenement, cree_le (le moment de l’événement) et donnees. La fiche est la même que celle de l’API, figée au moment de l’envoi, à une différence près : les étiquettes y sont des noms. Une réponse reçue sur LinkedIn :

{
  "evenement": "reponse.recue",
  "cree_le": "2026-08-26T15:04:05.000Z",
  "donnees": {
"canal": "linkedin",
"prospect": {
  "id": "6f2b…", "nom": "Martin Dupont", "entreprise": "Acme",
  "poste": "Directeur commercial", "url_linkedin": "https://www.linkedin.com/in/…",
  "localisation": "Lyon", "email": "martin@acme.fr", "email_score": 95,
  "telephone": "+33 6 12 34 56 78", "statut": "replied", "score": 82,
  "source": "extension", "offre": { "id": "9c1d…", "nom": "Paie externalisée" },
  "recherche_id": "4a7e…", "etiquettes": ["Chaud"],
  "campagnes": [{ "id": "b3f0…", "nom": "Relance DAF" }],
  "cree_le": "2026-08-20T09:12:00.000Z", "contacte_le": "2026-08-21T10:00:00.000Z",
  "connecte_le": "2026-08-22T08:30:00.000Z", "repondu_le": "2026-08-26T15:04:05.000Z",
  "rdv_le": null
}
  }
}

Un statut changé sur un contact WhatsApp :

{
  "evenement": "statut.change",
  "cree_le": "2026-09-24T10:12:44.000Z",
  "donnees": {
"canal": "whatsapp", "statut": "rdv", "statut_precedent": "actif",
"contact": {
  "id": "8a1c…", "nom": "Julie Leroy", "telephone": "+33 6 11 22 33 44",
  "prospect_id": "6f2b…", "statut": "rdv",
  "offre": { "id": "9c1d…", "nom": "Paie externalisée" },
  "repondu_le": "2026-09-23T17:40:00.000Z", "rdv_le": "2026-09-26T09:00:00.000Z",
  "derniere_activite_le": "2026-09-24T10:12:00.000Z", "cree_le": "2026-09-20T08:00:00.000Z",
  "etiquettes": ["Chaud"], "campagnes": [{ "id": "b3f0…", "nom": "Relance DAF" }]
}
  }
}

Sur un webhook où la case « Joindre le texte des réponses reçues » est cochée (décochée par défaut), reponse.recue porte en plus le message : "message": { "objet": "Re: votre offre", "texte": "Oui, appelons-nous jeudi.", "recu_le": "…" } (objet pour un email seulement, texte coupé à 5 000 caractères). Chaque webhook reçoit sa propre version : cocher la case sur l’un ne change rien aux autres.

En-têtes de chaque livraison : Content-Type: application/json, User-Agent: FantomHunt-Webhooks/1.0 et X-Fantomhunt-Signature.

Vérifier la signature

Chaque livraison porte l'en-tête X-Fantomhunt-Signature: t=<horodatage>,v1=<signature>. Recalculez le HMAC-SHA256 de `${t}.${corps}` avec le secret affiché dans Réglages : s'il diffère, ou si l'horodatage est trop vieux, rejetez la livraison. Zapier et Make peuvent l'ignorer (leurs URL sont secrètes) ; un serveur à vous devrait toujours vérifier.

const crypto = require('crypto');

function verifier(enteteSignature, corpsBrut, secret) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(enteteSignature || '');
  if (!m) return false;
  const [, t, v1] = m;
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // anti-rejeu : 5 min
  const attendu = crypto.createHmac('sha256', secret)
.update(t + '.' + corpsBrut).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(attendu));
}
Prêt à brancher vos outils ?Créez votre clé et votre premier webhook dans les réglages de votre espace.
Ouvrir mes réglages