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.
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.
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:
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.
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:
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.
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:
Webapp deployen voor webhooks
- Klik rechtsboven op Implementeren, dan Nieuwe implementatie.
- Kies als type Webapp.
- Zet Uitvoeren als op Mijzelf, zodat het script jouw rechten gebruikt.
- Zet Wie heeft toegang op Iedereen, want een extern systeem moet erbij kunnen.
- Klik op Implementeren en kopieer de webapp-URL voor de verzendende dienst.
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:
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());
}
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 een externe API aanroepen. Voor de deploy-details lees je deployen als webapp of add-on.