Document Service (MDS)

Inleiding

Magda Documentendienst of Magda Document Service (MDS) laat directe communicatie met de burger of onderneming toe via eBox en/of aangetekende zending.

Sommige projecten maken nog gebruik van de legacy connector Magda Document (eBox).

Use cases

  • Voor het versturen van een beslissing controleren of een burger of onderneming over een actieve eBox beschikt, om te bepalen of digitale verzending mogelijk is of dat een aangetekende zending nodig is.

  • Een officieel document (bv. een beslissing, attest of uitnodiging) digitaal bezorgen aan een burger of onderneming via hun eBox.

  • Nagaan of een verzonden bericht door de ontvanger geopend werd, bijvoorbeeld om te bepalen of een wettelijke termijn (bv. bezwaartermijn) reeds is beginnen lopen.

  • Automatisch overschakelen naar een aangetekende zending op papier wanneer blijkt dat de ontvanger geen actieve eBox heeft.

Setup

Deze REST-gebaseerde connector (document-service-bean) staat los van de Magda-connectoren (magda-bean) die SOAP-gebaseerd zijn. Onderstaande setup en onboardingsprocedure zijn in grote lijnen dezelfde als bij Magda (zie MAGDA algemene setup), maar hou rekening met specifieke verschilpunten.

Dependency toevoegen aan pom.xml bestand

Voeg onderstaande dependency toe aan het pom.xml bestand van je applicatie. Dit zorgt ervoor dat de connector code ingeladen wordt bij de build van de applicatie.

 <dependency>
      <groupId>com.skryv.connectors</groupId>
      <artifactId>document-service</artifactId>
 </dependency>

Onboardingsprocedure

Het aansluitingsproces bij Digitaal Vlaanderen verloopt in verschillende stappen:

  1. Lees eerst de functionele documentatie van de Documentendienst.

  2. Vul het aansluitingsformulier in. Hou hiervoor klaar: het logo van je organisatie (JPG/PNG, max. 200 kB, 64×35 mm), minstens een algemene contactpersoon en een DPO/informatieveiligheidsverantwoordelijke, en (indien je organisatie nog niet via de Documentendienst verstuurt) een ondertekende Toetredingsovereenkomst. Wil je ook papieren zendingen versturen, dan zijn ook de facturatiegegevens van je printpartner nodig.

  3. Beveilig je aansluiting via Toegangsbeheer Vlaanderen (ACM). Start hiervoor tijdig een integratiedossier voor de Veiligheidsbouwstenen via het contactformulier.

  4. Wil je berichten sturen naar de eBox burger en/of eBox onderneming, dan doorloop je bijkomend een apart, specifiek onboardingtraject per doelgroep:

  5. Na een test- en acceptatiefase (zie acceptatiecriteria) volgt de opzet in productie.

Applicatie eigenschappen

Eigenschap

Default

Beschrijving

MDSTechnicalConnector

skryv.connectors.magda.document-service.private-key

Null

Private key

skryv.connectors.magda.document-service.certificate

Null

Certificate

MDSBusinessConnector

skryv.connectors.magda.document-service

Null

Basis-URL van de Documentendienst-API

legal.logging.appclientid

Null

Id

MDSTokenFetcher

skryv.connectors.geosecure.document-service.scope

dv_notificaties_import

GeoSecure OAuth scope. Scope van je machtiging binnen DOSIS. Dit bepaalt welke acties je mag uitvoeren.

skryv.connectors.geosecure.document-service.request-path

https://authenticatie-ti.vlaanderen.be/op/v1/token

Url waar de applicatie op inlogt om vervolgens een token te verkrijgen waarmee de veilige communicatie tot stand gebracht kan worden.

skryv.connectors.geosecure.document-service.app-number

Null

GeoSecure app number. Client Id voor je applicatie. Hiermee moet je inloggen op het beheerdersportaal.

skryv.connectors.geosecure.document-service.keypath

Null

GeoSecure keypath. Pad naar private key in AWS Secrets Manager.

skryv.connectors.geosecure.document-service.aws.seed.enabled

false

Waarde: boolean. Indien true worden authenticatiegegevens opgehaald uit AWS Secrets Manager. Indien false, dan worden de lokaal opgeslagen authenticatiegegevens gebruikt.

