Bjet24

API v1 · OpenAPI 3.1 · stabiel

API-referentie

Verstuur post vanuit je CRM, ERP of backoffice. Eén base-URL, authenticatie met Bearer-key, facturatie via je wallet — geen kaartbetaling per call.

Overzicht

Een stateless REST API, JSON in/out, versiebeheerd. Alle routes hebben prefix /v1.

  • Base-URLhttps://bjet24.com/api
  • Versiev1 · OpenAPI 3.1
  • Formaatapplication/json
  • AuthBearer / X-Api-Key

Authenticatie

Elke aanvraag moet een geldige API-key bevatten in de Authorization-header (Bearer-formaat) of in de X-Api-Key-header. Keys hebben het formaat bjk_<id>_<secret>.

curl https://bjet24.com/api/v1/mails \
  -H "Authorization: Bearer bjk_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Beschikbare scopes

  • readlezen van verzendingen, offertes, lijsten
  • sendverzendingen aanmaken (debiteert wallet)
  • webhookswebhooks aanmaken/verwijderen
  • addressesHet adresboek beheren (afzenders en ontvangers).

Maak en herroep je keys vanaf /account/api-keys.

Foutformaat

Alle fouten retourneren een 4xx of 5xx HTTP-status en een JSON-body met code (machine) en message (mens). Validatiefouten bevatten een issues-array.

application/json
{
  "code": "VALIDATION_ERROR",
  "message": "Invalid request body",
  "issues": [
    { "path": ["pages"], "message": "Number must be greater than or equal to 1" }
  ]
}
  • VALIDATION_ERRORBody voldoet niet aan het schema. Zie issues.
  • UNAUTHORIZEDAPI-key ontbreekt of is ongeldig.
  • FORBIDDENKey heeft niet de vereiste scope voor deze route.
  • NOT_FOUNDResource niet gevonden of behoort niet tot je organisatie.
  • INSUFFICIENT_FUNDSWallet-saldo onvoldoende om de verzendkost te dekken.
  • PRICING_UNAVAILABLEPricing niet geconfigureerd voor de gevraagde zone/service. Contacteer support.

Idempotentie

Om duplicaten bij netwerk-retries te vermijden, geef een unieke externalId mee (typisch je CRM-id) bij POST /v1/mails. Herhaalde aanvragen met dezelfde externalId retourneren de bestaande verzending — geen nieuwe debiet.

Hoe werkt het

Bij de eerste succesvolle aanmaak wordt het paar (organisatie, externalId) vergrendeld. Elke volgende POST met dezelfde externalId retourneert 200 met de oorspronkelijke mailJobId — zelfs als de payload verschilt.

Ratebeperking

Limieten gelden per API-key. Aanvragen boven het quotum krijgen 429 met een Retry-After-header.

  • Lezen (GET)120 / min
  • Schrijven (POST, DELETE)60 / min
  • Max burst30

Offerte ophalen

POST/v1/quoteVereiste scope: read

Berekent de totale prijs voor een service / zone / aantal pagina's. Geen debiet. Handig om het tarief client-side te tonen vóór verzending.

Body van de aanvraag

  • zonestringverplicht
    NATIONALINTERNATIONAL

    Verzendzone. NATIONAL = België, INTERNATIONAL = buiten België.

  • serviceTypestringverplicht
    standardpriorregistered

    Type postservice. registered voegt verzendbewijs en tracking toe.

  • pagesintegerverplicht

    Totaal aantal afgedrukte pagina's (1 tot 2000).

  • colorbooleanoptioneelstandaard false

    Kleurendruk. Hoger tarief.

  • acknowledgmentReceiptbooleanoptioneelstandaard false

    Ontvangstbewijs (enkel registered). Hoger tarief.

  • recipientCountintegeroptioneelstandaard 1

    Aantal afzonderlijke ontvangers (1 tot 100). Vermenigvuldigt de eenheidsprijs.

Responses

  • 200Offerte berekend. Totaal inclusief btw indien van toepassing.
  • 400Ongeldige body. Zie issues.
  • 401API-key ontbreekt of is ongeldig.
curl -X POST https://bjet24.com/api/v1/quote \
  -H "Authorization: Bearer $BJET24_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "zone": "NATIONAL",
    "serviceType": "registered",
    "pages": 3,
    "color": false,
    "acknowledgmentReceipt": false,
    "recipientCount": 1
  }'

Presigned upload-URL

POST/v1/uploadsVereiste scope: send

Retourneert een PUT-URL voor S3, 10 minuten geldig. Upload je PDF of afbeelding, gebruik dan de geretourneerde key als s3Key in POST /v1/mails. Uploads gaan rechtstreeks naar S3 — geen grote payloads via onze API.

