Skip to main content

Sharing data automatically with other data owners

iCure allows to share data between different data owners, as explained in the guide How to share data between data owners, however this requires to perform an explicit request every time we want to share a new entity.

In some cases you may need to always share all data created by a data owner with other data-owners, for example you may want to always share all data created by a patient with their general practitioner. In these situations it may be more convenient to use the automatic-sharing feature of iCure.

note

In the following examples we use different instances of EhrLiteSDKs, to perform the requests as different users. The api we use are hcp1Api and hcp2Api to act as two different healthcare practitioners data owners (hcp1 and hcp2, respectively) and pApi to act as a patient data owner (p).

Start sharing data with another user

You can use the shareAllFutureDataWith method from the userApi to start sharing all new data the user creates with another user. This method lets you specify with whom you are sharing data and what is the kind of data you are sharing.

The following example shows how to automatically share the medical information for all new entities which will be created by hcp1 with hcp2.

info

The supported values for the kind argument of shareAllFutureDataWith are medicalInformation, administrativeInformation and all. If the kind argument is omitted, all data will be shared.

const user = await hcp1Api.userApi.shareAllFutureDataWith(
[hcp1Api.dataOwnerApi.getDataOwnerIdOf(hcp2User)],
'medicalInformation',
)
user
{
"id": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"rev": "3-b1ae24cb08f121ae1864cf8b7c61ed30",
"created": 1700058591266,
"name": "hcp1.1700058590373@icure.com",
"properties": {},
"roles": {},
"login": "hcp1.1700058590373@icure.com",
"groupId": "test-group",
"healthcarePartyId": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"sharingDataWith": {},
"email": "hcp1.1700058590373@icure.com",
"authenticationTokens": {}
}
Data creation example
const ssin = 'AAAA.BBB.1942'
const patient = await hcp1Api.patientApi.createOrModify(
new Patient({ firstName: 'John', lastName: 'Snow', ssin }),
)
const patient1 = await hcp1Api.patientApi.get(patient.id)
const patient2 = await hcp2Api.patientApi.get(patient.id)
// hcp2 can already access patient
const contentString = 'Hello world'
const observation = await hcp1Api.observationApi.createOrModifyFor(
patient.id,
new Observation({
tags: new Set([new CodingReference({ type: 'IC-TEST', code: 'TEST' })]),
localContent: mapOf({ en: new LocalComponent({ stringValue: contentString }) }),
}),
)
const observation1 = await hcp1Api.observationApi.get(observation.id)
const observation2 = await hcp2Api.observationApi.get(observation.id)
// hcp2 can already access dataSample
patient1
{
"id": "6808d1b2-72e9-4962-ac53-3fe749b02007",
"rev": "1-c3a442e1fcbebef88e76c3d4c7e87808",
"identifiers": [],
"created": 1700058603204,
"modified": 1700058603204,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"responsible": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"tags": {},
"codes": {},
"names": [
{
"family": "Snow",
"given": [
"John"
],
"prefix": [],
"suffix": [],
"text": "Snow John",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "unknown",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"ssin": "AAAA.BBB.1942",
"personalStatus": "unknown",
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "KkJTtfs/A/sZ8hKH4T48ZOGf8WnCE3sYhgxIjP3jyaU=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "John",
"lastName": "Snow"
}
patient2
{
"id": "6808d1b2-72e9-4962-ac53-3fe749b02007",
"rev": "1-c3a442e1fcbebef88e76c3d4c7e87808",
"identifiers": [],
"created": 1700058603204,
"modified": 1700058603204,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"responsible": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"tags": {},
"codes": {},
"names": [
{
"family": "Snow",
"given": [
"John"
],
"prefix": [],
"suffix": [],
"text": "Snow John",
"use": "official"
}
],
"languages": [],
"addresses": [],
"gender": "unknown",
"birthSex": "unknown",
"mergedIds": [],
"active": true,
"deactivationReason": "none",
"ssin": "AAAA.BBB.1942",
"personalStatus": "unknown",
"notes": [],
"relatives": [],
"patientPractitioners": [],
"patientProfessions": [],
"properties": {},
"systemMetaData": {
"hcPartyKeys": {},
"privateKeyShamirPartitions": {},
"secretForeignKeys": [],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"aesExchangeKeys": {},
"transferKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "KkJTtfs/A/sZ8hKH4T48ZOGf8WnCE3sYhgxIjP3jyaU=",
"publicKeysForOaepWithSha256": [],
"tags": {}
},
"firstName": "John",
"lastName": "Snow"
}
dataSample
{
"id": "23516360-bc7e-4675-b83a-3d4ed6ac8d47",
"identifiers": [],
"batchId": "a15b0f5f-0255-45c7-94ee-b1d9fa78ff08",
"healthcareElementIds": [],
"index": 0,
"valueDate": 20231115143003,
"openingDate": 20231115143003,
"created": 1700058603318,
"modified": 1700058603318,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"performer": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"localContent": {},
"qualifiedLinks": {},
"codes": {},
"tags": {},
"systemMetaData": {
"secretForeignKeys": [
"85214189-1c42-4e38-9d8a-f21ebd933b7f"
],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "niZbLMvtR9DnwnbEBwfRqt8PYOfeYnrkNZkX0UH0iBEJcACp0axGrbljPKBqihiEOZx1f69cc8S326qZNFLTayVwNxqRZe6mYjqA2T68u6I=",
"tags": {}
},
"notes": []
}
dataSample1
{
"id": "23516360-bc7e-4675-b83a-3d4ed6ac8d47",
"identifiers": [],
"batchId": "a15b0f5f-0255-45c7-94ee-b1d9fa78ff08",
"healthcareElementIds": [],
"index": 0,
"valueDate": 20231115143003,
"openingDate": 20231115143003,
"created": 1700058603318,
"modified": 1700058603318,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"performer": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"localContent": {},
"qualifiedLinks": {},
"codes": {},
"tags": {},
"systemMetaData": {
"secretForeignKeys": [
"85214189-1c42-4e38-9d8a-f21ebd933b7f"
],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "niZbLMvtR9DnwnbEBwfRqt8PYOfeYnrkNZkX0UH0iBEJcACp0axGrbljPKBqihiEOZx1f69cc8S326qZNFLTayVwNxqRZe6mYjqA2T68u6I=",
"tags": {}
},
"notes": []
}
dataSample2
{
"id": "23516360-bc7e-4675-b83a-3d4ed6ac8d47",
"identifiers": [],
"batchId": "a15b0f5f-0255-45c7-94ee-b1d9fa78ff08",
"healthcareElementIds": [],
"index": 0,
"valueDate": 20231115143003,
"openingDate": 20231115143003,
"created": 1700058603318,
"modified": 1700058603318,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"performer": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"localContent": {},
"qualifiedLinks": {},
"codes": {},
"tags": {},
"systemMetaData": {
"secretForeignKeys": [
"85214189-1c42-4e38-9d8a-f21ebd933b7f"
],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "niZbLMvtR9DnwnbEBwfRqt8PYOfeYnrkNZkX0UH0iBEJcACp0axGrbljPKBqihiEOZx1f69cc8S326qZNFLTayVwNxqRZe6mYjqA2T68u6I=",
"tags": {}
},
"notes": []
}

No automatic share on modify

The automatic data sharing applies only on entity creation, and not on modification. If a user is sharing data with another user and modifies an entity that is not yet shared with that user the updated entity won't automatically be shared with them.

const contentNotOnModify = "Won't automatically update who the data is shared with on modify"
const observationNotOnModify = await hcp1Api.observationApi.createOrModifyFor(
patient.id,
new Observation({
...existingObservation,
localContent: mapOf({ en: new LocalComponent({ stringValue: contentNotOnModify }) }),
}),
)
dataSampleNotOnModify
{
"id": "a29bf7e2-2560-4163-8960-28317aee402a",
"identifiers": [],
"batchId": "cc789e0b-3c41-4f90-b84e-1f7d3bee7c51",
"healthcareElementIds": [],
"index": 0,
"valueDate": 20231115143003,
"openingDate": 20231115143003,
"created": 1700058603418,
"modified": 1700058603418,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"performer": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"localContent": {},
"qualifiedLinks": {},
"codes": {},
"tags": {},
"systemMetaData": {
"secretForeignKeys": [
"85214189-1c42-4e38-9d8a-f21ebd933b7f"
],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "CqQUjNA3GL6WoVOYLCtfSnPu7dScZC1ZCkZuWKIpKrV6MMqBEAKoyx2g3Ylrlz/kmUhHnSMNMWWrkSYnxWZUtwyvGafx2pMVRCQdUYtSd43HZ1t8rxdIa9YL691jbLhsswgCVMVNfo4/sXJWrsMaRxOF6q+qwRtxO2T0MPzB+1o=",
"tags": {}
},
"notes": []
}

Uni-directional

Note that the auto-share is uni-directional: if hcp1 is automatically sharing data with hcp2 it does not mean that hcp2 will automatically data with hcp1. Anything created by hcp2 won't be accessible to hcp1 until hcp2 shares it.

const contentNotSharedBy2 = 'Hcp 2 is not sharing automatically with 1'
const observationNotSharedBy2 = await hcp2Api.observationApi.createOrModifyFor(
patient.id,
new Observation({
tags: new Set([new CodingReference({ type: 'IC-TEST', code: 'TEST' })]),
localContent: mapOf({ en: new LocalComponent({ stringValue: contentNotSharedBy2 }) }),
}),
)
dataSampleNotSharedBy2
{
"id": "03819de4-dc5d-407a-abf0-81139e1caea7",
"identifiers": [],
"batchId": "e2f038e5-5aed-4568-adff-11b0eeea2d58",
"healthcareElementIds": [],
"index": 0,
"valueDate": 20231115143003,
"openingDate": 20231115143003,
"created": 1700058603581,
"modified": 1700058603581,
"author": "74ef1fd5-3d37-402a-834e-1925966dafb3",
"performer": "3c35814b-f25f-40c3-a09b-970f13efad11",
"localContent": {},
"qualifiedLinks": {},
"codes": {},
"tags": {},
"systemMetaData": {
"secretForeignKeys": [
"85214189-1c42-4e38-9d8a-f21ebd933b7f"
],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "P3JNxAEtvwNiYSL4FCjTNyMCEp92BcpfdJteTL2UGlSul/c351eOOwJrAXhH15TPPvvlRYCzJ7+d+CLoISU7KuAo6bMLcjF0kITuAHt85NbSRRPjStOw8jihsw1QJXEG",
"tags": {}
},
"notes": []
}

Stop sharing

You can stop the automatic data share using the stopSharingDataWith method.

const userWithoutShare = await hcp1Api.userApi.stopSharingDataWith(
[hcp1Api.dataOwnerApi.getDataOwnerIdOf(hcp2User)],
'medicalInformation',
)
userWithoutShare
{
"id": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"rev": "6-c947237918dba9c9d488546cf9327ecd",
"created": 1700058591266,
"name": "hcp1.1700058590373@icure.com",
"properties": {},
"roles": {},
"login": "hcp1.1700058590373@icure.com",
"groupId": "test-group",
"healthcarePartyId": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"sharingDataWith": {},
"email": "hcp1.1700058590373@icure.com",
"authenticationTokens": {}
}
Data creation example
const contentNotSharedAnymore = 'Hcp 1 stopped sharing data automatically with 2'
const observationNotSharedAnymore = await hcp1Api.observationApi.createOrModifyFor(
patient.id,
new Observation({
tags: new Set([new CodingReference({ type: 'IC-TEST', code: 'TEST' })]),
localContent: mapOf({ en: new LocalComponent({ stringValue: contentNotSharedAnymore }) }),
}),
)
dataSampleNotSharedAnymore
{
"id": "a2556e71-9311-4b2e-8c0b-da6366a58723",
"identifiers": [],
"batchId": "1597a2a2-3b59-4a07-bad7-18eb9a6cf899",
"healthcareElementIds": [],
"index": 0,
"valueDate": 20231115143003,
"openingDate": 20231115143003,
"created": 1700058603676,
"modified": 1700058603676,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"performer": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"localContent": {},
"qualifiedLinks": {},
"codes": {},
"tags": {},
"systemMetaData": {
"secretForeignKeys": [
"85214189-1c42-4e38-9d8a-f21ebd933b7f"
],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "JEJAlxbtQZdtcJyAIzUcHYt0J9GYhdAbmSkPqd6ucbBW9u3KY90tFgcTpW8QnpIY/rE4ws8GrCPYafn303+9FdTw7K7ymaeyDxyogFvvgD4kLRBrCC6bNjOD9yC5Hqe6kgeGS82Q0DCF2wmXZ+G4iA==",
"tags": {}
},
"notes": []
}

Non-retroactivity

Both the shareAllFutureDataWith and stopSharingDataWith methods are not retroactive. This means that when a user starts sharing data with another user they will not give access to already existing data, and when they stop sharing data they will not revoke access to shared data.

Applicable to all data owners

Any data owner can automatically share data with any other data owner, regardless of their type (patient, healthcare professional, or medical device).

No chaining of automatic data share

The automatic data sharing applies only to entities created by the user which is sharing the data. If hcp1 shares all data with p and p shares all data with hcp2 when hcp1 creates a new entity it will only be shared with p, and not also with hcp2.

await hcp1Api.userApi.shareAllFutureDataWith(
[hcp1Api.dataOwnerApi.getDataOwnerIdOf(pUser)],
'medicalInformation',
)
await pApi.userApi.shareAllFutureDataWith(
[pApi.dataOwnerApi.getDataOwnerIdOf(hcp2User)],
'medicalInformation',
)

const contentNoChaining =
"Even if hcp1 shares with p and p shares with hcp2, hcp2 won't have automatic access to the data"
const observationNoChaining = await hcp1Api.observationApi.createOrModifyFor(
patient.id,
new Observation({
tags: new Set([new CodingReference({ type: 'IC-TEST', code: 'TEST' })]),
localContent: mapOf({ en: new LocalComponent({ stringValue: contentNoChaining }) }),
}),
)
dataSampleNoChaining
{
"id": "23ca2ecf-5a51-4475-8c5d-1e0e3edd2044",
"identifiers": [],
"batchId": "1f87c776-38de-4ae0-804f-df875ce2576a",
"healthcareElementIds": [],
"index": 0,
"valueDate": 20231115143003,
"openingDate": 20231115143003,
"created": 1700058603838,
"modified": 1700058603839,
"author": "7ea0d7ec-04e6-4fbc-bc15-fdfe946db182",
"performer": "b9bdc8fd-b250-4b44-981d-a757ba9268c9",
"localContent": {},
"qualifiedLinks": {},
"codes": {},
"tags": {},
"systemMetaData": {
"secretForeignKeys": [
"85214189-1c42-4e38-9d8a-f21ebd933b7f"
],
"cryptedForeignKeys": {},
"delegations": {},
"encryptionKeys": {},
"securityMetadata": {
"secureDelegations": {},
"keysEquivalences": {}
},
"encryptedSelf": "eJll+WrKj7s1/jpuvCobDMSluDsdjCnHmof3Rpp9smytXre6MBdPNuEOlknwGYxUpXyUjsNb1XLXSGTFXfd6gM08mIxOgBnoK1g2aNn4a8pXD1q56tt/ZpW6wRN9xlUSx7aBkxb6NvyID2CrkHKRueiDg4hRb14wlp0odhLKh8MzRohpB3pqikFEMednbGtInReixDgDJ9qp9V2S+3dcdA==",
"tags": {}
},
"notes": []
}