Webhooks
To ensure the webhook is authentic and sent by B2Brouter, verify the signature included in the X-B2Brouter-Signature header.
Here is how you can verify the signature on your server:
-
Extract the Header Information: The
X-B2Brouter-Signatureheader contains two components:t: The UNIX timestamp when the payload was signed.s: The HMAC-SHA256 signature. Example header:
t=1732530076,s=9f117925ea533a2ea74b19699e03ab5de5664b4ff021d3d01eaff8868ed29e4d -
Recreate the Payload: Combine the received timestamp (
t) and the raw JSON payload (data) using a period (.):payload = "#{timestamp}.#{data}" -
Compute the HMAC-SHA256 Signature: Use the shared
signature_keyand the payload to compute the signature:computed_signature = HMAC-SHA256(signature_key, payload) -
Compare Signatures: Compare the
computed_signaturewith thesvalue from the header. If they match, the webhook is valid.
Examples
Section titled “Examples”- PHP:
$headers = getallheaders();$header = $headers['X-B2Brouter-Signature'];
preg_match('/t=([^,]+),s=(.+)/', $header, $matches);
$timestamp = $matches[1];$signatureHash = $matches[2];
$recalculatedHash = hash_hmac( 'sha256', $timestamp . '.' . file_get_contents('php://input'), 'your_webhook_secret');
$isValid = hash_equals($signatureHash, $recalculatedHash);Events
Section titled “Events”ledger.state_change— fired when a ledger (DGFiP Flux 10, Verifactu) transitions to a new state. See Submit a Flux-10 e-reporting file for the payload shape and the list of states.
Deliveries and retries
Section titled “Deliveries and retries”Each event creates a delivery: B2Brouter sends a POST with the signed payload to the webhook URL.
- A
2xxresponse completes the delivery. - If your server answers
5xxor429, does not answer in time, or cannot be reached (DNS, connection, TLS), B2Brouter tries the delivery again later. The interval between attempts grows with each attempt, and retries continue for about one week. This period can change. - Any other
4xxresponse is final: the delivery is not tried again.
Answer 2xx as soon as you receive the webhook, and process the event afterwards. A slow answer counts as a temporary error, and the delivery is repeated.
Delivery headers
Section titled “Delivery headers”In addition to X-B2Brouter-Signature, each attempt carries these headers:
X-B2Brouter-Delivery-Id: the identifier of the delivery. It is the same on all attempts of one delivery.X-B2Brouter-Delivery-Attempt: the attempt number, starting at1.
The same delivery can arrive more than once. Use X-B2Brouter-Delivery-Id to discard duplicates.
Deliveries do not always arrive in order: while one delivery waits for its retry, later events are still delivered. A webhook tells you that an object has changed. Before you act, read its current state with the API.
Webhooks log
Section titled “Webhooks log”In the Webhooks log, each delivery shows its state and the number of attempts:
- Retrying: the delivery failed and more attempts are scheduled.
- Gave up: all attempts are spent.
- Failed: your server answered with a final error (
4xx). - Delivered: the delivery is complete.
- Cancelled: the webhook was disabled or deleted before the delivery finished.
To repeat a delivery, open it in the log and use Resend. A resend carries the number of the last attempt in X-B2Brouter-Delivery-Attempt. The log keeps deliveries for 15 days.