Webhook: come collegare applicazioni e automatizzare eventi in modo sicuro 🔗

Webhook

Immagina di gestire un’applicazione web che deve aggiornarsi automaticamente quando accade qualcosa su un altro servizio. Un cliente completa un pagamento, un utente si registra su una piattaforma oppure un repository Git riceve un nuovo commit.

Potresti programmare uno script che interroga continuamente il servizio esterno per scoprire se ci sono novità. Funzionerebbe, ma sarebbe un po’ come controllare la cassetta della posta ogni trenta secondi nella speranza che arrivi una lettera. 📬

Esiste un approccio spesso più efficiente: lasciare che sia il servizio esterno ad avvisare la tua applicazione quando si verifica un evento.

È proprio questo il principio alla base dei webhook, uno degli strumenti più utili per integrare piattaforme, automatizzare processi e costruire applicazioni capaci di comunicare tra loro.

Che cos’è un webhook?

Un webhook è un meccanismo attraverso il quale un’applicazione invia automaticamente una richiesta HTTP a un’altra applicazione quando si verifica un determinato evento.

Il servizio che genera l’evento conosce un URL di destinazione, generalmente chiamato webhook endpoint, e invia una richiesta contenente le informazioni relative a ciò che è accaduto.

Per esempio, una piattaforma di pagamento potrebbe inviare un evento quando una transazione viene confermata:

POST /webhooks/payments
Content-Type: application/json

{
  "event_id": "evt_12345",
  "type": "payment.completed",
  "data": {
    "order_id": 784,
    "amount": 49.90,
    "currency": "EUR"
  }
}

La tua applicazione riceve la richiesta, verifica che sia autentica e aggiorna lo stato dell’ordine.

⚠️ Questo JSON è un esempio didattico: i campi reali dipendono dal servizio che invia il webhook.

Webhook e API REST: qual è la differenza?

Webhook e API REST non sono tecnologie concorrenti. Spesso vengono utilizzati insieme.

Con una normale API, il client invia una richiesta quando vuole ottenere informazioni o eseguire un’operazione.

Con un webhook, invece, è il servizio che genera l’evento a inviare una notifica verso un endpoint precedentemente configurato.

Facciamo un esempio concreto. 🛒

Un e-commerce deve conoscere lo stato di un pagamento.

  • Approccio polling: il negozio interroga periodicamente l’API del provider per verificare se il pagamento è stato completato.
  • Approccio webhook: il provider invia una notifica al negozio quando il pagamento cambia stato.

Il webhook può ridurre richieste inutili e tempi di aggiornamento. Tuttavia, non garantisce automaticamente che ogni evento arrivi una sola volta o nell’ordine previsto.

Per questo le integrazioni affidabili utilizzano spesso i webhook per ricevere notifiche e le API per verificare o recuperare lo stato aggiornato di una risorsa.

Come funziona un webhook, passo dopo passo

Il flusso tipico è piuttosto semplice:

  1. Registrazione: configuri l’URL che dovrà ricevere gli eventi.
  2. Evento: sulla piattaforma esterna accade qualcosa, per esempio una nuova registrazione.
  3. Notifica: il servizio invia una richiesta HTTP al tuo endpoint.
  4. Verifica: la tua applicazione controlla autenticità, formato e validità dell’evento.
  5. Elaborazione: il sistema aggiorna i dati o avvia un’attività.
  6. Risposta: l’endpoint comunica al mittente l’esito della ricezione.

Alcuni servizi ritentano automaticamente l’invio quando ricevono errori o non ottengono risposta. Le politiche di retry, i timeout e i codici considerati validi cambiano però da provider a provider.

1. Creare un endpoint webhook in PHP

Un endpoint PHP può ricevere il corpo di una richiesta HTTP utilizzando php://input.

Ecco un esempio minimale che mostra come leggere un payload JSON:

<?php

declare(strict_types=1);

header('Content-Type: application/json');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    header('Allow: POST');
    echo json_encode(['error' => 'Method not allowed']);
    exit;
}

$body = file_get_contents('php://input');

if ($body === false || strlen($body) > 65536) {
    http_response_code(413);
    echo json_encode(['error' => 'Invalid payload size']);
    exit;
}

$data = json_decode($body, true);

if (!is_array($data) || json_last_error() !== JSON_ERROR_NONE) {
    http_response_code(400);
    echo json_encode(['error' => 'Invalid JSON']);
    exit;
}

