# Webhooks uitgelegd: wat ze zijn en hoe je ze veilig opzet Een **webhook** is een manier waarop het ene systeem het andere automatisch op de hoogte brengt zodra er iets gebeurt. In plaats van dat jij steeds vraagt "is er al iets nieuws?", stuurt de bron zelf een berichtje naar een adres dat jij van tevoren hebt opgegeven. Het is daarmee de basis van vrijwel elke realtime integratie tussen apps. Technisch gezien is een webhook een **HTTP-callback**: zodra een gebeurtenis optreedt (bijvoorbeeld een nieuw formulier ingevuld, een betaling gelukt, een bestand gewijzigd), doet het bronsysteem een **HTTP POST** naar de **URL** die jij hebt geregistreerd. In de body van die POST zit doorgaans een JSON-payload met de details van de gebeurtenis. ## Webhook versus polling De tegenhanger van een webhook is **polling**: jij vraagt op een vast ritme (bijvoorbeeld elke minuut) aan een API of er iets veranderd is. Het verschil zit in wie het initiatief neemt: | Aspect | Polling (pull) | Webhook (push) | | --- | --- | --- | | Wie start | De client vraagt steeds opnieuw | De server stuurt zelf zodra er iets is | | Verkeer | Ook als er niets veranderd is | Alleen bij een echte gebeurtenis | | Vertraging | Tot het volgende ophaalmoment | Vrijwel direct | | Nodig wanneer | De bron biedt geen webhooks | Realtime updates gewenst | Voor realtime updates en gebeurtenissen die niet heel vaak voorkomen, zijn webhooks vrijwel altijd de betere keuze. Polling is alleen praktischer als een bron geen webhooks aanbiedt, of als er zo veel en zo continu wijzigingen zijn dat ophalen op een vast ritme eenvoudiger is. :::tip title="Combineer webhook en API" Bouw je een koppeling en biedt de bron zowel webhooks als een API aan? Gebruik de webhook voor het sein dat er iets gebeurd is, en haal indien nodig de volledige gegevens daarna via de API op. Zo combineer je snelheid met betrouwbaarheid. ::: ## De ontvangende kant veilig maken Een webhook-URL is in principe openbaar bereikbaar, want het bronsysteem moet erbij kunnen. Dat betekent dat ook anderen die URL kunnen aanroepen. Beveiliging draait daarom om twee vragen: komt deze aanvraag echt van de verwachte bron, en is hij onderweg niet aangepast? - **Gebruik uitsluitend HTTPS.** Zo is het verkeer versleuteld en kan de payload onderweg niet worden meegelezen of gewijzigd. - **Verifieer een handtekening.** De meeste serieuze webhook-aanbieders ondertekenen elke aanvraag met een **gedeeld geheim** via een **HMAC**-hash (in de praktijk meestal HMAC-SHA256). Die handtekening staat in een header. Jouw endpoint berekent met hetzelfde geheim de handtekening over de ontvangen body en vergelijkt die met de meegestuurde waarde. Komen ze niet overeen, dan weiger je de aanvraag. - **Bewaar het geheim veilig.** Zet het in omgevingsvariabelen of een secret manager, nooit hardcoded in je code en nooit in versiebeheer. :::warn title="Vertrouw geen ongeverifieerde aanvraag" Vertrouw nooit blind op een binnenkomende webhook. Zonder handtekeningverificatie kan iedereen die je URL kent valse gebeurtenissen sturen. Behandel de inhoud daarom pas als echt nadat de handtekening klopt. ::: ## Een endpoint stap voor stap opzetten :::howto title="Zo zet je een veilige webhook-endpoint op" 1. Maak een endpoint aan dat alleen via **HTTPS** bereikbaar is en alleen **POST** accepteert. 2. Lees eerst de **ruwe body** uit (de exacte bytes), voordat je de JSON parseert. 3. Bereken met je **gedeelde geheim** een HMAC-SHA256 over die ruwe body. 4. Vergelijk je berekende handtekening **in constante tijd** met de waarde uit de signature-header. 5. Klopt de handtekening niet, antwoord dan met `401` en stop. Klopt hij wel, ga door. 6. Antwoord snel met een `2xx`-status en doe het zware werk daarna asynchroon. 7. Bewaar de gebeurtenis-id zodat je een herhaling van dezelfde gebeurtenis kunt overslaan. ::: ## Twee veelgemaakte fouten Twee details bepalen vaak of verificatie wel of niet werkt: - **Vergelijk over de ruwe body.** Bereken de handtekening over de exacte bytes zoals ontvangen, vóór je de JSON parseert. Parse je eerst en serialiseer je daarna opnieuw, dan kan de inhoud net iets veranderen en klopt de handtekening niet meer. - **Vergelijk in constante tijd.** Gebruik een vergelijking die niet sneller stopt bij het eerste verschillende teken (een constant-time compare). Zo voorkom je dat een aanvaller via timing het geheim kan afleiden. ## Omgaan met opnieuw verzonden berichten Netwerken zijn niet perfect. Veel aanbieders sturen een webhook **opnieuw** als jouw endpoint niet snel genoeg een succesvolle respons geeft, of als die tijdelijk onbereikbaar was. Houd daar rekening mee: - **Reageer snel met een 2xx-status** zodra je de aanvraag hebt aangenomen, en doe zwaar werk daarna asynchroon. Anders denkt de bron dat het misging en stuurt hij nog eens. - **Maak je verwerking idempotent.** Dezelfde gebeurtenis kan meer dan eens binnenkomen. Gebruik een unieke gebeurtenis-id om dubbele verwerking te herkennen en over te slaan. :::info title="Webhooks testen zonder code" Wil je webhooks testen voordat je echte koppelingen bouwt? No-code platforms als Make, n8n of Zapier kunnen een webhook-URL voor je genereren en de binnenkomende payload tonen. Zo zie je precies welke gegevens een bron stuurt zonder direct code te schrijven. ::: Met HTTPS, handtekeningverificatie en idempotente verwerking heb je de drie pijlers van een betrouwbare webhook-koppeling te pakken: het verkeer is beschermd, je weet zeker van wie het komt, en dubbele of opnieuw verzonden berichten brengen je systeem niet in de war. :::faq ### Wat is het verschil tussen een webhook en een API? Een API roep je zelf aan wanneer jij iets nodig hebt. Een webhook werkt andersom: het bronsysteem roept jouw endpoint aan zodra er iets gebeurt. Vaak gebruik je ze samen, waarbij de webhook het seintje geeft en je daarna via de API de volledige gegevens ophaalt. ### Hoe weet ik zeker dat een webhook echt van de juiste bron komt? Door de handtekening te verifiëren. De aanbieder ondertekent de aanvraag met een gedeeld geheim, meestal via HMAC-SHA256, en zet die handtekening in een header. Jij berekent dezelfde handtekening over de ruwe body en accepteert de aanvraag alleen als beide overeenkomen. ### Wat betekent idempotent verwerken? Het betekent dat dezelfde gebeurtenis twee keer verwerken hetzelfde resultaat geeft als één keer. Omdat aanbieders een webhook opnieuw kunnen sturen, gebruik je een unieke gebeurtenis-id om al verwerkte berichten te herkennen en over te slaan. ### Waarom moet ik zo snel een 2xx-status teruggeven? De bron ziet een trage of mislukte respons als een fout en stuurt de webhook dan opnieuw. Door direct een 2xx te sturen en het echte werk asynchroon te doen, voorkom je onnodige herhalingen. ### Heb ik altijd een eigen server nodig voor webhooks? Nee. No-code platforms zoals Make, n8n en Zapier kunnen een webhook-URL voor je genereren en de payload verwerken, zodat je zonder eigen code een koppeling kunt bouwen of testen. :::