๐Ÿ“‘ NVI โ€” Nationale Verwijs Index

Lokalisatiedienst op basis van pseudoniemen. Vereist: mTLS รฉn een OAuth-token voor https://nvi.proeftuin.gf.irealisatie.nl.

Overzicht ๐Ÿ“œ mTLS ๐Ÿ”‘ OAuth ๐Ÿ‘ค PRS ๐Ÿ“‘ NVI

NVI โ€” Nationale Verwijs Index

De Nationale Verwijs Index slaat op welke zorgaanbieder betrokken is bij een persoon, zonder dat het BSN of het definitieve pseudoniem ooit in de NVI terechtkomt. In plaats daarvan stuurt de client de ruwe uitvoer van de PRS (jwe + blind_factor) rechtstreeks naar de NVI โ€” de NVI berekent het pseudoniem intern via de OPRF-unblindingstap. Elke aanvraag vereist mTLS รฉn een geldig OAuth-token.

Lokalisatie registreren (POST /NVIDataReference)

Registreer een lokalisatie door een NVIDataReference-resource te sturen. De subject.value bevat de JWE die je van de PRS hebt ontvangen; oprfKey is de base64-gecodeerde blind_factor uit stap 1 van het OPRF-protocol. De NVI gebruikt beide waarden intern om het pseudoniem te berekenen. Vereist OAuth-scope: epd:write.

Geldige careContext-codes

MedicationAgreement  ยท  LaboratoryTestResult  ยท  Encounter  ยท  Procedure  ยท  Condition  ยท  AllergyIntolerance  ยท  ImagingStudy

curl -s -X POST \
  --cert client-uzi-chain.crt \
  --key  client-uzi.key \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/fhir+json" \
  -d '{
    "resourceType": "NVIDataReference",
    "source": {
      "system": "urn:oid:2.16.528.1.1007.3.3",
      "value": "<custodian-ura>"
    },
    "careContext": {
      "coding": [{
        "system": "https://nvi.proeftuin.gf.irealisatie.nl/fhir/CodeSystem/care-context-type",
        "code":   "<code>"
      }]
    },
    "subject": {
      "system": "https://nvi.proeftuin.gf.irealisatie.nl/fhir/NamingSystem/nvi-pseudonym",
      "value":  "<jwe>"
    },
    "oprfKey": "<base64-blind-factor>"
  }' \
  https://nvi.proeftuin.gf.irealisatie.nl/NVIDataReference
// $jwe en $rawBlind komen uit pseudonymiseBsn() โ€” zie PRS-integratie
$resource = json_encode([
    'resourceType' => 'NVIDataReference',
    'source'       => [
        'system' => 'urn:oid:2.16.528.1.1007.3.3',
        'value'  => $custodianUra,
    ],
    'careContext'  => [
        'coding' => [[
            'system' => 'https://nvi.proeftuin.gf.irealisatie.nl/fhir/CodeSystem/care-context-type',
            'code'   => $code,
        ]],
    ],
    'subject'      => [
        'system' => 'https://nvi.proeftuin.gf.irealisatie.nl/fhir/NamingSystem/nvi-pseudonym',
        'value'  => $jwe,
    ],
    'oprfKey'      => base64_encode($rawBlind),
]);

[$status, $body] = curlRequest($certFile, $keyFile, 'https://nvi.proeftuin.gf.irealisatie.nl/NVIDataReference', [
    CURLOPT_POST       => true,
    CURLOPT_POSTFIELDS => $resource,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $jwtNvi,
        'Content-Type: application/json',
        'Accept: application/fhir+json',
    ],
]);
import base64, json, requests

# jwe en raw_blind komen uit de PRS OPRF-flow โ€” zie PRS-integratie
NVI_URL      = "https://nvi.proeftuin.gf.irealisatie.nl"
CUSTODIAN_URA = "<custodian-ura>"
code         = "<code>"

resource = {
    "resourceType": "NVIDataReference",
    "source": {
        "system": "urn:oid:2.16.528.1.1007.3.3",
        "value":  CUSTODIAN_URA,
    },
    "careContext": {
        "coding": [{
            "system": f"{NVI_URL}/fhir/CodeSystem/care-context-type",
            "code":   code,
        }]
    },
    "subject": {
        "system": f"{NVI_URL}/fhir/NamingSystem/nvi-pseudonym",
        "value":  jwe,
    },
    "oprfKey": base64.b64encode(raw_blind).decode(),
}

