Webhook cos’è? Se hai mai sentito parlare di “webhook” in una riunione tecnica, in una documentazione di Stripe o nelle impostazioni di Shopify e ti sei chiesto cosa significhi davvero, sei nel posto giusto. In questa guida 2021 vediamo, in modo chiaro e operativo, cos’è un webhook, come funziona, in che cosa differisce dalle classiche API REST in polling, e come si usa nelle integrazioni reali tra ERP, CRM, e-commerce e gateway di pagamento.
L’obiettivo è duplice: dare agli IT manager e ai project manager le categorie giuste per parlare con i fornitori, e fornire ai developer junior una mappa concettuale solida prima di scrivere il primo ricevitore. Per chi vuole partire dalle basi delle API, consigliamo prima la lettura del nostro pillar dedicato alla guida alle API REST per non sviluppatori: questo articolo ne è il complemento naturale.

1. Webhook: cos’è davvero (analogia “campanello vs chiamata”)
Il termine “webhook” nasce nel 2007 grazie a Jeff Lindsay, che lo introdusse per descrivere un meccanismo molto semplice: una callback HTTP. In pratica, un webhook è un endpoint URL che tu pubblichi sul tuo server e che un sistema esterno (Stripe, Shopify, Slack, GitHub, HubSpot…) chiama automaticamente quando accade un evento di interesse.
L’analogia più efficace è quella del campanello di casa. Immagina di aspettare un pacco. Hai due opzioni:
- Polling (chiamata): ogni 5 minuti scendi in strada e chiedi al corriere se è arrivato. Spreca tempo ed energia, soprattutto se il pacco arriverà solo nel pomeriggio.
- Webhook (campanello): lasci il citofono pronto. Quando il corriere arriva, suona. Tu rispondi solo quando serve.
Il webhook è esattamente questo: un meccanismo “push” event-driven. Il sistema sorgente dice “appena succede X, ti avviso io chiamando il tuo URL”. Tu non devi più chiedere continuamente “è successo qualcosa?”, ma reagire quando il messaggio arriva.
Questo cambia profondamente l’architettura delle integrazioni. Invece di costruire processi schedulati che ogni ora interrogano l’API di Shopify per scaricare nuovi ordini, registri un webhook su orders/create e ricevi l’ordine nel momento esatto in cui il cliente conclude il checkout. Il delta in termini di tempo, banda e affidabilità è enorme.
2. Webhook vs API REST polling: differenza fondamentale
Capire webhook vs API è il primo passo per progettare integrazioni sane. In realtà i due concetti non sono in contrapposizione: un webhook è una chiamata HTTP, e quasi sempre i sistemi che inviano webhook offrono anche API REST tradizionali. La differenza non è “tecnologica”, ma di direzione e di ingaggio.
| Aspetto | API REST (polling) | Webhook (push) |
|---|---|---|
| Chi inizia la chiamata | Il client (tu) | Il sistema sorgente (es. Stripe) |
| Quando avviene | Periodicamente (es. ogni 5 min) | Al momento dell’evento |
| Ritardo medio | Da pochi secondi a decine di minuti | Quasi tempo reale (millisecondi) |
| Carico | Alto: tante chiamate spesso a vuoto | Basso: solo eventi reali |
| Configurazione | Solo client | Server pubblico + URL accessibile |
| Affidabilità | Tu controlli i retry | Il provider gestisce i retry |
Detto questo, anche nel 2021 il polling resta utile in due scenari: quando il sistema sorgente non offre webhook (succede ancora con molti gestionali italiani), e quando devi fare reconciliation periodica per recuperare eventi persi (esempio: ogni notte scarichi tutti gli ordini delle ultime 48 ore per essere sicuro di non aver perso nulla).
La regola d’oro è: webhook per la reattività, polling per la consistenza. Un’integrazione robusta tipicamente li combina entrambi.
3. Come funziona tecnicamente un webhook
Tecnicamente, un webhook è una banale richiesta HTTP, di solito POST, verso un URL che tu hai dichiarato al provider. Il flusso è questo:
- Tu pubblichi un endpoint, ad esempio
https://app.tuodominio.it/webhooks/stripe. - Vai nel pannello del provider (Stripe, Shopify, GitHub…) e registri quell’URL, scegliendo a quali eventi iscriverti (es.
checkout.session.completed). - Quando l’evento si verifica, il provider esegue una richiesta
POSTverso il tuo URL, includendo nel body un payload JSON con i dati dell’evento. - Il tuo server elabora il payload e risponde con un codice
2xx(tipicamente200 OKo204 No Content) per confermare la ricezione. - Se rispondi con un errore
5xxo vai in timeout, il provider riproverà secondo la propria policy di retry.
Un payload tipico, semplificato, ha questa forma:
POST /webhooks/stripe HTTP/1.1
Host: app.tuodominio.it
Content-Type: application/json
Stripe-Signature: t=1614950820,v1=5257a869e7...
{
"id": "evt_1ICwS62eZvKYlo2C...",
"type": "checkout.session.completed",
"created": 1614950820,
"data": {
"object": {
"id": "cs_test_a1B2c3...",
"amount_total": 4990,
"currency": "eur",
"customer_email": "mario.rossi@example.it"
}
}
}
Da questo si capisce un punto cruciale: chi riceve il webhook deve avere un endpoint HTTPS pubblico e raggiungibile. Non puoi ricevere webhook su un server che sta dietro firewall o solo in rete locale, a meno di non usare tunnel come ngrok in fase di sviluppo.

