← For Dutch municipalities

Zaakgericht werken (ZGW APIs)

A gemeente keeps its case files (zaken) in a zaaksysteem, not in mailboxes. Goooy files mail, attachments and documents into a zaak through the VNG ZGW APIs: Zaken API 1.5 and Documenten API 1.4, as Open Zaak and other ZGW-compliant systems serve them.

Connecting

Admin → Archive → Zaaksysteem (ZGW APIs):

Field Meaning
Zaken API e.g. https://openzaak.gemeente.nl/zaken/api/v1
Documenten API e.g. https://openzaak.gemeente.nl/documenten/api/v1
Client ID + secret The application registered in the zaaksysteem’s autorisaties (ZGW JWT, HS256). The secret is stored sealed and never returned.
RSIN The bronorganisatie: 9 digits, checked with the 11-proef.
Document type The Catalogi API URL of the informatieobjecttype filed items get.

Test connection lists the open zaken the client may see. In the zaaksysteem, give the application these autorisaties, for the zaaktypen and the document type concerned:

Scope For
zaken.lezen finding a zaak and checking it is still open
zaken.bijwerken relating a document to the zaak (zaakinformatieobject)
documenten.aanmaken storing the document
documenten.bijwerken, documenten.lock a document above 1 MiB, which goes up in parts
documenten.verwijderen removing a document again when relating it fails

Exactly this set is what the Open Zaak drill below grants, so it is known to be enough for Open Zaak 1.31.

The URLs must be https:// and may not point at a private address (the same guard as the other connectors); with DATA_RESIDENCY=eu-strict the host must be on the allow-list.

Filing

  • Mail: the reading pane’s More menu → File in zaak…. Choose the zaak and what to file: the message itself (as .eml, with headers and attachments) and any of its attachments separately.
  • Files: select a file → details pane → Zaak → File in zaak….
  • Find a zaak by its number (exact), or by a word from its description among the 50 most recently started open zaken of your bronorganisatie. A closed zaak can’t be chosen.

Each item becomes an enkelvoudiginformatieobject (titel, bestandsnaam, formaat, auteur = your name, taal nld, the configured document type, the bytes as inhoud) and is related to the zaak with a zaakinformatieobject. Every request carries a JWT naming the client and you (user_id = your address, user_representation = your name), so the zaaksysteem’s audit trail shows who did it. Quarantined attachments and items over 20 MB are refused.

A document above 1 MiB is stored in parts (bestandsdelen, Documenten API 1.1+): Open Zaak refuses a JSON body over 2.5 MiB, which a document sent inline as base64 reaches at about 1.9 MiB. Titles, names and descriptions are cut to the zaaksysteem’s lengths by whole characters, so an emoji is never split. When the document is stored but can’t be related to the zaak (for instance because the zaak was closed in the meantime), it is deleted from the zaaksysteem again and you see why.

Afterwards the message or file shows the zaak number (“Zaak ZAAK-2026-0001”), and the filing is in the audit trail (zaak.file).

Limits

  • One direction. Goooy files into the zaak; documents added in the zaaksysteem don’t appear in Goooy, and a document edited later in Goooy is not updated in the zaak (file it again).
  • Items over 20 MB go in through the zaaksysteem itself.
  • One document type for everything filed; per-zaaktype types from the Catalogi API are not offered.
  • No Flows action or automatic filing yet (e.g. every mail to a shared mailbox about a zaak number).
  • Tested against Open Zaak 1.31.0 (below), not yet against a gemeente’s own installation or another ZGW implementation.

API

  • GET /zaken/status, GET /zaken?q=, GET /zaken/links?messageId=|fileId=, POST /zaken/links {zaakUrl, sourceType: MESSAGE|ATTACHMENT|FILE, sourceId, messageId?, owner?, titel?}.
  • Admin: GET|PUT /admin/zaaksysteem, POST /admin/zaaksysteem/checks.

Regression

  • apps/api/test/smoke-zaak.mjs (31 checks, in run-all.mjs): runs its own API and a mock ZGW server that checks the JWT signature and claims, the CRS headers, the required document fields and that zaak and document exist before relating them, and copies what the real Open Zaak does: the 2.5 MiB body limit, the upload in parts under a lock, refusing a split emoji, and ZaakClosed. Covers the connection (RSIN check, write-only secret, test with a wrong and a right secret), search, filing a message, an attachment, a file and a 3 MiB file, a zaak closed during filing, the refusals, the links and the audit entries.
  • npm run test:openzaak (scripts/openzaak-drill.sh, apps/api/test/smoke-openzaak.mjs, 21 checks): the same against a real Open Zaak 1.31.0 in Docker, with a client that has only the scopes above. Every filing is read back from Open Zaak: the bytes, the metadata, the relation to the zaak and Open Zaak’s own audit trail, which names the Goooy user for each filing.
  • apps/web/e2e/zaak.spec.ts: filing from the Files details pane (live page, /zaken intercepted, axe).