Nordlet

← Documentatie / Handleidingen

API-conventies

Verzoekstructuur, authenticatiescopes, lijstaanvragen, geldbedragen, fouten, idempotenty, limieten.

Verzoekstructuur

Elke bewerking is een RPC-achtige POST:

POST /v1/{module}/{resource}/{action}

Modules: reference, partners, catalog, sales, purchases, ledger, bank, declarations, files, webhooks, audit. Acties zijn werkwoorden: create, get, update, delete, list, plus domeinspecifieke acties zoals issue, register, match, apply-advance, generate.

Authenticatie en scopes

Authorization: Bearer <api key>. Sleutels bevatten scopes die per actie worden gecontroleerd:

  • {module}:read - ophaal- en lijstacties
  • {module}:write - mutaties
  • {module}:* of * - jokers

Ontbrekende scope leidt tot 403 forbidden. Ontbrekende of ongeldige sleutel leidt tot 401 unauthorized.

Lijstaanvragen

Alle list-acties delen dezelfde contractstructuur:

{
  "page": 1,
  "pageSize": 50,
  "sort": [{ "field": "createdAt", "dir": "desc" }],
  "filter": [{ "field": "paymentStatus", "op": "eq", "value": "unpaid" }]
}

Filteroperatoren: eq (gelijk aan), ne (ongelijk aan), contains (hoofdletterongevoelige tekstovereenkomst, alleen voor tekstvelden), gte (groter dan of gelijk aan), lte (kleiner dan of gelijk aan), in (een waarde uit een lijst van maximaal 500 waarden). Sorteerbare en filterbare velden zijn per eindpunt gewitlist (zie de OpenAPI-specificatie); onbekende velden retourneren de status 400. Voeg totals: ["field", …] toe aan het verzoek om numerieke velden op te tellen over alle overeenkomende rijen; wanneer de records een valuta bevatten, geeft totalsByCurrency dezelfde totalen uitgesplitst naar valutacode. Antwoorden: { rows, total, page, pageSize, totals?, totalsByCurrency? }.

Geld en datums

Monetaire waarden zijn decimale tekenreeksen met maximaal 4 decimalen ("121.0000") en mogen nooit als floats worden verwerkt. Btw wordt per regel berekend met afronding naar boven bij de helft (half-up rounding). Datums gebruiken de notatie YYYY-MM-DD; tijdstippen zijn ISO 8601 UTC.

Fouten

Overal wordt dezelfde envelopstructuur gehanteerd:

{
  "error": {
    "code": "validation",
    "message": "Request validation failed",
    "requestId": "k1x…",
    "key": "request_invalid",
    "fieldErrors": { "lines.0.unitPriceExclVat": ["Invalid value"] }
  }
}

Codes: validation (400/422, en 413 wanneer een geüpload bestand of verzoeklichaam te groot is), unauthorized (401), payment_required (402, de proefperiode of het prepaidsaldo is verlopen; het bericht geeft aan hoe u kunt doorgaan), forbidden (403), not_found (404), conflict (409), idempotency_key_reuse (422), idempotency_in_progress (409), rate_limited (429), internal (5xx). Wanneer het bericht een van de vaste berichten is, wordt de sleutel vermeld in key zodat een client zijn eigen vertaling kan tonen, en bevat params de waarden die daarin worden ingevoegd (bijvoorbeeld { "period": "2026-09" } voor een vergrendelde boekhoudperiode). Vermeld altijd de requestId wanneer u problemen meldt.

Idempotentie

Voeg Idempotency-Key: <any string ≤255 chars> toe aan elke muterende aanroep:

  • Opnieuw proberen met dezelfde sleutel en payload betekent dat de opgeslagen reactie byte voor byte wordt afgespeeld met x-idempotent-replay: true.
  • Dezelfde sleutel met een andere payload resulteert in 422 idempotency_key_reuse.
  • Een gelijktijdig duplicaat terwijl de eerste aanroep nog in behandeling is, resulteert in 409 idempotency_in_progress.
  • Sleutels behoren toe aan de API-sleutel of de gebruiker die ze verzendt, binnen het bedrijf waarvoor de aanroep wordt gedaan, zodat twee integraties van één bedrijf dezelfde sleutel kunnen gebruiken. Aanroepen die worden gedaan voordat een bedrijf bestaat, en account/*-aanroepen, bewaren sleutels per gebruiker, zodat een herhaalde account/companies/create-aanroep precies één bedrijf aanmaakt.
  • Een opgeslagen reactie wordt pas geretourneerd nadat de aanroeper opnieuw met succes de toegangscontroles heeft doorlopen (scope, rol, bedrijfs- en abonnementsstatus); anders ontvangt de aanroep de huidige foutmelding.
  • Sleutels verlopen na 24 uur. Foutreacties (4xx) worden eveneens opnieuw afgespeeld; 5xx-reacties worden niet opgeslagen, zodat nieuwe pogingen de bewerking opnieuw uitvoeren.

Limieten voor verzoeken (Rate limits)

300 verzoeken per minuut per API-sleutel (per aangeboden inloggegeven; niet-geauthenticeerde verzoeken worden beperkt per IP-adres). Respecteer bij een 429-fout de header retry-after. De headers x-ratelimit-* geven informatie over uw resterende budget.

Webhooks

Gebeurtenissen worden weggeschreven naar een transactionele uitgaande wachtrij in dezelfde databasetransactie als de wijziging zelf. Hierdoor genereert een teruggedraaid document nooit een gebeurtenis en gaat er geen enkele gebeurtenis verloren. Leveringen verlopen als volgt:

  • POST naar uw URL met de gebeurtenis in JSON-formaat
  • x-nordlet-timestamp: <unix seconds>, het tijdstip waarop de levering is ondertekend
  • x-nordlet-signature-v2: t=<timestamp>,v1=<hex HMAC-SHA256 of "<timestamp>.<raw body>"> op basis van uw abonnementsgeheim
  • x-nordlet-signature: sha256=<hex HMAC-SHA256 of the raw body>, ongewijzigd behouden voor bestaande ontvangers
  • x-nordlet-delivery bevat het leverings-id, dat identiek blijft bij elke herhaling van een levering
  • Een antwoord dat geen 2xx-status oplevert of een omleiding wordt na respectievelijk 30 seconden, 2 minuten, 10 minuten, 30 minuten, 1 uur, 3 uur, 6 uur en 12 uur opnieuw geprobeerd (ongeveer 24 uur in totaal), voordat de levering als mislukt wordt beschouwd
  • Elke levering wordt door één server tegelijk verzonden, zodat het draaien van meerdere API-instanties niet leidt tot dubbele verzending

Verifieer x-nordlet-signature-v2 altijd via een timingveilige vergelijking (constant-time comparison) voordat u de payload vertrouwt, en wijs leveringen af waarvan het tijdstip meer dan 5 minuten afwijkt van uw systeemklok. Het tijdstip maakt deel uit van de ondertekende tekst, zodat een onderschepte levering later niet opnieuw kan worden afgespeeld met een nieuw tijdstip. Sla de verwerkte x-nordlet-delivery-id's op om herhalingen binnen dat tijdsvenster te negeren. Een mislukte levering kan opnieuw worden verzonden via webhooks/deliveries/redeliver.

Audit

Elke mutatie wordt geregistreerd (actor, action, entity, diff) en kan worden opgevraagd via audit/list.

Boekhoudkundige garanties

  • Journaalposten zijn altijd in evenwicht; dit wordt afgedwongen door een uitgestelde databasetrigger op het moment van doorvoeren (commit), en niet uitsluitend door applicatielood.
  • Documentnummers vertonen geen hiaten per reeks of per jaar; toewijzing vindt plaats op een concurrency-veilige manier.
  • Vergrendelde boekhoudperiode wijzen elke boeking met een datum binnen die periode resoluut af (409).
  • Zacht verwijderde (soft-deleted) documenten behouden hun audit trail; uitgegeven of geregistreerde documenten kunnen niet worden verwijderd.