Eventi dei plugin o webhook? Questa guida spiega i due meccanismi in Shopware 6, la registrazione nel manifest.xml, la struttura del payload, la verifica della firma e gli errori più frequenti.
Shopware 6 offre due modi per reagire agli eventi del negozio, e vengono facilmente confusi. Il primo è il sistema di eventi PHP interno, a cui si agganciano i plugin e che gira all’interno del processo Shopware. Il secondo sono i webhook: fanno parte del sistema delle app e notificano un servizio esterno via HTTP.
Scegliere quello sbagliato costa tempo. Un subscriber di un plugin non gira su un’istanza Shopware Cloud e un webhook non può modificare ciò che accade durante una richiesta. Questa guida, pensata anche per team di sviluppo in Italia, spiega che cosa offrono i due meccanismi, come si registra e si protegge un webhook, quali comportamenti sono documentati e su quali non conviene fare affidamento.
Tutte le indicazioni tecniche si basano sulla documentazione ufficiale per sviluppatori di Shopware. Le funzioni che dipendono dalla versione sono indicate con il release in cui sono state introdotte. Le basi della piattaforma sono nella nostra pagina sullo sviluppo Shopware.
I plugin girano nel negozio. Registrano un subscriber che implementa EventSubscriberInterface, lo contrassegnano con il tag kernel.event_subscriber e ricevono gli eventi in modo sincrono, mentre la richiesta è ancora in elaborazione. Poiché il subscriber ha in mano l’oggetto evento, può influenzare ciò che accade dopo: modificare un prezzo, bloccare una scrittura, cambiare l’output della storefront.
Le app girano fuori dal negozio. Shopware comunica con loro esclusivamente via HTTP e i webhook sono il canale con cui il negozio comunica all’app che è successo qualcosa. L’app riceve a posteriori una richiesta POST e reagisce richiamando la Admin API. Non può più modificare l’operazione che ha generato l’evento.
Una regola pratica utile: se la logica deve girare durante la richiesta e modificarne il risultato, va in un plugin. Se reagisce a posteriori e vive sulla Sua infrastruttura, va in un’app con webhook. Per semplici notifiche senza un’app propria basta spesso anche l’azione „Call URL“ nel Flow Builder, che però è legata al piano Evolve.
Prima che parta il primo webhook servono quattro cose.
I webhook appartengono a un’app, non a un plugin. L’app è descritta da un manifest.xml ed esegue con il negozio un handshake di registrazione, durante il quale la Sua app genera e salva un secret per ogni negozio. Questo secret firma poi ogni richiesta webhook.
La consegna passa dalla message queue di Shopware. Se nessun consumer è attivo, i messaggi vengono scritti ma mai inviati, e nella storefront non compare alcun errore. È di gran lunga la causa più frequente per cui un webhook configurato correttamente sembra non fare nulla.
Shopware invia all’URL indicato nel manifest. Deve essere raggiungibile dal server del negozio e dovrebbe terminare TLS. Per lo sviluppo locale serve un servizio di tunneling, così il negozio raggiunge il Suo computer.
La maggior parte degli eventi webhook richiede un permesso corrispondente nel manifest. Chi sottoscrive order.written senza dichiarare order:read non supera la validazione. Shopware verifica i permessi dei webhook dalla versione 6.3.5.0.
Non c’è nessun plugin webhook da installare. I webhook si dichiarano direttamente nel manifest dell’app, in un blocco <webhooks>:
<webhooks>
<webhook name="product-changed"
url="https://example.com/event/product-changed"
event="product.written"/>
</webhooks>
Tre attributi sono obbligatori: name deve essere univoco all’interno del manifest, url è l’endpoint a cui Shopware invia e event è l’identificativo dell’evento che vuole ricevere.
Si possono usare solo gli eventi che Shopware contrassegna come „hookable“. L’insieme documentato copre le aree di cui ha bisogno la maggior parte delle integrazioni:
checkout.order.placed, order.written, order.deletedproduct.written, product.deleted, customer.written, category.written, media.written e i rispettivi corrispondenticheckout.customer.register, checkout.customer.login, checkout.customer.logout, customer.recovery.requeststate_enter.order.state.completed, state_enter.order_transaction.state.paid, state_enter.order_delivery.state.shipped e i relativi eventi state_leaveapp.installed, app.activated, app.deactivated, app.deleted e shopware.updatedDa Shopware 6.5.7.0 un webhook può avere l’attributo onlyLiveVersion="true". Senza questo attributo un webhook order.written scatta anche per le bozze versionate che nascono quando si modifica un ordine nell’amministrazione, cosa che di norma un’integrazione non vuole:
<webhook name="order-created"
url="https://example.com/event/order-created"
event="order.written"
onlyLiveVersion="true"/>
L’attributo viene valutato solo per gli eventi entity written.
Il body della richiesta è in JSON e ha sempre le stesse tre chiavi di primo livello:
{
"data": {
"payload": [
{
"entity": "product",
"operation": "delete",
"primaryKey": "7b04ebe416db4ebc93de4d791325e1d9",
"updatedFields": []
}
],
"event": "product.written"
},
"source": {
"url": "http://localhost:8000",
"appVersion": "0.0.1",
"shopId": "dgrH7nLU6tlE",
"eventId": "7b04ebe416db4ebc93de4d791325e1d9"
},
"timestamp": 123123123
}
Negli eventi entity written il payload non contiene l’entity completa. Shopware lo motiva chiaramente: poiché la consegna è asincrona, un’entity completa potrebbe essere già superata al momento dell’arrivo. Riceve il primaryKey e lo schema previsto è ricaricare lo stato attuale tramite la Admin API.
Le integrazioni che trattano il payload come fonte di verità prima o poi riscrivono dati obsoleti in un sistema collegato. Questa decisione va presa prima della prima riga di codice, non dopo.
source.shopId identifica il negozio e resta costante per tutta la sua vita.source.eventId resta uguale tra un tentativo e l’altro ed è quindi la chiave naturale per la deduplicazione.timestamp è il momento dell’elaborazione ed è disponibile dalla 6.4.1.0.Inoltre Shopware invia dalla 6.4.1.0 l’header sw-version e dalla 6.4.5.0 sw-context-language e sw-user-language.
Ogni richiesta webhook porta l’header shopware-shop-signature. Contiene un HMAC SHA-256 calcolato sul body grezzo della richiesta, con chiave lo shop secret che la Sua app ha generato alla registrazione. Un endpoint che salta questa verifica accetta qualsiasi cosa gli venga inviata da chiunque.
Il sistema delle app usa due secret diversi e confonderli è una causa frequente di verifiche fallite:
shopware-app-signature firma la query string della richiesta di registrazione e usa l’app secret condiviso con il Suo account Shopware.shopware-shop-signature firma il body della richiesta webhook e usa lo shop secret generato per ogni negozio alla registrazione.Calcoli l’hash del body grezzo prima di qualsiasi parsing JSON. I framework che riserializzano la richiesta producono una sequenza di byte diversa e quindi un HMAC diverso.
Rifiuti le richieste con un timestamp troppo vecchio. Un attaccante non può modificare il timestamp senza invalidare la firma, il che lo rende una protezione efficace contro le richieste ripetute.
Shopware consiglia di usare l’App PHP SDK o il Symfony Bundle invece di implementare la verifica da soli. Dalla 6.7.13.0 il secret di firma viene risolto al momento della consegna, così anche durante una rotazione del secret le consegne sono firmate con il secret attuale.
I webhook falliscono in silenzio. Nulla nella storefront indica che una consegna non è avvenuta. Il primo passo è quindi sempre capire se Shopware ci ha almeno provato.
Shopware registra i tentativi di consegna nella tabella webhook_event_log. Se non c’è una riga per l’evento atteso, il webhook non è mai stato messo in coda e il problema è nel manifest o nei permessi. Se c’è una riga che non lascia mai lo stato „queued“, il problema è nella message queue, non nel Suo endpoint.
Un’attività di pulizia rimuove le voci consegnate con successo o fallite definitivamente; quelle in corso o in nuovo tentativo restano. Dalla 6.7.4.0 le voci bloccate nello stato „queued“ vengono rimosse dopo il doppio della durata di conservazione configurata.
onlyLiveVersion non è impostato.Un endpoint minimale che registra il body grezzo e risponde rapidamente con 200 separa i problemi di consegna da quelli di elaborazione. Quando le consegne arrivano in modo affidabile, sposti l’elaborazione dietro una coda propria.
Le decisioni che rendono stabile un’integrazione webhook si prendono presto e la maggior parte deriva da una caratteristica: la consegna è asincrona e può essere ripetuta.
shopware-shop-signature sul body grezzo prima di qualsiasi altra cosa.source.eventId resta uguale tra i tentativi e riconosce una richiesta già elaborata.primaryKey con la Admin API.Due comportamenti mancano volutamente da questo elenco, perché Shopware non li documenta: il timeout HTTP esatto di una consegna e quali codici di stato vengono considerati errori. Un’integrazione che si basa su valori concreti poggia su un’ipotesi, non su una specifica. Se non vuole gestire un’app propria, molti scenari webhook si possono realizzare anche con una piattaforma di automazione come n8n.
No. I webhook fanno parte del sistema delle app e si dichiarano nel manifest dell’app. Non bisogna installare nulla dallo Shopware Store.
Nella maggior parte dei casi non è attivo alcun consumer della message queue. Shopware mette in coda la consegna e non la invia mai. Verifichi in webhook_event_log se l’evento è stato almeno accodato.
Perché la consegna è asincrona e un’entity completa potrebbe essere già superata al momento dell’arrivo. Shopware invia il primaryKey e si aspetta che carichi lo stato attuale tramite la Admin API.
La documentazione dei webhook non indica un numero specifico. La documentazione generale della message queue dice che i messaggi vengono ritentati tre volte prima di finire nel failure transport. Lo consideri un ordine di grandezza, non una garanzia, e deduplichi tramite source.eventId.
No. Un webhook è una notifica a posteriori. Per influenzare una richiesta in corso serve un plugin con un event subscriber PHP, il che richiede a sua volta un negozio self-hosted. Come sviluppiamo questi plugin, anche per aziende in Italia, lo mostriamo nella nostra pagina sullo sviluppo di plugin Shopware.
I webhook del sistema delle app fanno parte del core di Shopware dalla linea 6.3. Alcuni dettagli sono arrivati dopo: il campo timestamp e l’header sw-version nella 6.4.1.0, gli header di lingua nella 6.4.5.0 e onlyLiveVersion nella 6.5.7.0. La linea principale attuale è la 6.7.