Bjet24

Bjet24-webhooks: realtime opvolging van de status van elke postzending

In plaats van onze API te overstelpen met polling: hang er een webhook aan. Voor elke zending ontvangt u de overgangen (aangemaakt, afgegeven, in distributie, geleverd, ontvangstbewijs). Hier vindt u de structuur van de payloads, handtekeningverificatie en een klaar-om-te-plakken Next.js-handler.

11 mei 20267 min leestijd

Waarom een webhook (en geen polling)

Eens u de Bjet24 API hebt geïntegreerd voor geautomatiseerde zendingen, komt de volgende vraag snel: hoe weet u waar elk stuk staat zonder de API elke 30 seconden te bevragen?

Polling werkt, maar is duur (API-kost, latentie, te onderhouden code) en onnauwkeurig. Het juiste antwoord: webhooks. U geeft ons een HTTPS-URL, wij roepen u aan bij elke statusovergang met een ondertekende payload. Uw applicatie blijft passief en ontvangt de informatie binnen de seconde.

De gevolgde events

Bjet24 stelt voor postzendingen de volgende events beschikbaar:

  • mailing.created — de zending is via de API aangemaakt,
  • mailing.printed — de zending is gedrukt in het drukcentrum,
  • mailing.handed_over — de zending is aan bpost overgedragen,
  • mailing.in_delivery — de zending zit in de ronde van de postbode,
  • mailing.delivered — de zending is aan de bestemmeling afgegeven,
  • mailing.return_receipt — het ontvangstbewijs is getekend (enkel aangetekend),
  • mailing.failed — uitreikingsfalen (afwezigheidsbericht, weigering, retour).

Elk event bevat een mailing_id, een status, een tijdstempel in UTC ISO 8601 en een vrij metadata-object dat u bij aanmaak meegaf (bijvoorbeeld een intern invoice_id).

Een endpoint configureren

Aan Bjet24-zijde: u declareert een endpoint in de developer console of via de API. U koppelt eraan:

  • een publieke HTTPS-URL (minstens TLS 1.2),
  • een secret dat wij gebruiken om elk verzoek te ondertekenen,
  • de lijst van events die u wil ontvangen.

Aan de zijde van uw applicatie moet de handler:

  1. een JSON POST ontvangen,
  2. de handtekening X-Bjet24-Signature verifiëren,
  3. snel 2xx antwoorden (binnen 5 s),
  4. het event idempotent verwerken (het event_id is uniek).

Payloadstructuur

{
  "event_id": "evt_01HYZ...",
  "event_type": "mailing.delivered",
  "occurred_at": "2026-05-11T08:42:13Z",
  "data": {
    "mailing_id": "ml_01HYX...",
    "status": "delivered",
    "tracking_number": "ZA123456789BE",
    "recipient": {
      "name": "ACME BVBA",
      "address_line_1": "Wetstraat 16",
      "postal_code": "1000",
      "city": "Brussel"
    },
    "metadata": {
      "invoice_id": "INV-2026-0421"
    }
  }
}

Het veld metadata is een willekeurig JSON-object meegegeven bij de aanmaak van de zending. Gebruik het om de brug te slaan met uw interne identifiers zonder een correspondentietabel te moeten bijhouden.

De HMAC-handtekening

Elk verzoek bevat een header X-Bjet24-Signature met formaat t=TIMESTAMP,v1=SIGNATURE. De handtekening is een HMAC-SHA256 berekend op de string TIMESTAMP.RAW_BODY met uw secret.

Aanbevolen verificatie:

  • verwerp verzoeken waarvan de timestamp meer dan 5 minuten afwijkt van de serverklok (bescherming tegen replays),
  • vergelijk de handtekeningen in constante tijd (timingSafeEqual).

Voorbeeld: handler Next.js (App Router)

// app/api/webhooks/bjet24/route.ts
import { createHmac, timingSafeEqual } from "node:crypto"
import { NextRequest } from "next/server"

const SECRET = process.env.BJET24_WEBHOOK_SECRET!

export async function POST(req: NextRequest) {
  const raw = await req.text()
  const header = req.headers.get("x-bjet24-signature") ?? ""

  const parts = Object.fromEntries(
    header.split(",").map((kv) => kv.split("=")),
  )
  const ts = parts.t
  const sig = parts.v1
  if (!ts || !sig) return new Response("missing signature", { status: 400 })

  const tsNum = Number(ts)
  if (Math.abs(Date.now() / 1000 - tsNum) > 300) {
    return new Response("stale timestamp", { status: 400 })
  }

  const expected = createHmac("sha256", SECRET)
    .update(`${ts}.${raw}`)
    .digest("hex")

  const a = Buffer.from(expected, "hex")
  const b = Buffer.from(sig, "hex")
  if (a.length !== b.length || !timingSafeEqual(a, b)) {
    return new Response("invalid signature", { status: 401 })
  }

  const event = JSON.parse(raw) as {
    event_id: string
    event_type: string
    data: { mailing_id: string; status: string; metadata?: Record<string, string> }
  }

  // Idempotentie: negeer indien event_id reeds verwerkt.
  // Daarna schakel op event.event_type.
  if (event.event_type === "mailing.delivered") {
    // ...werk uw factuur / klantendossier bij...
  }

  return new Response("ok", { status: 200 })
}

