How to create a new instance in SFM

SFM ensures a distinction between information belonging to different journal systems. SFM has the term "instance" which corresponds to a "journal system", and where the information within the instance is available for the organizations that is created within this instance.

SFM is set up as a self service system, and when all formal work is in place, the host system (EHR/EPJ) may create a new instance in SFM for the EHR customer.

HelseID preparations

The EHR system vendor prepares the system as a "client system" in HelseID self service, registering the consumption of SFM API in the profile. For multi tenant solutions, a multi tenant HelseID client system may be selected. The Client system will in this case also be a HelseID client.

It is important to understand the differences between the two variants:

  • Multi tenant client will request token with a specific jounal-id
  • Single tentant client will present a pre-configured SFM-id.

Create Organization

For a new customer (doctors office new to SFM), the EHR superuser will create the organization element, using a token with a SFM-id or journal-id. Create is the only allowed operation with an unknown id. The Create payload must be corresponding to identifiers in the token. If successful validation, SFM will create a new database schema, containing one Organization and one Person.

General advice for both testing and production:

  • do a search(GET) operation on the Organization endpoint to verify the expected result of not finding anything
  • do a Create (POST) operation with proper http headers and a FHIR payload with Organization profiled as sfm-Organization with the following properties:

information needed for the Organization

- Organization.name
- Organization.Identifier[SFM-id] : matching the journal-id or SFM-id in token
- Organization.Identifier[ENH] : Organization matching the orgn_child in token if present, else the orgnr_parent
- Organization.Identifier[HERid] : Her id registered in Adresseregisteret for use in e-resept
- Organization.Type from the system: https://simplifier.net/r4medication/sfm-type-of-organization 
- Organization.telecom with a simple dummy phone number in test
- Organization.address with a simle dummy address in test
- Organization.extension.epjinfo shall be populated with info suitable for reporting to Reseptformidleren. Reseptformidleren will **reject the registration with an unknown systeminfo.systemcode**
- Organization.active = false: for now.

The operation takes some time to process as a new db-scheme is created at everthing is set up in SFM before you get 2xx code and the organziation structure in response. The new ID for this Organization is represented in the Location header.

You may now try to read back from Organzation and verify that you get at bundle back with your Organization, now given an ID. You may also try to read back from Person and verify that you are identified as an empty Person with your identifier. Note that in production we require that the next step is to update this Person instance with the correct name.

Example

In this example a new organisation Kolåsbakkane legekontor will be created using a new single tenant client (SFM-id not previously known by SFM). The EHR system creates a FHIR Organization payload with the essential properties, and selects active=false. Then this payload is POST-ed to the ./Organization endpoint:

    {
    "resourceType": "Organization",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2024-05-23T15:33:58.7998213+02:00",
        "profile": [
        "http://ehelse.no/fhir/StructureDefinition/sfm-Organization"
        ]
    },
    "extension": [
        {
        "extension": [
            {
            "extension": [
                {
                "url": "systemcode",
                "valueString": "DrWho"
                },
                {
                "url": "systemname",
                "valueString": "Doctor Who testtool"
                },
                {
                "url": "version",
                "valueString": "4.1"
                },
                {
                "url": "updatetime",
                "valueDateTime": "2024-05-23T15:30:17.0349469+02:00"
                }
            ],
            "url": "systeminfo"
            },
            {
            "extension": [
                {
                "url": "servicevendorname",
                "valueString": "Kolåsen vedlikehald"
                },
                {
                "url": "contactname",
                "valueString": "Didrik"
                },
                {
                "url": "contactemail",
                "valueString": "didrik@kolaasen.no"
                },
                {
                "url": "contactphone",
                "valueString": "98765432"
                }
            ],
            "url": "operationsuplierinfo"
            }
        ],
        "url": "http://ehelse.no/fhir/StructureDefinition/sfm-epjinfo"
        }
    ],
    "identifier": [
        {
        "use": "official",
        "system": "urn:oid:2.16.578.1.12.4.1.4.101",
        "value": "917897468"
        },
        {
        "use": "official",
        "system": "urn:oid:2.16.578.1.12.4.1.2",
        "value": "81420690"
        },
        {
        "use": "official",
        "system": "urn:oid:2.16.578.1.12.4.1.4.109",
        "value": "a99abfb4-2bea-4e0a-bb03-38e37febbd2c"
        }
    ],
    "active": false,
    "type": [
        {
        "coding": [
            {
            "system": "http://ehelse.no/fhir/CodeSystem/sfm-type-of-organization",
            "code": "3",
            "display": "Fastlege"
            }
        ]
        }
    ],
    "name": "Kolåsbakkane legekontor",
    "telecom": [
        {
        "system": "phone",
        "value": "12345678",
        "use": "work"
        }
    ],
    "address": [
        {
        "use": "work",
        "type": "physical",
        "text": "Testaddress",
        "line": [
            "Testveien 1"
        ],
        "city": "Oslo",
        "postalCode": "1234"
        }
    ]
    }

The corresponding token used contains SFM-id and organization ID (orgnr_parent corresponding to Identifier [ENH]):

    {
    "iss": "https://helseid-sts.test.nhn.no",
    "nbf": 1716470965,
    "iat": 1716470965,
    "exp": 1716471565,
    "aud": "e-helse:sfm.api",
    "scope": [
        "openid",
        "profile",
        "helseid://scopes/identity/pid",
        "helseid://scopes/identity/security_level",
        "helseid://scopes/hpr/hpr_number",
        "helseid://scopes/identity/assurance_level",
        "e-helse:sfm.api/sfm.api"
    ],
    "amr": [
        "pwd"
    ],
    "client_id": "dc7ce5b5-670a-40f8-bd64-801e408b7069",
    "client_amr": "private_key_jwt",
    "helseid://claims/client/claims/orgnr_parent": "917897468",
    "sub": "tzto6gPhyTQw2bR/Wl0kgF/mTH+jdQoUBvaYSObfmlQ=",
    "auth_time": 1716470964,
    "idp": "testidp-oidc",
    "helseid://claims/identity/pid": "17056600574",
    "helseid://claims/identity/security_level": "4",
    "helseid://claims/identity/assurance_level": "high",
    "helseid://claims/hpr/hpr_number": "431001110",
    "oldsub": "gD6VTyxDgGoCCqOBFCuxuykX7tXL1jiWy0Zg9L0f96I=",
    "helseid://claims/client/amr": "rsa_private_key",
    "e-helse:sfm.api/client/claims/sfm-id": "a99abfb4-2bea-4e0a-bb03-38e37febbd2c",
    "helseid://claims/client/client_tenancy": "single-tenant",
    "sid": "150C9C961CBBF4F67138FA317E2B1C8D",
    "jti": "FC0B6D1EFB47D09A7B62A653B0469174"
    }

This operation takes some time as a new database schema is created, on success SFM replies a payload with an ID of the newly created Organization instance and http status 201 Created. The Organization returned now contains ID for further API access.

Person, the superuser

SFM has two types of users:

  • Superuser ( FHIR:Person )
  • Health person (FHIR: Practitioner)

In smaller installations (doctor's offices) some of the employees can be both types. Superusers can change the organization, create new health professionals and new superusers, but not access health data or patient information. Healthcare professionals can create patients, open a patient treatment portal and have access to health data in the API.

Example

When creating an organization, behind the scenes SFM also creates the minimal superuser represented by the line: "helseid://claims/identity/pid": "17056600574" in the token. Next natural step is to update this Person resource with proper name:

Do a GET to the ./Person endpoint and receive a search bundle containing one single person object:

    {
    "resourceType": "Bundle",
    "id": "8fd540ca-4e21-4a89-8d40-b8c3cd2598a6",
    "meta": {
        "lastUpdated": "2024-05-23T13:47:42.6275835+00:00"
    },
    "type": "searchset",
    "total": 1,
    "link": [
        {
        "relation": "self",
        "url": "http://base-fhir.test2.forskrivning.no/Person?_count=100&_format=json"
        }
    ],
    "entry": [
        {
        "fullUrl": "http://base-fhir.test2.forskrivning.no/Person/5a7d3824-11ac-4826-89b7-ddfdc9918bff",
        "resource": {
            "resourceType": "Person",
            "id": "5a7d3824-11ac-4826-89b7-ddfdc9918bff",
            "meta": {
            "lastUpdated": "2024-05-23T15:35:03.7386838+02:00",
            "profile": [
                "http://ehelse.no/fhir/StructureDefinition/sfm-Person"
            ]
            },
            "identifier": [
            {
                "use": "official",
                "system": "urn:oid:2.16.578.1.12.4.1.4.1",
                "value": "17056600574"
            }
            ],
            "active": true
        },
        "search": {
            "mode": "include"
        }
        }
    ]
    }

It is now possible to read the particular Person item by GET to endpoint ./Person/5a7d3824-11ac-4826-89b7-ddfdc9918bff

    {
    "resourceType": "Person",
    "id": "5a7d3824-11ac-4826-89b7-ddfdc9918bff",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2024-05-23T15:35:03.7386838+02:00",
        "profile": [
        "http://ehelse.no/fhir/StructureDefinition/sfm-Person"
        ]
    },
    "identifier": [
        {
        "use": "official",
        "system": "urn:oid:2.16.578.1.12.4.1.4.1",
        "value": "17056600574"
        }
    ],
    "active": true
    }

This resource may now be updated with name and other properties by a PUT operation to Person endpoint with the id:
./Person/8fd540ca-4e21-4a89-8d40-b8c3cd2598a6

    {
    "resourceType": "Person",
    "id": "5a7d3824-11ac-4826-89b7-ddfdc9918bff",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2024-05-23T15:35:03.7386838+02:00",
        "profile": [
        "http://ehelse.no/fhir/StructureDefinition/sfm-Person"
        ]
    },
    "identifier": [
        {
        "use": "official",
        "system": "urn:oid:2.16.578.1.12.4.1.4.1",
        "value": "17056600574"
        }
    ],
    "name": [
        {
        "extension": [
            {
            "url": "http://hl7.no/fhir/StructureDefinition/no-basis-middlename",
            "valueString": "D"
            }
        ],
        "family": "Didrikson",
        "given": [
            "Didrik"
        ]
        }
    ],
    "gender": "male",
    "birthDate": "1966-05-17",
    "address": [
        {
        "use": "work",
        "type": "physical",
        "line": [
            "Testveien 1"
        ],
        "city": "Oslo",
        "postalCode": "1234"
        }
    ],

    "active": true
    }

SFM will respond http status 200

To allow other users into this instance of SFM, the superuser may now use HelseID to create other superusers, and Practitioners.

Practitioner - the healtcare user

Lets say that this superuser also is a doctor in this instance, a practitoner may be created:

    {
    "resourceType": "Practitioner",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2024-05-23T15:58:11.8597674+02:00",
        "profile": [
        "http://ehelse.no/fhir/StructureDefinition/sfm-Practitioner"
        ]
    },
    "identifier": [
        {
        "use": "official",
        "system": "urn:oid:2.16.578.1.12.4.1.4.1",
        "value": "17056600574"
        }
    ],
    "active": true,
    "name": [
        {
        "extension": [
            {
            "url": "http://hl7.no/fhir/StructureDefinition/no-basis-middlename",
            "valueString": "D"
            }
        ],
        "family": "Dirdrikson",
        "given": [
            "Didrik"
        ]
        }
    ],
    "address": [
        {
        "use": "work",
        "type": "physical",
        "line": [
            "Testveien 1"
        ],
        "city": "Oslo",
        "postalCode": "1234"
        }
    ],
    "gender": "male",
    "birthDate": "1966-05-17"
    }

SFM responds http 201 Created and the new resource as a Practitioner.

To illustrate the differences between single and multi tenancy, we now simumlate that the vendor for this office stars using multi tenancy client system in HelseID. SFM will only allow known "suppliers", and the vendor must contact sfm enable this in TEST. For production there will be formal processes taking care of this. For clients/vendors using HelseID on behalf of their customer, a delegation from customer to vendor exist in Altinn. For test the delegation is simulated by "Tenants" in HelseID self service. When everything is properly set up, the vendor may reuse the SFM-id from the singe client as journal-id in multi tenant for continued access to the SFM instance.

Here is an example of the multi tenancy token that provides access to the instance created above: (note that SFM-id have no meaning in this case)

    {
    "iss": "https://helseid-sts.test.nhn.no",
    "nbf": 1716473563,
    "iat": 1716473563,
    "exp": 1716477163,
    "aud": "e-helse:sfm.api",
    "scope": [
        "openid",
        "profile",
        "helseid://scopes/identity/pid",
        "helseid://scopes/identity/security_level",
        "helseid://scopes/hpr/hpr_number",
        "helseid://scopes/identity/assurance_level",
        "e-helse:sfm.api/sfm.api"
    ],
    "amr": [
        "pwd"
    ],
    "client_id": "8cd7c619-92db-4d55-89e2-383b75efc758",
    "client_amr": "private_key_jwt",
    "helseid://claims/client/claims/orgnr_parent": "917897468",
    "nhn:sfm:journal-id": "a99abfb4-2bea-4e0a-bb03-38e37febbd2c",
    "sub": "tzto6gPhyTQw2bR/Wl0kgF/mTH+jdQoUBvaYSObfmlQ=",
    "auth_time": 1716473563,
    "idp": "testidp-oidc",
    "helseid://claims/identity/pid": "17056600574",
    "helseid://claims/identity/security_level": "4",
    "helseid://claims/identity/assurance_level": "high",
    "helseid://claims/hpr/hpr_number": "431001110",
    "oldsub": "n57qJQXiVg8sRZRurRDMKiIm6LnWrSzENEcmOgYL/MI=",
    "helseid://claims/client/amr": "rsa_private_key",
    "helseid://claims/client/claims/orgnr_supplier": "994598759",
    "e-helse:sfm.api/client/claims/sfm-id": "ce75db36-c57b-4592-9d47-5dfae8a34340",
    "helseid://claims/client/client_tenancy": "multi-tenant",
    "sid": "9E10C7DFEDC83C399DDBCD03B0907DBF",
    "jti": "6745AAAE3691417B0139C645BA37F7F6"
    }

Activating the organization

For SFM Basis use, the last step is to update the Organization with active=true. SFM then reports the organization to e-resept by the key HER-id.

For SFM Full use, the next steps will be to migrate necessary personell and patient data to SFM by using the migration API before updating Organization to active=true.

Note on Practitioner in SFM Basis

In SFM basis there is an option to create practitioners "dynamically" on first access with a valid token. Instead of having to create all sfm-Practitioners upfront, SFM will then automatically sync to Helsepersonellregisteret, where SFM retrieves necessary information on the Practitioners by looking up the pid from the token for new/unknown users. This option needs to configured in agreement with NHN.