// Esempio didattico: qui mancano ancora
// la verifica della firma e la gestione dell'evento.

http_response_code(200);
echo json_encode(['received' => true]);

Questo codice mostra soltanto la struttura iniziale. Non è un endpoint webhook pronto per la produzione, perché manca la verifica dell’autenticità del mittente e la gestione sicura dell’evento.

Restituire una risposta positiva prima di aver verificato e registrato correttamente la richiesta potrebbe causare la perdita di eventi importanti.

2. Il rischio principale: chiunque potrebbe chiamare il tuo endpoint

Un URL pubblico non è automaticamente un URL sicuro.

Se il tuo webhook è raggiungibile da Internet, un attaccante potrebbe provare a inviare richieste costruite manualmente per simulare eventi legittimi.

Immagina un endpoint che imposta un ordine come pagato ogni volta che riceve questo JSON:

{
  "type": "payment.completed",
  "order_id": 784
}

Se il server non verifica l’origine e l’autenticità della richiesta, un malintenzionato potrebbe tentare di inviare lo stesso evento senza aver effettuato alcun pagamento.

🔐 La regola fondamentale è questa: non fidarti del contenuto di un webhook soltanto perché arriva all’URL corretto.

3. Verificare le firme HMAC

Molti provider utilizzano firme crittografiche per consentire al destinatario di verificare che il messaggio sia stato generato da chi possiede un segreto condiviso.

Uno schema comune utilizza HMAC con SHA-256.

Il mittente calcola una firma sul contenuto della richiesta utilizzando un segreto. Il destinatario ripete il calcolo e confronta il risultato con la firma ricevuta.

In PHP, un esempio semplificato potrebbe essere:

<?php

$secret = getenv('WEBHOOK_SECRET');

if (!$secret) {
    http_response_code(500);
    exit;
}

$body = file_get_contents('php://input');

$receivedSignature =
    $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

$expectedSignature = hash_hmac(
    'sha256',
    $body,
    $secret
);

if (!hash_equals($expectedSignature, $receivedSignature)) {
    http_response_code(401);
    exit;
}

⚠️ Questo esempio funziona soltanto con un protocollo che prevede esattamente una firma HMAC-SHA256 esadecimale del corpo grezzo, trasmessa nell’header indicato.

I provider reali possono utilizzare timestamp, prefissi, firme multiple e formati differenti. Devi sempre seguire la documentazione ufficiale del servizio, senza inventare il formato della firma.

Per esempio, Stripe documenta la verifica delle firme dei propri webhook, inclusa la protezione contro alcune forme di replay.

4. Perché i webhook possono arrivare più volte

Una situazione molto comune è ricevere due o più notifiche relative allo stesso evento.

Può succedere perché il provider non ha ricevuto una risposta in tempo, perché si è verificato un errore di rete o perché un evento è stato reinviato manualmente.

Il problema diventa serio quando ogni ricezione produce un effetto non ripetibile.

Immagina un webhook che aggiunge 100 crediti all’account di un utente. Se lo stesso evento arriva due volte e viene elaborato due volte, il saldo aumenta di 200 crediti.

Per evitare questo comportamento, bisogna progettare un’elaborazione idempotente: ricevere nuovamente lo stesso evento non deve ripetere effetti che dovrebbero verificarsi una sola volta.

Una soluzione comune consiste nel memorizzare un identificativo univoco dell’evento in una tabella del database, applicando un vincolo UNIQUE.

CREATE TABLE webhook_events (
    event_id VARCHAR(191) NOT NULL,
    event_type VARCHAR(100) NOT NULL,
    received_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (event_id)
) ENGINE=InnoDB;

La sola presenza della tabella non basta: l’inserimento dell’identificativo e l’operazione applicativa devono essere coordinati correttamente, idealmente attraverso una transazione quando possibile.

Se l’elaborazione coinvolge sistemi esterni, come l’invio di un’email, servono ulteriori accorgimenti per gestire retry ed effetti parzialmente completati.

5. Non elaborare tutto durante la richiesta HTTP

Un altro errore frequente consiste nel ricevere un webhook ed eseguire immediatamente tutte le operazioni necessarie.

Se l’evento richiede di generare un documento, chiamare un servizio esterno o elaborare molti dati, la richiesta potrebbe durare troppo a lungo.

Il provider potrebbe interpretare il ritardo come un errore e reinviare l’evento.

