Plugin-events of webhooks? Deze gids legt beide mechanismen in Shopware 6 uit en toont de registratie in de manifest.xml, de opbouw van de payload, de handtekeningcontrole en de meest voorkomende foutbronnen.
Shopware 6 biedt twee manieren om op gebeurtenissen in de webshop te reageren, en die worden gemakkelijk door elkaar gehaald. De ene is het interne PHP-eventsysteem, waarop plugins inhaken en dat binnen het Shopware-proces draait. De andere zijn webhooks: die horen bij het app-systeem en informeren een externe dienst via HTTP.
De verkeerde keuze kost tijd. Een plugin-subscriber draait niet op een Shopware Cloud-instantie, en een webhook kan niet veranderen wat er tijdens een request gebeurt. Deze gids legt uit wat beide mechanismen doen, hoe een webhook wordt geregistreerd en beveiligd, welk gedrag gedocumenteerd is en op welk gedrag u niet moet vertrouwen.
Alle technische gegevens zijn gebaseerd op de officiële Shopware-ontwikkelaarsdocumentatie. Versieafhankelijke functies zijn gemarkeerd met de release waarin ze zijn geïntroduceerd. De basis van het platform vindt u op onze pagina over Shopware-ontwikkeling.
Plugins draaien in de webshop. Ze registreren een subscriber die EventSubscriberInterface implementeert, voorzien die van de tag kernel.event_subscriber en ontvangen events synchroon, terwijl het request nog wordt verwerkt. Omdat de subscriber het eventobject in handen heeft, kan hij beïnvloeden wat er daarna gebeurt: een prijs aanpassen, een schrijfactie blokkeren, de output van de Storefront wijzigen.
Apps draaien buiten de webshop. Shopware communiceert er uitsluitend via HTTP mee, en webhooks zijn de manier waarop de webshop de app laat weten dat er iets is gebeurd. De app ontvangt achteraf een POST-request en reageert door via de Admin-API terug te roepen. De oorspronkelijke handeling kan ze niet meer veranderen.
Een bruikbare vuistregel: moet de logica tijdens het request draaien en het resultaat ervan veranderen, dan hoort ze in een plugin. Reageert ze achteraf en draait ze op uw eigen infrastructuur, dan hoort ze in een app met webhooks. Voor eenvoudige meldingen zonder eigen app volstaat vaak ook de actie “URL aanroepen” in de Flow Builder, die echter aan het abonnement Evolve gebonden is.
Voordat de eerste webhook afgaat, moeten vier zaken geregeld zijn.
Webhooks horen bij een app, niet bij een plugin. De app wordt beschreven door een manifest.xml en doorloopt met de webshop een registratiehandshake, waarbij uw app per webshop een secret genereert en opslaat. Dit secret ondertekent later elk webhookrequest.
De aflevering loopt via de message queue van Shopware. Draait er geen consumer, dan worden de berichten weggeschreven maar nooit verzonden, en in de Storefront verschijnt geen foutmelding. Dat is verreweg de meest voorkomende oorzaak dat een correct geconfigureerde webhook schijnbaar niets doet.
Shopware verstuurt naar de URL die in het manifest is opgegeven. Die moet vanaf de webshopserver bereikbaar zijn en hoort TLS te termineren. Voor lokale ontwikkeling hebt u een tunneldienst nodig, zodat de webshop uw computer kan bereiken.
De meeste webhook-events vereisen een bijbehorend recht in het manifest. Wie zich abonneert op order.written zonder order:read te declareren, loopt vast op de validatie. Shopware controleert webhookrechten sinds versie 6.3.5.0.
Er is geen webhookplugin om te installeren. Webhooks worden direct in het app-manifest gedeclareerd in een <webhooks>-blok:
<webhooks>
<webhook name="product-changed"
url="https://example.com/event/product-changed"
event="product.written"/>
</webhooks>
Drie attributen zijn verplicht: name moet binnen het manifest uniek zijn, url is het endpoint waarnaar Shopware verstuurt, en event is de identificatie van het event dat u wilt ontvangen.
Alleen events die Shopware als “hookable” markeert, kunnen worden gebruikt. De gedocumenteerde set dekt de gebieden af die de meeste integraties nodig hebben:
checkout.order.placed, order.written, order.deletedproduct.written, product.deleted, customer.written, category.written, media.written en hun tegenhangerscheckout.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 en de bijbehorende state_leave-eventsapp.installed, app.activated, app.deactivated, app.deleted en shopware.updatedSinds Shopware 6.5.7.0 kan een webhook het attribuut onlyLiveVersion="true" hebben. Zonder dit attribuut gaat een order.written-webhook ook af voor geversioneerde concepten die ontstaan bij het bewerken van een bestelling in de Admin, wat een integratie doorgaans niet wil:
<webhook name="order-created"
url="https://example.com/event/order-created"
event="order.written"
onlyLiveVersion="true"/>
Het attribuut wordt alleen bij entity-written-events geëvalueerd.
De request-body is JSON en heeft altijd dezelfde drie sleutels op het hoogste niveau:
{
"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
}
Bij entity-written-events bevat de payload niet de volledige entiteit. Shopware geeft daarvoor een duidelijke reden: omdat de aflevering asynchroon is, zou een volledige entiteit bij aankomst al verouderd kunnen zijn. U ontvangt de primaryKey, en het verwachte patroon is dat u de actuele toestand via de Admin-API ophaalt.
Integraties die de payload als bron van waarheid behandelen, schrijven vroeg of laat verouderde gegevens terug naar een gekoppeld systeem. Deze beslissing moet vóór de eerste regel code vallen, niet erna.
source.shopId identificeert de webshop en blijft gedurende de hele levensduur gelijk.source.eventId blijft bij herhalingen gelijk en is daarmee de natuurlijke sleutel voor deduplicatie.timestamp is het tijdstip van verwerking en is beschikbaar vanaf 6.4.1.0.Daarnaast verstuurt Shopware vanaf 6.4.1.0 de header sw-version en vanaf 6.4.5.0 sw-context-language en sw-user-language.
Elk webhookrequest bevat de header shopware-shop-signature. Die bevat een SHA-256-HMAC over de ruwe request-body, versleuteld met het shop-secret dat uw app bij de registratie heeft gegenereerd. Een endpoint dat deze controle overslaat, accepteert alles wat iemand ernaar verstuurt.
Het app-systeem gebruikt twee verschillende secrets, en het verwisselen ervan is een veelvoorkomende oorzaak van mislukte controles:
shopware-app-signature ondertekent de querystring van het registratierequest en gebruikt het app-secret dat u met uw Shopware-account deelt.shopware-shop-signature ondertekent de body van het webhookrequest en gebruikt het shop-secret dat per webshop bij de registratie ontstaat.Hash de ruwe body voordat er enige JSON-parsing plaatsvindt. Frameworks die het request opnieuw serialiseren, produceren een andere bytereeks en daarmee een andere HMAC.
Weiger requests met een te oude timestamp. Een aanvaller kan de tijdstempel niet wijzigen zonder de handtekening ongeldig te maken, wat hem tot een bruikbare bescherming tegen herhaalde requests maakt.
Shopware raadt aan de App PHP SDK of de Symfony Bundle te gebruiken in plaats van de controle zelf te implementeren. Sinds 6.7.13.0 wordt het handtekeningsecret op het moment van aflevering bepaald, zodat afleveringen ook bij een secretrotatie met het actuele secret zijn ondertekend.
Webhooks falen stil. Niets in de Storefront wijst erop dat een aflevering is uitgebleven. De eerste stap is daarom altijd vaststellen of Shopware het überhaupt heeft geprobeerd.
Shopware legt afleverpogingen vast in de tabel webhook_event_log. Is er geen regel voor het verwachte event, dan is de webhook nooit in de wachtrij geplaatst en ligt het probleem in het manifest of in de rechten. Is er een regel die de status “queued” nooit verlaat, dan ligt het probleem bij de message queue, niet bij uw endpoint.
Een opschoontaak verwijdert vermeldingen die succesvol zijn afgeleverd of definitief zijn mislukt; lopende of herhaalde vermeldingen blijven bewaard. Sinds 6.7.4.0 worden vermeldingen die in de status “queued” blijven hangen na tweemaal de geconfigureerde bewaartermijn verwijderd.
onlyLiveVersion niet is ingesteld.Een minimaal endpoint dat de ruwe body logt en snel met 200 antwoordt, scheidt afleverproblemen van verwerkingsproblemen. Zodra de afleveringen betrouwbaar binnenkomen, verplaatst u de verwerking naar een eigen wachtrij.
De beslissingen die een webhookintegratie stabiel houden, vallen vroeg, en de meeste volgen uit één eigenschap: de aflevering is asynchroon en kan worden herhaald.
shopware-shop-signature tegen de ruwe body voordat er iets anders gebeurt.source.eventId blijft bij herhalingen gelijk en herkent een request dat al is verwerkt.primaryKey de gegevens op met de Admin-API.Twee gedragingen ontbreken bewust in deze lijst, omdat Shopware ze niet documenteert: de exacte HTTP-time-out van een aflevering en welke statuscodes als fout gelden. Een integratie die op concrete waarden vertrouwt, bouwt op een aanname, niet op een specificatie. Wilt u geen eigen app beheren, dan kunnen veel webhookscenario’s ook via een automatiseringsplatform zoals n8n worden gerealiseerd.
Nee. Webhooks horen bij het app-systeem en worden in het app-manifest gedeclareerd. Er hoeft niets uit de Shopware Store te worden geïnstalleerd.
In de meeste gevallen draait er geen message-queue-consumer. Shopware plaatst de aflevering in de wachtrij en verstuurt die nooit. Controleer in webhook_event_log of het event überhaupt in de wachtrij is geplaatst.
Omdat de aflevering asynchroon is en een volledige entiteit bij aankomst al verouderd zou kunnen zijn. Shopware verstuurt de primaryKey en verwacht dat u de actuele toestand via de Admin-API ophaalt.
De webhookdocumentatie noemt geen webhookspecifiek aantal. De algemene message-queue-documentatie zegt dat berichten driemaal worden herhaald voordat ze naar het failure transport gaan. Beschouw dat als ordegrootte, niet als garantie, en dedupliceer via source.eventId.
Nee. Een webhook is een melding achteraf. Om een lopend request te beïnvloeden, hebt u een plugin met een PHP-event-subscriber nodig, wat op zijn beurt een zelf gehoste webshop vereist. Hoe wij zulke plugins ontwikkelen, laten we zien op onze pagina over Shopware-pluginontwikkeling.
Webhooks van het app-systeem maken sinds de lijn 6.3 deel uit van de kern van Shopware. Enkele details kwamen later: het veld timestamp en de header sw-version in 6.4.1.0, de taalheaders in 6.4.5.0 en onlyLiveVersion in 6.5.7.0. De actuele hoofdlijn is 6.7.