# Webhooks ontvangen en verwerken met Apps Script Webhooks ontvangen en verwerken met Apps Script maakt van je script een ontvangstpunt voor andere systemen. Een betaalprovider, formuliertool of chatdienst kan data naar jouw script sturen zodra er iets gebeurt. In dit artikel leer je een webapp deployen, de doPost-functie schrijven, de payload uitlezen en het endpoint beveiligen. [[TOC]] ## Hoe een webhook in Apps Script werkt Een webhook is een HTTP-request dat een extern systeem naar jouw URL stuurt zodra er een gebeurtenis plaatsvindt. Om zo'n request te ontvangen, deploy je je script als webapp. Apps Script roept dan automatisch `doPost(e)` aan bij een POST-request, of `doGet(e)` bij een GET-request. In het event-object `e` zit de meegestuurde data. :::info title="doPost en doGet" Voor webhooks gebruik je vrijwel altijd `doPost(e)`, omdat systemen data meesturen in de body van een POST. De payload zit in `e.postData.contents` als string. De volledige eventstructuur staat in de officiele documentatie op developers.google.com/apps-script/guides/web. ::: ## De doPost-functie schrijven Je verwerkingsfunctie leest de binnenkomende JSON en geeft een antwoord terug: ```javascript function doPost(e) { const data = JSON.parse(e.postData.contents); Logger.log('Ontvangen: ' + JSON.stringify(data)); const blad = SpreadsheetApp.openById('jouw-sheet-id').getSheetByName('Webhooks'); blad.appendRow([new Date(), data.type, data.bericht]); return ContentService .createTextOutput(JSON.stringify({ status: 'ok' })) .setMimeType(ContentService.MimeType.JSON); } ``` `ContentService` bouwt het antwoord dat het externe systeem terugkrijgt. Veel diensten verwachten een 200-status met een korte bevestiging. :::tip title="Bevestig snel, verwerk daarna" Veel webhook-leveranciers (Stripe, Mollie, GitHub) verwachten binnen enkele seconden een 200-antwoord en proberen het anders opnieuw. Houd de logica in `doPost` daarom kort. Zwaar werk zoals e-mails versturen of veel rijen wegschrijven kun je beter doorschuiven naar een trigger of een wachtrij in een sheet, zodat de afzender meteen een bevestiging krijgt. ::: ## Het endpoint beveiligen met een token Een publieke webapp-URL is voor iedereen bereikbaar. Daarom controleer je een geheime token voordat je iets verwerkt: ```javascript function doPost(e) { const geheim = PropertiesService.getScriptProperties().getProperty('WEBHOOK_TOKEN'); const data = JSON.parse(e.postData.contents); if (!data.token || data.token !== geheim) { return ContentService .createTextOutput(JSON.stringify({ status: 'unauthorized' })) .setMimeType(ContentService.MimeType.JSON); } verwerkWebhook(data); return ContentService .createTextOutput(JSON.stringify({ status: 'ok' })) .setMimeType(ContentService.MimeType.JSON); } ``` De token bewaar je in de Script Properties, niet hardgecodeerd in je broncode. :::danger Deploy je webapp met toegang Iedereen, dan kan letterlijk iedereen op internet je doPost aanroepen. Zonder tokencontrole kan een aanvaller ongewenste data in je spreadsheet schrijven of je quota opsouperen. Controleer altijd een geheime token, bewaar die in PropertiesService en nooit in de code zelf. Geeft de afzender een echte handtekening mee (zoals een HMAC-header bij Stripe of GitHub), gebruik dan die handtekening in plaats van een eigen token. ::: ## De webapp deployen Om een URL te krijgen moet je deployen als webapp: :::howto title="Webapp deployen voor webhooks" 1. Klik rechtsboven op **Implementeren**, dan **Nieuwe implementatie**. 2. Kies als type **Webapp**. 3. Zet **Uitvoeren als** op **Mijzelf**, zodat het script jouw rechten gebruikt. 4. Zet **Wie heeft toegang** op **Iedereen**, want een extern systeem moet erbij kunnen. 5. Klik op **Implementeren** en kopieer de webapp-URL voor de verzendende dienst. ::: :::warn Elke keer dat je je code wijzigt, moet je een nieuwe versie implementeren of je bestaande implementatie bijwerken, anders draait de oude code nog. Beheer dit via **Implementeren**, dan **Implementaties beheren**, en kies bij Versie de optie **Nieuw**. Werk je dezelfde implementatie bij, dan blijft de webapp-URL hetzelfde en hoeft de afzender niets aan te passen. ::: ## De payload testen Voordat een echt systeem aanlevert, test je het endpoint zelf met een POST. Je kunt dat doen vanuit een ander script of met een tool zoals curl: ```javascript function testWebhook() { const url = 'jouw-webapp-url'; const payload = { token: 'geheim123', type: 'test', bericht: 'Hallo' }; const response = UrlFetchApp.fetch(url, { method: 'post', contentType: 'application/json', payload: JSON.stringify(payload) }); Logger.log(response.getContentText()); } ``` :::faq ### Wat is het verschil tussen doGet en doPost? `doGet` reageert op GET-requests met data in de URL, `doPost` op POST-requests met data in de body. Webhooks gebruiken vrijwel altijd POST. ### Waarom krijgt het externe systeem een foutpagina? Vaak omdat je je code wijzigde maar geen nieuwe versie deployde, of omdat de toegang niet op Iedereen staat. Werk je implementatie bij en controleer de toegangsinstelling. ### Hoe beveilig ik een publiek endpoint? Met een geheime token in de payload die je vergelijkt met een waarde in PropertiesService. Verwerk alleen requests met de juiste token. Levert de afzender een handtekening-header zoals HMAC, gebruik dan die handtekening. ### Kan ik de ruwe request-headers lezen? Apps Script geeft beperkte toegang tot headers. De payload lees je via `e.postData.contents`; voor authenticatie gebruik je een token in de body of een query-parameter via `e.parameter`. ### Waarom is e undefined als ik de functie gewoon uitvoer in de editor? Het event-object `e` wordt alleen gevuld bij een echte POST naar de webapp-URL. Voer je `doPost` direct uit in de editor, dan is er geen request en dus geen payload. Test daarom altijd via een echte request, bijvoorbeeld met de testWebhook-functie hierboven of met curl. ### Wat doe ik als de webhook gevoelige persoonsgegevens bevat? Schrijf niet meer weg dan nodig, log geen ruwe payloads met persoonsgegevens en zet de toegang strak. Controleer de token of handtekening, en overweeg de data versleuteld of in een afgeschermde sheet te bewaren in lijn met de AVG. ::: ## Volgende stap Webhooks ontvangen vult mooi aan op zelf API's aanroepen, zie [[apps-script-externe-api|een externe API aanroepen]]. Voor de deploy-details lees je [[apps-script-deployment|deployen als webapp of add-on]].