{"id":1390,"date":"2021-09-03T16:24:00","date_gmt":"2021-09-03T14:24:00","guid":{"rendered":"https:\/\/brentasoft.com\/blog\/?p=1390"},"modified":"2026-06-03T15:32:00","modified_gmt":"2026-06-03T13:32:00","slug":"webhook-vs-polling-integrazioni-2021","status":"publish","type":"post","link":"https:\/\/brentasoft.com\/blog\/webhook-vs-polling-integrazioni-2021\/","title":{"rendered":"Webhook vs API polling: quale scegliere per le tue integrazioni (2021)"},"content":{"rendered":"<div class=\"tldr-box\" style=\"background:#f0f9ff;border-left:4px solid #0284c7;padding:18px 22px;margin:24px 0;border-radius:6px;\">\n<p><strong>TL;DR \u2014 Webhook o polling per integrare due sistemi?<\/strong><\/p>\n<ul>\n<li><strong>Polling<\/strong>: il tuo software chiama l&#8217;API a intervalli regolari (es. ogni 5 minuti). Semplice, funziona dietro qualunque firewall, ma spreca banda e introduce latenza.<\/li>\n<li><strong>Webhook<\/strong>: il fornitore invia una richiesta <strong>HTTPS<\/strong> al tuo endpoint nel momento esatto in cui accade l&#8217;evento. Latenza sotto il secondo, ma richiede endpoint pubblico, validazione <strong>HMAC<\/strong>, gestione <strong>idempotency<\/strong> e <strong>retry policy<\/strong> robusta.<\/li>\n<li><strong>Regola pratica<\/strong>: webhook ovunque disponibile (pagamenti, ordini, ticket), polling come fallback per API legacy. In produzione vince l&#8217;<em>hybrid<\/em>: webhook real-time + polling di riconciliazione ogni 6-12 ore.<\/li>\n<li><strong>Per una PMI<\/strong>: il salto da polling 5 min a webhook real-time riduce la latenza da 300 secondi a 1-2 secondi e taglia le chiamate API di 50-100x.<\/li>\n<\/ul>\n<\/div>\n<h2 id=\"contesto-2021\">Le integrazioni SaaS nel 2021 sono diventate un problema operativo<\/h2>\n<p>Nel 2021 la PMI italiana media non lavora pi\u00f9 con un solo gestionale: usa un <strong>CRM<\/strong> sul cloud, una piattaforma e-commerce, un sistema di fatturazione elettronica, uno strumento di customer support, un&#8217;app di project management, una suite di marketing automation e quasi sempre un ERP on-premise sopravvissuto da prima della migrazione. Secondo gli osservatori pubblicati nel 2021 (Productiv, Okta), l&#8217;azienda B2B sotto i 500 dipendenti utilizza in media tra <strong>50 e 80 applicazioni SaaS<\/strong> distinte, e il numero cresce del 30% annuo. Ogni applicazione \u00e8 un silos di dati che deve dialogare con almeno tre o quattro altre per non costringere gli operatori al copia-incolla manuale.<\/p>\n<p>A quel volume il problema dell&#8217;integrazione diventa <em>il<\/em> problema. Lo affronti in due modi: o <strong>fai polling<\/strong> sulle API delle altre piattaforme (interroghi periodicamente &#8220;ci sono novit\u00e0?&#8221;), o ricevi un <strong>webhook<\/strong>, cio\u00e8 una notifica HTTP che parte automaticamente quando qualcosa cambia dall&#8217;altra parte. Entrambe le strade funzionano, ma scegliere male significa pagare in tre modi: <em>banda sprecata<\/em>, <em>dati in ritardo<\/em>, o <em>integrazioni fragili che si rompono ogni cambio di rete<\/em>.<\/p>\n<p>In questa guida confronto polling e webhook nel concreto, con esempi 2021 da <strong>Stripe webhooks<\/strong>, <strong>Shopify<\/strong>, <strong>GitHub<\/strong> e da progetti reali in PMI italiane. Vedrai quando preferire uno o l&#8217;altro, come implementare la sicurezza con <strong>HMAC SHA-256<\/strong>, come gestire <strong>idempotency<\/strong> e <strong>retry<\/strong>, e una <strong>roadmap di 60 giorni<\/strong> per migrare da polling a webhook senza incidenti.<\/p>\n<h2 id=\"cosa-e-polling\">Cos&#8217;\u00e8 l&#8217;API polling e come funziona<\/h2>\n<p>Il <strong>polling<\/strong> \u00e8 il pattern pi\u00f9 antico e semplice delle integrazioni: ogni X minuti il tuo software esegue una chiamata <strong>HTTPS<\/strong> verso un endpoint REST del fornitore e chiede &#8220;dammi tutto quello che \u00e8 successo dall&#8217;ultimo controllo&#8221;. L&#8217;endpoint risponde con un payload <strong>JSON<\/strong> contenente gli eventi nuovi, e tu li processi.<\/p>\n<h3>Meccanismo: intervallo, cursore, rate limiting<\/h3>\n<p>Un job di polling ben fatto memorizza un <strong>cursore<\/strong> (timestamp <code>updated_at<\/code> o id autoincrementale, o opaque token restituito dall&#8217;API) e a ogni chiamata lo invia per ottenere solo i delta. Esempio classico: <code>GET \/orders?since=2021-09-03T14:23:45Z<\/code>, ricevi solo gli ordini cambiati dopo quel timestamp.<\/p>\n<p>Il problema \u00e8 il <strong>rate limit<\/strong>: tutte le API serie 2021 ne hanno uno. Shopify d\u00e0 2 req\/sec per shop con leaky bucket, HubSpot 100 req in 10 secondi, GitHub 5000 req\/ora autenticate. Se hai 15 integrazioni con polling ogni minuto su 20 endpoint diversi, fai 4320 chiamate\/ora su una sola API \u2014 il 99% torna vuoto perch\u00e9 nulla \u00e8 cambiato. Spreco di banda, rate limit saturato, latenza media pari a met\u00e0 dell&#8217;intervallo.<\/p>\n<h3>Quando il polling resta la scelta giusta<\/h3>\n<ul>\n<li><strong>API senza webhook<\/strong>: ERP legacy, gestionali on-premise, sistemi bancari corporate, parecchi vecchi portali italiani espongono solo REST in lettura. Non hai alternativa.<\/li>\n<li><strong>Dati a bassa frequenza con tolleranza al ritardo<\/strong>: listini che cambiano una volta al giorno, anagrafiche, tabelle di lookup. Polling notturno alle 03:00, fine.<\/li>\n<li><strong>Ambienti di rete restrittivi<\/strong>: se sei dietro firewall corporate senza endpoint pubblico, ricevere webhook \u00e8 complicato. Il polling parte da te verso l&#8217;esterno, attraversa il NAT, non richiede aperture inbound.<\/li>\n<\/ul>\n<h2 id=\"cosa-e-webhook\">Cos&#8217;\u00e8 un webhook e perch\u00e9 ha cambiato le integrazioni<\/h2>\n<p>Un <strong>webhook<\/strong> \u00e8 un <em>HTTP callback<\/em>: configuri presso il fornitore (Stripe, Shopify, GitHub) un URL HTTPS pubblico del tuo sistema; quando succede un evento \u2014 ordine creato, pagamento riuscito, ticket chiuso \u2014 il fornitore invia un <strong>POST<\/strong> al tuo URL con un payload <strong>JSON<\/strong>.<\/p>\n<p>Mentre il polling \u00e8 <em>pull<\/em>, il webhook \u00e8 <em>push<\/em>. L&#8217;evento ti arriva nel momento esatto in cui accade, non al prossimo tick. Se Stripe Checkout completa un pagamento alle 16:24:00, alle 16:24:01 il tuo backend ha gi\u00e0 ricevuto <code>checkout.session.completed<\/code> e aggiornato il database. Nessuna chiamata sprecata, latenza <strong>sub-secondo<\/strong>.<\/p>\n<h3>Anatomia del payload<\/h3>\n<p>Un payload webhook contiene almeno: <em>tipo evento<\/em> (<code>order.created<\/code>, <code>invoice.paid<\/code>), <em>timestamp<\/em>, <em>oggetto modificato<\/em>. Quasi sempre un <strong>event_id<\/strong> univoco \u2014 fondamentale per l&#8217;<strong>idempotency<\/strong> \u2014 e una firma <strong>HMAC<\/strong> negli header HTTP. Stripe invia <code>Stripe-Signature<\/code> con timestamp e firma <strong>HMAC SHA-256<\/strong> calcolata sul body, cos\u00ec puoi rifiutare richieste non firmate.<\/p>\n<p>Per il modello concettuale ne avevo parlato a marzo in <a href=\"https:\/\/brentasoft.com\/blog\/webhook-cos-e-integrazioni-guida\/\">cos&#8217;\u00e8 un webhook<\/a>: qui mi concentro sul confronto operativo con il polling.<\/p>\n<h2 id=\"confronto-tecnico\">Confronto tecnico: latenza, banda, complessit\u00e0, retry<\/h2>\n<h3>Latenza end-to-end<\/h3>\n<p>Polling: latenza media = <em>intervallo \/ 2<\/em>. Polling ogni 5 minuti significa 150 secondi medi, 300 secondi nel caso peggiore. Webhook: <strong>200-1500 ms<\/strong> end-to-end con piattaforme mature come Stripe o Shopify.<\/p>\n<h3>Costo banda e chiamate<\/h3>\n<p>Shop con 200 ordini al giorno e polling ogni 5 minuti: 288 chiamate per intercettare 200 eventi, 88 a vuoto (30%). Stesso shop con webhook: 200 richieste in entrata, zero a vuoto, -69% di traffico API.<\/p>\n<h3>Complessit\u00e0 di implementazione<\/h3>\n<p>Polling: triviale. Scheduler, HTTP client, cursore, parser. Due ore. Webhook: serve endpoint pubblico HTTPS, validazione firma, parsing, storage idempotency, queue, <strong>DLQ<\/strong>. Due-tre giorni, ma il framework \u00e8 poi riutilizzabile.<\/p>\n<h3>Retry policy<\/h3>\n<p>Polling: se la chiamata fallisce, riprovi al ciclo successivo. Webhook: \u00e8 il fornitore a riprovare se rispondi 5xx o vai in timeout. <strong>Stripe webhooks<\/strong> riprova per 3 giorni con <strong>exponential backoff<\/strong>, GitHub 8 ore, Shopify 48 ore con 19 tentativi. Tu devi garantire che l&#8217;endpoint sia <em>idempotente<\/em>: stesso evento ricevuto due volte non deve produrre due ordini.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/brentasoft.com\/blog\/wp-content\/uploads\/2021\/09\/webhook-vs-polling-integrazioni-2021-server-rack.jpg\" alt=\"Patch panel rack server con cavi ethernet e luci LED blu - architettura polling API\" title=\"Polling API: chiamate periodiche sull'infrastruttura di rete\" loading=\"lazy\" \/><\/p>\n<h2 id=\"quando-polling\">Quando preferire polling: tre scenari concreti<\/h2>\n<h3>API legacy senza webhook<\/h3>\n<p>Gestionali italiani on-premise (TeamSystem Polyedro, Zucchetti, Esa Software, Mago.NET) espongono API REST o SOAP in lettura ma non eventi push. Polling intelligente: usa <code>If-Modified-Since<\/code> o <strong>ETag<\/strong> per ridurre traffico, batchifica le query (500 record alla volta, non 50), valuta <em>change data capture<\/em> direttamente sul database se hai accesso SQL.<\/p>\n<h3>Dati a bassissima frequenza<\/h3>\n<p>Listini fornitori settimanali, cambi valuta, indici ISTAT, codici tributo. Configurare un webhook per dati che cambiano una volta al mese \u00e8 overkill, e spesso quelle fonti non li offrono.<\/p>\n<h3>Reti corporate restrittive<\/h3>\n<p>Sistema dietro firewall enterprise senza traffico inbound. Soluzione 2021 pulita: polling outbound, o strumenti tipo <strong>Hookdeck<\/strong> (lanciato nel 2020) come proxy webhook con connessione persistente in uscita verso il tuo backend.<\/p>\n<h2 id=\"quando-webhook\">Quando preferire webhook: real-time, volumi alti, cross-SaaS<\/h2>\n<h3>Pagamenti, ordini, ticket<\/h3>\n<p>Se vendi online con <strong>Stripe webhooks<\/strong>, PayPal IPN, Adyen, devi processare <code>payment_intent.succeeded<\/code> in tempo reale per fatturare, decrementare il magazzino, mandare la conferma. Cinque minuti di ritardo = ticket di supporto, contestazioni, chargeback. Stesso ragionamento per i ticket di customer service: se Zendesk o Freshdesk creano un ticket, il tuo CRM lo deve vedere nel secondo successivo.<\/p>\n<h3>Volumi alti<\/h3>\n<p>Quando hai migliaia di eventi al giorno su una integrazione, il polling diventa proibitivo: o riduci l&#8217;intervallo (e aumenti latenza), o lo aumenti (e saturi il rate limit). I webhook scalano col volume reale di eventi, non con i &#8220;controlli vuoti&#8221;.<\/p>\n<h3>Cross-SaaS via orchestratori<\/h3>\n<p>Piattaforme come <strong>Zapier<\/strong>, Integromat, <strong>n8n<\/strong> self-hosted, <strong>Pipedream<\/strong> hanno i webhook come input nativo. Configuri &#8220;quando Stripe registra un pagamento&#8221; e l&#8217;orchestratore propaga: crea cliente HubSpot, fattura in Fatture in Cloud, Slack al commerciale. Confronto delle tre piattaforme in <a href=\"https:\/\/brentasoft.com\/blog\/zapier-vs-integromat-n8n-confronto-2021\/\">Zapier vs Integromat vs n8n<\/a>.<\/p>\n<h2 id=\"pattern-hybrid\">Il pattern hybrid: webhook + polling di backup<\/h2>\n<p>In produzione per integrazioni mission-critical il pattern vincente \u00e8 <strong>entrambi<\/strong>. Webhook come canale primario real-time. Polling ogni 6-12 ore come riconciliazione, che recupera tutti gli eventi delle ultime 24 ore e verifica che nessuno sia perso.<\/p>\n<p>Perch\u00e9 serve? I webhook <em>possono<\/em> essere persi: il fornitore pu\u00f2 smettere di riprovare oltre un limite, l&#8217;endpoint pu\u00f2 essere down durante un deploy, una richiesta pu\u00f2 fallire la firma per mismatch durante rotazione chiavi. Una riconciliazione notturna cattura questi edge case e garantisce <em>eventual consistency<\/em>. La maggior parte delle implementazioni Stripe in produzione include un job notturno su <code>GET \/v1\/events?created[gte]=&lt;24h_ago&gt;<\/code>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/brentasoft.com\/blog\/wp-content\/uploads\/2021\/09\/webhook-vs-polling-integrazioni-2021-architettura.jpg\" alt=\"Sviluppatore che disegna diagramma architetturale event-driven su lavagna - progettazione webhook\" title=\"Progettare un sistema event-driven con webhook\" loading=\"lazy\" \/><\/p>\n<h2 id=\"implementare-webhook\">Implementare un webhook robusto: la checklist 2021<\/h2>\n<h3>HTTPS obbligatorio<\/h3>\n<p>Webhook su HTTP plaintext = suicidio: chiunque sniffi il traffico vede payload e firme. Tutti i provider seri (Stripe, Shopify, GitHub) rifiutano endpoint non <strong>HTTPS<\/strong> in produzione. Let&#8217;s Encrypt, TLS 1.2 minimo, TLS 1.3 quando il client lo supporta.<\/p>\n<h3>Validazione firma HMAC<\/h3>\n<p>Ogni webhook serio firma il payload con shared secret e <strong>HMAC SHA-256<\/strong>. Il tuo endpoint deve:<\/p>\n<ol>\n<li>Estrarre la firma dall&#8217;header (<code>Stripe-Signature<\/code>, <code>X-Hub-Signature-256<\/code> per GitHub, <code>X-Shopify-Hmac-Sha256<\/code>).<\/li>\n<li>Ricalcolare l&#8217;<strong>HMAC<\/strong> sul body raw (mai sul body deserializzato e riserializzato \u2014 l&#8217;ordine dei campi <strong>JSON<\/strong> rompe la firma).<\/li>\n<li>Confrontare con funzione <em>constant-time<\/em> per evitare timing attack (<code>hash_equals()<\/code> in PHP, <code>crypto.timingSafeEqual()<\/code> in Node).<\/li>\n<li>Rifiutare con 401 se la firma non corrisponde.<\/li>\n<\/ol>\n<p>Dettagli nella guida ad <a href=\"https:\/\/brentasoft.com\/blog\/api-security-best-practice-2021\/\">API security best practice 2021<\/a>.<\/p>\n<h3>Idempotency: la regola d&#8217;oro<\/h3>\n<p>I webhook arrivano duplicati. Sempre. Stripe lo dichiara esplicitamente: &#8220;your endpoint should be designed to be idempotent&#8221;. Ogni evento ha un <strong>event_id<\/strong>, e il primo step del tuo handler deve essere: <em>ho gi\u00e0 processato questo event_id?<\/em> Se s\u00ec, rispondi 200 OK e non fare nulla. Se no, scrivi un record in <code>processed_events(event_id PRIMARY KEY, processed_at)<\/code> in transazione con il lavoro vero. Il vincolo di primary key ti garantisce a livello database che non potrai processarlo due volte. Pattern universale: <em>idempotency-key<\/em> header lo trovi in Stripe, Square, Plaid.<\/p>\n<h3>Retry e backoff<\/h3>\n<p>Mai rispondere 200 se non hai effettivamente processato l&#8217;evento: il fornitore non riprover\u00e0 pi\u00f9. Mai rispondere 4xx per errori transienti: il fornitore non riprover\u00e0 perch\u00e9 interpreta 4xx come &#8220;sei sbagliato tu&#8221;. Usa 5xx per dire &#8220;riprova&#8221;, e processa con coda interna (RabbitMQ, AWS <strong>SQS<\/strong>, GCP Pub\/Sub, Azure Event Grid, o worker Redis) per ack-are subito al fornitore con 200 e processare in background con tuoi retry e <strong>exponential backoff<\/strong>.<\/p>\n<h3>Dead letter queue<\/h3>\n<p>Eventi che falliscono N volte (es. 5 tentativi con backoff) non vanno buttati: mandali in <strong>DLQ<\/strong> (<em>dead letter queue<\/em>), coda separata per intervento umano. Un job di monitoring controlla la lunghezza della <strong>DLQ<\/strong> e ti alerta se cresce \u2014 segnale che qualcosa di sistemico si \u00e8 rotto.<\/p>\n<h2 id=\"implementare-polling\">Implementare polling efficiente: backoff, ETag, cursore<\/h2>\n<h3>Exponential backoff su errori<\/h3>\n<p>Se l&#8217;API risponde 429 (rate limit) o 503, non ricominciare al ciclo successivo: aumenta progressivamente l&#8217;intervallo (1, 2, 4, 8, max 30 min) finch\u00e9 non torna 2xx. Onora sempre <code>Retry-After<\/code> se presente.<\/p>\n<h3>Conditional requests con ETag e Last-Modified<\/h3>\n<p>Molte API supportano <code>If-None-Match: &lt;etag&gt;<\/code> e <code>If-Modified-Since<\/code>. Se la risorsa non \u00e8 cambiata, risposta 304 Not Modified senza body \u2014 banda risparmiata. Per dataset grossi \u00e8 un acceleratore enorme.<\/p>\n<h3>Cursore persistente con safety watermark<\/h3>\n<p>Salva il cursore in una tabella dedicata, non in memoria. Aggiungi un <em>safety watermark<\/em>: invece di ripartire dall&#8217;ultimo timestamp esatto, sottrai 30 secondi per coprire eventi out-of-order (comuni in API distribuite). La deduplica per ID lato tuo gestisce gli eventi visti due volte.<\/p>\n<h3>Cursor-based pagination, non offset<\/h3>\n<p>Per dataset grossi evita <code>?page=1&amp;per_page=50<\/code>: la offset pagination si rompe se i dati cambiano fra una pagina e l&#8217;altra. Usa <em>cursor-based<\/em> (<code>?after=&lt;opaque_token&gt;<\/code>) \u2014 vedi <a href=\"https:\/\/brentasoft.com\/blog\/rest-api-design-best-practice-2021\/\">REST API design best practice 2021<\/a>.<\/p>\n<h2 id=\"sicurezza\">Sicurezza dei webhook nel 2021: HMAC, IP whitelist, JWT<\/h2>\n<h3>Layer 1: firma HMAC SHA-256<\/h3>\n<p>Shared secret + <strong>HMAC SHA-256<\/strong> sul body + confronto constant-time. Difesa principale non negoziabile. Senza firma valida, 401.<\/p>\n<h3>Layer 2: IP whitelist<\/h3>\n<p>Alcuni fornitori pubblicano i range IP. GitHub pubblica i meta endpoint, Stripe ha una lista documentata ma raccomanda di non basarsi solo su quella. L&#8217;IP whitelisting a livello firewall o reverse proxy blocca scanner random \u2014 non sostituisce la firma <strong>HMAC<\/strong>, la integra.<\/p>\n<h3>Layer 3: replay protection con timestamp<\/h3>\n<p>La firma <strong>HMAC<\/strong> non impedisce che un attaccante intercetti una richiesta valida e la rigiochi ore dopo. Stripe aggiunge un timestamp nel payload firmato: il tuo endpoint rifiuta richieste pi\u00f9 vecchie di 5 minuti. Implementa lo stesso check ovunque puoi.<\/p>\n<h3>Layer 4: JWT per webhook interni<\/h3>\n<p>Quando il fornitore del webhook \u00e8 un tuo microservizio interno, usa <strong>JWT<\/strong> firmati con RS256: il chiamante firma con chiave privata, il ricevente verifica con la pubblica. Niente shared secret da rotare manualmente. Vedi <a href=\"https:\/\/brentasoft.com\/blog\/microservizi-vs-monolite-guida-2021\/\">microservizi vs monolite<\/a>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/brentasoft.com\/blog\/wp-content\/uploads\/2021\/09\/webhook-vs-polling-integrazioni-2021-monitoring.jpg\" alt=\"Dashboard di monitoring webhook con log richieste e risposte JSON - tooling sviluppatori\" title=\"Tooling per webhook: dashboard di monitoring e debug\" loading=\"lazy\" \/><\/p>\n<h2 id=\"strumenti-2021\">Strumenti 2021 per webhook e polling: il toolkit<\/h2>\n<h3>Testing e sviluppo locale<\/h3>\n<ul>\n<li><strong>ngrok<\/strong>: tunnel che espone <code>localhost:3000<\/code> su URL HTTPS pubblico. Indispensabile per testare webhook in dev.<\/li>\n<li><strong>Webhook.site<\/strong>: URL pubblico che logga tutte le richieste con headers e body. Ispeziona cosa ti manda un fornitore prima di scrivere il codice.<\/li>\n<li><strong>Postman<\/strong> e Insomnia: testano API REST e simulano chiamate webhook. Postman ha mock server integrati.<\/li>\n<li><strong>Stripe CLI<\/strong>: forward dei webhook Stripe verso il tuo localhost con replay degli eventi storici.<\/li>\n<\/ul>\n<h3>Produzione: orchestrazione e reliability<\/h3>\n<ul>\n<li><strong>Hookdeck<\/strong> (lanciato 2020): proxy webhook con coda, retry, dashboard, replay. Riduce la pressione di affidabilit\u00e0 sul tuo endpoint.<\/li>\n<li><strong>Pipedream<\/strong>: piattaforma serverless per workflow webhook-driven in JavaScript\/Python. 500+ integrazioni.<\/li>\n<li><strong>n8n<\/strong> self-hosted: alternativa open source a Zapier. Lo installi su Docker, ottieni un orchestratore visuale senza pagare per esecuzione.<\/li>\n<li><strong>Zapier<\/strong> e Integromat (rebrand a Make solo nel 2022): low-code dominanti con 3000+ app connesse.<\/li>\n<\/ul>\n<h3>Code e processing asincrono<\/h3>\n<ul>\n<li>RabbitMQ: broker AMQP self-hosted o managed. Code, exchange, routing, DLQ.<\/li>\n<li>AWS <strong>SQS<\/strong> + <strong>SNS<\/strong>: code FIFO\/standard managed, integrate con Lambda. Standard per AWS cloud-native.<\/li>\n<li>GCP Pub\/Sub: equivalente Google con push subscription verso endpoint HTTPS. Buono su Cloud Run.<\/li>\n<li>Azure Event Grid: il servizio Microsoft per eventi e webhook su Azure.<\/li>\n<\/ul>\n<h3>Endpoint nativi pi\u00f9 usati<\/h3>\n<ul>\n<li><strong>Stripe webhooks<\/strong>: il gold standard per documentazione, retry, signing, CLI di test. Se devi imparare un buon sistema webhook, studia Stripe.<\/li>\n<li><strong>GitHub webhooks<\/strong>: per CI\/CD e automation. Documentazione chiara, firma HMAC SHA-256 dal 2019.<\/li>\n<li><strong>Shopify webhooks<\/strong>: indispensabili per e-commerce. Eventi su ordini, prodotti, carrelli abbandonati, customer.<\/li>\n<li><strong>WooCommerce webhooks REST API<\/strong>: nativi nel core di WooCommerce, configurabili dall&#8217;admin WordPress.<\/li>\n<\/ul>\n<h2 id=\"errori-comuni\">Errori comuni nelle integrazioni webhook<\/h2>\n<h3>Idempotency mancante<\/h3>\n<p>L&#8217;errore numero uno: il dev assume che un webhook arrivi una volta sola e non implementa la deduplica. Risultato: doppi ordini, doppi pagamenti, doppie fatture la prima volta che Stripe riprova (succede settimanalmente). Implementa sempre la tabella <code>processed_events<\/code>.<\/p>\n<h3>Timeout troppo bassi<\/h3>\n<p>Stripe aspetta 30 secondi prima di considerare un webhook fallito. Se il tuo endpoint processa l&#8217;evento in modo sincrono (write DB, API esterne, mail) e impiega 35 secondi, Stripe ti riprova e finisci in loop con duplicati. Regola: rispondi 200 entro 1 secondo, processa in coda asincrona.<\/p>\n<h3>Nessuna DLQ, nessun monitoring<\/h3>\n<p>L&#8217;evento fallisce N volte, muore. Nessuno se ne accorge. Sei mesi dopo scopri che mancano 400 ordini perch\u00e9 un type di evento crashava il parser. Una <strong>DLQ<\/strong> con alerting Prometheus\/Datadog ti avvisa entro un&#8217;ora.<\/p>\n<h3>Signing key committata su Git<\/h3>\n<p>Classico. Usa variabili d&#8217;ambiente, vault, secret manager (AWS Secrets Manager, HashiCorp Vault). Mai in chiaro.<\/p>\n<h3>Parsing JSON prima della validazione firma<\/h3>\n<p>Bug subdolo: deserializzi il body, ricalcoli la firma sul body riserializzato, firma diversa perch\u00e9 pretty-printing o ordine chiavi cambiano. <em>Calcola la firma sul body raw<\/em> ricevuto, poi parse-a il <strong>JSON<\/strong>. In molti framework devi configurare esplicitamente parser raw per gli endpoint webhook.<\/p>\n<h2 id=\"caso-reale\">Caso reale: PMI italiana, Shopify \u2192 Odoo da polling a webhook<\/h2>\n<p>Cliente settore arredamento \u2014 fatturato ~3.5M\u20ac, 4 sedi tra Veneto e Lombardia \u2014 60-90 ordini al giorno su <strong>Shopify<\/strong> Plus da riconciliare nel loro <strong>ERP Odoo<\/strong> per fatturazione, magazzino, planning produzione.<\/p>\n<h3>Situazione iniziale<\/h3>\n<p>Sviluppo originale del 2019 faceva polling su Shopify ogni 5 minuti. Job che interrogava <code>GET \/admin\/api\/2021-04\/orders.json?updated_at_min=...<\/code> e sincronizzava in Odoo via XML-RPC. Tre problemi:<\/p>\n<ul>\n<li>Latenza media 150 secondi: i clienti che chiamavano per chiedere lo stato dell&#8217;ordine subito dopo l&#8217;acquisto si sentivano dire &#8220;non lo vediamo ancora&#8221;.<\/li>\n<li>Rate limit saturo: 288 chiamate\/giorno solo per ordini, pi\u00f9 altri 4 job (prodotti, varianti, clienti, inventory). Errori 429 alle 11 del mattino.<\/li>\n<li>Eventi persi su modifiche: ordini cambiati e ri-cambiati nello stesso intervallo perdevano stati intermedi (partial refund seguito da fulfillment).<\/li>\n<\/ul>\n<h3>La migrazione<\/h3>\n<p>Pattern hybrid implementato in 7 settimane. Webhook Shopify per <code>orders\/create<\/code>, <code>orders\/updated<\/code>, <code>orders\/paid<\/code>, <code>orders\/fulfilled<\/code>, <code>orders\/cancelled<\/code>, <code>refunds\/create<\/code>. Endpoint Python su server pubblico esposto via Cloudflare, validazione firma <strong>HMAC SHA-256<\/strong>, scrittura su coda RabbitMQ, worker che sincronizza in Odoo via XML-RPC con <strong>idempotency<\/strong> su <code>X-Shopify-Webhook-Id<\/code>. In parallelo, vecchio polling ridotto a job notturno alle 03:00 che recupera gli ordini delle ultime 24 ore e fa diff con Odoo. <strong>DLQ<\/strong> monitorata via Grafana con alert Telegram.<\/p>\n<h3>Risultati a 90 giorni<\/h3>\n<ul>\n<li><strong>Latenza media<\/strong> da 150 secondi a <strong>900 ms<\/strong> (-99.4%).<\/li>\n<li><strong>Chiamate API<\/strong> a Shopify da 288\/giorno a 8 (-97%).<\/li>\n<li><strong>Discrepanze in riconciliazione<\/strong>: 0.3% nei primi 30 giorni, 0.05% dopo 60 giorni di tuning.<\/li>\n<li><strong>Ticket &#8220;non vedo il mio ordine&#8221;<\/strong>: -82% nel primo mese.<\/li>\n<\/ul>\n<p><script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Migrare da polling a webhook in 60 giorni\",\n  \"description\": \"Roadmap operativa in 4 fasi per migrare un'integrazione PMI da API polling a webhook real-time senza interrompere la produzione.\",\n  \"totalTime\": \"P60D\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Assessment e design (settimane 1-2)\",\n      \"text\": \"Inventario delle integrazioni esistenti con frequenza, volume e criticita. Verifica supporto webhook lato fornitore. Documenta eventi e payload. Scegli architettura di processing: queue (RabbitMQ, SQS), worker, persistenza idempotency. Decidi dove esporre l'endpoint.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Implementazione endpoint e validazione (settimane 3-4)\",\n      \"text\": \"Scrivi endpoint HTTPS con validazione firma HMAC SHA-256, dedup su event_id, scrittura su coda. Testa con ngrok in locale e Webhook.site per debug. Unit test sulla validazione firma. Deploy in staging.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Shadow mode (settimane 5-6)\",\n      \"text\": \"Webhook attivi in produzione, polling esistente non disattivato. Per due settimane girano in parallelo: webhook scrive su tabella separata, polling continua sul flusso principale. Confronto dati e correzione discrepanze.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Cutover e backoff polling (settimane 7-8)\",\n      \"text\": \"Switch del flusso principale ai webhook. Polling passa da ogni 5 minuti a ogni 6 ore come riconciliazione. Configura alerting su DLQ, rate errore endpoint, gap event_id consecutivi. Go-live e retrospettiva a 30 giorni.\"\n    }\n  ]\n}\n<\/script><\/p>\n<h2 id=\"roadmap\">Roadmap di 60 giorni per migrare da polling a webhook<\/h2>\n<p>Per chi parte da polling e vuole passare a webhook senza interrompere la produzione, ecco la roadmap che usiamo nei progetti reali.<\/p>\n<h3>Settimane 1-2: assessment e design<\/h3>\n<p>Inventario integrazioni esistenti: lista endpoint polling-ati, frequenza, volume eventi\/giorno, criticit\u00e0. Per ognuna verifica se il fornitore supporta webhook. Documenta eventi necessari e payload attesi. Scegli l&#8217;architettura di processing: coda (RabbitMQ, <strong>SQS<\/strong>), worker, persistenza idempotency. Decidi dove esporre l&#8217;endpoint (server proprio, reverse proxy, <strong>Hookdeck<\/strong>).<\/p>\n<h3>Settimane 3-4: implementazione endpoint e validazione<\/h3>\n<p>Scrivi l&#8217;endpoint HTTPS con validazione firma <strong>HMAC SHA-256<\/strong>, dedup su event_id, scrittura su coda. Testa con <strong>ngrok<\/strong> in locale e <strong>Webhook.site<\/strong> per il debug. Unit test sulla funzione di validazione firma. Deploy in staging.<\/p>\n<h3>Settimane 5-6: shadow mode<\/h3>\n<p>Webhook attivi in produzione, <em>polling non disattivato<\/em>. Per due settimane girano entrambi in parallelo: il webhook scrive su tabella separata, il polling continua sul flusso principale. Confronta i dati: ogni evento visto dal webhook deve essere visto dal polling, e viceversa. Le discrepanze ti dicono dove correggere.<\/p>\n<h3>Settimane 7-8: cutover e backoff polling<\/h3>\n<p>Switch del flusso principale ai webhook. Il polling passa da &#8220;ogni 5 minuti&#8221; a &#8220;ogni 6 ore&#8221; come riconciliazione. Monitora le discrepanze tra le due fonti: deve essere &lt;0.5%. Configura alerting su <strong>DLQ<\/strong>, su rate di errore endpoint, su gap di event_id consecutivi. Go-live, retrospettiva a 30 giorni.<\/p>\n<h2 id=\"faq\">Domande frequenti<\/h2>\n<h3>Quanto costa migrare da polling a webhook per una PMI italiana?<\/h3>\n<p>Una migrazione completa per una singola integrazione media (es. Shopify \u2192 ERP) costa tipicamente tra 4000 e 9000 euro tutto incluso: assessment, sviluppo endpoint, queue, testing shadow, monitoring. Il ROI si misura in mesi quando l&#8217;integrazione \u00e8 critica \u2014 il caso reale sopra ha ammortizzato il costo in 3 mesi solo per ticket di supporto risparmiati.<\/p>\n<h3>Posso usare un orchestratore (Zapier\/n8n) invece di scrivere codice?<\/h3>\n<p>S\u00ec, per flussi semplici sotto i 10.000 eventi\/mese le piattaforme low-code sono ottime. Zapier costa di pi\u00f9 ma \u00e8 pi\u00f9 semplice, n8n self-hosted \u00e8 gratis ma richiede DevOps, Pipedream \u00e8 una via di mezzo. Per volumi alti o logiche complesse (transazioni multi-step, retry custom, idempotency cross-evento) conviene codice custom.<\/p>\n<h3>Cosa succede se il mio endpoint webhook va down per un&#8217;ora?<\/h3>\n<p>Dipende dal fornitore. Stripe riprova per 3 giorni con backoff esponenziale, Shopify per 48 ore con 19 tentativi, GitHub per 8 ore. Un downtime di 1 ora non fa perdere eventi se il fornitore implementa retry. Combinandolo con il pattern hybrid (polling notturno di riconciliazione) la perdita \u00e8 zero anche con downtime pi\u00f9 lunghi.<\/p>\n<h3>Webhook funzionano dietro firewall corporate?<\/h3>\n<p>Non senza esporre un endpoint pubblico. Le opzioni: aprire porta inbound (sconsigliato), reverse proxy in DMZ (es. nginx) che inoltra al backend interno, oppure servizio tipo <strong>Hookdeck<\/strong> con connessione persistente in uscita.<\/p>\n<h3>Devo cifrare il payload webhook oltre alla firma?<\/h3>\n<p>Se trasporti dati sensibili (GDPR, dati di pagamento PCI), s\u00ec. L&#8217;HTTPS cripta il trasporto, la firma <strong>HMAC<\/strong> garantisce autenticit\u00e0 non confidenzialit\u00e0. Per payload PCI o sanitari valuta JWE (JWT cifrato) o encryption applicativa del body. La maggior parte dei provider mainstream non offre payload cifrati nativi.<\/p>\n<h3>Quanto deve essere veloce il mio endpoint webhook?<\/h3>\n<p>Regola pratica: rispondi 200 al fornitore entro <strong>1 secondo<\/strong>, idealmente sotto i 200 ms. Tutto il lavoro pesante (DB write, API esterne, mail) va in coda asincrona.<\/p>\n<h3>Posso testare webhook senza un fornitore reale?<\/h3>\n<p>S\u00ec. <strong>Stripe<\/strong> CLI genera eventi finti con firma valida. <strong>GitHub<\/strong> permette rilanci manuali dall&#8217;admin del repo. Per test generici scrivi uno script Python o curl che POST-a payload di esempio con firma <strong>HMAC<\/strong> calcolata dal tuo secret di test. <strong>Postman<\/strong> ha collection di esempio per Stripe, Shopify, GitHub.<\/p>\n<div class=\"cta-box\" style=\"background:linear-gradient(135deg,#0284c7 0%,#0369a1 100%);color:#fff;padding:32px;border-radius:10px;margin:40px 0;text-align:center;\">\n<h3 style=\"color:#fff;margin-top:0;\">Vuoi costruire integrazioni webhook robuste per il tuo business?<\/h3>\n<p style=\"font-size:1.05em;margin:18px 0;\">Brentasoft progetta e implementa integrazioni API e webhook tra CRM, ERP, e-commerce e piattaforme SaaS. Idempotency, retry, monitoring, riconciliazione \u2014 chiavi in mano, con SLA e supporto continuativo.<\/p>\n<p style=\"margin:18px 0;\"><a href=\"https:\/\/brentasoft.com\/soluzioni\/integrazione-api.php\" style=\"display:inline-block;background:#fff;color:#0284c7;padding:14px 28px;border-radius:6px;text-decoration:none;font-weight:600;margin:6px;\">Scopri Integrazione API<\/a> <a href=\"https:\/\/brentasoft.com\/soluzioni\/gestionali-personalizzati.php\" style=\"display:inline-block;background:transparent;color:#fff;border:2px solid #fff;padding:12px 26px;border-radius:6px;text-decoration:none;font-weight:600;margin:6px;\">Gestionali personalizzati<\/a> <a href=\"https:\/\/brentasoft.com\/preventivatore.php\" style=\"display:inline-block;background:#fbbf24;color:#0a0a0f;padding:14px 28px;border-radius:6px;text-decoration:none;font-weight:600;margin:6px;\">Richiedi preventivo<\/a><\/p>\n<\/div>\n<p><script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Quanto costa migrare da polling a webhook per una PMI italiana?\",\n      \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Una migrazione completa per una singola integrazione media (es. Shopify verso ERP) costa tipicamente tra 4000 e 9000 euro tutto incluso: assessment, sviluppo endpoint, queue, testing shadow, monitoring. Il ROI si misura in mesi quando l'integrazione e critica.\"}\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Posso usare un orchestratore (Zapier\/n8n) invece di scrivere codice?\",\n      \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Si, per flussi semplici sotto i 10000 eventi\/mese le piattaforme low-code sono ottime. Zapier costa di piu ma e piu semplice, n8n self-hosted e gratis ma richiede DevOps, Pipedream e una via di mezzo. Per volumi alti o logiche complesse conviene codice custom.\"}\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Cosa succede se il mio endpoint webhook va down per un'ora?\",\n      \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Dipende dal fornitore. Stripe riprova per 3 giorni con backoff esponenziale, Shopify per 48 ore con 19 tentativi, GitHub per 8 ore. Un downtime di 1 ora non fa perdere eventi se il fornitore implementa retry. Con polling notturno di riconciliazione la perdita e zero.\"}\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"I webhook funzionano dietro un firewall corporate?\",\n      \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Non senza esporre un endpoint pubblico. Opzioni: aprire porta inbound (sconsigliato), reverse proxy in DMZ che inoltra al backend interno, oppure servizio tipo Hookdeck con connessione persistente in uscita.\"}\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Devo cifrare il payload webhook oltre alla firma?\",\n      \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Se trasporti dati sensibili (GDPR, dati di pagamento PCI) si. HTTPS cripta il trasporto, HMAC garantisce autenticita non confidenzialita. Per payload PCI o sanitari valuta JWE o encryption applicativa del body.\"}\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Quanto deve essere veloce il mio endpoint webhook?\",\n      \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Rispondi 200 al fornitore entro 1 secondo, idealmente sotto i 200 ms. Tutto il lavoro pesante (DB write, API esterne, mail) va in coda asincrona con retry interni.\"}\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Posso testare i webhook senza un fornitore reale?\",\n      \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Si. Stripe CLI genera eventi finti con firma valida. GitHub permette rilanci manuali dall'admin del repo. Per test generici scrivi script Python o curl che POST-a payload di esempio con firma HMAC calcolata dal tuo secret di test. Postman ha collection per Stripe, Shopify, GitHub.\"}\n    }\n  ]\n}\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR \u2014 Webhook o polling per integrare due sistemi? Polling: il tuo software chiama l&#8217;API a intervalli regolari (es. ogni 5 minuti). Semplice, funziona dietro qualunque firewall, ma&hellip;<\/p>\n","protected":false},"author":2,"featured_media":1391,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"Webhook vs API polling 2021: guida pratica integrazioni | Brentasoft","_seopress_titles_desc":"Webhook o polling per le tue integrazioni SaaS? Confronto tecnico 2021 con casi d'uso, sicurezza HMAC SHA-256, retry policy, idempotency e roadmap.","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"Webhook vs API polling 2021: guida pratica integrazioni | Brentasoft","_seopress_social_fb_desc":"Webhook o polling per le tue integrazioni SaaS? Confronto tecnico 2021 con casi d'uso, sicurezza HMAC SHA-256, retry policy, idempotency e roadmap.","_seopress_social_fb_img":"https:\/\/brentasoft.com\/blog\/wp-content\/uploads\/2021\/09\/webhook-vs-polling-integrazioni-2021-featured.jpg","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"Webhook vs API polling 2021: guida pratica integrazioni | Brentasoft","_seopress_social_twitter_desc":"Webhook o polling per le tue integrazioni SaaS? Confronto tecnico 2021 con casi d'uso, sicurezza HMAC SHA-256, retry policy, idempotency e roadmap.","_seopress_social_twitter_img":"https:\/\/brentasoft.com\/blog\/wp-content\/uploads\/2021\/09\/webhook-vs-polling-integrazioni-2021-featured.jpg","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"webhook,API polling,integrazioni API,webhook HMAC,retry policy,idempotency","footnotes":""},"categories":[9],"tags":[],"class_list":["post-1390","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-guide-e-tutorial"],"_links":{"self":[{"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/posts\/1390","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/comments?post=1390"}],"version-history":[{"count":2,"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/posts\/1390\/revisions"}],"predecessor-version":[{"id":1396,"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/posts\/1390\/revisions\/1396"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/media\/1391"}],"wp:attachment":[{"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/media?parent=1390"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/categories?post=1390"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brentasoft.com\/blog\/wp-json\/wp\/v2\/tags?post=1390"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}