WooCommerce webhook werkt niet is een van de tijdrovendste meldingen in shop-onderhoud. In mijn ervaring firet vaak 90% van de events wel, maar de 10% die mist zit precies op je koppeling met CRM, ERP of e-mail-tool. Een gemene detail: WooCommerce zet een webhook na 5 opeenvolgende responses buiten 2xx en 3xx automatisch op “disabled”. Daarna verlies je 100% van je events zonder duidelijke waarschuwing in de interface. Dit artikel loopt in 8 checks op volgorde van waarschijnlijkheid door de oorzaken: van webhook-status en delivery-logs tot HPOS-impact, curl-tests en cron-configuratie. Aan het einde weet je waar het vastzit en heb je een reproduceerbare fix.
De aanpak is systematisch, want raden kost tijd en frustratie. Werk de checks op volgorde af, log wat je test, en zet één ding per keer aan of uit.

Hoe WooCommerce webhooks technisch werken
Kort model. Er gebeurt iets in de shop (nieuwe order, product-update, klant-registratie). WooCommerce vuurt intern een hook (woocommerce_new_order, woocommerce_update_product). De webhook-configuratie luistert naar die hook. Action Scheduler zet een asynchrone taak in de queue. Die taak stuurt via HTTP POST de JSON-payload naar de ingestelde delivery-URL. De ontvanger reageert met een HTTP-status. 2xx = succes; alles anders = fail en retry.
Twee gevolgen. Een: webhooks zijn asynchroon, dus vertraging tussen event en delivery is normaal (seconden tot minuten). Twee: de retry-logica is beperkt (5 pogingen); na 5 failures gaat de webhook op disabled.
WooCommerce webhook werkt niet: 8 checks op volgorde
De volgorde is gebaseerd op hoe vaak elk probleem in de praktijk voorkomt.
- Webhook-status. Staat hij nog op active, of is hij door de 5-failure-regel op disabled gezet?
- Delivery-logs lezen. WooCommerce → Status → Logs, source
webhooks-delivery. - Action Scheduler backlog. Zit de taak in de queue vast?
- HPOS aan of uit. High-Performance Order Storage verandert de payload-structuur voor order-webhooks.
- Trigger-context. Firet de hook wel? Bulk-edits en REST-updates gedragen zich soms anders.
- Endpoint reachability. Is de ontvanger überhaupt bereikbaar? TLS, auth, DNS.
- Payload-validatie. Krijgt de ontvanger een 4xx door schema-mismatch?
- Cron-config. Draait
wp-cronbetrouwbaar, of loopt hij achter?
Loop deze in volgorde af. Vaak vind je de oorzaak al bij check 1, 2 of 3.
Check 1: status van de webhook (active/paused/disabled)
Ga naar WooCommerce → Settings → Advanced → Webhooks. Kijk in de kolom “Status”. Drie mogelijke waarden:
- Active: webhook is aan en firet.
- Paused: handmatig gepauzeerd door een admin.
- Disabled: automatisch uitgezet na 5 opeenvolgende responses buiten 2xx en 3xx.
Staat hij op disabled? Klik hem open en zet de status terug naar active. Dat is de fix voor de acute onderbreking. Voor de echte oorzaak moet je door naar check 2, want anders staat hij binnen een uur weer op disabled.
Check 2: delivery-logs lezen (WooCommerce Status Logs)
Ga naar WooCommerce → Status → Logs. In de dropdown rechtsboven zoek je naar een bestand dat begint met webhooks-delivery (bijvoorbeeld webhooks-delivery-2026-07-19-abc123.log). Klik erop.
Wat je zoekt: de laatste failed delivery. Elke log-regel bevat de webhook-ID, de HTTP-status-code van de ontvanger, en (bij fouten) de response-body of foutmelding. Typische patronen:
Response: 401of403: authenticatie-probleem bij de ontvanger. Signature-check faalt of de API-key is verlopen.Response: 404: de endpoint-URL bestaat niet meer. Ontvanger heeft de URL gewijzigd of de app is offline.Response: 500: de ontvanger crasht op jouw payload. Meestal een schema-mismatch (check 7).cURL error 28: Connection timed out: de ontvanger reageert niet binnen de timeout (meestal 5 seconden). Netwerk of trage endpoint.cURL error 60: SSL certificate problem: TLS-certificaat van de ontvanger is verlopen of ongeldig.
Deze log-regels vertellen je in één blik welke check je vervolgens moet doen.

