POC IZNC - Integrated Care Network Communication
0.1.2 - ci-build
POC IZNC - Integrated Care Network Communication - Local Development build (v0.1.2) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
| Page standards status: Draft |
⚠️ STATUS: DRAFT - FOR REVIEW
This specification is currently in draft status and is open for review and feedback. Implementation details may change based on community input and practical experience.
Author: roland@headease.nl
This document is released under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.
RESTful API exposed by the Matrix Bridge that the Chat Application Backend calls to interact with Matrix messaging.
Identity Model:
The Matrix Bridge handles the translation between this API and the underlying Matrix protocol.
┌──────────────────────────────────────────┐
│ Chat Application Backend │
│ - DigID authentication (BSN) │
│ - User session management │
│ - Frontend WebSocket connections │
│ - Webhook endpoint for events │
└──────────────────┬──────────────────┬────┘
│ ▲
│ REST API (calls) │ Webhooks (pushed)
│ │
▼ │
┌──────────────────────────────────────────┐
│ Matrix Bridge API (NEW) │
│ - BSN-based user discovery │
│ - Care network/thread management │
│ - Message operations │
│ - Subscription management │
│ - Event notification via webhooks │
└──────────────────┬───────────────────────┘
│ Matrix Protocol
▼
┌───────────────────────┐
│ Matrix Homeserver │
│ (Synapse) │
└───────────────────────┘
BSN is NOT used for routine operations. Per the NUTS Instant Communication specification:
User DigID login → BSN obtained
↓
Chat Backend stores BSN in user session
↓
Chat Backend calls Matrix Bridge with BSN
↓
Matrix Bridge checks internal mapping: BSN → Matrix user ID?
↓
NO → Matrix Bridge creates: @iznc_{hash}:homeserver.example.com
Matrix Bridge stores mapping (encrypted): BSN ↔ Matrix user ID
↓
YES → Matrix Bridge uses existing Matrix user ID
↓
Matrix Bridge performs operation using Matrix user ID
↓
Matrix Bridge returns result (no Matrix user ID exposed)
supplier-a.example.com)supplier-b.example.com)@iznc_user:supplier-a.example.com and @iznc_user:supplier-b.example.comNote: All endpoints accept BSN in the request body. Matrix Bridge handles BSN → Matrix user ID resolution internally.
POST /api/v1/care-networks/discover
Purpose: Discover care networks (Matrix spaces) for the organizations (URA) that the user is involved with. Typically returns one care network per URA, but technically multiple networks per URA are possible.
Request:
{
"uras": ["90000001", "90000002"],
"userBsn": "123456789"
}
Request Fields:
uras: List of URA numbers (zorgorganisatie identificatie) that the user is involved withuserBsn: BSN of the user requesting access (for authorization)Response:
{
"careNetworks": [
{
"careNetworkId": "!space123:homeserver.example.com",
"ura": "90000001",
"organizationName": "Ziekenhuis Voorbeeld",
"name": "Zorgnetwerk Jan Jansen - Ziekenhuis Voorbeeld",
"subject": {
"matrixUserId": "@iznc_abc123def:homeserver.example.com",
"name": "Jan Jansen",
"role": "patient"
},
"participants": [
{
"matrixUserId": "@iznc_abc123def:homeserver.example.com",
"name": "Jan Jansen",
"role": "patient"
},
{
"userId": "@marie.jansen:homeserver.example.com",
"name": "Marie Jansen",
"role": "mantelzorger"
},
{
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith",
"role": "care-professional",
"uziNumber": "12345678"
}
],
"createdAt": "2025-01-15T10:00:00Z",
"threadCount": 5,
"unreadCount": 2
},
{
"careNetworkId": "!space456:homeserver.example.com",
"ura": "90000002",
"organizationName": "Huisartsenpraktijk De Hof",
"name": "Zorgnetwerk Jan Jansen - De Hof",
"subject": {
"matrixUserId": "@iznc_abc123def:homeserver.example.com",
"name": "Jan Jansen",
"role": "patient"
},
"participants": [
{
"matrixUserId": "@iznc_abc123def:homeserver.example.com",
"name": "Jan Jansen",
"role": "patient"
},
{
"userId": "@dr.jones:homeserver.example.com",
"name": "Dr. Jones",
"role": "care-professional",
"uziNumber": "87654321"
}
],
"createdAt": "2025-01-14T09:00:00Z",
"threadCount": 3,
"unreadCount": 0
}
]
}
Response Fields:
careNetworks: Array of care networks (typically one per URA, but multiple per URA is possible)ura: The URA number this care network is associated withorganizationName: Name of the care organizationBackend Action:
@iznc_{hash}:homeserver.example.comPOST /api/v1/subscriptions
Purpose: Create a subscription to receive real-time events for a care network. Similar to FHIR subscriptions.
Request:
{
"bsn": "123456789",
"careNetworkId": "!space123:homeserver.example.com",
"webhookUrl": "https://chat-backend.example.com/webhooks/events",
"events": ["message.new", "message.read", "thread.new", "participant.joined"]
}
Response:
{
"subscriptionId": "sub-uuid-1234",
"careNetworkId": "!space123:homeserver.example.com",
"webhookUrl": "https://chat-backend.example.com/webhooks/events",
"status": "active",
"createdAt": "2025-01-15T10:30:00Z"
}
Note: Response does not include BSN for security reasons.
Backend Action:
POST /api/v1/subscriptions/search
Request:
{
"bsn": "123456789"
}
Response:
{
"subscriptions": [
{
"subscriptionId": "sub-uuid-1234",
"careNetworkId": "!space123:homeserver.example.com",
"status": "active",
"createdAt": "2025-01-15T10:30:00Z"
}
]
}
DELETE /api/v1/subscriptions/{subscriptionId}
Purpose: Remove a subscription when user logs out or care network is no longer needed.
Response:
{
"subscriptionId": "sub-uuid-1234",
"status": "deleted",
"deletedAt": "2025-01-15T12:00:00Z"
}
POST /api/v1/care-networks/{careNetworkId}/threads/search
Purpose: List all conversation threads (Matrix rooms) within a care network.
Request:
{
"bsn": "123456789"
}
Response:
{
"careNetworkId": "!space123:homeserver.example.com",
"threads": [
{
"threadId": "!room456:homeserver.example.com",
"topic": "Medicatie vraag",
"participants": [
{
"userId": "@jan.jansen:homeserver.example.com",
"name": "Jan Jansen",
"role": "patient"
},
{
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith",
"role": "care-professional"
}
],
"lastMessage": {
"text": "U kunt het innemen met of zonder voedsel",
"sender": {
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith"
},
"timestamp": "2025-01-15T11:30:00Z"
},
"unreadCount": 1,
"createdAt": "2025-01-15T10:00:00Z"
}
]
}
Backend Action:
POST /api/v1/threads
Purpose: Start a new conversation thread within a care network, targeting specific participants.
Request:
{
"initiatorBsn": "123456789",
"careNetworkId": "!space123:homeserver.example.com",
"topic": "Afspraak maken voor controle",
"participantIds": [
{ "type": "bsn", "value": "123456789" },
{ "type": "matrixUserId", "value": "@dr.smith:homeserver.example.com" }
],
"initialMessage": {
"text": "Ik wil graag een afspraak maken voor een controle"
}
}
Note: Participants can be identified by BSN (for users in the same organization) or Matrix user ID (for users from other suppliers in federated care networks).
Response:
{
"threadId": "!newroom789:homeserver.example.com",
"careNetworkId": "!space123:homeserver.example.com",
"topic": "Afspraak maken voor controle",
"participants": [
{
"userId": "@jan.jansen:homeserver.example.com",
"name": "Jan Jansen"
},
{
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith"
}
],
"createdAt": "2025-01-15T12:00:00Z",
"initialMessageId": "$msg123"
}
Backend Action:
POST /api/v1/threads/{threadId}/messages/search
Purpose: Retrieve message history for a conversation thread.
Request:
{
"bsn": "123456789",
"limit": 50,
"before": "$event123",
"after": "$event456"
}
Request Fields:
bsn: User BSN (required)limit: Number of messages to return (optional, default: 50)before: Event ID to paginate before (optional)after: Event ID to paginate after (optional)Response:
{
"threadId": "!room456:homeserver.example.com",
"messages": [
{
"messageId": "$event123",
"sender": {
"userId": "@jan.jansen:homeserver.example.com",
"name": "Jan Jansen",
"role": "patient"
},
"text": "Kan ik deze medicatie met eten innemen?",
"attachments": [],
"timestamp": "2025-01-15T11:00:00Z",
"readBy": [
{
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith",
"timestamp": "2025-01-15T11:05:00Z"
}
],
"replyTo": null
},
{
"messageId": "$event124",
"sender": {
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith",
"role": "care-professional"
},
"text": "Ja, u kunt het innemen met of zonder voedsel",
"timestamp": "2025-01-15T11:30:00Z",
"readBy": [],
"replyTo": "$event123"
}
],
"pagination": {
"prevBatch": "t123-456",
"nextBatch": "t789-012",
"hasMore": false
}
}
Backend Action:
POST /api/v1/threads/{threadId}/messages
Request:
{
"senderBsn": "123456789",
"text": "Dank voor de informatie",
"attachments": [
{
"filename": "recept.pdf",
"contentType": "application/pdf",
"data": "base64-encoded-data"
}
],
"replyTo": "$event124"
}
Note: Sender identified by BSN.
Response:
{
"messageId": "$event125",
"threadId": "!room456:homeserver.example.com",
"sender": {
"userId": "@jan.jansen:homeserver.example.com",
"name": "Jan Jansen"
},
"text": "Dank voor de informatie",
"timestamp": "2025-01-15T11:45:00Z",
"status": "sent"
}
Backend Action:
POST /api/v1/threads/{threadId}/read
Request:
{
"bsn": "123456789",
"lastReadMessageId": "$event124"
}
Response:
{
"threadId": "!room456:homeserver.example.com",
"lastReadMessageId": "$event124",
"timestamp": "2025-01-15T11:50:00Z"
}
Backend Action:
GET /api/v1/users/{userId}
Response:
{
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith",
"role": "care-professional",
"uziNumber": "12345678",
"email": "dr.smith@hospital.nl",
"avatarUrl": "mxc://homeserver.example.com/avatar123"
}
The Matrix Bridge pushes events to the Chat Application Backend via webhooks configured in subscriptions.
All webhook POSTs have this structure:
{
"subscriptionId": "sub-uuid-1234",
"eventType": "message.new",
"careNetworkId": "!space123:homeserver.example.com",
"timestamp": "2025-01-15T12:00:00Z",
"data": {
// Event-specific data
}
}
{
"subscriptionId": "sub-uuid-1234",
"eventType": "message.new",
"careNetworkId": "!space123:homeserver.example.com",
"timestamp": "2025-01-15T12:00:00Z",
"data": {
"threadId": "!room456:homeserver.example.com",
"messageId": "$event125",
"sender": {
"userId": "@dr.smith:homeserver.example.com",
"name": "Dr. Smith"
}
}
}
Action: Chat Application Backend should:
GET /api/v1/threads/{threadId}/messages{
"subscriptionId": "sub-uuid-1234",
"eventType": "message.read",
"careNetworkId": "!space123:homeserver.example.com",
"timestamp": "2025-01-15T12:05:00Z",
"data": {
"threadId": "!room456:homeserver.example.com",
"messageId": "$event124",
"reader": {
"userId": "@jan.jansen:homeserver.example.com",
"name": "Jan Jansen"
}
}
}
Action: Chat Application Backend should:
{
"subscriptionId": "sub-uuid-1234",
"eventType": "thread.new",
"careNetworkId": "!space123:homeserver.example.com",
"timestamp": "2025-01-15T12:10:00Z",
"data": {
"threadId": "!newroom789:homeserver.example.com",
"topic": "Nieuwe vraag over medicatie",
"creator": {
"userId": "@jan.jansen:homeserver.example.com",
"name": "Jan Jansen"
}
}
}
{
"subscriptionId": "sub-uuid-1234",
"eventType": "participant.joined",
"careNetworkId": "!space123:homeserver.example.com",
"timestamp": "2025-01-15T12:15:00Z",
"data": {
"threadId": "!room456:homeserver.example.com",
"participant": {
"userId": "@nurse.jones:homeserver.example.com",
"name": "Verpleegkundige Jones"
}
}
}
All endpoints use standard HTTP status codes and return errors in this format:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "No user found with BSN 123456789",
"details": {
"bsn": "123456789"
}
}
}
Error Codes:
USER_NOT_FOUND: BSN cannot be resolved to Matrix userCARE_NETWORK_NOT_FOUND: Care network (space) does not existTHREAD_NOT_FOUND: Thread (room) does not existACCESS_DENIED: User does not have access to resourceINVALID_BSN: BSN format is invalidSUBSCRIPTION_NOT_FOUND: Subscription ID does not existWEBHOOK_FAILED: Failed to deliver webhook notificationThe Matrix Bridge maintains an encrypted database mapping between BSN and Matrix user IDs:
@iznc_{hash}:homeserver.example.comA care network is represented as:
#careteam/{careTeamId}:homeserver.example.comStatus: Extension to Matrix Specification
This POC introduces a URA-based discovery mechanism for care networks that is not currently part of the Matrix specificatie instante netwerk communicatie:
Current Matrix Spec:
POC Extension:
POST /api/v1/care-networks/discover with URA identifiers in request bodyRationale:
Future Actions: