Envelopify API

Verstuur echte brieven met postzegels vanuit je eigen software. Eén aanroep per brief. Wij printen, plakken echte postzegels en posten via bpost. bpost bezorgt binnen 2 tot 3 werkdagen na afgifte. Privacy: pdf’s en ontvangersgegevens worden standaard 30 dagen na posten gewist (klantkeuze 7 tot 90 dagen, dagelijkse opruiming). Daarna blijft de status beschikbaar, maar zijn ontvangersvelden leeg en geeft de pdf-download 404. Invulvelden worden alleen verwerkt in de brief, niet nog eens als losse gegevens bewaard.

Basis-URLhttps://envelopify.lovable.app/api/v1

Bouw het met AI

Geef deze link aan je AI-assistent en laat hem de koppeling bouwen. De volledige documentatie staat als gewone tekst klaar (in het Engels).

Lees de documentatie van de Envelopify API op https://envelopify.lovable.app/llms-full.txt. Bouw in mijn app een koppeling die automatisch een brief verstuurt wanneer [gebeurtenis, bv. er een factuur aangemaakt wordt]. Roep de API enkel aan vanuit een serverfunctie, bewaar de API-sleutel als geheim (secret) en nooit in de browser. Begin met mijn testsleutel (test_...). Toon fouten uit de API in gewone taal aan de gebruiker en bewaar het id en de status van elke brief.

Ook beschikbaar: openapi.json, developers.md en llms.txt.

In 5 minuten starten

  1. Sleutel aanmaken. Maak een gratis account, ga naar API-sleutels en kies Testsleutel maken. Vervang in de voorbeelden test_JOUW_SLEUTEL door je sleutel.
  2. Testbrief sturen. De aanroep bij Brief versturen gebruikt onze voorbeeld-pdf en werkt zoals hij er staat. Er wordt niets geprint of aangerekend.
  3. Status opvragen. Neem het id uit het antwoord en vraag de brief op met GET /api/v1/letters/{id}. Met /pdf erachter zie je de pdf zoals wij hem printen.
  4. Statusmeldingen instellen. Registreer een https-link met POST /api/v1/webhooks, dan laten we je weten wanneer je brief geprint en gepost is.
  5. Live gaan. Laad tegoed op in het portaal en klik bij je sleutel op Zet live. Nieuwe sleutels starten altijd in testmodus. Je sleutel zelf verandert niet.

Maak een gratis account om je sleutel te maken.

Inloggen met sleutel

Stuur je sleutel mee in elke aanvraag via de header Authorization: Bearer <sleutel>. Nieuwe sleutels starten in testmodus; je zet ze live in het portaal (API-sleutels, Zet live). De modus hangt aan de sleutel, niet aan het begin van de tekst. Met een sleutel in testmodus worden brieven nooit verstuurd of aangerekend; ze krijgen status received. We tonen een sleutel maar één keer. Bewaar hem als geheim op je server en nooit in browsercode. Een ontbrekende, ongeldige of ingetrokken sleutel geeft 401 unauthorized.

Gebeurtenis in wachtrijPOST/api/v1/flow-events

Voor een actieve herinneringsflow met een bewaarde ontvanger. Maakt een eenmalige reeks, niet onmiddellijk een brief. De dagelijkse verwerking gebruikt dezelfde prijs- en stopcontrole. Bij onvoldoende tegoed blijft de gebeurtenis in de wachtrij. event_key voorkomt dubbels per flow en sleutelmodus. Dagmaximum en wachttijd per ontvanger gelden ook in testmodus; testreeksen versturen en kosten niets en worden alleen door een beheerder getest.

VeldTypeVerplichtUitleg
flow_idtekstjaId van actieve flow.
contact_idtekstjaId van eigen ontvanger.
event_keytekstjaUnieke gebeurtenisreferentie, 1 tot 120 tekens.
order_centsgetalBedrag voor flowvoorwaarde, standaard 0.
variablesobjectSjabloonvelden, enkel nodige gegevens.

Voorbeeldverzoek

curl -X POST https://envelopify.lovable.app/api/v1/flow-events \
  -H "Authorization: Bearer test_JOUW_SLEUTEL" \
  -H "Content-Type: application/json" \
  -d '{
  "flow_id": "b1d1a7f7-3db2-43df-a896-bc9dc10c6029",
  "contact_id": "b1d1a7f7-3db2-43df-a896-bc9dc10c6029",
  "event_key": "herinnering-104",
  "variables": {}
}'
202 · Voorbeeldantwoord
{
  "status": "queued",
  "test": true
}

Brief versturenPOST/api/v1/letters

Maakt een brief aan. Geef precies één bron: een pdf (pdf_base64 of pdf_url) of een sjabloon (template_id of template_code) met variables. Bij een pdf geldt je accountkeuze: gratis adresblad vooraan of een wit adresvak op de eerste pagina met options.address_on_first_page. Klein gaat tot 50 g, middel tot 100 g en groot tot 350 g. Middel en groot zijn alleen beschikbaar met een bevestigde, geactiveerde meerprijs. Het adresblad telt mee voor het gewicht, niet voor de basisprijs. Antwoord 201 met id, status, prijs met opsplitsing (price_breakdown), aantal vellen (adresblad inbegrepen), uiterste postdatum volgens de snelheid en test. Met een testsleutel is de status received en post_date leeg. Een geweigerde brief geeft 422 met een foutcode en het letter_id.

VeldTypeVerplichtUitleg
options.address_on_first_pageja/neeVoor opgeladen pdf: wit vast adresvak op de eerste pagina, zonder extra adresblad. Bedekte inhoud wordt wit. Zonder keuze geldt je accountstandaard (aanvankelijk adresblad).
options.correctionsobjectPdf-correcties: region {left,top,width,height} in mm op A4, window left/right/both, first_page, white_margins, flatten en a4_portrait. Zonder dit object geldt de bewaarde accountregel. Met region wordt het oude adresvak wit gemaakt. Je origineel blijft bewaard.
recipient.languagetekstOptioneel: nl, fr, en of de. Kies de bewaarde sjabloonvariant voor deze taal; anders de basistekst. Zonder taal kiezen we volgens de Belgische postcode.
recipient.companytekstOptioneel. Bedrijfsnaam.
recipient.nametekstjaNaam van de ontvanger. Naam of bedrijf is verplicht.
recipient.streettekstjaStraat.
recipient.numbertekstjaHuisnummer.
recipient.boxtekstOptioneel. Busnummer.
recipient.postal_codetekstjaPostcode. In België 4 cijfers.
recipient.citytekstjaGemeente.
recipient.countrytekstLandcode (2 letters), standaard BE. Ook alle andere EU-landen (bv. NL, FR, DE), +€1,50 per brief, levertermijn 5 tot 10 werkdagen na verzending, geen express.
pdf_base64tekstPdf als base64, A4, maximaal 20 MB.
pdf_urltekstRechtstreekse openbare https-link naar je pdf, maximaal 20 MB. Geen doorverwijzing, login, privaat netwerk of afwijkende poort.
template_idtekstId van een sjabloon, in plaats van een pdf.
template_codetekstOf de code van een sjabloon, bv. herinnering.
variablesobjectWaarden voor de velden in je sjabloon, bv. { "voornaam": "An" }.
options.flatja/neeOngevouwen in grote envelop, handmatig verwerkt. Alleen beschikbaar na activering. Meerprijs via /price.
options.registeredja/neeAangetekend papier, alleen BE en standard/express, na activering. Opvolging: registered_tracking, registered_handed_in_at en tijdelijke registered_receipt_url.
options.colorja/neeKleur. Standaard zwart-wit. Meerprijs per vel via /price.
options.duplexja/neeDubbelzijdig: twee pagina's per vel. Standaard enkelzijdig.
options.qr_trackingja/neeDynamische QR-code met scanmeting, +€0,05 per brief.
options.speedtekstSnelheid: `standard` (binnen 3 werkdagen verstuurd), `express` (zelfde werkdag als aangeleverd vóór 12:00, +€0,15 per brief, minimum €15,00 per dag) of `flex` (binnen 5 werkdagen, €-0,05 per brief). Standaard `standard`.
options.qr_target_urltekstVerplicht bij qr_tracking. Https-link waar de QR-code naartoe gaat. Achteraf aanpasbaar in het portaal.
enclosure_batch_idtekstId van ontvangen drukwerk, zichtbaar in het portaal. Eén exemplaar per brief, alleen na activering en ontvangstcontrole. Annulering voor productie geeft voorraad terug.
referencetekstOptioneel. Jouw eigen referentie, bv. factuurnummer.
post_ontekstOptioneel: gekozen postdag (YYYY-MM-DD), een werkdag maximaal 90 kalenderdagen vooruit. Geen bezorgdatum. Tegoed wordt bij aanmaak gereserveerd door afboeking en bij annuleren vóór productie teruggestort.

Voorbeeldverzoek

curl -X POST https://envelopify.lovable.app/api/v1/letters \
  -H "Authorization: Bearer test_JOUW_SLEUTEL" \
  -H "Idempotency-Key: factuur-2026-104" \
  -H "Content-Type: application/json" \
  -d '{
  "recipient": {
    "name": "An Peeters",
    "street": "Meir",
    "number": "12",
    "postal_code": "2000",
    "city": "Antwerpen"
  },
  "pdf_url": "https://envelopify.lovable.app/voorbeeld.pdf",
  "options": {
    "color": false
  },
  "reference": "factuur-2026-104"
}'
201 · Voorbeeldantwoord
{
  "id": "b1d1a7f7-3db2-43df-a896-bc9dc10c6029",
  "status": "scheduled",
  "price_cents": 129,
  "price_breakdown": {
    "unit_price_cents": 129,
    "tier": 1,
    "tier_fixed": false,
    "volume_30d": 120,
    "letters_to_next_tier": 379,
    "pages": 1,
    "sheets": 1,
    "address_sheet": true,
    "total_sheets": 2,
    "color": false,
    "duplex": false,
    "speed": "standard",
    "destination": "BE",
    "options": [],
    "total_cents": 129,
    "on_request": false,
    "currency": "EUR",
    "vat_included": false
  },
  "sheet_count": 2,
  "post_date": "2026-11-13",
  "free_trial": false,
  "test": false
}

Status opvragenGET/api/v1/letters/{id}

Geeft alle velden van de brief, de tijdstippen, de prijsopsplitsing, het aantal QR-scans (scan_count) en zodra hij gepost is een tijdelijke link naar de foto van de batch (batch_photo_url, 1 uur geldig).

Voorbeeldverzoek

curl -X GET https://envelopify.lovable.app/api/v1/letters/b1d1a7f7-3db2-43df-a896-bc9dc10c6029 \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord
{
  "id": "b1d1a7f7-3db2-43df-a896-bc9dc10c6029",
  "tracking_code": "B1D1A7F7",
  "reference": "factuur-2026-104",
  "status": "posted",
  "test": false,
  "reject_reason": null,
  "return_reason": null,
  "recipient": {
    "company": null,
    "name": "An Peeters",
    "street": "Meir",
    "number": "12",
    "box": null,
    "postal_code": "2000",
    "city": "Antwerpen",
    "country": "BE"
  },
  "source": "pdf",
  "color": false,
  "duplex": false,
  "qr_tracking": false,
  "sheet_count": 2,
  "price_cents": 129,
  "price_breakdown": {
    "unit_price_cents": 129,
    "tier": 1,
    "tier_fixed": false,
    "volume_30d": 120,
    "letters_to_next_tier": 379,
    "pages": 1,
    "sheets": 1,
    "address_sheet": true,
    "total_sheets": 2,
    "color": false,
    "duplex": false,
    "speed": "standard",
    "destination": "BE",
    "options": [],
    "total_cents": 129,
    "on_request": false,
    "currency": "EUR",
    "vat_included": false
  },
  "speed": "standard",
  "post_deadline": "2026-11-13",
  "created_at": "2026-11-12T10:02:11Z",
  "scheduled_at": "2026-11-12T10:02:11Z",
  "printed_at": "2026-11-13T09:40:00Z",
  "posted_at": "2026-11-13T16:02:11Z",
  "returned_at": null,
  "post_date": "2026-11-13",
  "scan_count": 0,
  "batch_photo_url": null
}

Pdf bekijkenGET/api/v1/letters/{id}/pdf

Geeft de definitieve pdf zoals wij hem printen (application/pdf), met adresblad. Enkel voor je eigen brieven. Een geweigerde brief heeft geen pdf en geeft 404.

Voorbeeldverzoek

curl -X GET https://envelopify.lovable.app/api/v1/letters/b1d1a7f7-3db2-43df-a896-bc9dc10c6029/pdf \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord

LijstGET/api/v1/letters

Geeft je recentste brieven, nieuwste eerst, in data. Is er meer, dan krijg je een next_cursor die je meegeeft als cursor.

FilterTypeUitleg
statustekstFilter op status, bv. posted.
referencetekstFilter op je referentie.
fromtekstVanaf datum, bv. 2026-11-01.
totekstTot en met datum.
limitgetalStandaard 25, maximaal 100.
cursortekstWaarde van next_cursor.

Voorbeeldverzoek

curl -X GET https://envelopify.lovable.app/api/v1/letters?status=posted&limit=50 \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord
{
  "data": [
    {
      "id": "b1d1a7f7-3db2-43df-a896-bc9dc10c6029",
      "status": "posted",
      "reference": "factuur-2026-104"
    }
  ],
  "next_cursor": "MjAyNi0xMS0xMlQxMDo..."
}

AnnulerenDELETE/api/v1/letters/{id}

Annuleert een brief zolang de batch van die dag nog open is. Je tegoed wordt teruggestort en je krijgt de brief terug met status rejected. Is de batch al afgesloten, dan krijg je 409 cutoff_passed.

Voorbeeldverzoek

curl -X DELETE https://envelopify.lovable.app/api/v1/letters/b1d1a7f7-3db2-43df-a896-bc9dc10c6029 \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord

Prijs berekenenPOST/api/v1/price

Berekent de prijs van een brief met je huidige schijf, zonder iets aan te maken of af te rekenen. Zelfde opties als een brief, maar met het aantal bedrukte pagina's in plaats van een pdf. Met address_sheet (standaard true) reken je het gratis adresblad mee voor het maximum aantal vellen, zoals bij een opgeladen pdf; zet het op false voor een sjabloonbrief. Niet-geactiveerde gewichtsklassen geven 422 weight_class_unavailable. Met options.address_on_first_page bereken je zonder extra adresblad.

VeldTypeVerplichtUitleg
options.address_on_first_pageja/neeVoor opgeladen pdf: wit vast adresvak op de eerste pagina, zonder extra adresblad. Bedekte inhoud wordt wit. Zonder keuze geldt je accountstandaard (aanvankelijk adresblad).
options.flatja/neeOngevouwen in grote envelop, handmatig verwerkt. Alleen beschikbaar na activering. Meerprijs via /price.
options.registeredja/neeAangetekend papier, alleen BE en standard/express, na activering. Opvolging: registered_tracking, registered_handed_in_at en tijdelijke registered_receipt_url.
enclosure_batch_idtekstId van ontvangen drukwerk, zichtbaar in het portaal. Eén exemplaar per brief, alleen na activering en ontvangstcontrole. Annulering voor productie geeft voorraad terug.
pagesgetaljaAantal bedrukte pagina's (het adresblad niet meegerekend).
address_sheetja/neeGratis adresblad meerekenen voor het maximum aantal vellen. Standaard true.
options.countrytekstBestemmingsland, standaard BE. Een ander EU-land voegt de toeslag EU toe.
options.colorja/neeKleur, meerprijs per vel via /price.
options.duplexja/neeDubbelzijdig.
options.qr_trackingja/neeQR-code met scanmeting.
options.speedtekststandard, express of flex.

Voorbeeldverzoek

curl -X POST https://envelopify.lovable.app/api/v1/price \
  -H "Authorization: Bearer test_JOUW_SLEUTEL" \
  -H "Content-Type: application/json" \
  -d '{
  "pages": 3,
  "address_sheet": true,
  "options": {
    "color": false,
    "duplex": false,
    "qr_tracking": false,
    "speed": "standard"
  }
}'
200 · Voorbeeldantwoord
{
  "price_breakdown": {
    "unit_price_cents": 129,
    "tier": 1,
    "tier_fixed": false,
    "volume_30d": 120,
    "letters_to_next_tier": 379,
    "pages": 3,
    "sheets": 3,
    "address_sheet": true,
    "total_sheets": 4,
    "color": false,
    "duplex": false,
    "speed": "standard",
    "destination": "BE",
    "options": [
      {
        "code": "extra_sheets",
        "label": "Extra vellen (2)",
        "amount_cents": 20
      }
    ],
    "total_cents": 149,
    "on_request": false,
    "currency": "EUR",
    "vat_included": false
  }
}

Sjablonen opvragenGET/api/v1/templates

Geeft je sjablonen in data.

Voorbeeldverzoek

curl -X GET https://envelopify.lovable.app/api/v1/templates \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord
{
  "data": [
    {
      "id": "6c1f...",
      "name": "Herinnering",
      "code": "herinnering",
      "body": "Beste {{voornaam}}, ...",
      "created_at": "2026-11-12T10:00:00Z"
    }
  ]
}

Sjabloon makenPOST/api/v1/templates

Maakt een sjabloon. Velden staan tussen dubbele accolades, bv. {{voornaam}}. Een code die al bestaat geeft 409 conflict.

VeldTypeVerplichtUitleg
nametekstjaNaam.
codetekstjaUnieke code: letters, cijfers, - en _.
bodytekstjaTekst met velden.

Voorbeeldverzoek

curl -X POST https://envelopify.lovable.app/api/v1/templates \
  -H "Authorization: Bearer test_JOUW_SLEUTEL" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Herinnering",
  "code": "herinnering",
  "body": "Beste {{voornaam}},\n\nWe ontvingen nog geen betaling van {{bedrag}}."
}'
201 · Voorbeeldantwoord

Tegoed en prijzenGET/api/v1/balance

Geeft je huidig tegoed, je schijf, het aantal echte brieven in de voorbije 30 dagen, hoeveel brieven je nog verwijderd bent van de volgende korting en de prijslijst in cent, excl. btw: prijs per brief per schijf, meerprijzen voor opties en snelheden, en de regels voor express. free_letters_remaining is het aantal gratis proefbrieven dat je nog hebt.

Voorbeeldverzoek

curl -X GET https://envelopify.lovable.app/api/v1/balance \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord
{
  "credit_cents": 4950,
  "free_letters_remaining": 3,
  "company_verified": true,
  "tier": 1,
  "tier_fixed": false,
  "volume_30d": 120,
  "letters_to_next_tier": 380,
  "unit_price_cents": 129,
  "tiers": [
    {
      "tier": 1,
      "from": 0,
      "unit_price_cents": 129
    },
    {
      "tier": 2,
      "from": 500,
      "unit_price_cents": 109
    },
    {
      "tier": 3,
      "from": 5000,
      "unit_price_cents": 99
    }
  ],
  "options": {
    "extra_sheet_cents": 10,
    "qr_tracking_cents": 5
  },
  "speeds": [
    {
      "speed": "standard",
      "name": "Standaard",
      "amount_cents": 0,
      "working_days": 3
    },
    {
      "speed": "express",
      "name": "Express",
      "amount_cents": 15,
      "working_days": 0
    },
    {
      "speed": "flex",
      "name": "Flex",
      "amount_cents": -5,
      "working_days": 5
    }
  ],
  "express": {
    "minimum_cents": 1500,
    "max_letters_per_day": 1000,
    "before_hour": 12
  },
  "heavy_letter": {
    "from_grams": 50,
    "amount_cents": 60
  },
  "eu": {
    "surcharge_cents": 150,
    "countries": [
      "AT",
      "DE",
      "FR",
      "NL",
      "..."
    ],
    "delivery": "5 tot 10 werkdagen na verzending",
    "express": false
  },
  "daily_letter_max": 1000,
  "max_sheets": 8,
  "currency": "EUR",
  "vat_included": false
}

Je account en bedrijfscontroleGET/api/v1/account

Geeft de gegevens van je eigen account. company_verified is true als je btw-nummer gecontroleerd is bij de Europese btw-controle (VIES) of door ons manueel. verification_status is verified, none (niet geverifieerd), pending (controle volgt later) of invalid. Bij een geverifieerd bedrijf staan ook official_name en official_address uit het officiële register. GET /balance bevat ook company_verified. De status kan je niet via de API wijzigen: dat gebeurt enkel na een echte controle in het portaal.

Voorbeeldverzoek

curl -X GET https://envelopify.lovable.app/api/v1/account \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord
{
  "customer_id": "4f6c2a1e-...",
  "company": "Jouw Bedrijf",
  "email": "post@jouwbedrijf.be",
  "company_verified": true,
  "verification_status": "verified",
  "vat_number": "BE0123456749",
  "official_name": "Jouw Bedrijf BV",
  "official_address": "Kerkstraat 1\n2000 Antwerpen",
  "checked_at": "2026-11-12T10:00:00Z",
  "free_letters_remaining": 3
}

Statusmeldingen opvragenGET/api/v1/webhooks

Toont je geregistreerde links en notification_groups. null betekent alle bestaande gebeurtenissen; een lijst beperkt meldingen tot gekozen groepen.

Voorbeeldverzoek

curl -X GET https://envelopify.lovable.app/api/v1/webhooks \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord
{
  "data": [
    {
      "id": "a3c2...",
      "url": "https://jouwsite.be/hooks/envelopify",
      "active": true,
      "created_at": "2026-11-12T10:00:00Z"
    }
  ]
}

Statusmelding registrerenPOST/api/v1/webhooks

Registreert een https-link. Het antwoord bevat eenmalig een secret waarmee je de handtekening controleert.

VeldTypeVerplichtUitleg
urltekstjaHttps-link die onze POST ontvangt.
notification_groupslijstOptioneel: problems (review/rejected), sent (posted/registered_handed_in), undeliverable (returned), delivered (binnenkort, nog geen gebeurtenissen). Weglaten bewaart alle bestaande gebeurtenissen, [] ontvangt niets. Instelbaar per adres in het portaal.

Voorbeeldverzoek

curl -X POST https://envelopify.lovable.app/api/v1/webhooks \
  -H "Authorization: Bearer test_JOUW_SLEUTEL" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://jouwsite.be/hooks/envelopify"
}'
201 · Voorbeeldantwoord
{
  "id": "a3c2...",
  "url": "https://jouwsite.be/hooks/envelopify",
  "active": true,
  "created_at": "2026-11-12T10:00:00Z",
  "secret": "whsec_..."
}

Statusmelding verwijderenDELETE/api/v1/webhooks/{id}

Verwijdert een link.

Voorbeeldverzoek

curl -X DELETE https://envelopify.lovable.app/api/v1/webhooks/a3c2... \
  -H "Authorization: Bearer test_JOUW_SLEUTEL"
200 · Voorbeeldantwoord
{
  "id": "a3c2...",
  "deleted": true
}

Statusmeldingen

Bij elke gebeurtenis sturen we een POST naar al je actieve links met { event, letter_id, status, occurred_at, letter }. Elke melding draagt de header x-envelopify-signature: de HMAC-SHA256 (hex) van de ruwe inhoud met je geheim. Controleer die voor je de melding vertrouwt en antwoord met een 2xx-status. Lukt een melding niet (geen 2xx of geen antwoord binnen 8 seconden), dan proberen we ze tot 3 keer opnieuw (bij je volgende gebeurtenis en bij elke productieronde), dus 4 pogingen in totaal. Testbrieven blijven op received en geven geen meldingen.

GebeurtenisWanneer
letter.scheduledIngepland voor een postdag, tegoed afgeboekt
letter.reviewAdres te controleren: wij kijken het na voor we printen
letter.checkedAdres goedgekeurd na controle, ingepland
letter.rejectedAfgekeurd na controle of geannuleerd vóór productie, teruggezet op je Envelopify-tegoed, niet uitbetaald
letter.printedGeprint en gefrankeerd
letter.postedAfgegeven bij bpost
letter.returnedTeruggekomen als onbestelbaar
letter.registered_handed_inAangetekend afgegeven, tracking en bewijs beschikbaar
letter.scannedQR-code gescand
{
  "event": "letter.posted",
  "letter_id": "b1d1a7f7-3db2-43df-a896-bc9dc10c6029",
  "status": "posted",
  "occurred_at": "2026-11-13T16:02:12Z",
  "letter": {
    "id": "b1d1a7f7-3db2-43df-a896-bc9dc10c6029",
    "tracking_code": "B1D1A7F7",
    "reference": "factuur-2026-104",
    "status": "posted",
    "posted_at": "2026-11-13T16:02:11Z"
  },
  "created_at": "2026-11-13T16:02:12Z"
}

Handtekening controleren:

// Node 18+ with Express: verify a webhook signature
import crypto from "node:crypto";
import express from "express";

const SECRET = "whsec_JOUW_GEHEIM"; // returned once when you create the webhook
const app = express();

app.post("/hooks/envelopify", express.raw({ type: "application/json" }), (req, res) => {
  const expected = crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
  const given = req.get("x-envelopify-signature") ?? "";
  const ok = given.length === expected.length && crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
  if (!ok) return res.status(401).end();
  const { event, letter } = JSON.parse(req.body.toString("utf8"));
  console.log(event, letter.id, letter.status);
  res.status(200).end();
});

app.listen(3000);

Dubbels vermijden

Stuur een header Idempotency-Key mee, bv. je factuurnummer. Stuur je dezelfde sleutel opnieuw, binnen 24 uur, dan krijg je de bestaande brief terug (status 200) in plaats van een nieuwe, en wordt er niets extra aangerekend. Na 24 uur geldt de sleutel als nieuw.

Statussen

StatusBetekenis
receivedOntvangen. Testbrieven blijven in deze status.
scheduledIngepland voor een postdag, tegoed afgeboekt.
reviewTe controleren: de postcode bestaat niet of past niet bij de gemeente. Wij keuren het adres goed of af (tegoed terug). Zie address_warning.
printedGeprint en gefrankeerd.
postedAfgegeven bij bpost.
returnedTeruggekomen als onbestelbaar.
rejectedGeweigerd of geannuleerd. De reden staat in reject_reason.

Foutcodes

Fouten hebben altijd de vorm { error: { code, message } }. De code (error.code) is altijd dezelfde, in elke taal: gebruik die in je logica. De melding (error.message) is in het Nederlands en mag je zo tonen aan je gebruiker.

CodeHTTPBetekenis
sender_not_verified422Echte verzending, ook gratis proefpost, vereist een bevestigd e-mailadres en nagekeken bedrijf. Testmodus blijft beschikbaar.
weight_class_unavailable422Gewichtsklasse niet geactiveerd of boven 350 gram.
service_unavailable422De gekozen dienst of ontvangen foldervoorraad is nog niet beschikbaar.
invalid_post_date422De gekozen postdag is geen geldige werkdag binnen 90 dagen.
address_incomplete422Er ontbreekt een adresveld of de postcode klopt niet.
insufficient_balance422Je tegoed volstaat niet.
pdf_invalid422De pdf kan niet geopend worden, is geen pdf of is groter dan 20 MB.
too_many_sheets422Meer dan 8 vellen, adresblad inbegrepen.
express_limit422Meer dan 1.000 expressbrieven op één dag.
country_not_supported422Land buiten België en de EU.
express_not_available422Express kan niet naar andere EU-landen.
daily_limit422Dagelijks maximum brieven bereikt (standaard 1.000, aanpasbaar op aanvraag).
template_invalid422Sjabloon niet gevonden of er ontbreken velden.
invalid_request400De aanvraag is niet geldig, bv. een ontbrekende bron of foute QR-link.
unauthorized401Sleutel ontbreekt, is ongeldig of ingetrokken.
not_found404Brief, webhook of eindpunt bestaat niet. Ook zonder sleutel.
cutoff_passed409Annuleren kan niet meer, de brief is in productie.
not_cancellable409Annuleren kan niet, bv. omdat de brief al geweigerd of geannuleerd is.
conflict409Er bestaat al een sjabloon met deze code.
rate_limited429Meer dan 60 aanvragen per minuut. Kijk naar de header Retry-After.
server_error500Er liep iets mis aan onze kant.
{
  "error": {
    "code": "address_incomplete",
    "message": "Een Belgische postcode bestaat uit 4 cijfers"
  }
}

Limieten

Maximaal 60 aanvragen per minuut per sleutel. Daarboven krijg je 429 rate_limited en een header Retry-After. Pdf's mogen maximaal 20 MB zijn, een brief maximaal 350 g, middel en groot alleen na activering, maximaal 1.000 expressbrieven per dag en standaard maximaal 1.000 brieven per dag per account. De error.code is taalonafhankelijk en verandert niet; de message is Nederlands. CORS staat open, maar gebruik je sleutel nooit in browsercode.

Prijzen

Eén prijs per brief, excl. btw, alles inbegrepen: 1 vel (enkel- of dubbelzijdig, zwart-wit), envelop, echte postzegels en posten. Volgens je echte brieven in de glijdende voorbije 30 dagen, de nieuwe brief meegeteld, zonder maandreset: €1,29 onder 500, €1,09 vanaf 500, €0,99 vanaf 5.000. Kleur: +€0,08 per vel. Dubbelzijdig zonder meerprijs. Extra vel: +€0,10 per vel bovenop het eerste (dubbelzijdig zijn het twee pagina's per vel). QR-code met scanmeting: +€0,05. Het adresblad is gratis en telt niet mee voor de prijs. Een standaardbrief gaat tot 8 vellen in totaal, adresblad inbegrepen; grotere brieven kunnen op aanvraag via WhatsApp. Snelheden: Standaard (binnen 3 werkdagen verstuurd), Express (+€0,15, zelfde werkdag als aangeleverd vóór 12:00, anders de volgende werkdag) en Flex (€-0,05, binnen 5 werkdagen). Verstuurd betekent: door ons afgegeven aan bpost. bpost bezorgt binnen 2 tot 3 werkdagen na afgifte. Minimum express via de API: zijn je expressbrieven van één dag om 12:00 samen minder dan €15,00, dan houden we het verschil af met de regel "Aanvulling minimum express" in je bewegingen. Je tegoed moet dat bedrag bij het aanmaken al dekken. Maximum 1.000 expressbrieven per dag. Elk antwoord met een prijs bevat price_breakdown met unit_price_cents, tier, volume_30d, letters_to_next_tier, sheets, total_sheets, speed, options (lijst met code, label, amount_cents: extra_sheets, qr_tracking, express, flex) en total_cents. Gratis proefbrieven: elk nieuw account krijgt 3 echte brieven gratis, ook via de API met je sleutel in livemodus. Voorwaarden: snelheid standard, maximaal 3 vellen inhoud, bevestigd e-mailadres en maximaal 3 proefbrieven per ontvangstadres. Een brief die niet voldoet, wordt gewoon van je tegoed betaald. Een proefbrief heeft free_trial: true en price_cents: 0; annuleren voor productie geeft hem terug. GET /balance toont free_letters_remaining. Zware brief: boven 50 g komt er +€0,60 per brief bij (optie heavy_letter). Andere EU-landen: +€1,50 per brief (optie eu), levertermijn 5 tot 10 werkdagen na verzending, geen express. Adrescontrole: bij een Belgisch adres kijken we of de postcode bestaat en bij de gemeente past. Twijfel je antwoord niet weg: de brief krijgt status review met address_warning en wij keuren hem goed of af (tegoed terug).

Alle tarieven en de rekenhulp staan op de prijzenpagina.