Check 3: Action Scheduler backlog
WooCommerce gebruikt Action Scheduler voor asynchrone taken. Ga naar WordPress → Tools → Scheduled Actions.
Filter op status “Failed” of “In-progress”. Zoek naar acties met hook woocommerce-... of wc-webhook-delivery. Twee scenario’s:
- Grote backlog van pending acties (honderden of duizenden). Je wp-cron loopt achter. Ga door naar check 8.
- Veel failed acties met dezelfde error. De webhook-delivery zelf faalt herhaaldelijk. Ga terug naar check 2.
Als de queue vast zit, kun je hem handmatig legen via WP-CLI (voorzichtig, alleen na back-up):
wp action-scheduler runDat forceert een run van pending acties in de terminal in plaats van via wp-cron. Voor grote queues (10k+) doe je dit in batches.
Check 4: HPOS aan of uit – impact op order-webhooks
HPOS (High-Performance Order Storage) is stable en default voor nieuwe installs sinds WC 8.2 (oktober 2023); daarvoor was het opt-in beschikbaar. HPOS slaat orders op in aparte tabellen (wp_wc_orders) in plaats van in wp_posts.
Wat verandert er voor webhooks? De payload-structuur voor order-events blijft compatibel via de standaard API, maar als je custom code gebruikt die direct $order->get_meta() of get_post_meta() aanroept, kan de payload leeg of anders zijn.
Check je HPOS-status: WooCommerce → Settings → Advanced → Features. “High-Performance Order Storage” toggle. Als je HPOS recent hebt aangezet en de webhook is daarna gaan haperen, is dit de kandidaat-oorzaak. Custom webhook-code die op oude order-meta rekent, moet worden aangepast om de HPOS-compatibele CRUD-methoden ($order->get_meta_data(), $order->update_meta_data()) te gebruiken.
Voor de officiële uitleg van webhook-events en payload-structuur is de WooCommerce webhook documentatie de bron.
Check 5: trigger-context (bulk edit, REST API, CLI)
Niet elke actie firet dezelfde webhook. Voorbeelden waar mensen tegenaan lopen:
- Bulk-edit van orders in de admin. WooCommerce firet
order.updatedper order, maar op grote batches (100+ orders) kan Action Scheduler achter raken en enkele webhooks missen. wp wc order updatevia WP-CLI. Firet standaard geen webhook-trigger, tenzij je expliciet de action-hook aanroept.- REST API PUT/PATCH op orders. Firet meestal wel, maar sommige custom endpoints slaan de hook over.
Test dit door één order handmatig te wijzigen in de admin (bijvoorbeeld status “processing” → “completed”). Kijk in de delivery-logs of er direct een new delivery-poging staat. Zo ja: de webhook firet, maar bepaalde trigger-contexten worden overgeslagen. Zo nee: het probleem zit elders in de keten.

Check 6: endpoint reachability + TLS + auth
Test of jouw server de ontvanger überhaupt kan bereiken. Vanaf de shell van je hosting (SSH):
curl -X POST \
-H "Content-Type: application/json" \
-H "X-WC-Webhook-Signature: dummy" \
-d '{"test": true}' \
https://receiver.example/webhook-endpointVerwacht je een 200 of 401 (authenticatie is de volgende check)? Krijg je een timeout, dan is er een netwerkprobleem tussen jouw hosting en de ontvanger. Firewall, DNS of TLS.
Signature-verificatie werkt bij WooCommerce webhooks via de header X-WC-Webhook-Signature. Dit is een HMAC-SHA256 van de request-body, gehashed met de secret die je in de webhook-configuratie hebt ingesteld. Als de ontvanger die signature verifieert (goed idee, security) en jouw secret staat verkeerd geconfigureerd, krijg je 401 of 403 op elke delivery.
Fix: check of de secret aan beide kanten identiek is. Whitespace of onzichtbare karakters bij copy-paste zijn een klassieke valkuil.
Check 7: payload-validatie aan ontvangerkant
Krijg je consequent 400 of 500? Dan is de payload waarschijnlijk valide JSON, maar niet wat de ontvanger verwacht.
Vergelijk de veldnamen en -types in de payload met de API-docs van de ontvanger. Typische mismatches:
- Prijs als string vs float. WooCommerce stuurt prijzen soms als string (
"29.95"), ontvanger verwacht een numerieke waarde. - Ontbrekende metavelden. Custom order-meta die de ontvanger nodig heeft, zit niet in de standaard payload. Oplossing:
add_filter('woocommerce_webhook_payload', ...)om extra velden mee te sturen. - Datum-format. WooCommerce stuurt ISO 8601 met tijdzone, sommige APIs willen alleen datum.
Log de payload aan jouw kant (error_log(json_encode($payload))) en compare met wat de ontvanger accepteert in hun sandbox of test-endpoint.
Check 8: cron-config en WP_CRON
Als de queue in Action Scheduler backlog toont, is wp-cron je bottleneck. Standaard triggert WordPress cron-taken bij elk page-bezoek. Op sites met weinig verkeer draait cron zelden en lopen webhook-deliveries dus achter.
De robuuste fix: zet wp-cron uit en gebruik een echte system cron. In wp-config:
define('DISABLE_WP_CRON', true);En op je hosting-panel (of via crontab):
*/5 * * * * curl -s https://jouwshop.nl/wp-cron.php?doing_wp_cron > /dev/nullDat draait wp-cron elke 5 minuten via een echte cron. Voor WooCommerce-shops met veel webhook-traffic werk je zo betrouwbaarder dan met de standaard triggering. Voor sites waar dit onderhoud vast onderdeel is, past het naast een backup-testroutine als preventieve stap in de onderhoudscyclus.
Wanneer je een specialist inschakelt
Twee scenario’s rechtvaardigen externe hulp. Als check 4 (HPOS) of check 7 (payload-mismatch) in het spel is, zit je in custom development-werk waar een verkeerde patch nieuwe problemen introduceert. Ook bij intermitterende webhook-failures (soms wel, soms niet) is een gestructureerde debugging-sessie met logging en reproductie meestal effectiever dan zelf blijven proberen.
Een WooCommerce webhook-debugging sessie inclusief de partij aan de andere kant (Exact Online, Moneybird, Mailchimp, ActiveCampaign of custom) kost bij mij twee tot vier uur op 105 euro per uur voor het senior werk. Als de webhook aan checkout of betaling hangt en de shop live rammelt, werk ik op 175 euro per uur voor spoed. Verbeteren boven herbouwen, direct contact zonder tussenlagen, en geen bureau-tarieven. De source-code en de webhook-configuratie blijven van jou; ik document alles wat we aanpassen zodat je niet vastzit bij één partij.
Multi-stack noot. Elke koppel-partij heeft zijn eigen signature-check en veld-verwachtingen. Exact Online, Moneybird, Mailchimp en ActiveCampaign gedragen zich alle vier anders. Bij headless WooCommerce (via WPGraphQL of headless front-ends) firen webhooks nog steeds vanuit WC core, niet vanuit de headless-laag; dat scheelt debugging-oppervlak.