skryv.connectors.geosecure.document-service.aws.keypath

false

Pad naar lokale opslag van je key pair.

skryv.connectors.geosecure.jwks

Null

GeoSecure JWKS URL.

Externe documentatie

Klik hier voor alle technische documentatie langs de kant van de documentendienst service.

Services en functies

Overzicht

Functie

Retourtype

Info

checkEboxActiveCitizen

EboxInfo

Controleert of een burger (INSZ) toestemming gaf voor eBox

checkEboxActiveCompany

EboxInfo

Controleert of een onderneming (KBO-nummer) toestemming gaf voor eBox

publishMessage

MdsPublishMessageResponse

Verstuurt een document via eBox en/of papier, afhankelijk van de configuratie

getMessageStatusEBox

EBoxMessageStatus

Vraagt de verzend-/leesstatus op van een eerder verstuurd eBox-bericht

getMessageStatusPaper

PaperMessageStatus

Vraagt de verzendstatus op van een eerder verstuurde papieren zending

Elke functie hieronder is, naast de workflow expressie, ook rechtstreeks aanroepbaar vanuit Java-code door MDSCamundaConnector (bean mds) te injecteren in je klasse.

Java
@RequiredArgsConstructor
public class MyOwnService {
    private final MDSCamundaConnector mds;
}

checkEboxActiveCitizen & checkEboxActiveCompany

Controleer of de opgegeven persoon (personen) of onderneming (ondernemingen) over een actieve eBox beschikken. Zie ook de service taak templates ‘Controleer of eBox actief is voor burger’ en ‘Controleer of eBox actief is voor onderneming’.

Workflow expression 1

${mds.checkEboxActiveCitizen(String rrn)}

Variant voor burger.

Workflow expression 2

${mds.checkEboxActiveCompany(String kboNr)}

Variant voor onderneming.

Java-code 1

EboxInfo eboxInfo = mds.checkEboxActiveCitizen(rrn);

Variant voor burger.

Java-code 2

EboxInfo eboxInfo = mds.checkEboxActiveCompany(kboNr);

Variant voor onderneming

Input

Inputparameters

Data type

Voorbeeld

Uitleg

rrn

String

‘85010212345’

Rijksregisternummer (INSZ) van de burger waarvoor je nagaat of er een actieve eBox is.

kboNr

String

'0406798006'

Ondernemingsnummer (KBO-nummer) waarvoor je nagaat of er een actieve eBox is.

Output

Je krijgt een EboxInfo-object terug met:

  • eboxId: bevestiging van het opgevraagde eboxType (CITIZEN/ENTERPRISE) en eboxIdValue (INSZ of KBO-nummer);

  • exclusivelyEbox (boolean): geeft aan of de ontvanger toestemming (consent) heeft gegeven voor eBox. Dit is het eigenlijke antwoord op de vraag "heeft deze persoon/onderneming een actieve eBox";

  • lastConnectionDate, totalNumberOfMessages, totalNumberOfUnreadMessages : enkel aanwezig bij checkEboxActiveCompany (ondernemingen), nooit bij burgers.

Belangrijke nuance: een ongeldig of onbestaand identificatienummer geeft geen fout, maar gewoon exclusivelyEbox: false — je moet dus niet verwachten dat elke foutieve input een exceptie oplevert.

Gepseudonimiseerd voorbeeld burger:

JSON
{
   "eboxId": {
      "eboxType": "CITIZEN",
      "eboxIdValue": "850102XXX45"
   },
   "exclusivelyEbox": true
}

Gepseudonimiseerd voorbeeld onderneming:

JSON
{
    "eboxId": {
        "eboxType": "ENTERPRISE",
        "eboxIdValue": "0406798006"
    },
    "exclusivelyEbox": true,
    "lastConnectionDate": "2024-04-19T20:00:00Z",
    "totalNumberOfMessages": 47,
    "totalNumberOfUnreadMessages": 3
}

Error-handling

Deze REST-dienst gebruikt HTTP-statuscodes, geen klassieke MAGDA-Uitzonderingen-lijst:

HTTP-status

Betekenis

400

Invalid data supplied

401

Invalid authorization

404

No mailbox found

500

Unexpected Server Error

502

Bad Gateway

503

Service unavailable

504

Gateway Timeout

In onze Java-code (MDSCamundaConnector.checkEboxActive) wordt elke fout — zowel een HTTP-foutstatus als een onverwacht leeg antwoord — omgezet naar een MDSException, net zoals bij de andere MDS-functies:

// Voorbeeld: MDSException opvangen
try {
    EboxInfo eboxInfo = mds.checkEboxActiveCitizen(rrn);
    if (Boolean.TRUE.equals(eboxInfo.getExclusivelyEbox())) {
        // ontvanger heeft een actieve eBox
    }
} catch (MDSException e) {
    throw new BpmnError("MDS_EBOX_CHECK_MISLUKT", e.getErrorMessage());
}

Kanttekening: als er geen enkele identifier werd meegegeven, of het antwoord onverwacht leeg is, gooit de connector zelf al een MDSException ("Empty response" / "No input ID given to check."), nog vóór er sprake is van een HTTP-foutstatus.

Bij een fout krijg je een RFC 7807-achtige body terug (title, status, detail, instance — laatste is het correlatie-ID, te vermelden bij contact met de MAGDA helpdesk):

JSON
{
   "title": "Unauthorized",
   "status": "401",
   "detail": "Invalid token"
}

publishMessage

Versturen van communicatie via eBox en/of papieren zending. Zie ook Studio service taak template ‘Verstuur documenten'.

Workflow expression

${mds.publishMessage(execution)}

Deze functie neemt geen losse parameters — execution wordt automatisch door Studio meegegeven. De eigenlijke configuratie gebeurt via de onderstaande input-parameters op de service taak zelf.

Java-code

MdsPublishMessageResponse response = mds.publishMessage(execution);

Service taak input parameters

Deze input parameters worden via de service taak template ‘Verstuur documenten' op de service taak geplaatst.

Inputparameters

Data type

Voorbeeld

Uitleg

deliveryType

String (keuzelijst)

'AUTOMATIC'

Verzendmethode: AUTOMATIC, PAPER, EBOX, of PAPER_AND_EBOX

eboxIdentifier

String

'85010212345'

INSZ of KBO-nummer van de ontvanger (nodig bij elke verzendmethode behalve PAPER)

eboxType

String (keuzelijst)

'CITIZEN'

CITIZEN of ENTERPRISE

eboxSubjectNL

String

‘Beslissing over uw aanvraag’

Onderwerp van het eBox-bericht, Nederlands

eboxSubjectDE

String

'Entscheidung über Ihren Antrag'

Onderwerp van het eBox-bericht, Duits

eboxSubjectFR

String

'Décision concernant votre demande'

Onderwerp van het eBox-bericht, Frans

priority

String (keuzelijst)

'dlp4'

bpost-prioriteitscode voor de papieren zending: dlp1, dlp3 of dlp4 (default)

side

String (keuzelijst)

'RV'

Druk recto-verso (RV) of enkelzijdig (RS) — enkel relevant bij papieren zending

registeredMail

String/Boolean

‘true’

Aangetekende zending (enkel relevant bij papieren zending)

expirationDate

String

'2025-12-31'

Vervaldatum van het eBox-bericht

eboxTavInsz

String

'85010212345'

"Ter attentie van"-persoon binnen een ondernemings-eBox (INSZ en naam)

eboxTavNaam

String

'Jan Peeters'

"Ter attentie van"-persoon binnen een ondernemings-eBox (naam)

receiverAddressFirstName

String

‘Anna’

Voornaam van de ontvanger (papieren zending)

receiverAddressLastName

String

‘Peeters’

Achternaam van de ontvanger (papieren zending)

receiverAddressOrganisation

String

'Voorbeeld Bouwonderneming NV'

Organisatienaam van de ontvanger, indien van toepassing (papieren zending)

pathReceiverAddress

String

'aanvrager.adres'

Verwijzing naar het adresveld van de ontvanger in het formulier. De connector verwacht onder dit pad de volgende sub-velden: .street, .housenumber, .boxnumber, .zipcode, .municipality. Bijvoorbeeld: als pathReceiverAddress = 'aanvrager.adres', dan leest de connector aanvrager.adres.street, aanvrager.adres.housenumber, enzovoort.