Retry-beleid

Als uw endpoint 5xx antwoordt of niet antwoordt, proberen wij het opnieuw met exponentiële backoff gedurende 24 uur (doorgaans 6 tot 8 retries). Zolang u 2xx antwoordt, beschouwen wij het event als geleverd.

Praktisch gevolg: uw handler moet idempotent zijn. Hetzelfde event_id kan meermaals binnenkomen (bijvoorbeeld wanneer u 2xx antwoordde maar de verbinding net daarvoor werd verbroken). Bewaar de verwerkte event_id-waarden en negeer duplicaten.

Drie goede gewoontes

  • Log alles. Bewaar de ruwe payloads minstens enkele dagen. Onbetaalbaar om een onverwachte status te debuggen.
  • Ontkoppel de verwerking. Antwoord onmiddellijk 200, zet daarna het echte werk in een queue (BullMQ, SQS, enz.). U vermijdt opeenstapeling van retries.
  • Versioneer uw handler. Wanneer u de businesslogica wijzigt, deploy de nieuwe handler op een geversionneerde URL en migreer progressief.

Samengevat

Een Bjet24-webhook aansluiten duurt 30 minuten: een ondertekend endpoint, een HMAC-verificatie, een idempotente verwerking. In ruil krijgt u realtime zicht op al uw postzendingen in België — zonder API-schuld en zonder te onderhouden cron. Voor een kmo die werkt met professionele bulkverzendingen via bpost, is dit de eenvoudigste manier om "de post is vertrokken" om te zetten in bruikbare informatie in uw CRM of ERP.

Veelgestelde vragen

Hoe verifieer ik de handtekening van een Bjet24-webhook?

Elk verzoek van Bjet24 bevat een X-Bjet24-Signature-header met formaat t=TIMESTAMP,v1=SIGNATURE. Bereken een HMAC-SHA256 op de string TIMESTAMP.RAW_BODY met uw secret en vergelijk het resultaat in constante tijd via timingSafeEqual. Verwerp verzoeken waarvan de timestamp meer dan 5 minuten afwijkt van uw serverklok om replay-aanvallen te voorkomen.

Wat gebeurt er als mijn webhook-endpoint niet antwoordt?

Als uw endpoint een 5xx-code retourneert of niet antwoordt binnen de toegestane tijd, probeert Bjet24 het automatisch opnieuw met exponentiële backoff gedurende 24 uur, doorgaans 6 tot 8 pogingen. Zodra uw endpoint een 2xx-code retourneert, wordt het event als geleverd beschouwd en stoppen de retries. Het is aanbevolen om onmiddellijk 200 te antwoorden en de verwerking aan een asynchrone queue te delegeren.

Hoe voorkom ik dat hetzelfde webhook-event twee keer wordt verwerkt?

Elk event heeft een unieke event_id. Sla de al verwerkte identifiers op in een database of Redis-cache en negeer stilzwijgend events waarvan de identifier al aanwezig is. Deze idempotentie is onmisbaar omdat hetzelfde event meermaals kan worden verzonden bij verbindingsverlies tussen de levering en uw 2xx-antwoord.

Welke postale statusevents kan ik ontvangen via webhooks?

De webhooks dekken alle belangrijke overgangen van een postzending: aanmaak via de API (mailing.created), drukken (mailing.printed), overdracht aan bpost (mailing.handed_over), bezorgronde (mailing.in_delivery), levering aan de bestemmeling (mailing.delivered), ondertekening van het ontvangstbewijs (mailing.return_receipt) en uitreikingsfalen (mailing.failed). U kiest de events die u wilt ontvangen bij de declaratie van het endpoint.

Kan ik een webhook-endpoint lokaal testen vóór de productie-uitrol?

Ja. Gebruik een tool zoals ngrok of Cloudflare Tunnel om uw lokale server tijdelijk via een publieke HTTPS-URL bloot te stellen. Declareer die URL in de developer console, verstuur testberichten en observeer de ontvangen payloads. Op die manier kunt u de handtekeningverificatie en eventverwerking valideren zonder te deployen naar productie.

Klaar om post te versturen?

Verzend uw brief of aangetekende zending in enkele minuten, zonder afdrukken of postkantoor.

Hoe het werkt

Gerelateerde artikelen

Reacties (0)

Reacties laden…

Een reactie achterlaten

Uw reactie wordt gepubliceerd na goedkeuring door een moderator.