C'est l'une des questions les plus fréquentes quand on commence à construire des intégrations : est-ce que je dois poller l'API toutes les X minutes, ou est-ce que je configure un webhook ?
La réponse dépend de quelques critères simples. Voici comment décider.
Les deux approches
Polling : vous demandez
Votre serveur → API tierce : "Est-ce qu'il y a du nouveau ?"
↑ ↓
└────── répond "non" ou "oui + données"
Votre système interroge périodiquement une API pour détecter des changements.
// Exemple : vérifier de nouveaux leads toutes les 5 minutes
async function pollForNewLeads() {
const lastCheck = await getLastCheckTime()
const response = await fetch(
`https://api.crm.com/leads?created_after=${lastCheck.toISOString()}`,
{ headers: { Authorization: `Bearer ${process.env.CRM_API_KEY}` } }
)
const leads = await response.json()
if (leads.length > 0) {
await processLeads(leads)
}
await updateLastCheckTime(new Date())
}
// Dans n8n : nœud Schedule Trigger toutes les 5 minutes
Webhook : on vous notifie
API tierce → Votre endpoint : "Événement ! Voici les données."
↑
└── Vous avez juste à traiter la requête entrante
L'API tierce appelle votre endpoint dès qu'un événement se produit.
// Votre endpoint webhook (Next.js Route Handler)
export async function POST(request: Request) {
const payload = await request.json()
// Vérifier la signature (sécurité)
const signature = request.headers.get('x-webhook-signature')
if (!verifySignature(payload, signature)) {
return new Response('Unauthorized', { status: 401 })
}
// Traiter l'événement
if (payload.event === 'lead.created') {
await processNewLead(payload.data)
}
return new Response('OK', { status: 200 })
}
Tableau comparatif
| Critère | Polling | Webhook | | ----------------- | -------------------------------------- | -------------------------------------------- | | Latence | Intervalle de poll (1min → 1h) | Quasi-temps réel (< 1s) | | Ressources | Requêtes inutiles si pas de changement | Uniquement quand il y a du nouveau | | Complexité | Simple à implémenter | Nécessite un endpoint public | | Fiabilité | Dépend de la disponibilité API | L'émetteur peut retry si votre endpoint fail | | Coût API | Chaque poll = 1 requête (quotas) | 0 requête si pas d'événement | | Disponibilité | API tierce doit supporter le polling | Votre serveur doit être accessible |
Quand utiliser le polling
Utilisez le polling quand :
- L'API ne supporte pas les webhooks — encore fréquent avec les vieilles APIs
- Vous n'avez pas d'endpoint public — développement local, réseau privé
- La donnée n'a pas besoin d'être temps réel — reporting quotidien, batch overnight
- L'événement est difficile à modéliser — "détecte si la valeur dépasse X"
// Bon cas pour le polling : alerte si stock < seuil
// L'API ne génère pas d'événement "stock bas"
async function checkInventoryAlerts() {
const products = await shopifyClient.products.list({ limit: 250 })
const lowStock = products.filter(p =>
p.variants.some(v => v.inventory_quantity < v.inventory_policy_threshold)
)
if (lowStock.length > 0) {
await sendSlackAlert({
message: `⚠️ ${lowStock.length} produits en stock critique`,
products: lowStock.map(p => p.title),
})
}
}
Quand utiliser les webhooks
Utilisez les webhooks quand :
- La réactivité est importante — paiement confirmé → envoyer l'email dans la seconde
- Le volume d'événements est élevé — éviter des milliers de requêtes inutiles
- L'API les supporte — Stripe, GitHub, HubSpot, Notion, Typeform...
- Vous voulez du vrai temps réel — notification push, chatbot, alertes critiques
Gestion des webhooks en production
La partie délicate des webhooks : vous devez être robuste à la réception.
// Pattern recommandé : répondre vite, traiter en async
export async function POST(request: Request) {
const payload = await request.json()
// 1. Valider immédiatement
if (!isValidPayload(payload)) {
return new Response('Bad Request', { status: 400 })
}
// 2. Répondre vite — Stripe abandonne après 30s
const response = new Response('Accepted', { status: 202 })
// 3. Traiter en arrière-plan (Edge Function, Queue, etc.)
void processWebhookAsync(payload)
return response
}
Vérification de signature — obligatoire :
function verifyStripeSignature(payload: string, signature: string): boolean {
const expectedSig = crypto
.createHmac('sha256', process.env.STRIPE_WEBHOOK_SECRET!)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(`sha256=${expectedSig}`))
}
Ne jamais skip cette vérification — n'importe qui peut appeler votre endpoint sans ça.
Le piège que tout le monde découvre trop tard : les doublons
Les fournisseurs de webhooks (Stripe en tête) garantissent une livraison au moins une fois, pas exactement une fois. En pratique : un timeout réseau, une réponse lente de votre endpoint, ou un simple retry automatique côté émetteur, et vous recevez deux fois le même événement — parfois à quelques secondes d'écart, parfois plusieurs heures après.
Si votre traitement n'est pas idempotent, ça se traduit par un email envoyé deux fois, un paiement compté deux fois dans un dashboard, ou une entrée dupliquée en base. Le fix est simple à condition d'y penser dès le départ :
async function processWebhookAsync(payload: StripeEvent) {
// Chaque événement Stripe a un id unique et stable, même en cas de retry
const alreadyProcessed = await db.webhookEvents.findUnique({
where: { eventId: payload.id },
})
if (alreadyProcessed) {
console.log(`Événement ${payload.id} déjà traité, on ignore`)
return
}
await db.webhookEvents.create({ data: { eventId: payload.id, processedAt: new Date() } })
await handleEvent(payload)
}
Une table (ou même une entrée Redis avec TTL) qui garde trace des event.id déjà traités suffit dans la grande majorité des cas. Le coût est négligeable comparé au temps perdu à débugger "pourquoi ce client a reçu deux factures" trois semaines après la mise en prod.
L'approche hybride
Dans la pratique, on combine souvent les deux :
- Webhook pour les événements critiques en temps réel (paiement, lead entrant)
- Polling pour la réconciliation périodique (vérifier qu'aucun webhook n'a été manqué)
Stripe → Webhook → Traiter paiement → Envoyer email
↓ (si webhook manqué)
Polling quotidien → Réconcilier avec Stripe API
C'est l'architecture utilisée par Stripe lui-même pour ses propres systèmes critiques.
En résumé
Webhook = temps réel, efficace, mais nécessite un endpoint robuste Polling = simple, universel, mais consomme des ressources à vide
La règle pratique : si l'API le supporte et que vous avez besoin de réactivité, utilisez les webhooks. Sinon, le polling avec un bon intervalle est parfaitement suffisant pour 80% des cas.