4. Casi d’uso 2021: Stripe, Shopify, Slack, GitHub
I webhook nel 2021 sono diventati lo standard per integrare quasi qualsiasi servizio cloud. Vediamo i casi più comuni che troviamo nei progetti di integrazione API per PMI italiane.
Stripe: pagamenti e abbonamenti
Stripe è il caso scuola. Quando un cliente completa un pagamento, Stripe invia un webhook checkout.session.completed al tuo server. Solo a quel punto puoi creare l’ordine nel tuo gestionale, generare la fattura, abilitare l’accesso al servizio. Affidarsi solo al redirect del browser è rischioso (l’utente può chiudere la pagina): il webhook è la fonte di verità.
Shopify: ordini e magazzino
Shopify offre webhook su orders/create, orders/paid, products/update, inventory_levels/update. Tipico utilizzo: quando arriva un ordine su Shopify, un webhook scarica i dati nel modulo e-commerce Odoo e crea automaticamente la commessa di spedizione. Quando il magazzino aggiorna le giacenze, un webhook in direzione opposta sincronizza le quantità sul sito.
Slack: notifiche operative
Gli “Incoming Webhook” di Slack permettono al tuo software di pubblicare messaggi in un canale. Esempio: ogni volta che il monitoring rileva un errore in produzione, un webhook posta automaticamente in #alerts-erp. Zero email, reazione immediata del team.
GitHub: CI/CD e automazioni
Quando uno sviluppatore fa git push, GitHub invia un webhook al server di build (Jenkins, GitLab CI, CircleCI) che avvia automaticamente test e deploy. È il cuore di qualsiasi pipeline DevOps moderna.
HubSpot, Mailchimp, Typeform
Ogni volta che un lead compila un form, un webhook può inviare i dati direttamente al CRM aziendale, marcando il contatto come “interessato” e attivando la sequenza commerciale. Questa è la base dell’automazione dei processi commerciali.
5. Sicurezza dei webhook: HMAC signature e timestamp
Pubblicare un endpoint sul web significa esporlo al mondo. Chiunque può inviarti una POST finta che sembra venire da Stripe. Senza protezioni, un attaccante potrebbe forgiare un payload “pagamento confermato” e farti spedire un prodotto mai pagato. Per questo i webhook seri usano la firma HMAC.
Il meccanismo è elegante:
- Provider e ricevente condividono un secret generato in fase di setup (mai trasmesso nel payload).
- Il provider calcola un hash HMAC-SHA256 del body (spesso concatenato a un timestamp) usando il secret come chiave.
- Lo trasmette in un header (es.
Stripe-Signature,X-Hub-Signature-256per GitHub). - Il ricevente ricalcola lo stesso HMAC con il proprio secret e lo confronta con l’header. Se coincidono, il payload è autentico.
Inoltre molte implementazioni includono un timestamp nel calcolo: il ricevente accetta solo richieste con timestamp recenti (es. ultimi 5 minuti) per prevenire i replay attack, ovvero tentativi di rispedire una richiesta legittima catturata in passato.
Buone pratiche aggiuntive nel 2021:
- Endpoint sempre su HTTPS con certificato valido (Let’s Encrypt è gratuito, non ci sono scuse).
- Secret diversi per ogni provider, custoditi in variabili d’ambiente, mai committati in git.
- Confronto delle firme con funzioni constant-time (es.
hash_equalsin PHP) per evitare timing attack. - Logging di tutti i webhook ricevuti, validati e rifiutati, per audit e debugging.
- Rate limiting sull’endpoint per mitigare flood.