receiverAddressCountry

String (vast)

'BE'

Land van de ontvanger (standaard vastgezet op België)

returnAddressOrganisation

String

'Agentschap Wonen-Vlaanderen'

Organisatienaam voor het retouradres. De connector ondersteunt ook returnAddressFirstName, returnAddressLastName en returnAddressLine2 voor het retouradres — deze zijn echter niet zichtbaar in het huidige Studio-taaktemplate en dus niet rechtstreeks instelbaar via de service-taak.

returnAddressLine1

String

'Havenlaan 88 bus 40B'

Straat en nummer van het retouradres

returnAddressPostalCode

String

'1000'

Postcode van het retouradres

returnAddressCity

String

'Brussel'

Gemeente van het retouradres

returnAddressCountry

String (vast)

'BE'

Land van het retouradres (standaard vastgezet op België)

documents

Map (verborgen)

{'upfile1': 'beslissing.pdf'}

Map met attachments (prefix-id/bestandsnaam), maximaal 6 bijlagen (upfile1 t.e.m. upfile6), samen niet groter dan 7 MB.

Output

Je krijgt een MdsPublishMessageResponse-object terug, met een status-veld dat drie waarden kan hebben: SUCCESS, WARNING of ERROR. Controleer dit veld altijd eerst, vooraleer je de overige velden gebruikt:

  • Bij SUCCESS of WARNING:

    • eboxMessageId en eboxExpirationDate — enkel aanwezig als het bericht (mede) via eBox verstuurd werd;

    • paperMessageId en paperExpirationDate — enkel aanwezig als het bericht (mede) via papier verstuurd werd;

    • Bij deliveryType = PAPER_AND_EBOX kunnen dus beide ingevuld zijn.

  • Bij WARNING: consentMessage bevat een waarschuwing over de toestemming (consent) van de ontvanger voor eBox — het bericht is dan wel verstuurd, maar er is iets met de eBox-toestemming dat aandacht verdient (bv. de ontvanger heeft geen actieve eBox-toestemming, waardoor het bericht mogelijk toch niet leesbaar is voor de ontvanger via eBox).

  • Bij ERROR: errorMessage bevat de foutmelding, en consentMessage kan ook hier gevuld zijn.

Gebruik eboxMessageId/paperMessageId als input voor getMessageStatusEBox/getMessageStatusPaper, om later de verzend- of leesstatus op te vragen.

Belangrijke validatiebeperking: de som van alle bijlagen mag niet groter dan 7 MB zijn. Is dat wel het geval, dan krijg je hier al een fout (status = ERROR, met een duidelijke foutmelding) vóór de aanroep zelfs naar MAGDA vertrekt.

Gepseudonimiseerde voorbeelden:

Geslaagd, verstuurd via eBox én papier

JSON
{
  "status": "SUCCESS",
  "eboxMessageId": "AB12345678",
  "eboxExpirationDate": "2025-12-31T00:00:00Z",
  "paperMessageId": "PP98765432",
  "paperExpirationDate": "2025-12-31T00:00:00Z"
}

Geslaagd, maar met een consent-waarschuwing

JSON
{
  "status": "WARNING",
  "eboxMessageId": "AB12345678",
  "eboxExpirationDate": "2025-12-31T00:00:00Z",
  "consentMessage": "De ontvanger heeft geen actieve toestemming voor eBox."
}

Mislukt (bijvoorbeeld te grote bijlage)

JSON
{
  "status": "ERROR",
  "errorMessage": "Max file size for all attachments is 7 MB."
}

Error-handling

In tegenstelling tot de klassieke SOAP-MAGDA-diensten (Persoon, Gezin, ...) werkt deze functie niet met een aparte Uitzonderingen-lijst die een BpmnError vereist. In de meeste gevallen krijg je gewoon een geldig antwoord terug met status = ERROR, dat je zelf moet controleren.

// Voorbeeld: status controleren na publishMessage
MdsPublishMessageResponse response = mds.publishMessage(execution);

if ("ERROR".equals(response.getStatus())) {
    throw new BpmnError("MDS_PUBLICATIE_MISLUKT", response.getErrorMessage());
}

