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.
In the following examples we use different instances of EhrLiteSDK
s, 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
.
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": []
}