Body van de aanvraag

  • filenamestringverplicht

    Originele bestandsnaam. Gebruikt voor logs en facturatie.

  • mimeTypestringverplicht
    application/pdfimage/jpegimage/pngimage/heicimage/heif

    MIME-type. PDF aanbevolen voor post; afbeeldingen worden automatisch geconverteerd.

  • sizeBytesintegerverplicht

    Grootte in bytes. Max 20 MB.

Responses

  • 200Presigned URL geretourneerd. Upload binnen 10 minuten via PUT.
  • 400Ongeldige body. Zie issues.
  • 401API-key ontbreekt of is ongeldig.
curl -X POST https://bjet24.com/api/v1/uploads \
  -H "Authorization: Bearer $BJET24_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "contract.pdf",
    "mimeType": "application/pdf",
    "sizeBytes": 124532
  }'

Verzending aanmaken en versturen

POST/v1/mailsVereiste scope: send

Plaatst de verzending in de wachtrij en debiteert direct je wallet. Met dryRun=true wordt gevalideerd en getarifeerd zonder debiet of aanmaak. Geef externalId mee voor idempotentie en webhookUrl voor een per-verzending callback.

Body van de aanvraag

  • zonestringverplicht
    NATIONALINTERNATIONAL

    Verzendzone. NATIONAL = België, INTERNATIONAL = buiten België.

  • serviceTypestringverplicht
    standardpriorregistered

    Type postservice. registered voegt verzendbewijs en tracking toe.

  • pagesintegerverplicht

    Totaal aantal afgedrukte pagina's (1 tot 2000).

  • colorbooleanoptioneelstandaard false

    Kleurendruk. Hoger tarief.

  • acknowledgmentReceiptbooleanoptioneelstandaard false

    Ontvangstbewijs (enkel registered). Hoger tarief.

  • scheduledDropAtstring (ISO 8601)optioneel

    Geplande depositodatum/-tijd (ISO 8601). Indien afwezig, volgende cutoff.

  • recipientsRecipient[]verplicht

    Lijst van ontvangers (1 tot 100). Elk krijgt een afgedrukt exemplaar.

  • senderSenderoptioneel

    Afzenderadres op de envelop. Indien afwezig, standaardadres van je account.

  • filesFile[]verplicht

    Bestanden om af te drukken (1 tot 20). Worden in volgorde samengevoegd. s3Key komt van POST /v1/uploads.

  • externalIdstringoptioneel

    Caller-id (bv. CRM-id). Garandeert idempotentie.

  • webhookUrlstring (uri)optioneel

    Webhook-URL specifiek voor deze verzending. Overschrijft globale config.

  • dryRunbooleanoptioneelstandaard false

    Indien true, valideer en tarifeer zonder debiet of opslag. Antwoord identiek maar mailJobId is null.

Responses

  • 201Verzending aangemaakt en in wachtrij. Wallet gedebiteerd.
  • 200Idempotentie-hit — verzending bestond al met dezelfde externalId.
  • 400Ongeldige body. Zie issues.
  • 402Wallet-saldo onvoldoende. Laad op en probeer opnieuw.
  • 503Pricing niet geconfigureerd voor zone/service.
curl -X POST https://bjet24.com/api/v1/mails \
  -H "Authorization: Bearer $BJET24_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "zone": "NATIONAL",
    "serviceType": "registered",
    "pages": 3,
    "color": false,
    "recipients": [{
      "name": "Jean Dupont",
      "line1": "Rue de la Loi 16",
      "zip": "1000",
      "city": "Brussels",
      "country": "BE"
    }],
    "files": [{
      "s3Key": "uploads/2026-05-19/8af9...c12.pdf",
      "filename": "contract.pdf",
      "mimeType": "application/pdf",
      "sizeBytes": 124532
    }],
    "externalId": "crm-contract-7281"
  }'

Verzendingen oplijsten

GET/v1/mailsVereiste scope: read

Retourneert je verzendingen, nieuwste eerst. Cursor-gepagineerd.

Queryparameters

  • statusstringoptioneel

    Filter op status (queued, printed, posted, delivered, failed).

  • externalIdstringoptioneel

    Filter op exacte externalId.

  • limitintegeroptioneelstandaard 20

    Aantal resultaten per pagina (1 tot 100).

  • cursorstringoptioneel

    Paginatie-cursor uit het vorige antwoord.

Responses

  • 200Gepagineerde lijst van verzendingen.
cURL
curl "https://bjet24.com/api/v1/mails?status=queued&limit=20" \
  -H "Authorization: Bearer $BJET24_KEY"