if ("WARNING".equals(response.getStatus())) {
    // Bericht is verstuurd, maar met een consent-waarschuwing - eventueel loggen
    LOGGER.warn("MDS consent-waarschuwing: {}", response.getConsentMessage());
}

getMessageStatusEBox

Check voor een verstuurd bericht of de ontvanger deze gelezen heeft of niet. Zie service task template ‘Haal verzendstatus op voor eBox’.

Workflow expression

${mds.getMessageStatusEBox(String messageId, String eboxType, String eboxIdValue)}

Java-code

EBoxMessageStatus status = mds.getMessageStatusEBox(messageId, eboxType, eboxIdValue);

Input

Inputparameters

Data type

Voorbeeld

Uitleg

messageId

String

${mdsPublishMessage.eboxMessageId}

Id van het eBox-bericht — haal je uit de respons van publishMessage

eboxType

String

'CITIZEN'

CITIZEN of ENTERPRISE

eboxIdValue

String

'85010212345'

INSZ of KBO-nummer van de ontvanger

Output

Je krijgt een EBoxMessageStatus-object terug met:

  • messageId — het opgevraagde bericht-ID;

  • eboxId (eboxType, eboxIdValue) — bevestiging van de ontvanger;

  • expirationDate — de vervaldatum van het bericht in eBox;

  • readStatus (boolean) — geeft aan of de hoofdinhoud door de ontvanger geopend is (standaard false)

  • visible — of het bericht nog zichtbaar is (wordt false na de vervaldatum);

  • statuses (optioneel) — extra detail bij een gelezen bericht: id ("200"), status ("Read"), updated (moment van eerste lezing).

Belangrijke nuance: in tegenstelling tot wat je zou verwachten, is readStatus niet enkel bij een reeds-gelezen bericht aanwezig — het staat er altijd bij, met standaardwaarde false. Enkel het statuses-blok (met de leesdatum) komt er pas bij zodra het bericht effectief gelezen is.

Gepseudonimiseerd voorbeelden:

Nog niet gelezen

JSON
{
  "objectType": "EBoxMessageStatus",
  "messageId": "AB12345678",
  "eboxId": {
    "eboxType": "CITIZEN",
    "eboxIdValue": "85010212345"
  },
  "expirationDate": "2025-12-31T00:00:00.000Z",
  "readStatus": false,
  "visible": true
}

Gelezen

JSON
{
  "objectType": "EBoxMessageStatus",
  "messageId": "AB12345678",
  "eboxId": {
    "eboxType": "CITIZEN",
    "eboxIdValue": "85010212345"
  },
  "expirationDate": "2025-12-31T00:00:00.000Z",
  "readStatus": true,
  "visible": true,
  "statuses": [
    {
      "id": "200",
      "status": "Read",
      "updated": "2025-06-12T14:32:00.000Z"
    }
  ]
}

Error-handling

Deze functie gebruikt HTTP-statuscodes, geen klassieke MAGDA-Uitzonderingen-lijst.

HTTP-status

Betekenis

400

Invalid data supplied

401

Invalid authorization

404

Messages not found

500

Unexpected Server Error

502

Bad Gateway

503

Service unavailable

504

Gateway Timeout

In onze Java-code (MDSCamundaConnector.getMessageStatusEBox) wordt elke fout (een HTTP-foutstatus, maar ook een onverwacht leeg antwoord) omgezet naar een MDSException:

// Voorbeeld: MDSException opvangen
try {
    EBoxMessageStatus status = mds.getMessageStatusEBox(messageId, eboxType, eboxIdValue);
    if (Boolean.TRUE.equals(status.getReadStatus())) {
        // bericht is gelezen
    }
} catch (MDSException e) {
    throw new BpmnError("MDS_STATUSOPVRAAG_EBOX_MISLUKT", e.getErrorMessage());
}

Kanttekening: als het antwoord van MDS onverwacht leeg is (geen responseMessage, of een lege messageStatuses-lijst), gooit de connector zelf al een MDSException ("Empty response or response messsage." / "Empty response - no message statuses returned for ..."), nog vóór er sprake is van een HTTP-foutstatus. Bij dat laatste scenario wordt, indien aanwezig, ook een eventuele consent-waarschuwing uit de X-Magda-Exceptions-header gelogd (maar niet in de exceptie zelf meegegeven).