Una soluzione più robusta è:

  1. verificare autenticità e validità della richiesta;
  2. registrare l’evento in modo persistente;
  3. inserirlo in una coda di elaborazione;
  4. rispondere rapidamente al provider;
  5. elaborare l’evento attraverso un worker separato.

Per piccoli progetti PHP, una coda può essere implementata anche utilizzando MariaDB e un processo pianificato, purché siano gestiti correttamente concorrenza, blocchi, retry e stati di elaborazione.

Non è sempre necessario introdurre immediatamente Redis, RabbitMQ o altre infrastrutture. L’importante è scegliere una soluzione proporzionata al carico e alle esigenze del progetto.

6. Gestire gli eventi fuori ordine

Non tutti i provider garantiscono che gli eventi vengano consegnati nello stesso ordine in cui si verificano.

Potresti ricevere prima la notifica di una modifica recente e successivamente quella di una modifica precedente.

Se la tua applicazione aggiorna lo stato semplicemente in base all’ultimo evento ricevuto, rischia di tornare a una condizione ormai superata.

Quando possibile, conviene utilizzare l’evento come segnale per recuperare lo stato corrente della risorsa attraverso l’API ufficiale del provider.

In alternativa, puoi progettare una macchina a stati che consenta soltanto transizioni valide e utilizzi identificativi di versione o timestamp affidabili, secondo il contratto del servizio.

7. Logging e monitoraggio dei webhook

Un’integrazione webhook dovrebbe permetterti di capire cosa è successo quando qualcosa non funziona.

Registra almeno:

  • identificativo dell’evento;
  • tipo di evento;
  • orario di ricezione;
  • esito della verifica della firma;
  • stato dell’elaborazione;
  • numero di tentativi;
  • eventuali errori applicativi.

Evita invece di registrare indiscriminatamente payload contenenti dati personali, token o informazioni riservate.

📊 Una piccola dashboard che mostra eventi ricevuti, completati e falliti può diventare estremamente utile quando le integrazioni iniziano a crescere.

8. Quando conviene utilizzare i webhook?

I webhook sono particolarmente utili quando un’applicazione deve reagire a eventi esterni senza interrogare continuamente un servizio.

Alcuni esempi pratici:

  • 💳 aggiornare un ordine dopo la conferma di un pagamento;
  • 📦 sincronizzare informazioni di spedizione;
  • 👤 attivare un account dopo un evento di registrazione;
  • 🛠️ avviare una pipeline dopo un push su Git;
  • 📨 elaborare notifiche provenienti da un servizio email;
  • 🔄 sincronizzare informazioni tra applicazioni SaaS.

Non sono però sempre la soluzione ideale. Se il provider non offre webhook affidabili, se devi recuperare uno storico completo o se ti serve riconciliare dati potenzialmente mancanti, può essere necessario affiancarli a richieste API periodiche.

Checklist per un webhook affidabile

  • ☐ Accetto soltanto i metodi HTTP previsti?
  • ☐ Impongo limiti alla dimensione del payload?
  • ☐ Verifico la firma secondo le specifiche del provider?
  • ☐ Gestisco eventuali timestamp e protezioni anti-replay?
  • ☐ Verifico la struttura e il tipo di evento?
  • ☐ Impedisco elaborazioni duplicate?
  • ☐ Gestisco eventi fuori ordine?
  • ☐ Registro l’evento prima di confermarne la ricezione?
  • ☐ Dispongo di retry controllati per gli errori temporanei?
  • ☐ Posso diagnosticare gli eventi falliti senza esporre dati sensibili?

Conclusione: piccole notifiche, grandi possibilità 🚀

I webhook sono uno strumento semplice nel concetto, ma estremamente potente nella pratica.

Permettono di costruire integrazioni reattive, ridurre interrogazioni inutili e collegare servizi differenti senza dover sviluppare continuamente meccanismi di sincronizzazione personalizzati.

La vera difficoltà non sta nel ricevere una richiesta HTTP, ma nel gestirla correttamente quando arrivano eventi duplicati, richieste non autentiche, errori di rete e notifiche fuori ordine.

Con firme verificate, elaborazione idempotente, code e monitoraggio, anche un’applicazione relativamente semplice può integrare servizi esterni in modo affidabile.

E spesso basta proprio un webhook ben progettato per trasformare due applicazioni separate in un sistema che lavora davvero insieme. 🔗

Vuoi aggiungere qualcosa?

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *