Programmeercode op een laptopscherm
Voor ontwikkelaars

Incasso API
van factuur tot dossier in één request.

Koppel uw software, CRM of facturatiesysteem rechtstreeks aan nl.legal. Eén POST en uw vordering staat als dossier bij ons klaar, inclusief PDF-facturen, AI-factuurcontrole en een gratis testomgeving.

Gratis testomgeving

Met een nll_test_-key test u de volledige integratie, inclusief validatie en AI-controle, zonder dat er ooit een echt dossier ontstaat.

AI-factuurcontrole

Meegestuurde PDF's worden automatisch vergeleken met uw opgave. Wijkt een totaalbedrag af, dan krijgt u een waarschuwing terug. Uw opgave blijft altijd leidend.

WIK-proof samenvoegen

Stuurt u een vervolgfactuur met hetzelfde klantnummer? Dan voegen wij die conform de Wet Incassokosten automatisch toe aan het lopende dossier.

In drie stappen live

  1. 1
    Vraag een API-key aan via het contactformulier of uw accountmanager. U ontvangt een test-key (nll_test_…) en na acceptatie een live-key (nll_live_…).
  2. 2
    Test de verbinding met GET https://nl.legal/api/v1/ping. Met uw key in de Authorization-header ziet u direct of alles klopt.
  3. 3
    Dien uw eerste opdracht in met POST /api/v1/orders. U krijgt synchroon het dossiernummer terug.

Voorbeeld: opdracht indienen (curl)

curl -X POST https://nl.legal/api/v1/orders \
  -H "Authorization: Bearer nll_live_UW_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "type": "incasso",
    "reference": "ORDER-2026-0042",
    "description": "Onbetaalde facturen voor webdesign",
    "debtors": [{
      "type": "business",
      "company_name": "Voorbeeld Webshop B.V.",
      "customer_number": "KLANT-1234",
      "email": "administratie@voorbeeldwebshop.nl",
      "address": {
        "street": "Hoofdstraat",
        "house_number": "12",
        "postal_code": "1234 AB",
        "city": "Amsterdam"
      }
    }],
    "invoices": [{
      "invoice_number": "F2026-0815",
      "invoice_date": "2026-04-01",
      "due_date": "2026-04-15",
      "amount_cents": 125000,
      "description": "Webdesign april 2026"
    }]
  }'

Response (201 Created)

{
    "id": "ord_b2b332c6a34ebb12",
    "object": "order",
    "mode": "live",
    "type": "incasso",
    "reference": "ORDER-2026-0042",
    "case": {
        "case_number": "IN211543",
        "new": true
    },
    "debtors": [
        { "name": "Voorbeeld Webshop B.V.", "customer_number": "KLANT-1234" }
    ],
    "invoice_count": 1,
    "total_amount_cents": 125000,
    "warnings": [],
    "created_at": "2026-06-10T18:00:40+02:00"
}

Met een test-key (nll_test_…) krijgt u exact dezelfde response, maar dan met "mode": "test", "case_number": null en een test_mode-warning: er wordt dan geen dossier aangemaakt.

Endpoints

POST /api/v1/orders

Dien een incasso-opdracht in: type (pre-incasso of incasso), één of meer debiteuren, één of meer facturen en optioneel PDF-bijlagen. Synchroon antwoord met dossiernummer. Ondersteunt de Idempotency-Key-header tegen dubbele indiening.

GET /api/v1/orders

Lijst uw opdrachten met cursorpaginatie, voor reconciliatie. Filter op case_number (zoek op IN-nummer), reference, customer_number of type.

GET /api/v1/orders/{orderId}

Vraag de actuele status op: dossierstatus, of het dossier nog openstaat en het actuele openstaande saldo (inclusief rente en kosten) in centen.

POST /api/v1/orders/{orderId}/hold · /withdraw · /payments

Stuuracties op een lopend dossier: pauze aanvragen, intrekken, of een rechtstreeks aan u betaald bedrag melden. Elke actie zet een taak met instructies op het dossier die een behandelaar verwerkt; de API muteert zelf niets financieels.

GET POST /api/v1/creditors na activering

Crediteurenbeheer: vraag de crediteuren op namens wie u mag indienen, of maak een nieuwe crediteur aan onder uw account. Alleen beschikbaar als nl.legal deze functie voor uw API-key heeft goedgekeurd en geactiveerd (standaard uit); zonder activering geeft de API code creditor_feature_disabled. Zie indienen namens een andere crediteur.

POST /api/v1/tools/wik geen key nodig

Bereken de buitengerechtelijke incassokosten (Besluit BIK) en optioneel de wettelijke (handels)rente over een hoofdsom. Openbaar hulpmiddel, geen API-key vereist. Zie de incassokosten-API.

POST /api/v1/tools/rol-router geen key nodig

Geef woonplaats en naam van de gedaagde op en krijg de bevoegde rechtbank, de kantonlocatie, het postbusadres, de roldagen en de eerstvolgende haalbare roldatum terug. Openbaar hulpmiddel, geen API-key vereist. Zie de rechtbank-API.

GET /api/v1/ping

Verbindings- en authenticatietest. Werkt ook zonder key (dan authenticated: false).

Alle endpoints, velden, foutcodes en voorbeelden staan in de API-reference, met een interactieve variant om verzoeken direct uit te proberen. De machine-leesbare specificatie staat op /api/v1/openapi.json (OpenAPI 3.1), direct bruikbaar in Postman, Insomnia of uw codegenerator.

Goed om te weten

Bedragen in centen

Alle bedragen zijn gehele getallen in eurocenten: € 1.250,00 is 125000. Geen floats, geen komma/punt-verwarring en geen afrondingsfouten, exact zoals Stripe en Mollie dat doen.

Opdrachtgever = uw API-key

U stuurt nooit een opdrachtgever mee. Uw API-key is gekoppeld aan uw bedrijf; elke opdracht komt automatisch op uw naam binnen. Dient u in namens meerdere crediteuren, bijvoorbeeld als beheerder of softwarepakket? Zie dan hieronder bij indienen namens een andere crediteur.

Indienen namens een andere crediteur na activering

Sommige opdrachtgevers dienen niet voor zichzelf in, maar namens anderen. Denk aan een vastgoedbeheerder die voor zijn verhuurders huurachterstanden uit handen geeft, of een facturatie- of boekhoudpakket dat incasso als dienst aanbiedt aan de eigen gebruikers. Daarvoor is er crediteurenbeheer: u maakt eenmalig een crediteur aan via POST /api/v1/creditors (met uw eigen reference als kenmerk) en kiest die crediteur daarna bij het indienen met het veld creditor, bijvoorbeeld {"creditor": {"reference": "VHR-001"}}. Het dossier komt dan op naam van die crediteur te staan, terwijl u als opdrachtgever gekoppeld blijft en alles via uw eigen key kunt volgen.

Deze functie staat standaard uit. Zij moet vooraf door nl.legal worden goedgekeurd en voor uw API-key worden geactiveerd; neem daarvoor contact op via incasso@nl.legal. Zonder activering geeft de API een 403 met code creditor_feature_disabled. Laat u het veld creditor weg, dan werkt de API precies zoals altijd: uw eigen organisatie is de crediteur. Of de functie voor uw key aanstaat, ziet u aan features.creditor_management in de response van /ping.

Eén opdracht = één vordering

Een opdracht kan meerdere facturen en meerdere debiteuren bevatten, maar meerdere debiteuren betekent altijd: dezelfde vordering, samen aangesproken (bijvoorbeeld twee contractspartijen of partners). Losse vorderingen op verschillende debiteuren dient u in als losse opdrachten.

Klantnummer en de Wet Incassokosten

Geef per debiteur uw eigen customer_number mee. Dient u later een vervolgfactuur in voor dezelfde debiteur terwijl er nog een dossier openstaat, dan voegen wij die vordering automatisch aan dat dossier toe, zoals de Wet Incassokosten dat vraagt. U herkent dit aan case.new: false en de warning attached_to_existing_case.

Titel van de vordering

Geef desgewenst een title mee in de vorm "overeenkomst van opdracht voor ...". Laat u het veld leeg, dan genereert onze AI er automatisch een in dat formaat op basis van uw omschrijving en de facturen.

Eigen metadata

Het optionele metadata-object (vrije sleutel/waarde-paren) wordt opgeslagen, in elke response teruggegeven en als notitie bij het dossier gezet. Ideaal om uw eigen identifiers, zoals een PO-nummer of kostenplaats, mee te koppelen.

Maatwerkvelden (UDF)

Werkt u met dossiervelden die specifiek voor uw situatie zijn? Geef die mee in het optionele udf_fields-object als sleutel/waarde-paren; u kunt er meerdere tegelijk meesturen en ze worden als veld op het dossier gezet. Welke veldnamen voor uw account beschikbaar zijn, stemmen wij met u af; gebruik exact die sleutels. Een onbekende sleutel wordt overgeslagen met de waarschuwing udf_field_unknown. Voorbeeld: {"uw_veldnaam_1": "waarde", "uw_veldnaam_2": "2026-06-01"}.

Toegang en key-rotatie

Een key komt nooit bij gegevens van een andere opdrachtgever. Per key bepalen wij of die alleen de eigen ingediende opdrachten ziet, of alle API-opdrachten van uw organisatie. Met die tweede instelling blijven uw opdrachten zichtbaar nadat u een key vernieuwt. De API toont uitsluitend opdrachten die via de API zijn ingediend; dossiers die buiten de API om in ons systeem zijn aangemaakt, zijn via de API niet zichtbaar.

Consument: WIK-aanmaning verplicht

Dient u een incasso (geen pre-incasso) in tegen een particulier (type: individual), dan vereist de wet dat de incassokosten zijn aangezegd met een 14-dagenbrief (art. 6:96 BW). Stuur die WIK-aanmaning als PDF mee en label de bijlage met document_type: "wik_letter". Ontbreekt de aanmaning, dan weigeren wij de opdracht met code wik_letter_required. Onze AI controleert de brief ook inhoudelijk. Nog geen 14-dagentermijn gehad? Dien dan in als pre-incasso; dan versturen wij de aanmaning.

Sturen op een lopend dossier

Na het indienen kunt u een dossier bijsturen: een pauze aanvragen (/hold), het laten intrekken (/withdraw) of melden dat de debiteur rechtstreeks aan u betaalde (/payments, bedrag in centen). Elke melding komt als taak met instructies op het dossier; een behandelaar verwerkt die. Zo blijft het traject juridisch zuiver en raakt een intrekking netjes verrekend met de no-cure-no-pay-afspraak.

PDF-bijlagen en AI-controle

Facturen stuurt u mee als base64-PDF, maximaal 30 bijlagen per opdracht. Bij een consumenten-incasso telt naast elke factuur ook de WIK-aanmaning mee; met factuur plus aanmaning per vordering passen er dus 15 facturen in één opdracht. Meer facturen voor dezelfde debiteur verdeelt u over meerdere opdrachten met hetzelfde customer_number; die komen conform de WIK in één dossier terecht. Limieten op de binaire inhoud: max. 10 MB per bestand en 25 MB per opdracht; daarnaast mag de volledige base64-aanvraag niet groter zijn dan 40 MB (base64 is circa 33% groter dan binair). Elk bestand wordt gevalideerd op echtheid en veiligheid. Daarna leest onze AI een selectie van de bijlagen mee en vergelijkt die met uw opgave en onderling. Wijkt een totaalbedrag af, dan krijgt u ai_invoice_mismatch; verschillen tussen de documenten (bijv. een ander adres, factuurnummer of btw-nummer op de factuur dan op de WIK-brief) geven ai_document_mismatch. Reken op 5 tot 30 seconden verwerkingstijd bij een opdracht met bijlagen en stel uw time-out ruim in (minimaal 120 seconden), met een Idempotency-Key als vangnet. Uw opgave blijft leidend; wat u met de waarschuwing doet, bepaalt u zelf.

Idempotency

Stuur per opdracht een unieke Idempotency-Key-header mee (bijvoorbeeld een UUID). Valt de verbinding weg en doet uw systeem een retry, dan ontstaat er gegarandeerd geen dubbel dossier: u krijgt exact dezelfde response nogmaals.

Rate limits

Standaard 30 verzoeken per minuut en 500 per dag. Elke response op /orders bevat RateLimit-Limit, RateLimit-Remaining en RateLimit-Reset headers; bij overschrijding krijgt u een 429 met Retry-After. Hogere limieten nodig? Neem contact op.

Webhooks

Wij sturen events naar uw eigen endpoint zodra er iets verandert aan een van uw dossiers: payment.received, correspondence.sent, case.updated en case.closed. U laat uw endpoint-URL bij ons instellen en krijgt een signing-secret. Zo hoeft u niet te pollen. Zie hieronder hoe u de handtekening verifieert.

Voorbeelden in uw taal

PHP

<?php
$opdracht = [
    'type' => 'incasso',
    'reference' => 'ORDER-2026-0042',
    'debtors' => [[
        'type' => 'business',
        'company_name' => 'Voorbeeld Webshop B.V.',
        'customer_number' => 'KLANT-1234',
        'address' => [
            'street' => 'Hoofdstraat', 'house_number' => '12',
            'postal_code' => '1234 AB', 'city' => 'Amsterdam',
        ],
    ]],
    'invoices' => [[
        'invoice_number' => 'F2026-0815',
        'invoice_date' => '2026-04-01',
        'payment_term_days' => 14,
        'amount_cents' => 125000, // € 1.250,00
    ]],
    'attachments' => [[
        'filename' => 'F2026-0815.pdf',
        'content_base64' => base64_encode(file_get_contents('factuur.pdf')),
    ]],
];

$ch = curl_init('https://nl.legal/api/v1/orders');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('NLLEGAL_API_KEY'),
        'Content-Type: application/json',
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => json_encode($opdracht),
    CURLOPT_TIMEOUT => 60,
]);
$result = json_decode(curl_exec($ch), true);

if (curl_getinfo($ch, CURLINFO_HTTP_CODE) === 201) {
    echo "Dossier aangemaakt: " . $result['case']['case_number'];
    foreach ($result['warnings'] as $warning) {
        echo "\nLet op: " . $warning['message'];
    }
} else {
    echo "Fout: " . $result['detail'];
}

Python

import base64
import os
import uuid

import requests

opdracht = {
    "type": "pre-incasso",
    "reference": "ORDER-2026-0042",
    "debtors": [{
        "type": "individual",
        "first_name": "Jan",
        "last_name": "Jansen",
        "customer_number": "KLANT-5678",
        "address": {
            "street": "Kerkstraat", "house_number": "1",
            "postal_code": "9712 AB", "city": "Groningen",
        },
    }],
    "invoices": [{
        "invoice_number": "F2026-0901",
        "invoice_date": "2026-05-01",
        "due_date": "2026-05-15",
        "amount_cents": 50000,  # € 500,00
    }],
}

with open("factuur.pdf", "rb") as f:
    opdracht["attachments"] = [{
        "filename": "F2026-0901.pdf",
        "content_base64": base64.b64encode(f.read()).decode(),
    }]

response = requests.post(
    "https://nl.legal/api/v1/orders",
    json=opdracht,
    headers={
        "Authorization": f"Bearer {os.environ['NLLEGAL_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    timeout=60,
)

if response.status_code == 201:
    data = response.json()
    print("Dossier aangemaakt:", data["case"]["case_number"])
else:
    print("Fout:", response.json()["detail"])

Foutafhandeling

Fouten volgen RFC 9457 (application/problem+json). Bij validatiefouten bevat het veld errors per veld wat er mis is, inclusief het exacte pad, zoals invoices[0].amount_cents. Bij elke fout vóór verwerking geldt: er is geen dossier aangemaakt.

Status Code Betekenis
400invalid_json / empty_bodyLege body of ongeldige JSON.
401unauthorizedAPI-key ontbreekt, is ongeldig of ingetrokken.
404not_foundOnbekend endpoint of opdracht-ID bestaat niet voor uw account.
405method_not_allowedVerkeerde HTTP-methode; zie de Allow-header.
403creditor_feature_disabledCrediteurenbeheer is niet geactiveerd voor uw API-key (standaard uit; activering via incasso@nl.legal).
409idempotency_conflictIdempotency-Key hergebruikt voor andere inhoud.
409creditor_existsEr bestaat al een crediteur met deze reference binnen uw account.
413payload_too_largeDe volledige (base64-gecodeerde) aanvraag is groter dan 40 MB.
415unsupported_media_typeContent-Type is geen application/json.
422validation_errorEén of meer velden ongeldig; zie errors.
422invalid_attachmentPDF geweigerd (geen PDF, beschadigd of wachtwoord-beveiligd).
422unknown_creditorDe opgegeven crediteur (id of reference) is niet gevonden binnen uw account; zie GET /api/v1/creditors.
429rate_limitedLimiet bereikt; wacht het aantal seconden in Retry-After.
502upstream_errorDossiersysteem tijdelijk niet beschikbaar; herhaal later met dezelfde Idempotency-Key.

Gratis tool: incassokosten & rente berekenen

Met POST /api/v1/tools/wik berekent u de buitengerechtelijke incassokosten volgens het Besluit BIK (artikel 6:96 BW) over een hoofdsom, en optioneel de wettelijke rente (consument) of handelsrente (zakelijk) als u een vervaldatum meegeeft. Dit endpoint vereist geen API-key. Geef include_vat: true mee om 21% btw over de kosten mee te rekenen. De uitkomst is indicatief en geen juridisch advies.

curl -X POST https://nl.legal/api/v1/tools/wik \
  -H "Content-Type: application/json" \
  -d '{
    "amount_cents": 44086,
    "debtor_type": "consumer",
    "due_date": "2026-01-01"
  }'

# Antwoord:
{
  "object": "wik_calculation",
  "principal_amount_cents": 44086,
  "collection_costs_cents": 6613,
  "collection_costs_vat_cents": 0,
  "interest": { "amount_cents": 778, "rate_percent": 4, "days": 162 },
  "total_amount_cents": 51477
}

Webhooks

In plaats van te pollen, ontvangt u een melding zodra er iets gebeurt op een van uw dossiers. U laat uw endpoint-URL bij ons instellen en krijgt een signing-secret. Wij sturen dan een POST met een JSON-event naar uw endpoint. Reageer binnen enkele seconden met een 2xx-status; lukt dat niet, dan proberen wij het opnieuw met oplopende tussenpozen (tot 6 keer).

Voorbeeld-event

POST https://uw-systeem.nl/webhooks/nllegal
X-NLLegal-Event: payment.received
X-NLLegal-Timestamp: 1749626412
X-NLLegal-Signature: 9f86d081884c7d659a2feaa0c55ad015...

{
  "id": "evt_2208770e3e58e856",
  "object": "event",
  "type": "payment.received",
  "created_at": "2026-06-11T06:50:12+00:00",
  "data": {
    "order_id": "ord_b2b332c6a34ebb12",
    "case_number": "IN211543",
    "reference": "ORDER-2026-0042",
    "case_event": "case_payments"
  }
}

Handtekening verifiëren

Elke aflevering bevat de headers X-NLLegal-Signature, X-NLLegal-Timestamp en X-NLLegal-Event. Bereken zelf de HMAC en vergelijk timing-safe. Verwerp afwijkende handtekeningen en oude timestamps.

<?php
$secret    = getenv('NLLEGAL_WEBHOOK_SECRET'); // whsec_...
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_NLLEGAL_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_NLLEGAL_TIMESTAMP'] ?? '';

// Verwerp oude berichten (replay-bescherming)
if (abs(time() - (int) $timestamp) > 300) {
    http_response_code(400); exit;
}

$expected = hash_hmac('sha256', $timestamp . '.' . $payload, $secret);
if (!hash_equals($expected, $signature)) {
    http_response_code(401); exit; // ongeldige handtekening
}

$event = json_decode($payload, true);
// ... verwerk $event['type'] en $event['data'] ...
http_response_code(200);

Event-types

payment.receivedEr is een betaling op het dossier geboekt.
correspondence.sentEr is correspondentie (brief/e-mail) verstuurd.
invoice.updatedEen factuur/vordering op het dossier is gewijzigd.
case.updatedHet dossier is bijgewerkt.
case.closedHet dossier is gesloten.

Versie & compatibiliteit

Dit is de eerste release van de API (versie v1). De versie staat in het pad (/api/v1). Niet-brekende toevoegingen, zoals nieuwe velden of waarschuwingscodes, doen wij binnen v1; een eventuele brekende wijziging krijgt een nieuwe major-versie in het pad, zodat uw bestaande integratie blijft werken. Behandel onbekende velden en waarschuwingscodes daarom tolerant.

Veelgestelde vragen over de incasso API

Ja. nl.legal is een incassobureau met Justis-vergunning 00030 en een eigen REST API, gedocumenteerd met een OpenAPI 3.1-specificatie. Met één POST naar /api/v1/orders staat uw vordering als dossier klaar. Wij hebben de API zelf gebouwd en draaien er onze eigen Moneybird-koppeling op.

Voor de koppeling zelf brengen wij niets in rekening, ook niet voor de testomgeving. U betaalt alleen voor de incasso die eruit voortkomt, en de minnelijke fase gaat op basis van No Cure No Pay.

Ja. Met een key die begint met nll_test_ doorloopt u de volledige integratie, inclusief validatie en de AI-factuurcontrole, zonder dat er ooit een echt dossier ontstaat. Werkt alles, dan wisselt u de key om naar nll_live_ en staat u live.

Twee endpoints staan open. De incassokosten-API rekent de WIK-staffel en de rente uit over een hoofdsom, en de rechtbank-API geeft de bevoegde kantonrechter, de postbus en de eerstvolgende haalbare roldatum. Voor beide is geen account nodig.

Voor Moneybird ligt er een kant-en-klare koppeling. Voor elk ander pakket, CRM of eigen systeem gebruikt u de API rechtstreeks: als het HTTP-verzoeken kan versturen, kan het koppelen. Wilt u helemaal niet bouwen, dan zijn CSV-upload en de andere manieren van indienen er ook nog.

Ja, met crediteurenbeheer. Een vastgoedbeheerder kan bijvoorbeeld voor elke verhuurder een crediteur aanmaken via POST /api/v1/creditors en die bij het indienen kiezen met het veld creditor. Het dossier komt dan op naam van die crediteur, terwijl u als opdrachtgever alles via uw eigen key volgt. Deze functie staat standaard uit en moet vooraf door nl.legal worden goedgekeurd en geactiveerd; vraag dit aan via incasso@nl.legal.

Stuur een Idempotency-Key mee bij het indienen. Komt hetzelfde verzoek met dezelfde key en dezelfde inhoud nog een keer binnen, dan krijgt u exact dezelfde response terug in plaats van een tweede dossier. Dat vangt netwerk-retries en dubbele klikken af.

Dat hangt af van wat u indient. Heeft de consument de 14-dagentermijn al gehad, stuur de aanmaning dan als PDF mee bij een incasso-opdracht. Is die termijn nog niet gelopen, dien dan in als pre-incasso; dan versturen wij de 14-dagen brief zelf.

Klaar om te koppelen?

Vraag vandaag een gratis test-key aan en dien morgen uw eerste opdracht in. Gebruikt u Moneybird, dan hoeft u niet te bouwen: daarvoor is er een kant-en-klare koppeling.

Chat via WhatsApp (opent in nieuw venster)
Chat via WhatsApp