Bij een fout krijg je een RFC 7807-achtige body terug (title, status, detail, instance — laatste is het correlatie-ID, te vermelden bij contact met de MAGDA helpdesk):

JSON
{
    "title": "Unexpected Server Error",
    "detail": "Failed to persist the file",
    "instance": "b45754d6-e1a6-4c88-b089-c529825d9e6c"
}

getMessageStatusPaper

Check voor een verstuurd bericht of de ontvanger deze gelezen heeft of niet. Zie service task template ‘Haal verzendstatus op voor papier’.

Workflow expression

${mds.getMessageStatusPaper(String messageId)}

Java-code

PaperMessageStatus status = mds.getMessageStatusPaper(messageId);

Input

Inputparameters

Data type

Voorbeeld

Uitleg

messageId

String

${mdsPublishMessage.paperMessageId}

Id van de papieren zending — haal je uit de respons van publishMessage

Output

Je krijgt een PaperOrEmailMessageStatus-object terug met:

  • messageId;

  • shippingDate — datum waarop de printpartner meldde dat het bericht bij bpost afgeleverd werd (enkel gevuld in status SENT);

  • mailId — id van bpost (enkel bij status SENT);

  • trackAndTraceUri — enkel aanwezig als het een aangetekende zending is, met een gekende postcode én een mailId;

  • statuses[].status — met deze mogelijke waarden: Pending, Processing, Printed, Sent (eindstatus), Cancelled (uitgestelde papieren zending die niet meer nodig was omdat het eBox-bericht tijdig gelezen werd), Error (niet-fatale fout, wordt proactief opgevolgd door het MAGDA-team), Failed (fatale fout, eindstatus).

Nuttige nuance over Cancelled: dit bevestigt een interessant automatisch mechanisme bij deliveryType = PAPER_AND_EBOX — als de ontvanger het eBox-bericht op tijd leest, wordt de papieren verzending simpelweg geannuleerd in plaats van toch nog verstuurd te worden.

Gepseudonimiseerd voorbeeld:

JSON
{
  "objectType": "PaperOrEmailMessageStatus",
  "messageId": "PP98765432",
  "shippingDate": "2025-06-10T16:01:43.000Z",
  "mailId": "010541288500452621900095554841",
  "trackAndTraceUri": "https://track.bpost.cloud/btr/web/#/search?lang=en&itemCode=010541288500452621900095554841&postalCode=1700",
  "statuses": [
    { "id": "200", "status": "Sent" }
  ]
}

Error-handling

Zelfde HTTP-statuscodes en foutstructuur als bij getMessageStatusEBox (beide lopen via hetzelfde /messages/statusRequest-eindpunt, enkel met een ander deliveryChannel).

HTTP-status

Betekenis

400

Invalid data supplied

401

Invalid authorization

404

Messages not found

500

Unexpected Server Error

502

Bad Gateway

503

Service unavailable

504

Gateway Timeout

In onze Java-code (MDSCamundaConnector.getMessageStatusPaper) wordt elke fout — een HTTP-foutstatus, maar ook een onverwacht leeg antwoord — omgezet naar een MDSException:

// Voorbeeld: MDSException opvangen
try {
    PaperMessageStatus status = mds.getMessageStatusPaper(messageId);
    String currentStatus = status.getStatuses().get(0).getStatus();
    if ("Failed".equals(currentStatus)) {
        throw new BpmnError("MDS_PAPIEREN_ZENDING_MISLUKT", "Fatale fout bij papieren zending: " + messageId);
    }
    if ("Cancelled".equals(currentStatus)) {
        // Uitgestelde papieren zending was niet nodig - eBox-bericht werd tijdig gelezen
    }
} catch (MDSException e) {
    throw new BpmnError("MDS_STATUSOPVRAAG_PAPER_MISLUKT", e.getErrorMessage());
}

Kanttekening: in tegenstelling tot getMessageStatusEBox wordt hier bij een leeg antwoord geen enkele poging gedaan om een eventuele X-Magda-Exceptions-header te loggen. De code gaat hier meteen naar de generieke MDSException(EMPTY_RESPONSE).