Aan de slag
Webhooks
Met webhooks verwittigt ProFactuur je eigen systeem zodra er iets gebeurt. Zo hoef je niet telkens zelf op te vragen of er iets veranderd is.
Endpoint toevoegenLink naar deze sectie
- Ga naar Instellingen, API en klik bij Webhooks een https-URL aan.
- Kies Live of Test en vink de gebeurtenissen aan die je wil ontvangen.
- Kopieer het geheim (begint met
whsec_). Je ziet het maar één keer. Kwijt? Klik Geheim vernieuwen.
GebeurtenissenLink naar deze sectie
| Type | Wanneer |
|---|---|
factuur.definitief | Een factuur kreeg een nummer |
factuur.verzonden | Een factuur werd verstuurd via Peppol of e-mail |
factuur.betaald | Een factuur werd als betaald gemarkeerd |
factuur.peppol_afgeleverd | Peppol bevestigt de aflevering |
factuur.peppol_geweigerd | De ontvanger weigerde de factuur via Peppol |
factuur.peppol_fout | Verzending via Peppol is mislukt |
creditnota.definitief | Een creditnota kreeg een nummer |
creditnota.verzonden | Een creditnota werd verstuurd |
inbox.ontvangen | Er kwam een document binnen via Peppol |
offerte.geaccepteerd | Een offerte werd geaccepteerd |
offerte.geweigerd | Een offerte werd geweigerd |
klant.aangemaakt | Er werd een klant toegevoegd |
klant.bijgewerkt | Een klant werd gewijzigd |
PayloadLink naar deze sectie
Elke verzending is een POST met een JSON-body. id is uniek per gebeurtenis: gebruik het om dubbele verwerking te vermijden. data bevat het object zoals de API het teruggeeft.
{
"id": "evt_4b1d...",
"type": "factuur.betaald",
"aangemaakt_op": "2026-10-11T09:30:00Z",
"test": false,
"data": {
"id": "9a2b...",
"type": "factuur",
"nummer": "2026-0042",
"status": "betaald",
"totaal_incl": 726
}
}Bij factuur.verzonden en creditnota.verzonden staat in data ook kanaal: peppol of email.
Handtekening controlerenLink naar deze sectie
Elke verzending draagt de header ProFactuur-Signature: t=<timestamp>,v1=<handtekening>. De handtekening is een HMAC-SHA256 met je geheim over de tekst <timestamp>.<ruwe body>, als hex.
- Lees
tenv1uit de header. - Bereken HMAC-SHA256 over
t+.+ de ruwe body, met je geheim. - Vergelijk met
v1in constante tijd. - Weiger als
tmeer dan 5 minuten afwijkt van nu. Zo kan niemand een oude verzending opnieuw afspelen.
import crypto from "node:crypto";
// Gebruik de ruwe body, niet een opnieuw opgebouwd JSON-object.
export function verify(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return parts.v1?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}import hmac, hashlib, time
def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t = int(parts.get("t", 0))
if not t or abs(time.time() - t) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))<?php
function verify(string $rawBody, string $header, string $secret, int $tolerance = 300): bool {
$parts = [];
foreach (explode(",", $header) as $p) { [$k, $v] = array_pad(explode("=", $p, 2), 2, ""); $parts[$k] = $v; }
$t = (int)($parts["t"] ?? 0);
if (!$t || abs(time() - $t) > $tolerance) return false;
$expected = hash_hmac("sha256", $t . "." . $rawBody, $secret);
return hash_equals($expected, $parts["v1"] ?? "");
}
// $ok = verify(file_get_contents("php://input"), $_SERVER["HTTP_PROFACTUUR_SIGNATURE"], $secret);Antwoorden en nieuwe pogingenLink naar deze sectie
Antwoord binnen 10 seconden met een 2xx-statuscode. Alles anders telt als mislukt. Doe zware verwerking dus best na je antwoord.
| Poging | Wachttijd na vorige |
|---|---|
| 1 | meteen |
| 2 | 1 minuut |
| 3 | 5 minuten |
| 4 | 30 minuten |
| 5 | 2 uur |
| 6 | 6 uur |
| 7 | 24 uur |
Mislukt ook de laatste poging, dan blijft het endpoint actief en krijgt de eigenaar van de onderneming een melding. Je kan elke verzending later zelf opnieuw versturen.
Logboek en testenLink naar deze sectie
- Per endpoint zie je de laatste 100 verzendingen met tijd, gebeurtenis, statuscode, aantal pogingen en de payload.
- Met Opnieuw versturen stuur je een verzending nog eens, met een nieuw
id. - Met Testgebeurtenis sturen krijg je een gebeurtenis van het type
webhook.test.
Volgorde en dubbelsLink naar deze sectie
Gebeurtenissen kunnen in een andere volgorde of meer dan eens toekomen. Bewaar de id's die je al verwerkte en haal bij twijfel het object op via de API.
