Webhooks
Ontvang realtime events via HTTP POST naar jouw endpoint
Laatst bijgewerkt op
Webhooks ontvangen realtime events via HTTP POST naar een door jou geconfigureerde URL. Dezelfde events zijn ook beschikbaar via SSE. Webhooks zijn per organisatie geconfigureerd - elke organisatie heeft zijn eigen webhooks.
Beheer
Zie de OpenAPI-specificatie voor volledige request- en response-schema's.
| Method | Pad | Beschrijving |
|---|---|---|
| GET | /api/orgs/:orgId/webhooks | Webhooks ophalen |
| GET | /api/orgs/:orgId/webhooks/delivery-stats | Leveringsstatistieken ophalen |
| POST | /api/orgs/:orgId/webhooks/retry-deliveries | Leveringen opnieuw proberen. Body: mode (failed of force) en optioneel id voor één webhook. failed: alleen definitief mislukte leveringen, direct. force: wachtende en definitief mislukte leveringen op de achtergrond, negeert wachttijden. |
| GET | /api/orgs/:orgId/webhooks/:id | Webhook op ID ophalen |
| POST | /api/orgs/:orgId/webhooks | Webhook aanmaken |
| PATCH | /api/orgs/:orgId/webhooks/:id | Webhook bijwerken |
| DELETE | /api/orgs/:orgId/webhooks/:id | Webhook verwijderen |
Webhook aanmaken
POST /api/orgs/org_abc123/webhooks
Content-Type: application/json
x-api-key: tkn_xxx{
"url": "https://jouw-server.com/webhooks/tillor",
"subscribedEventKeys": ["invoice:created", "invoice:paid", "customer:updated"],
"enabled": true
}- url - HTTPS-endpoint die POST-requests accepteert
- subscribedEventKeys - Array van event keys of
["*"]voor alle events. De volledige lijst staat in Tillor onder Profielmenu → Ontwikkelaars bij Webhook toevoegen → Geabonneerde gebeurtenissen.
Een paar events komen zo vaak voor dat je ze niet kunt kiezen en dat ze ook niet via * aankomen, zoals de fysieke staat van barrières, het typen in de inbox, controller-logs en voertuigaanwezigheid. Die staan niet in de lijst hieronder. Welke events je kunt kiezen, hangt ook af van je permissies.
- enabled -
trueom levering in te schakelen
Je mag alleen events kiezen waarvoor je organisatielid de juiste permissie heeft (bijv. banktransacties voor bankAccountTransaction:*). Wildcard * is alleen beschikbaar voor leden met volledige toegang (*). Bij een ongeldige combinatie geeft de API een foutmelding. Een webhook stuurt de volledige payload door, met de gekoppelde gegevens (zoals de klant bij een reservatie). Daarom moet je ook die domeinen mogen lezen om een webhook aan te maken, de URL of events te wijzigen of hem weer in te schakelen.
Webhook-payload
Elke webhook-levering is een POST met:
Headers:
Content-Type: application/jsonX-Webhook-Event-ID- stabiele unieke ID voor deze logische levering (zelfde waarde bij retries)X-Webhook-Signature- HMAC-SHA256 handtekening van de body, formaatsha256=<hex>(zie Handtekening verifiëren)
Body:
{
"event": "invoice:created",
"data": {},
"timestamp": 1735689600000,
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"spanId": "00f067aa0ba902b7",
"triggeredBy": {
"id": "usr_63x8jp68is",
"name": "Niels"
}
}| Veld | Type | Beschrijving |
|---|---|---|
event | string | Event key (bijv. invoice:created) |
data | object | Event-specifieke payload |
timestamp | number | Unix timestamp (ms) wanneer het event werd uitgezonden |
traceId | string | OpenTelemetry trace-id van de Tillor-actie die dit event veroorzaakte. Geef deze door bij support; het is geen geheim. |
spanId | string (optioneel) | Span binnen die trace |
triggeredBy | object | null | Gebruiker die de actie uitvoerde (id, name). null bij systeemacties (cron, bank-sync, …) |
Zie Voorbeelden voor volledige payload-voorbeelden.
Handtekening verifiëren
Elke webhook bevat een eigen signing secret (64 hex-karakters, zichtbaar in de webhooktabel via Ondertekeningssleutel tonen op Profielmenu → Ontwikkelaars). Tillor ondertekent elke POST met die secret zodat jij kunt verifiëren dat het verzoek écht van Tillor komt en dat de body niet is aangepast.
Hoe Tillor ondertekent:
- Bereken
HMAC-SHA256(signingSecret, raw_request_body)(lowercase hex). - Stuur dat als
X-Webhook-Signature: sha256=<hex>.
Hoe jij verifieert:
- Lees de ruwe request-body (vóór JSON-parsen - anders matcht de hash niet).
- Bereken zelf
HMAC-SHA256(signingSecret, raw_body)in hex. - Vergelijk met de waarde achter
sha256=uit deX-Webhook-Signatureheader met een constant-time vergelijking.
import crypto from "node:crypto";
function verifyTillorWebhook(rawBody, headerSignature, signingSecret) {
const expected = crypto.createHmac("sha256", signingSecret).update(rawBody).digest("hex");
const received = headerSignature.replace(/^sha256=/, "");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(received, "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Behandel de secret als wachtwoord
De signing secret kun je in Tillor tonen via Ondertekeningssleutel tonen in de webhooktabel. Sla 'm op als secret (env var, vault) en log 'm nooit. Vermoed je een lek? Verwijder de webhook en maak een nieuwe aan; daarmee krijg je een nieuwe secret.
Leveringsgedrag en retries
- Antwoord met een 2xx-status om succes te bevestigen.
- Bij een mislukte levering (niet-2xx, netwerkfout of geblokkeerd doel) probeert Tillor de levering automatisch opnieuw met steeds langere tussenpozen. Elke poging hergebruikt dezelfde payload, dezelfde handtekening en hetzelfde event-id (idempotent).
| Poging | Wachttijd sinds vorige poging |
|---|---|
| 1 | direct |
| 2 | 1 seconde |
| 3 | 2 seconden |
| 4 | 4 seconden |
| 5 | 8 seconden |
| 6 | 5 minuten |
| 7 | 30 minuten |
| 8 | 2 uur |
| 9 | 6 uur |
| 10 | 24 uur |
- Slaagt één van de pogingen (2xx) → de levering is afgerond.
- Slaagt ook poging 10 (na 24u) niet → de levering wordt definitief gemarkeerd als mislukt en niet verder geprobeerd.
- Wordt de webhook intussen uitgeschakeld, dan stopt Tillor met opnieuw proberen.
Idempotentie
Elke retry hergebruikt dezelfde X-Webhook-Event-ID en X-Webhook-Signature. Dedupliceer aan jouw kant op die header zodat een succesvolle retry na een trage 200 geen dubbele verwerking veroorzaakt.
Meldingen bij aanhoudende fouten
Als leveringen voor een webhook-endpoint blijven mislukken, stuurt Tillor maximaal twee meldingen per incident (per endpoint):
- Na 5 minuten aanhoudende fouten - e-mail naar het organisatie-e-mailadres (
supportEmail, andersemail) en naar organisatieleden met rechten om organisatie-instellingen te wijzigen, plus push (indien ingeschakeld) voor die leden. De e-mail vermeldt sinds wanneer de leveringen mislukken. Datums in de e-mail gebruiken de tijdzone uit Instellingen > Algemeen (standaardEurope/Brussels). - Bij definitieve mislukking - dezelfde ontvangers krijgen één melding wanneer het eerste event in dat incident na alle pogingen definitief mislukt is gemarkeerd.
Je krijgt geen melding per mislukt event. Zodra alle mislukte leveringen voor een endpoint zijn opgelost (succesvol afgeleverd), start een volgend incident opnieuw met dezelfde regels.
Op Profielmenu → Ontwikkelaars toont de webhooktabel per endpoint een compacte leveringsstatus (aantallen wachtend op opnieuw proberen en definitief mislukt). Klik op het ℹ-icoon voor details, inclusief de volledige foutmelding en de payload van de meest recente poging.
- Mislukte opnieuw proberen (↻): alleen definitief mislukte leveringen voor die webhook.
- Forceer opnieuw proberen (⚡): alle wachtende én definitief mislukte leveringen voor die webhook, ongeacht geplande wachttijden. Tillor start dit op de achtergrond zodat grote wachtrijen (bijv. duizenden events) veilig verwerkt worden.
- Alles forceer opnieuw proberen rechtsboven naast Webhook toevoegen: hetzelfde voor alle ingeschakelde webhooks in de organisatie.
Event types
Event keys gebruiken het formaat entity:action of entity:subresource:action. De volledige lijst, met de permissie per event en een voorbeeld-payload, staat in de Event-index. Die pagina wordt uit de code gegenereerd en is dus altijd volledig. Dezelfde keys staan in Tillor onder Profielmenu → Ontwikkelaars bij Webhook toevoegen → Geabonneerde gebeurtenissen.
Webhooks vs SSE
| Use case | Aanbeveling |
|---|---|
| Server-side integratie | Webhooks - Jouw server ontvangt POSTs |
| Eenvoudige logging | Webhooks - Minimale setup |
| Realtime dashboard, live updates in app | SSE - Eén verbinding, lage latentie. |
| Veel event types, client-side filteren | SSE - Gebruik events query-param om verkeer te beperken. |
Gerelateerd
- OpenAPI - Volledige API-specificatie
- HTTP API - REST API en API-sleutels
- SSE - Zelfde events via Server-Sent Events
- Automatiseringen - Eigen berichten versturen vanuit een automatisering