session = requests.Session()
session.cert = ("client-uzi-chain.crt", "client-uzi.key")
resp = session.post(
    f"{NVI_URL}/NVIDataReference",
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type":  "application/json",
        "Accept":         "application/fhir+json",
    },
    json=resource,
)
resp.raise_for_status()
Testdata โ€” bekende BSN met resultaten

BSN 900184590 met code MedicationRequest levert meerdere registraties op in de proeftuin en is geschikt om het opvragen te testen.

Lokalisaties opvragen (GET /v1-poc/fhir/List)

Zoek op persoon via de subject:identifier query-parameter. De waarde is een base64url-gecodeerde JSON-string die zowel de evaluated_output (JWE) als de blind_factor bevat โ€” de NVI gebruikt die twee waarden om intern het pseudoniem te berekenen en de juiste records te vinden. Vereist OAuth-scope: epd:read.

Identifier opbouwen

De identifier-waarde is: base64url( json({"evaluated_output": <jwe>, "blind_factor": base64(<rawBlind>)}) )
Let op: blind_factor gebruikt standaard Base64 (niet Base64url), evaluated_output is de JWE-string ongewijzigd.

Bouw de identifier op met PHP of Python en gebruik de waarde als query-parameter.

curl -s \
  --cert client-uzi-chain.crt \
  --key  client-uzi.key \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/fhir+json" \
  "https://nvi.proeftuin.gf.irealisatie.nl/v1-poc/fhir/List?subject:identifier=http://minvws.github.io/generiekefuncties-docs/NamingSystem/nvi-identifier|<identifier-value>"
// $jwe en $rawBlind komen uit pseudonymiseBsn() โ€” zie PRS-integratie
$json = json_encode([
    'evaluated_output' => $jwe,
    'blind_factor'     => base64_encode($rawBlind),
], JSON_UNESCAPED_SLASHES);

// base64url: geen padding, - en _ i.p.v. + en /
$identifierValue = rtrim(strtr(base64_encode($json), '+/', '-_'), '=');

$system = 'http://minvws.github.io/generiekefuncties-docs/NamingSystem/nvi-identifier';
$query  = 'subject:identifier=' . $system . '|' . $identifierValue;

[$status, $body] = curlRequest($certFile, $keyFile,
    'https://nvi.proeftuin.gf.irealisatie.nl/v1-poc/fhir/List?' . $query,
    [
        CURLOPT_HTTPGET    => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $jwtNvi,
            'Accept: application/fhir+json',
        ],
    ]
);

$bundle = json_decode($body, true);
foreach ($bundle['entry'] ?? [] as $entry) {
    $r = $entry['resource'];
    echo $r['id'] . ' โ€” code: ' . ($r['careContext']['coding'][0]['code'] ?? '?') . "\n";
}
import base64, json, requests

# jwe en raw_blind komen uit de PRS OPRF-flow โ€” zie PRS-integratie
NVI_URL = "https://nvi.proeftuin.gf.irealisatie.nl"

identifier_json = json.dumps(
    {"evaluated_output": jwe, "blind_factor": base64.b64encode(raw_blind).decode()},
    separators=(",", ":"),
)
identifier_value = base64.urlsafe_b64encode(identifier_json.encode()).rstrip(b"=").decode()

system = "http://minvws.github.io/generiekefuncties-docs/NamingSystem/nvi-identifier"
query  = f"subject:identifier={system}|{identifier_value}"

session = requests.Session()
session.cert = ("client-uzi-chain.crt", "client-uzi.key")
resp = session.get(
    f"{NVI_URL}/v1-poc/fhir/List?{query}",
    headers={
        "Authorization": f"Bearer {token}",
        "Accept":         "application/fhir+json",
    },
)
resp.raise_for_status()
bundle = resp.json()
for entry in bundle.get("entry", []):
    r = entry["resource"]
    print(r["id"], "โ€”", r.get("careContext", {}).get("coding", [{}])[0].get("code", "?"))

Optionele filters

ParameterVoorbeeldOmschrijving
codeMedicationAgreementFilter op zorgcontext-type
source:identifierurn:ietf:rfc:3986|EHR-SYS-001Filter op bronidentificatie

Lokalisatie verwijderen (DELETE /NVIDataReference/<id>)

curl -s -X DELETE \
  --cert client-uzi-chain.crt \
  --key  client-uzi.key \
  -H "Authorization: Bearer $TOKEN" \
  "https://nvi.proeftuin.gf.irealisatie.nl/NVIDataReference/<id>"
FHIR CapabilityStatement

De volledige API-beschrijving is beschikbaar via: curl https://nvi.proeftuin.gf.irealisatie.nl/fhir/metadata

← PRS ← Terug naar overzicht