Webhook : définition et connexion d’une IA à un formulaire
Comprendre les webhooks simplement : FastAPI reçoit un formulaire, l'IA catégorise la demande et l'enregistre dans un tableau. Tutoriel Python, Make et Zapier.
👁 117 lectures
Un webhook est une adresse URL vers laquelle une application envoie d’elle-meme des donnees a une autre des qu’un evenement survient : soumission d’un formulaire, reception d’un e-mail ou confirmation de paiement. Au lieu d’interroger un serveur toutes les minutes pour savoir si du nouveau contenu est disponible, vous attendez simplement qu’il vienne frapper a votre porte. Voici une mise en pratique complete : un serveur local en Python (FastAPI) receptionne une demande de formulaire, un modele d’IA la classe puis redige un brouillon de reponse, et le resultat est stocke dans une feuille de calcul. La meme logique est ensuite detaillee avec Make et Zapier. Ce guide s’inscrit dans le cadre de notre parcours consacre a l’automatisation avec des agents IA.
Situation au 4 octobre 2026
- Configuration du test : Windows 11, Python 3.13, FastAPI 0.142.2, uvicorn 0.54.0, modele
openai/gpt-5.6-lunavia OpenRouter. - Duree d’une requete : 1,7 a 2,1 s entre l’envoi et la reponse, pour un cout d’environ 0,00014 EUR (0,00016 USD). Taux BCE du 12.10.2026 : 1 EUR = 1,1181 USD (source : https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml).
- Make : le forfait gratuit donne acces a 1 000 credits par mois et 2 scenarios actifs. Zapier : 100 taches mensuelles, Zaps limites a deux etapes, les webhooks etant reserves aux offres payantes (a partir d’environ 17,88 EUR par mois, soit 19,99 USD, en facturation annuelle).
- Code : pack agenti-starter, fichiers
06_webhook.pyet06_test_webhook.py.
Webhook : definition simple et fonctionnement
Il existe deux manieres pour un programme de detecter un nouvel evenement :
- L’interrogation periodique (polling) : votre application consulte toutes les cinq minutes une boite mail ou une feuille de calcul pour reperer d’eventuelles nouveautes. Ce procede est simple, mais induit un temps de latence et consomme inutilement des requetes ;
- Le webhook : vous transmettez votre adresse (par exemple
https://votredomaine.fr/webhook/formulaire) a un service externe, et celui-ci y envoie aussitot une requete HTTP POST contenant les donnees en JSON des qu’une action a lieu.
Un webhook est donc un appel d’API standard, mais inverse : ce n’est pas vous qui appelez le service, c’est lui qui contacte votre application. Si les concepts de requetes HTTP et de format JSON ne vous sont pas familiers, consultez notre guide d’initiation aux API.
Cas d’usage courants recevant des webhooks :
- Les formulaires en ligne (Tally, Typeform, Google Forms via script, formulaires WordPress) ;
- Les plateformes de paiement (Stripe informe par exemple de la validation d’une transaction) ;
- Les boutiques en ligne (WooCommerce, Shopify lors de la creation d’une commande) ;
- Les outils collaboratifs (GitHub, Slack, Trello, Calendly) ;
- Les plateformes d’automatisation (Make, Zapier et n8n disposent de modules preconfigures pour receptionner des webhooks).
Le flux mis en place
- Le formulaire de contact envoie un payload JSON : prenom, e-mail, message.
- Le serveur local verifie la cle secrete transmise dans l’en-tete HTTP afin d’empecher toute requete frauduleuse.
- Le modele d’IA analyse le message et renvoie un JSON structure : categorie, niveau d’urgence evalue de 1 a 3, resume en quelques mots et proposition de reponse.
- Le serveur insere cette ligne dans un fichier CSV (equivalent local d’un tableau en ligne) et renvoie la reponse traitee.
Code du serveur webhook en Python
Installation des dependances requises : pip install fastapi uvicorn openai python-dotenv. Renseignez dans votre fichier .env les variables OPENROUTER_API_KEY ainsi que WEBHOOK_SECRET (une chaine aleatoire robuste).
"""06 - Webhook : un formulaire envoie une demande -> le serveur interroge le modele -> le resultat est enregistre dans un CSV et renvoye.
Demarrage : uvicorn 06_webhook:app --port 8000 (ou : python 06_webhook.py)
Test : curl -X POST http://127.0.0.1:8000/webhook/formulaire -H "X-Webhook-Secret: ..." -H "Content-Type: application/json"
-d "{\"prenom\":\"Claire\",\"email\":\"claire@example.com\",\"message\":\"Le numero de TVA est incorrect sur la facture\"}"
"""
import csv, datetime, json, os, pathlib
from dotenv import load_dotenv
from fastapi import FastAPI, Header, HTTPException
from openai import OpenAI
from pydantic import BaseModel
load_dotenv()
SECRET = os.getenv("WEBHOOK_SECRET", "changer-ce-secret") # Chaine identique a renseigner dans Make/Zapier/formulaire
MODELE = os.getenv("MODEL", "openai/gpt-5.6-luna")
FICHIER_CSV = pathlib.Path("demandes.csv")
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"])
app = FastAPI()
class Demande(BaseModel): # Structure attendue du JSON envoye par le formulaire
prenom: str
email: str
message: str
@app.post("/webhook/formulaire")
def receptionner(d: Demande, x_webhook_secret: str = Header(default="")):
if x_webhook_secret != SECRET: # Protege l'URL contre l'envoi de requetes non autorisees
raise HTTPException(status_code=401, detail="secret invalide")
r = client.chat.completions.create(model=MODELE, response_format={"type": "json_object"}, messages=[
{"role": "system", "content": "Tu es un assistant de support client. Renvoie un JSON avec les cles : categorie (factures|reclamation|"
"devis|autre), urgence (1-3, 3 = tres urgent), resume (max 12 mots), brouillon_reponse (2-3 phrases polies)."},
{"role": "user", "content": f"De : {d.prenom}\nMessage : {d.message}"}])
resultat = json.loads(r.choices[0].message.content)
nouveau_fichier = not FICHIER_CSV.exists()
with FICHIER_CSV.open("a", newline="", encoding="utf-8-sig") as f:
w = csv.writer(f, delimiter=";")
if nouveau_fichier:
w.writerow(["date_heure", "prenom", "email", "categorie", "urgence", "resume", "brouillon_reponse"])
w.writerow([datetime.datetime.now().isoformat(timespec="seconds"), d.prenom, d.email, resultat.get("categorie"),
resultat.get("urgence"), resultat.get("resume"), resultat.get("brouillon_reponse")])
return {"ok": True, **resultat, "cout_usd": getattr(r.usage, "cost", None)}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)
Points cles de cette implementation :
class Demande(BaseModel): definit la structure attendue. FastAPI bloque automatiquement toute requete incomplete ou mal formee avec une erreur 422, evitant ainsi des appels inutiles a l’IA ;- L’en-tete
X-Webhook-Secret: toute tentative d’acces ne disposant pas du secret retourne une erreur 401 immediate sans generer de frais ; response_format={"type": "json_object"}: garantit un retour au format JSON direct, facilement exploitable par le script ;- L’encodage
utf-8-sig: assure une ouverture sans defaut d’accentuation dans les tableurs comme Microsoft Excel.
Lancement et validation pratique
Ouvrez un premier terminal pour executer l’application : uvicorn 06_webhook:app --port 8000. Dans un second terminal, lancez un script de test simulant les emissions de formulaires. Les requetes d’origine ont ete testees initialement avec des textes en polonais ; les voici traduites en francais pour illustrer la demarche :
"""Envoie 3 requetes types vers le webhook local, a l'image d'un formulaire externe ou d'un flux Make/Zapier."""
import os, time, requests
URL = "http://127.0.0.1:8000/webhook/formulaire"
SECRET = os.getenv("WEBHOOK_SECRET", "changer-ce-secret")
# Test de verification de securite : secret incorrect
print("secret incorrect ->", requests.post(URL, json={"prenom": "X", "email": "x@example.com", "message": "test"},
headers={"X-Webhook-Secret": "tentative"}).status_code)
# Echantillons de test (traduction d'exemples testes a l'origine en polonais)
exemples = [
("Claire", "Bonjour, sur la facture FV/2026/09/027, le numero de TVA est incorrect. J'ai besoin d'un rectificatif avant vendredi pour clore le mois."),
("Marc", "Quel est le tarif pour deployer un chatbot sur une boutique en ligne de 300 produits ? Nous visons novembre."),
("Sophie", "Le cable commande est arrive casse, l'embout est fendu. Je demande un remboursement.")
]
for prenom, texte in exemples:
t = time.time()
r = requests.post(URL, json={"prenom": prenom, "email": f"{prenom.lower()}@example.com", "message": texte},
headers={"X-Webhook-Secret": SECRET}, timeout=60)
print(f"\n{prenom} : {texte}\n-> HTTP {r.status_code} en {time.time() - t:.1f} s : {r.json()}")
Voici les donnees recueillies lors du test realise le 4 octobre a 14:11 (traduction fidele de la sortie console issue des tests effectues en polonais) :
> python 06_test_webhook.py
secret incorrect -> 401
Claire : Bonjour, sur la facture FV/2026/09/027, le numero de TVA est incorrect. J'ai besoin d'un rectificatif avant vendredi pour clore le mois.
-> HTTP 200 en 2.1 s : {'ok': True, 'categorie': 'factures', 'urgence': 3, 'resume': 'TVA incorrecte sur facture, rectificatif requis avant vendredi', 'brouillon_reponse': 'Bonjour Claire, nous verifions la facture FV/2026/09/027 et preparons un rectificatif avec le bon numero de TVA. Nous traitons cette demande en priorite pour vendredi.', 'cout_usd': 0.0001746}
Marc : Quel est le tarif pour deployer un chatbot sur une boutique en ligne de 300 produits ? Nous visons novembre.
-> HTTP 200 en 1.8 s : {'ok': True, 'categorie': 'devis', 'urgence': 2, 'resume': 'Demande de devis et delai pour chatbot e-commerce', 'brouillon_reponse': 'Bonjour Marc, nous vous preparons une estimation pour l integration d un chatbot sur votre boutique de 300 produits ainsi qu un creneau en novembre. Merci de nous transmettre le lien du site.', 'cout_usd': 0.000162}
Sophie : Le cable commande est arrive casse, l'embout est fendu. Je demande un remboursement.
-> HTTP 200 en 1.7 s : {'ok': True, 'categorie': 'reclamation', 'urgence': 2, 'resume': 'Cable endommage, embout fendu ; demande de remboursement.', 'brouillon_reponse': 'Nous sommes desoles pour ce cable defectueux. Pourriez-vous nous faire parvenir des photos du dommage ainsi que votre numero de commande afin de proceder au remboursement ?', 'cout_usd': 0.0001504}
> type demandes.csv
date_heure;prenom;email;categorie;urgence;resume;brouillon_reponse
2026-10-04T14:11:16;Claire;claire@example.com;factures;3;TVA incorrecte sur facture, rectificatif requis avant vendredi;Bonjour Claire, nous verifions la facture FV/2026/09/027 et preparons un rectificatif avec le bon numero de TVA. Nous traitons cette demande en priorite pour vendredi.
2026-10-04T14:11:18;Marc;marc@example.com;devis;2;Demande de devis et delai pour chatbot e-commerce;Bonjour Marc, nous vous preparons une estimation pour l integration d un chatbot sur votre boutique de 300 produits ainsi qu un creneau en novembre. Merci de nous transmettre le lien du site.
2026-10-04T14:11:19;Sophie;sophie@example.com;reclamation;2;"Cable endommage, embout fendu ; demande de remboursement.";Nous sommes desoles pour ce cable defectueux. Pourriez-vous nous faire parvenir des photos du dommage ainsi que votre numero de commande afin de proceder au remboursement ?
Observations a retenir :
- Le test sans secret d’authentification est refuse d’emblee via un statut HTTP 401 sans solliciter l’IA ;
- Les categories attribuees sont parfaitement conformes aux sollicitations. L’urgence maximale (niveau 3) n’a ete affectee qu’a la requete mentionnant un delai court (« avant vendredi ») ;
- Les reponses generees sont pertinentes : dans le cas de la reclamation, l’IA a judicieusement demande une photo justificative et le numero de commande ;
- Un detail typographique : le modele peut occasionnellement employer des tirets longs cadratins. Si votre charte l’interdit, precisez-le explicitement dans le prompt systeme.
Une difficulte rencontree lors des essais : sous Git Bash sur Windows, envoyer des caracteres accentues directement dans l’argument -d '...' d’un appel curl a corrompu l’encodage (erreur HTTP 400 « There was an error parsing the body »). L’ecriture du payload dans un fichier externe transmis via --data-binary @fichier.json ou l’usage d’un script Python a resolu l’anomalie.
Comment exposer un webhook sur internet
Une URL en 127.0.0.1 reste confinee a votre environnement local. Pour recevoir des signaux emis depuis des services externes en ligne, plusieurs solutions existent :
- Pour la phase de test : un tunnel securise comme ngrok ou Cloudflare Tunnel, fournissant un lien public HTTPS temporaire pointant vers votre port local 8000 ;
- Pour une mise en production : un hebergement dedie ou une plateforme cloud telle que Railway, qui permet d’executer directement le script Python et d’obtenir une adresse permanente ;
- Sans infrastructure dediee : receptionner directement le webhook dans des plateformes comme Make, Zapier ou n8n qui se chargeront d’interroger ensuite l’IA.
Privilegiez systematiquement le protocole HTTPS et l’usage d’un secret partage. Des acteurs tels que Stripe ou GitHub renforcent ce mecanisme en signant chaque payload avec une cle HMAC, ce qui permet de controler l’authenticite de l’expediteur par validation cryptographique.
Configuration identique sur Make (No-Code)
- Creez un nouveau scenario et ajoutez en declencheur le module Webhooks, Custom webhook. Make genere automatiquement une adresse URL.
- Collez cette URL dans les parametres de votre outil de formulaire (Typeform, Tally, module WordPress) et soumettez une donnee de test pour que Make en deduise le schema JSON.
- Inserez un module OpenAI (ou un module HTTP vers OpenRouter) configurant les memes instructions et le formatage JSON.
- Ajoutez le module JSON, Parse JSON afin de transformer la sortie du modele en variables manipulables.
- Ajoutez ensuite le module Google Sheets, Add a row pour mapper chaque donnee vers les colonnes appropriees.
- Optionnel : inserez un filtre conditionnel « urgence = 3 » suivi d’un module d’alerte immediate.
Sur Make, chaque execution consomme quelques credits (un par module traverse). Le palier gratuit accorde 1 000 operations par mois et 2 scenarios actifs. Pour approfondir le fonctionnement de cette plateforme, retrouvez notre article detaille sur le fonctionnement et la tarification de Make.
Configuration identique sur Zapier
- Declencheur (Trigger) : Webhooks by Zapier, Catch Hook (fournissant l’URL d’ecoute), ou directement le connecteur de votre outil de formulaire s’il figure au catalogue.
- Action : module ChatGPT ou AI by Zapier pour executer la classification et la generation.
- Action : module Google Sheets, Create Spreadsheet Row.
Le connecteur Webhooks de Zapier etant une fonctionnalite Premium, son acces necessite une offre payante (formule Professional des environ 17,88 EUR / mois soit 19,99 USD en engagement annuel, ou 26,82 EUR / mois soit 29,99 USD sans engagement ; conversion indicative basee sur le taux BCE du 12.10.2026 : 1 EUR = 1,1181 USD). De plus, ce flux comprend trois etapes, depassant la limite imposee par l’offre gratuite. Une analyse comparative approfondie est disponible dans notre article Zapier : fonctionnement et tarifs.
Python, Make ou Zapier : quel choix selon vos besoins
| Solution | Cout fixe | Prerequis | Public cible |
|---|---|---|---|
| Serveur dedie (FastAPI) | Hebergement (gratuit en local avec tunnel) | Bases de Python | Maitrise totale du code et cout d’execution minimal par requete |
| n8n (auto-heberge) | Version Community gratuite, frais de serveur | Gestion d’un VPS | Volumes importants de donnees avec hebergement souverain |
| Make | Des 0 EUR (1 000 operations) | Navigateur web | Scenarios automatises complexes et embranchements conditionnels |
| Zapier | Webhooks reserves au plan Professional | Navigateur web | Deploiement ultra-rapide sans maintenance technique |
Foire aux questions
Qu’est-ce qu’un webhook en termes simples ?
Il s’agit d’une adresse web dediee sur laquelle un service informatique envoie automatiquement un message des qu’un evenement defini se produit, en y joignant les donnees correspondantes.
Quelle est la difference fondamentale entre un webhook et une API ?
Avec une API classique, vous sollicitez un service pour recuperer des informations. Avec un webhook, vous etes notifie directement des qu’une information est produite : le service distant realise lui-meme la requete vers votre point d’entree.
Un webhook est-il securise ?
La securite depend de votre mise en oeuvre. Un chiffrement HTTPS combine a un jeton secret dans les en-tetes constitue le strict minimum. Pour les flux critiques, la signature HMAC, la verification de l’horodatage pour eviter les attaques par rejeu et la limitation de taille du payload sont fortement recommandees.
Comment tester un webhook sans hebergement public ?
Vous pouvez tester votre script directement sur l’adresse locale 127.0.0.1 via une requete simulee, ou utiliser un outil de tunnelisation qui assigne temporairement une adresse web accessible a votre port machine.
Que se passe-t-il si votre serveur d’ecoute est temporairement inaccessible ?
Tout depend de l’emetteur. Des acteurs comme Stripe tentent de reemettre la requete a intervalles reguliers. A l’inverse, un formulaire web basique abandonnera l’envoi. Pour les architectures a fort trafic, il convient de renvoyer un accuse de reception immediat et de deleguer le traitement lourd de l’IA a une file d’attente asynchrone.
Peut-on declencher un agent autonome avec un webhook ?
Absolument. C’est l’un des mecanismes les plus frequents : la reception du signal initie une boucle de raisonnement et l’execution d’outils d’automatisation. Nous detaillons cette construction dans notre guide expliquant comment concevoir un agent IA en Python.
Google · Vos sourcesPromptif plus haut dans Google - en un clicAjouter aux sources préférées →Sources et verification des informations
- Grilles tarifaires : Make, Zapier, n8n (verifiees le 4 octobre 2026).
- Documentation officielle FastAPI.
- Tests pratiques : realises sur environnement local le 4 octobre 2026 a 14:11 avec des donnees simulees.