6. Come implementare il ricevitore di un webhook
Vediamo a livello concettuale come si scrive un ricevitore di webhook nei tre stack più diffusi nel 2021. Non sono esempi pronti per la produzione, ma servono a fissare la struttura mentale.
PHP / Laravel
// routes/api.php
Route::post('/webhooks/stripe', [StripeWebhookController::class, 'handle']);
// app/Http/Controllers/StripeWebhookController.php
public function handle(Request $request) {
$payload = $request->getContent();
$signature = $request->header('Stripe-Signature');
$secret = env('STRIPE_WEBHOOK_SECRET');
if (!$this->verifySignature($payload, $signature, $secret)) {
return response('Invalid signature', 401);
}
$event = json_decode($payload, true);
// dispatch su queue per non bloccare il provider
ProcessStripeEvent::dispatch($event);
return response('', 200);
}
Node.js / Express
app.post('/webhooks/stripe',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body, sig, process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
queue.add('stripe-event', event);
res.json({ received: true });
}
);
Python / FastAPI
@app.post("/webhooks/stripe")
async def stripe_webhook(request: Request):
payload = await request.body()
sig = request.headers.get("stripe-signature")
try:
event = stripe.Webhook.construct_event(
payload, sig, settings.STRIPE_WEBHOOK_SECRET
)
except stripe.error.SignatureVerificationError:
raise HTTPException(401, "Invalid signature")
background_tasks.add_task(process_event, event)
return {"received": True}
Il pattern è sempre lo stesso: verifica la firma, accoda l’elaborazione, rispondi 200 il prima possibile. Mai fare lavoro pesante (query lente, chiamate ad altre API, invio email) nel ciclo di richiesta del webhook. La maggior parte dei provider ha timeout di 5-30 secondi: se ci metti di più, ti rispediranno la stessa richiesta.
7. Gestione retry: cosa fare se il ricevitore è giù
Cosa succede se il tuo server è offline al momento del webhook? Tutti i provider seri implementano una policy di retry. Ecco le strategie tipiche nel 2021:
- Stripe: retry per 3 giorni con backoff esponenziale. Smette dopo molti tentativi falliti e marca l’evento come “failed” nel pannello.
- Shopify: retry per 48 ore, fino a 19 tentativi. Disattiva l’endpoint dopo 19 fallimenti consecutivi.
- GitHub: retry minimi (8 tentativi nelle prime 8 ore). Conta sulla pagina “Recent Deliveries” per il rinvio manuale.
- HubSpot: retry fino a 24 ore con backoff.
Per il ricevente questo significa che non puoi presumere che ogni evento arrivi una sola volta. Devi progettare l’integrazione assumendo che lo stesso webhook possa arrivare due, tre, dieci volte. Da qui la necessità dell’idempotenza.
Inoltre conviene sempre integrare un meccanismo di fallback via polling: una volta al giorno scarichi gli ordini delle ultime 48 ore via API REST e verifichi che siano tutti già nel tuo sistema. Se ne manca qualcuno (perché il webhook è andato perso definitivamente), lo recuperi a posteriori. Questo schema è particolarmente importante per le integrazioni con web app e PWA business critical.
8. Idempotenza: perché conta nei webhook
Un’operazione è idempotente quando eseguirla N volte produce lo stesso risultato di eseguirla una volta sola. Nei webhook l’idempotenza non è un nice-to-have, è il bug fix più importante che puoi prevenire.
Esempio concreto: arriva il webhook order.paid di Stripe. Il tuo handler crea l’ordine nel gestionale, manda la fattura via email, addebita il magazzino. Tutto bello. Ma il provider, per un timeout di rete, rispedisce lo stesso evento. Il tuo server riceve di nuovo order.paid e, se non sei idempotente, crea un secondo ordine, manda una seconda fattura, scarica un secondo pezzo dal magazzino. Disastro.
Le strategie 2021 per garantire idempotenza:
- Event ID univoco: ogni provider include un ID dell’evento (es.
evt_1ICwS6...in Stripe). Salvi questi ID in una tabella e ignori gli eventi già processati. - Lock applicativo: prima di elaborare l’evento, prendi un lock su
event_id(in Redis o in DB) e lo rilasci a fine processing. - Operazioni naturalmente idempotenti: se devi solo “settare lo stato dell’ordine a PAGATO”, farlo due volte non cambia nulla. Il problema esiste invece su INSERT, send email, accrediti.
- Transazioni atomiche: wrappa “marca evento come processato” e “applica il side effect” in un’unica transazione DB.
9. Webhook nelle integrazioni e-commerce, gestionale, CRM
Nei progetti reali raramente costruiamo un’integrazione webhook isolata: quasi sempre fa parte di un flusso multi-sistema. Vediamo tre scenari ricorrenti per le PMI italiane nel 2021.
E-commerce → ERP
Cliente compra su Shopify/WooCommerce → webhook al middleware → middleware crea l’ordine in Odoo/SAP/gestionale custom → ERP genera DDT, fattura elettronica via SDI, prepara la spedizione. Sul ritorno: ERP emette webhook (o evento interno) verso il sito per aggiornare lo stato a “spedito” e inviare il tracking al cliente.
Form lead → CRM → Marketing automation
Utente compila form su sito (Typeform, Gravity Forms, custom) → webhook a HubSpot/Mailchimp → CRM crea/aggiorna il contatto → trigger sequenza email + notifica Slack al commerciale. Il tutto in 1-2 secondi, senza intervento umano.
Pagamento ricorrente → Servizio
SaaS in abbonamento: Stripe Subscriptions invia webhook invoice.paid ogni mese → backend prolunga la validità dell’account. Quando arriva invoice.payment_failed, parte una sequenza di dunning (email di sollecito) e dopo N tentativi falliti il servizio viene sospeso.
In tutti questi casi il middleware (proprietario o in cloud, vedi sezione successiva) fa da “centralino” e disaccoppia i sistemi: se Shopify cambia il formato dei suoi webhook, modifichi solo il middleware, non l’ERP.
10. Strumenti per testare webhook nel 2021
Sviluppare e debuggare integrazioni webhook è notoriamente fastidioso, perché il tuo localhost non è raggiungibile dal mondo esterno. Per fortuna nel 2021 abbiamo strumenti maturi:
- Webhook.site: il modo più rapido per ispezionare cosa invia un provider. Ti dà un URL temporaneo e mostra in tempo reale ogni richiesta che lo colpisce, con headers, body, query string. Perfetto per “vedere com’è fatto” un webhook prima di scrivere il codice.
- ngrok: crea un tunnel HTTPS pubblico verso il tuo localhost (es.
https://abc123.ngrok.io→localhost:8000). Configuri Stripe/Shopify per chiamare l’URL ngrok e debugghi in locale come se fossi in produzione. - Stripe CLI: il comando
stripe listen --forward-to localhost:8000/webhooks/stripesimula i webhook in locale senza nemmeno bisogno di ngrok. Esiste anchestripe trigger checkout.session.completedper generare eventi a comando. - Postman: per inviare a mano richieste POST al tuo endpoint con payload personalizzati, utile per testare i casi limite e gli errori.
- Zapier / Integromat: piattaforme low-code che permettono di costruire integrazioni webhook senza scrivere codice. Hanno limiti (cost per task, latenza), ma sono un ottimo prototipo. Nota: nel 2021 si chiama ancora Integromat, il rebrand in Make arriverà nel 2022.
- n8n: alternativa open source self-hosted a Zapier, ottima quando i dati non possono uscire dall’azienda.
11. Errori comuni nelle implementazioni webhook
Negli anni abbiamo visto i seguenti errori ricorrenti, dai progetti più semplici a quelli enterprise:
- Non verificare la firma HMAC: l’endpoint accetta qualsiasi payload, esponendosi a frode.
- Elaborare in modo sincrono operazioni lente: chiamate ad altre API, invio email, generazione PDF. Risultato: timeout, retry infiniti, payload duplicati.
- Non gestire l’idempotenza: ordini doppi, fatture doppie, email doppie quando un retry arriva.
- Rispondere con codici di errore per logiche applicative: se l’ordine “esiste già”, non rispondere 500. Rispondi 200 (l’evento l’hai ricevuto correttamente, semplicemente non c’era nulla da fare).
- Mancanza di logging: quando qualcosa non funziona, senza log dettagliati il debug è un incubo.
- Endpoint dietro autenticazione standard (Basic Auth, sessione): il provider non ha modo di autenticarsi nel modo che ti aspetti. Usa solo HMAC o IP allowlist.
- Hardcoding del secret nel codice: deve stare in
.env, mai in git. - Nessun monitoring: se i webhook smettono di arrivare per un’ora, te ne accorgi solo quando il cliente chiama arrabbiato. Implementa health check + alert.
- Mancanza di reconciliation: dopo un downtime di 2 ore, alcuni eventi sono andati persi per sempre. Senza un job notturno di riconciliazione via API, hai dati mancanti.
12. Domande frequenti sui webhook
Webhook e API REST sono la stessa cosa?
No, ma sono complementari. Un webhook è una chiamata HTTP in entrata verso il tuo server, fatta dal provider quando accade un evento. Un’API REST è una chiamata HTTP in uscita dal tuo server, fatta da te quando vuoi leggere o scrivere dati. Stripe, Shopify, GitHub espongono entrambe.
Posso ricevere webhook senza un server pubblico?
In sviluppo sì, usando ngrok o servizi simili che tunnellano il traffico dal cloud al tuo localhost. In produzione hai bisogno di un server con IP pubblico e dominio HTTPS valido. Soluzioni serverless come AWS Lambda + API Gateway o Cloudflare Workers funzionano benissimo come ricevitori, anche per piccoli volumi a costo quasi zero.
Quanti webhook posso ricevere al secondo?
Dipende dall’infrastruttura. Un’app PHP/Laravel su un VPS modesto regge tranquillamente 50-100 webhook al secondo se l’handler accoda subito su Redis/RabbitMQ e risponde 200. Se invece processa tutto sincrono, il limite scende drasticamente. La regola: thin handler, fat worker.
Cosa fare se perdo un webhook?
I provider conservano gli eventi per giorni o settimane. Stripe e Shopify hanno una pagina “Webhook deliveries” da cui puoi rinviare manualmente un evento. Per i casi sistematici, implementa un job di reconciliation che ogni notte scarichi via API gli eventi delle ultime 48 ore e verifichi la sincronia con il tuo database.
Posso usare Zapier al posto di scrivere codice?
Sì, per integrazioni semplici a basso volume Zapier (e n8n self-hosted) è perfetto. I limiti emergono quando: (a) il volume mensile supera i piani gratuiti, (b) servono trasformazioni dati complesse, (c) la latenza diventa critica, (d) non puoi inviare i dati a un servizio terzo per ragioni GDPR. In quei casi serve codice custom.
I webhook funzionano con Telegram, WhatsApp, email?
Telegram Bot API supporta webhook nativamente (puoi ricevere ogni messaggio inviato al bot via POST). WhatsApp Business API anche, ma richiede approvazione Meta. Le email no: sono push, ma usano SMTP/IMAP, non webhook HTTP. Servizi come SendGrid e Mailgun emettono però webhook su eventi correlati (delivered, bounced, opened).
Per approfondire
Riferimento concettuale su Wikipedia (Webhook) e documentazione operativa lato provider: Stripe Webhooks.
Devi integrare sistemi via webhook?
Brentasoft sviluppa integrazioni custom con webhook tra ERP, CRM, e-commerce, gateway pagamento e servizi terzi per PMI italiane: ricevitori sicuri, retry, idempotenza e monitoring.