Een app koppelen
Een app van een dataontvanger praat alleen met de gateway van de eigen connector. Wat de dataspace verder vraagt, doet de connector: laten zien dat je organisatie lid is, de overeenkomst sluiten, de levering starten, het toegangstoken geldig houden en elk verzoek tekenen. Je app roept een gewone HTTP-API aan, met een eigen sleutel.
Drie begrippen
Section titled “Drie begrippen”- Abonnement. Lopende toegang tot één product van een rechthebbende, onder één overeenkomst. Je
krijgt het als de rechthebbende je aanvraag goedkeurt. Elk abonnement heeft een alias, en daarmee
een basis-URL:
{gateway}/{alias}. Je kunt twee abonnementen op hetzelfde product hebben, bijvoorbeeld een om te lezen en een om te sturen. - App. Een applicatie die data ophaalt, met een naam, de abonnementen die hij mag gebruiken, een permissie (Lezen of Lezen en sturen) en een of meer sleutels. Vergelijk het met een fine-grained personal access token op GitHub.
- Sleutel. Het geheim waarmee een app de gateway aanroept. Een sleutel hoort bij precies één app.
Een app krijgt nooit meer dan de overeenkomst toestaat. Wat hij mag, is de doorsnede van de app en het abonnement: een app met Lezen en sturen leest alleen bij een abonnement dat alleen lezen toestaat. De gateway controleert de app; de rechthebbende en de datahouder controleren de overeenkomst.
Een verzoek
Section titled “Een verzoek”De app zet achter de basis-URL van een abonnement het pad van de API van de datahouder. Voor gebouwdata is dat het Buildinglinks-protocol, met het gebouw als BAG-id in het pad. Alles na de alias gaat ongewijzigd door.
GET /gateway/rtm-01/v1/buildings/nl.bag.pand.0599100000701251/points/valuesHost: dataplane.intern:8090Authorization: Bearer <sleutel van de app>De gateway accepteert de sleutel ook in de header X-Api-Key. Hij controleert dan:
- de sleutel, en of zijn app dit abonnement mag gebruiken en, bij een schrijfactie, mag sturen;
- of het abonnement actief is.
Daarna zet hij het toegangstoken van de levering erbij, tekent hij het verzoek met de sleutel van je data plane en stuurt hij het naar de data plane van de datahouder. Die controleert het token, de overeenkomst, het gebouw en de punten, en stuurt het verzoek door naar het systeem. Het antwoord komt ondertekend terug; de gateway controleert die handtekening en geeft het antwoord door aan de app.
De app kent dus geen Dataspace Protocol, DID’s of lidmaatschapsbewijzen. Hij ziet het toegangstoken nooit, en kent het adres en de sleutel van het systeem van de datahouder niet.
TechnischWat de gateway toevoegt
Naar de data plane van de datahouder gaat hetzelfde verzoek, op
{data plane van de datahouder}/public/v1/buildings/…. De gateway vervangt de sleutel van de app
door twee headers:
Authorization: Bearer <toegangstoken>: een JWT van de data plane van de datahouder, met onder meer de levering en de overeenkomst. Het is een uur geldig. Verloopt het binnen 30 seconden, dan vraagt de gateway bij het volgende verzoek eerst een nieuw aan bij/tokenvan de datahouder, met een verklaring die hij tekent met de sleutel van je data plane.BL-Request-Signature: een JWS van je data plane over methode, pad, query, de SHA-256 van de body en de levering. De datahouder accepteert elke handtekening één keer, en alleen als hij minder dan 60 seconden oud is.
Het antwoord draagt BL-Response-Signature, een JWS van de datahouder over de hash van de
handtekening op het verzoek, de status en de SHA-256 van de body. De gateway controleert die tegen het
DID-document van wie levert, ook als dat een andere partij is dan de rechthebbende.
Fouten
Section titled “Fouten”Fouten van de gateway en van de data plane van de datahouder hebben één vorm, zodat de app één foutmodel heeft:
{ "error": { "code": "upstream_unavailable", "message": "…", "retryable": true } }| Status | Code | Betekenis |
|---|---|---|
401 |
unauthenticated |
geen sleutel, of een onbekende |
403 |
forbidden |
de app mag dit abonnement niet gebruiken of mag niet sturen, of de datahouder weigert het verzoek (buiten de overeenkomst) |
503 |
upstream_unavailable |
het abonnement is niet actief, bijvoorbeeld gepauzeerd; retryable: true |
502 |
upstream_unavailable |
de data plane van de datahouder is niet bereikbaar of gaf een ongeldig antwoord |
503 |
evidence_unavailable |
een schrijfactie kon niet worden vastgelegd en is dus niet verstuurd |
Een fout van het systeem van de datahouder zelf, zoals point_not_writable of rate_limited, geeft
de gateway ongewijzigd door, met de status die het systeem gaf.
Lezen en sturen
Section titled “Lezen en sturen”Lezen is een GET. Alles wat iets verandert, zoals een POST met setpoints of een PATCH van de
fallback-policy, is een schrijfactie. Een schrijfactie komt alleen door als je app Lezen en sturen
heeft én de overeenkomst sturen toestaat. Een aanvraag om te sturen keurt de rechthebbende altijd zelf
goed.
Een overeenkomst die sturen toestaat, vraagt standaard ondertekende verzoeken. De gateway legt een schrijfactie dan vast voordat hij hem verstuurt, en de data plane van de datahouder doet hetzelfde voordat het systeem iets met het verzoek doet. Een antwoord zonder geldige handtekening van de datahouder geeft de gateway dan niet door aan de app; alleen een foutmelding van de controles van de datahouder zelf komt ongetekend door, want die bevat geen data. Het systeem antwoordt op een schrijfactie met een ontvangstbevestiging; hoe die eruitziet, staat bij een backend koppelen.
POST /gateway/rtm-01/v1/buildings/nl.bag.pand.0599100000701251/setpointsAuthorization: Bearer <sleutel van de app>Content-Type: application/json
{ "issued_at": "2026-09-29T10:00:00Z", "valid_until": "2026-09-29T10:05:00Z", "idempotency_key": "rtm-01-42", "setpoints": [{ "point_id": "9b41d0aa", "value": 21.5 }]}Geef een schrijfactie een idempotentiesleutel en een geldigheid mee. Dan kan je app een verzoek na een time-out veilig herhalen, en voert het systeem een verouderde opdracht niet meer uit. Stel ook een fallback-policy in, zodat het gebouw terugvalt op veilige waarden als je app stilvalt.
Instellen in de beheeromgeving
Section titled “Instellen in de beheeromgeving”- Toegang aanvragen. Zoek onder Data zoeken het product dat je nodig hebt en vraag toegang aan, met de voorwaarde die past (lezen, of lezen en sturen). Na goedkeuring door de rechthebbende heb je een abonnement. Heb je als rechthebbende een datahouder aangewezen, dan hoeft dat niet: bij elke aanwijzing maakt je connector zelf een abonnement op je eigen data.
- Een app maken. Kies onder Apps Nieuwe app. Geef een naam, kies de abonnementen en de permissie. Kies Alle abonnementen, ook later alleen bewust: zo’n app krijgt ook abonnementen die er later bij komen, en met Lezen en sturen kan hij daar ook sturen.
- De sleutel bewaren. De sleutel wordt één keer getoond; de connector bewaart alleen een hash. Zet hem in de geheimen van je app.
- De basis-URL gebruiken. Op de pagina van een abonnement staat onder Gebruiken in een app de basis-URL, met de apps die het abonnement al hebben.
- Testen. Daar staat ook Verbinding testen: één leesverzoek door de hele keten, zoals je app het doet. Testen kan iemand met de rol operator of admin. Gaat het mis, dan zegt de test waar: bij je eigen data plane, bij de datahouder, bij de overeenkomst of bij het systeem erachter.
Een app maken, wijzigen en verwijderen kan iemand met de rol operator of admin; een viewer kijkt mee. Elke wijziging komt in het auditlog.
Sleutels verlopen niet. Een verplichte vervaldatum is bij een app die dag en nacht draait een storing die wacht om te gebeuren. Wissel een sleutel zonder onderbreking: maak een tweede sleutel, zet die in je app en verwijder daarna de oude. Een sleutel die 90 dagen niet is gebruikt, en een nieuw abonnement dat nog bij geen app hoort, staan op de startpagina onder Signalen.
TechnischHetzelfde via de beheer-API
Met een API-sleutel voor de beheer-API (Authorization: Bearer) maak je abonnementen en apps ook
automatisch aan. De deelnemers vind je met GET /api/v1/dataspace/participants, hun catalogus met
GET /api/v1/dataspace/catalog?participant=<DID>.
POST /api/v1/connectionsContent-Type: application/json
{ "alias": "rtm-01", "provider_did": "did:web:…", "dataset_id": "…", "offer_id": "…"}Het antwoord is 202 met het abonnement in de status negotiating; de connector werkt op de
achtergrond verder. De alias bestaat uit 2 tot 63 kleine letters, cijfers of koppeltekens, en begint
met een letter of cijfer.
POST /api/v1/appsContent-Type: application/json
{ "name": "Rapportage", "subscriptions": ["rtm-01"], "write": false }Het antwoord bevat de eerste sleutel, één keer. subscriptions: null geeft alle abonnementen, ook
latere; laat je het veld weg, dan krijgt de app geen enkel abonnement. Een extra sleutel maak je met
POST /api/v1/apps/{id}/keys.
| Verzoek | Wat het doet |
|---|---|
GET /api/v1/connections/{alias} |
één abonnement, met de status en de foutmelding als er iets mis is |
POST /api/v1/connections/{alias}/test |
de verbindingstest |
POST /api/v1/connections/{alias}/retry |
opnieuw aanvragen na failed, expired of terminated |
DELETE /api/v1/connections/{alias} |
opzeggen: de levering en de overeenkomst eindigen; een abonnement op je eigen data eindigt alleen met zijn aanwijzing |
Als de toegang stopt
Section titled “Als de toegang stopt”De gateway geeft alleen verzoeken door voor een abonnement dat actief is. In alle andere gevallen
krijgt je app 503 met retryable: true, en de status van het abonnement zegt waarom. De
beheeromgeving toont een abonnement als Nog niet actief, Loopt, Gepauzeerd of Beëindigd; de
beheer-API geeft de status preciezer:
| Status in de API | Wat er gebeurt |
|---|---|
negotiating |
de connector vraagt de toegang aan |
awaiting_approval |
de rechthebbende beoordeelt de aanvraag; zonder besluit verloopt ze na de termijn van de rechthebbende, standaard 7 dagen |
transferring |
de overeenkomst is gesloten; de connector start de levering |
active |
de gateway geeft verzoeken door |
suspended |
de levering staat tijdelijk stil, en wordt weer actief als ze hervat |
failed, expired, terminated |
er komt niets meer; de reden staat bij het abonnement |
Toegang stopt op een van deze manieren:
- De rechthebbende trekt de toegang in. Dat is blijvend, met een reden. De levering eindigt.
- De overeenkomst loopt af. De rechthebbende toetst de voorwaarden bij elke nieuwe levering en daarna elke minuut zolang de levering loopt. Is de einddatum voorbij, dan eindigt de levering.
- Je lidmaatschap eindigt. Schorst de Trust Authority je organisatie, dan trekt ze je lidmaatschapsbewijs in. Rechthebbenden kijken elke minuut in het register en beëindigen leveringen aan wie geen actief lid meer is.
- De datahouder levert niet meer. Eindigt de aanwijzing achter een levering, dan weigert de data plane van de datahouder vanaf dat moment je verzoeken en een nieuw toegangstoken. Hij stopt de levering en meldt dat aan de rechthebbende, die haar beëindigt.
- Je zegt zelf op. Met Opzeggen eindigen de levering en de overeenkomst eronder.
Een abonnement dat is beëindigd (failed, expired of terminated), kun je opnieuw aanvragen. De connector
onderhandelt dan een nieuwe overeenkomst en houdt dezelfde alias, dus de basis-URL in je app blijft
gelijk. De oude overeenkomst eindigt daarbij.