Eén verzending ophalen

GET/v1/mails/{id}Vereiste scope: read

Retourneert het volledige detail: status, ontvangers, bestanden, bedragen, timestamps.

Padparameters

  • idstringverplicht

    Id van de verzending (mj_…).

Responses

  • 200Detail van de verzending.
  • 404Resource niet gevonden.
cURL
curl https://bjet24.com/api/v1/mails/mj_01HZX5K8... \
  -H "Authorization: Bearer $BJET24_KEY"

Levenscyclus simuleren (sandbox)

POST/v1/mails/{id}/simulateVereiste scope: send

Alleen testmodus. Laat een sandbox-verzending door haar levenscyclus lopen en activeert de bijbehorende `test`-webhook. Zonder `to` gaat de verzending één stap vooruit (queued → printed → posted → delivered); met `to` springt ze rechtstreeks naar die status — bv. {"to":"failed"} om foutafhandeling te testen. Sandbox-verzendingen evolueren ook vanzelf: dit endpoint dient voor deterministisch testen op aanvraag. Geweigerd (403) met een live-sleutel.

Padparameters

  • idstringverplicht

    Id van de verzending (mj_…).

Body van de aanvraag

  • tostringoptioneel
    printedposteddeliveredfailed

    Doelstatus. Weggelaten: één stap vooruit. Waarden: printed, posted, delivered, failed. Een directe sprong activeert alleen de webhook van de bereikte status.

Responses

  • 200Overgang toegepast — retourneert de vorige en de nieuwe status.
  • 400Ongeldige body. Zie issues.
  • 403Live-inloggegevens — simulatie is alleen voor testmodus.
  • 404Resource niet gevonden.
  • 409Overgang niet mogelijk (al in eindstatus of onbereikbaar doel).
cURL
# Test mode only — advance the sandbox mail one step
curl -X POST https://bjet24.com/api/v1/mails/mj_01HZX5K8.../simulate \
  -H "Authorization: Bearer $BJET24_TEST_KEY"

# …or jump straight to a status (e.g. test failure handling)
curl -X POST https://bjet24.com/api/v1/mails/mj_01HZX5K8.../simulate \
  -H "Authorization: Bearer $BJET24_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"failed"}'

Adressen weergeven

GET/v1/addressesVereiste scope: addresses

Geeft de opgeslagen adresboekvermeldingen terug — afzenders en ontvangers. Filterbaar op type en zoektekst.

Queryparameters

  • kindstringoptioneel
    SENDERRECIPIENT

    Filter op adrestype.

  • qstringoptioneel

    Zoektekst op naam, stad, postcode of label.

  • limitintegeroptioneelstandaard 100

    Maximaal aantal teruggegeven adressen (1–200).

Responses

  • 200De lijst met adresboekvermeldingen.
  • 401API-key ontbreekt of is ongeldig.
cURL
curl "https://bjet24.com/api/v1/addresses?kind=RECIPIENT&limit=50" \
  -H "Authorization: Bearer $BJET24_KEY"

Een adres aanmaken

POST/v1/addressesVereiste scope: addresses

Slaat een adres op in het boek — bijvoorbeeld om uw CRM-contacten te synchroniseren.

Body van de aanvraag

  • kindstringverplicht
    SENDERRECIPIENT

    Adrestype: afzender (SENDER) of ontvanger (RECIPIENT).

  • namestringverplicht

    Naam van de ontvanger of afzender.

  • line1stringverplicht

    Eerste adresregel (straat en nummer).

  • line2stringoptioneel

    Optionele adrestoevoeging (bus, verdieping…).

  • zipstringverplicht

    Postcode.

  • citystringverplicht

    Stad.

  • countrystringverplicht

    ISO 3166-1 alpha-2-landcode (bv. BE).

  • labelstringoptioneel

    Optioneel intern label, bv. Hoofdkantoor of Klant X.

  • isDefaultbooleanoptioneelstandaard false

    Stelt dit adres in als standaardadres voor zijn type.

Responses

  • 201Het adres, in zijn publieke vorm.
  • 400Ongeldige body. Zie issues.
curl -X POST https://bjet24.com/api/v1/addresses \
  -H "Authorization: Bearer $BJET24_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "RECIPIENT",
    "name": "Jean Dupont",
    "line1": "Rue de la Loi 16",
    "zip": "1000",
    "city": "Brussels",
    "country": "BE",
    "label": "Client 7281"
  }'

Een adres ophalen

GET/v1/addresses/{id}Vereiste scope: addresses

Geeft één adresboekvermelding terug.

Padparameters

  • idstringverplicht

    Adres-identificatie.

Responses

  • 200Het adres, in zijn publieke vorm.
  • 404Resource niet gevonden.
cURL
curl https://bjet24.com/api/v1/addresses/adr_01HZX5K8... \
  -H "Authorization: Bearer $BJET24_KEY"

Een adres bijwerken

PATCH/v1/addresses/{id}Vereiste scope: addresses

Werkt de opgegeven velden van een bestaand adres bij. Weggelaten velden blijven ongewijzigd.

Padparameters

  • idstringverplicht

    Adres-identificatie.

Body van de aanvraag

  • kindstringoptioneel
    SENDERRECIPIENT

    Adrestype: afzender (SENDER) of ontvanger (RECIPIENT).

  • namestringoptioneel

    Naam van de ontvanger of afzender.

  • line1stringoptioneel

    Eerste adresregel (straat en nummer).

  • line2stringoptioneel

    Optionele adrestoevoeging (bus, verdieping…).

  • zipstringoptioneel

    Postcode.

  • citystringoptioneel

    Stad.

  • countrystringoptioneel

    ISO 3166-1 alpha-2-landcode (bv. BE).

  • labelstringoptioneel

    Optioneel intern label, bv. Hoofdkantoor of Klant X.

  • isDefaultbooleanoptioneel

    Stelt dit adres in als standaardadres voor zijn type.

Responses

  • 200Het adres, in zijn publieke vorm.
  • 400Ongeldige body. Zie issues.
  • 404Resource niet gevonden.
cURL
curl -X PATCH https://bjet24.com/api/v1/addresses/adr_01HZX5K8... \
  -H "Authorization: Bearer $BJET24_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "city": "Bruxelles", "isDefault": true }'

Een adres verwijderen

DELETE/v1/addresses/{id}Vereiste scope: addresses

Verwijdert een adres definitief uit het boek.

Padparameters

  • idstringverplicht

    Adres-identificatie.

Responses

  • 200Adres verwijderd.
  • 404Resource niet gevonden.
cURL
curl -X DELETE https://bjet24.com/api/v1/addresses/adr_01HZX5K8... \
  -H "Authorization: Bearer $BJET24_KEY"

Je webhooks oplijsten

GET/v1/webhooksVereiste scope: read

Retourneert alle actieve webhook-endpoints op je account.

Responses

  • 200Lijst van webhooks (zonder secret).
cURL
curl https://bjet24.com/api/v1/webhooks \
  -H "Authorization: Bearer $BJET24_KEY"

Webhook registreren

POST/v1/webhooksVereiste scope: webhooks

Maakt een webhook-endpoint aan. Het signing secret wordt SLECHTS EENMAAL geretourneerd — bewaar het direct, het kan niet opnieuw worden opgehaald.

Body van de aanvraag

  • urlstring (uri)verplicht

    HTTPS-URL waar events worden gepost.

  • eventsstring[]verplicht
    MAIL_QUEUEDMAIL_PRINTEDMAIL_POSTEDMAIL_DELIVEREDMAIL_FAILED

    Lijst van events die je wil ontvangen. Minstens één vereist.

Responses

  • 201Webhook aangemaakt. Bewaar het geretourneerde secret.
  • 400Ongeldige body. Zie issues.
curl -X POST https://bjet24.com/api/v1/webhooks \
  -H "Authorization: Bearer $BJET24_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/webhooks/bjet24",
    "events": ["MAIL_QUEUED", "MAIL_POSTED", "MAIL_DELIVERED", "MAIL_FAILED"]
  }'

Webhook verwijderen

DELETE/v1/webhooks/{id}Vereiste scope: webhooks

Schakelt het endpoint onmiddellijk uit. Events worden niet meer afgeleverd.

Padparameters

  • idstringverplicht

    Id van de webhook (wh_…).

Responses

  • 200Webhook verwijderd.
  • 404Resource niet gevonden.
cURL
curl -X DELETE https://bjet24.com/api/v1/webhooks/wh_01HZX5K8... \
  -H "Authorization: Bearer $BJET24_KEY"

Webhook-events

Vijf events dekken de levenscyclus van een verzending. Elke aflevering bevat de JSON-payload, de X-Bjet24-Event-header en de handtekening.

  • MAIL_QUEUEDVerzending in wachtrij na walletdebet.
  • MAIL_PRINTEDAfgedrukt in het atelier.
  • MAIL_POSTEDAfgegeven op het postkantoor.
  • MAIL_DELIVEREDBezorgd (enkel registered).
  • MAIL_FAILEDDruk-, depot- of annulatiefout.

Voorbeeld payload

application/json
{
  "event": "MAIL_POSTED",
  "mailJobId": "mj_01HZX5K8...",
  "externalId": "crm-contract-7281",
  "status": "posted",
  "postedAt": "2026-05-19T16:42:11.000Z"
}

Handtekening & verificatie

Elke webhook-aflevering wordt ondertekend met HMAC-SHA256 met het secret dat bij aanmaak werd geretourneerd. Verifieer de handtekening vóór je de payload verwerkt.

Handtekening-header

X-Bjet24-Signature: t=<ts>,v1=<hex>

De timestamp is in Unix-seconden. De handtekening is berekend op <ts>.<rawBody> met je webhook-secret.
Node.js
import crypto from 'node:crypto'

export function verifyBjet24(req, secret) {
  const header = req.headers['x-bjet24-signature']
  // header looks like: t=1714940000,v1=<hmac-sha256-hex>
  const [tPart, sPart] = header.split(',')
  const ts = tPart.split('=')[1]
  const sig = sPart.split('=')[1]

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${ts}.${req.rawBody}`)
    .digest('hex')

  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    throw new Error('Bad signature')
  }
  if (Date.now() / 1000 - Number(ts) > 300) {
    throw new Error('Replay')
  }
}

Replay-bescherming

Weiger afleveringen waarvan de timestamp ouder is dan 5 minuten. Combineer geldige handtekening + recente timestamp om replay-aanvallen te blokkeren.

Een externe applicatie verbinden (OAuth2)

Wanneer een applicatie (een CRM, een zakelijke tool) namens meerdere Bjet24-gebruikers moet handelen — elk met hun eigen portefeuille — gebruik dan OAuth2 in plaats van een API-sleutel. De gebruiker verbindt zijn account met één klik, zonder een sleutel te kopiëren en plakken.

API-sleutel of OAuth2?

Een API-sleutel volstaat als u alleen post verstuurt voor uw eigen account. OAuth2 is vereist wanneer uw applicatie meerdere afzonderlijke Bjet24-klanten bedient: elke gebruiker verleent toegang en zijn eigen portefeuille wordt belast.

Uw applicatie registreren

Een Bjet24-beheerder registreert uw applicatie en bezorgt u een client_id, een client_secret en de toegestane redirect_uri-waarden.

De Authorization Code + PKCE-flow

1. Stuur de gebruiker naar het toestemmingsscherm.

GET /oauth/authorize
https://bjet24.com/fr/oauth/authorize
  ?response_type=code
  &client_id=bjc_xxxxxxxxxxxxxxxxxxxxxxxx
  &redirect_uri=https://your-app.example.com/callback
  &scope=send%20read%20wallet
  &state=<opaque-random>
  &code_challenge=<base64url(sha256(code_verifier))>
  &code_challenge_method=S256

2. Wissel de ontvangen code in voor een tokenpaar.

POST /api/oauth/token
curl -X POST https://bjet24.com/api/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d client_id=bjc_xxxxxxxxxxxxxxxxxxxxxxxx \
  -d client_secret=$BJET24_CLIENT_SECRET \
  -d code=$AUTH_CODE \
  -d redirect_uri=https://your-app.example.com/callback \
  -d code_verifier=$PKCE_VERIFIER
200 OK
{
  "access_token": "bja_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "bjr_...",
  "scope": "send read wallet"
}

3. Roep de API aan met het access token als Bearer-token.

cURL
curl https://bjet24.com/api/v1/wallet \
  -H "Authorization: Bearer bja_..."

4. Vernieuw het verlopen access token met het refresh token.

POST /api/oauth/token
curl -X POST https://bjet24.com/api/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=refresh_token \
  -d client_id=bjc_xxxxxxxxxxxxxxxxxxxxxxxx \
  -d client_secret=$BJET24_CLIENT_SECRET \
  -d refresh_token=$REFRESH_TOKEN

Levensduur en intrekking

Een access token leeft 1 u, een refresh token 60 dagen en roteert bij elk gebruik. De gebruiker kan de toegang op elk moment intrekken vanuit zijn Bjet24-account; uw applicatie kan ook POST /api/oauth/revoke aanroepen.

OAuth-scopes

De scopes die bij autorisatie worden gevraagd, bepalen wat uw applicatie mag doen.

  • sendverzendingen aanmaken (debiteert wallet)
  • readlezen van verzendingen, offertes, lijsten
  • webhookswebhooks aanmaken/verwijderen
  • walletHet portefeuillesaldo van de gebruiker raadplegen.
  • addressesHet adresboek beheren (afzenders en ontvangers).