Use the Dataverse healthcare APIs

The Dataverse healthcare APIs contain custom-built API endpoints that allow you to exchange FHIR (Fast Healthcare Interoperability Resources) data with Microsoft Cloud for Healthcare. This article explains how to use the Dataverse healthcare upsert and retrieve bundle APIs and also covers some common usage scenarios.

For more information about these APIs, go to Overview of Dataverse healthcare APIs.

Invoke the upsert bundle API from the web API

The upsert bundle API schema name is msind_UpsertBundle. It has two request parameters and can be invoked as follows:

POST [Organization URI]/api/data/v9.1/msind_UpsertBundle 
OData-MaxVersion: 4.0
OData-Version: 4.0
Content-Type: application/json; charset=utf-8 

{
  "msind_JSON": "<The FHIR bundle that needs to be inserted (required value).>",
  "msind_BundleTag": "<A tag that helps in identifying the bundles when parsing the logs in Dataverse (optional value).>"
} 

The response contains the status of the complete request, and the detailed status of each resource and its expanded elements.

{
    "msind_Status": "<A Boolean indicating whether the bundle was successfully processed and all valid resources were upserted into Dataverse.>",
    "msind_StatusDetail": "<Provides information about the msind_Status value.>",
    "msind_Results": [
        {
            "msind_fhirresourceid": "<The FHIR ID of the resource in the bundle. If an entry in the result pertains to an expanded record, the value will be the FHIR ID of the root resource.>",
            "msind_fhirresourcetype": "<The FHIR resource type of the resource in the bundle. If an entry in the result pertains to an expanded record, the value will be the FHIR resource type of the root resource.>",
            "msind_resultingrecordid": "<The Dataverse ID after the record has been upserted. If an entry in the result pertains to an expanded record, the value will be the Dataverse ID of the root resource.>",
            "msind_resultingrecordtype": "<The name of the Dataverse entity that the record was upserted into. If an entry in the result pertains to an expanded record, the value will be the name of the Dataverse entity of the expanded record.>",
            "msind_requestactionperformed": "<The type of action performed.>",
            "msind_requeststatus": "<The status of the request.>",
            "msind_requeststatusdetail": "<Detailed information about the msind_requeststatus value.>"
        }
      ]
}

For detailed information about the msind_requestactionperformed and msind_requeststatus parameters along with their expected values, go to Types of request actions performed and Types of request status.

Common warnings and error scenarios

This section lists some of the commonly seen warnings and errors while using the upsert bundle API.

Entity map is disabled

By default, all the entity maps shipped by Microsoft Cloud for Healthcare are disabled. When you try to ingest data for a specific resource, the related entity maps must first be enabled. In case the bundle contains resources for which the entity maps aren't enabled, the response displays a warning as follows:

{
    "msind_StatusDetail": "The upsert bundle transaction completed without errors. Review the related logs for additional details.",
    "msind_Status": true,
    "msind_Results": [
        {
            "msind_requeststatus": 935000001,
            "msind_requeststatusdetail": "Warning: Unable to locate entity map for FHIR Resource: Patient. Ensure you have enabled the map for this resource. Once fixed, resubmit the bundle to re-process this record.",
            "msind_fhirresourceid": "patient1",
            "msind_fhirresourcetype": "Patient"
        }
    ]
} 

The msind_Status is marked as true and the msind_requestStatus within msind_Results is marked as 935000001 (Warning). This behavior occurs because you might intentionally disable the entity map to avoid ingesting "Patient" resources, even if they're in the bundle.

Invalid map

Attribute maps drive the transformations between Dataverse and FHIR. One of the key attribute map elements driving this transformation is the FHIR element map, which expects a JPath. If the JPath is incorrect, you can expect the following response:

{
    "msind_StatusDetail": "Warning: There were records that encountered errors. Inspect the individual records error details.",
    "msind_Status": false,
    "msind_Results": [
        {
            "msind_requeststatus": 935000002,
            "msind_requeststatusdetail": "Error: An error occurred while trying to transform the FHIR resource to the Dataverse record. Target table: contact. Exception detail: Unexpected end of content while loading JObject. Path 'c', line 1, position 112.
             Table: contact
             Attribute Map Id: f8ce8297-b4fe-ea11-a815-000d3a37def4
             Column: mobilephone
             Action: 440670000
             FHIR Map: {'s': '$.telecom[?(@use=='mobile')].value', 'c': {'p': 'telecom[0]', 'a': [{'use': 'mobile'}, {'value': '%'}]}",
            "msind_fhirresourceid": "patient1",
            "msind_fhirresourcetype": "Patient"
          }
        }
    ]
} 

The msind_Status is marked as false and the msind_requestStatus within msind_Results is marked as 935000002 (Error). The information in msind_requeststatusdetail helps you identify the incorrect map.

Referential integrity is lost

In each resource in a FHIR bundle, many elements are references to other resources. The upsert bundle API tries to resolve these references when it upserts records into Dataverse. If the API fails to resolve any of these references, it fails to upsert the record, and ensures that the referential integrity isn't lost. In such a scenario, the response would be as follows:

{
    "msind_StatusDetail": "Warning: There were records that encountered errors. Inspect the individual records error details.",
    "msind_Status": false,
    "msind_Results": [
        {
            "msind_fhirresourceid": "careteam2",
            "msind_fhirresourcetype": "CareTeam",
            "msind_resultingrecordid": "",
            "msind_resultingrecordtype": "",
            "msind_requeststatus": 935000002,
            "msind_requeststatusdetail": "Error: An error occurred while trying to upsert the record. Exception Details: A record with the specified key values does not exist in msemr_encounter entity (-2147088239)."
        } 
    ]
} 

The msind_Status is marked as false and the msind_requestStatus within msind_Results is marked as 935000002 (Error). The information in msind_requeststatusdetail helps you identify which reference failed to resolve.

Invoke the retrieve bundle API from the web API

The retrieve bundle API (msind_RetrieveBundle) has one request parameter and can be invoked as follows:

POST [Organization URI]/api/data/v9.1/msind_RetrieveBundle
OData-MaxVersion: 4.0 
OData-Version: 4.0 
Content-Type: application/json; charset=utf-8

{
    "msind_FHIRQuery": "<The FHIR query to execute (required value).>"
} 

For the list of supported FHIR queries, go to Supported FHIR queries.

The response contains the status of the complete request, and the detailed status of each resource and its expanded elements.

{
    "msind_Status": "<A Boolean indicating whether the action was successfully processed.>",
    "msind_StatusDetail": "<Provides detailed information about the msind_Status value.>",
    "msind_JSON": "<FHIR JSON representation.>"
} 

Common warnings and error scenarios

This section lists some of the commonly seen warnings and errors while using the retrieve bundle API.

Invalid FHIR resource ID

Currently, the FHIR query request parameter expects a FHIR ID. If Dataverse doesn't have a record with the FHIR ID, the response would be as follows:

{
  "msind_StatusDetail": {
    "Message": "The request failed due to the following error.",
    "Error": [
      {
        "Message": "Resource type Patient with id <ResourceId> couldn't be found."
      }
    ]
  },
  "msind_JSON": {
    "resourceType": "OperationOutcome",
    "id": "7ee485e2-3797-4ee3-9916-4fc4dd7a6ecd",
    "meta": {
      "lastUpdated": "2022-05-06T15:21:23.8078182+05:30"
    },
    "issue": [
      {
        "severity": "error",
        "code": "not-found",
        "diagnostics": "Resource type Patient with id <ResourceId> couldn't be found."
      }
    ]
  },
  "msind_Status": false
} 

Attribute map is disabled

If the FHIR query contains an element search, the retrieve bundle API uses the enabled attribute maps to construct a FHIR JSON. In case any of the attribute maps for the elements in the query are disabled, the response would be as follows:

{
"msind_StatusDetail": {
    "Message": "Request processed successfully with the following warning/information.",
    "Warning": [
      {
        "Message": "Attribute map is disabled for attribute name: msemr_asserter."
      }
    ]
  },
  "msind_JSON": "<FHIR JSON>",
  "msind_Status": true
} 

Write back to an alternate endpoint

You can configure an alternate endpoint to which the writeback service can post a FHIR bundle containing the FHIR resource created or updated. To learn how to configure this alternate endpoint, see Alternate outbound endpoint settings.

The FHIR bundle contains a single resource (for all the updates) that the alternate endpoint can process. This processing can include updating the outbound FHIR message or routing it to another endpoint. When the receiving endpoint completes processing, the writeback service expects a return bundle containing the response from the remote FHIR service. This response is needed to update the Dataverse record with the new FHIR version ID and the last modified values.

If the alternate endpoint posts to a FHIR service, such as the Azure Health Data Services FHIR service, returning the response from the FHIR service should be sufficient. Otherwise, the alternate endpoint developer should construct this bundle response. This bundle should be of the type batch-response and should contain the updated FHIR resource details.

Here's an example of a bundle that contains the FHIR Patient resource being updated:

{
  "resourceType": "Bundle",
  "type": "batch",
  "entry": [
    {
      "resource": {
        "resourceType": "Patient",
        "id": "f1fdbe3a-e266-4028-aa35-9c440daeeda4",
        "meta": {
          "versionId": "1",
          "lastUpdated": "2024-07-18T15:03:42.826+00:00",
          "profile": [
            "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
          ]
        },
        "identifier": [ {
            "type": {
              "coding": [ {
                  "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
                  "code": "MR",
                  "display": "Medical Record Number"
                }
              ],
              "text": "Medical Record Number"
            },
            "system": "http://hospital.smarthealthit.org",
            "value": "f1fdbe3a-e266-4028-aa35-9c440daeeda4"
          }
        ],
        "name": [ {
            "use": "official",
            "family": "Ambler",
            "given": [ "Joseph" ],
            "prefix": [ "Mr." ]
          }
        ],
        "telecom": [ {
            "system": "phone",
            "value": "555-795-6145",
            "use": "home"
          }
        ],
        "gender": "male",
        "birthDate": "1972-02-05",
        "deceasedDateTime": "1989-11-04T07:41:10+00:00",
        "address": [ {
            "line": [ "115 Reynolds Throughway Unit 51" ],
            "city": "Woburn",
            "state": "MA",
            "country": "US"
          }
        ],
        "maritalStatus": {
          "coding": [ {
              "system": "http://terminology.hl7.org/CodeSystem/v3-MaritalStatus",
              "code": "M",
              "display": "M"
            }
          ],
          "text": "M"
        },
        "multipleBirthInteger": 2,
        "communication": [
          {
            "language": {
              "coding": [ {
                  "system": "urn:ietf:bcp:47",
                  "code": "en-US",
                  "display": "English"
                }
              ],
              "text": "English"
            }
          }
        ]
      },
      "request": {
        "method": "PUT",
        "url": "Patient?_id=f1fdbe3a-e266-4028-aa35-9c440daeeda4"
      }
    }
  ]
}

Following is an example response returned for the previous message after posting to the Azure Health Data Services FHIR service:

{
  "resourceType": "Bundle",
  "type": "batch-response",
  "entry": [
    {
      "resource": {
        "resourceType": "Patient",
        "id": "f1fdbe3a-e266-4028-aa35-9c440daeeda4",
        "meta": {
          "versionId": "2",
          "lastUpdated": "2024-07-18T15:08:14.343+00:00",
          "profile": [
            "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
          ]
        },
        "identifier": [ {
            "type": {
              "coding": [ {
                  "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
                  "code": "MR",
                  "display": "Medical Record Number"
                }
              ],
              "text": "Medical Record Number"
            },
            "system": "http://hospital.smarthealthit.org",
            "value": "f1fdbe3a-e266-4028-aa35-9c440daeeda4"
          }
        ],
        "name": [ {
            "use": "official",
            "family": "Ambler",
            "given": [ "Joseph" ],
            "prefix": [ "Mr." ]
          }
        ],
        "telecom": [ {
            "system": "phone",
            "value": "555-795-6145",
            "use": "home"
          }
        ],
        "gender": "male",
        "birthDate": "1972-02-05",
        "deceasedDateTime": "1989-11-04T07:41:10+00:00",
        "address": [ {
            "line": [ "115 Reynolds Throughway Unit 51" ],
            "city": "Woburn",
            "state": "MA",
            "country": "US"
          }
        ],
        "maritalStatus": {
          "coding": [ {
              "system": "http://terminology.hl7.org/CodeSystem/v3-MaritalStatus",
              "code": "M",
              "display": "M"
            }
          ],
          "text": "M"
        },
        "multipleBirthInteger": 2,
        "communication": [
          {
            "language": {
              "coding": [ {
                  "system": "urn:ietf:bcp:47",
                  "code": "en-US",
                  "display": "English"
                }
              ],
              "text": "English"
            }
          }
        ]
      },
      "response": {
        "status": "200",
        "etag": "W/\"2\"",
        "lastModified": "2024-07-18T15:08:14+00:00"
      }
    }
  ]
}

The two key differences are the versionId and lastUpdated fields. These fields are required to update the Dataverse record on completion.

A second outbound message is sent containing the FHIR Provenance record details. This resource tracks the activity from the previous Patient update. Similar to other updates, the writeback service posts it as a bundle and expects a bundle of the type batch-response to complete the operation.

Here's an example of the provenance post and response for the previous writeback messages. In this example, the writeback service posts a new provenance record and adds the corresponding metadata to the response.

{
  "resourceType": "Bundle",
  "type": "batch",
  "entry": [
    {
      "resource": {
        "resourceType": "Provenance",
        "agent": {
          "who": {
            "reference": "Device/CDSSyncAgent"
          }
        },
        "target": {
          "reference": "Patient/f1fdbe3a-e266-4028-aa35-9c440daeeda4",
          "identifier": {
            "system": "Microsoft Cloud for Healthcare",
            "value": "{\"DataSource\":\"Microsoft Healthcare Writeback Data Source\",\"FHIRVersion\":\"2\",\"CDSETag\":\"2c27d21e-8ce5-4c0b-9f04-eecc6414b57e\",\"CDSReference\":\"contact/6ec787f4-1645-ef11-8409-000d3a8e806f\",\"SyncStatus\":\"Updated\",\"DateRecorded\":\"2024-07-18T15:08:24.1936902Z\",\"CDSContextUserId\":\"8e6fab4b-85e5-eb11-bacb-000d3a181fef\"}"
          }
        },
        "recorded": "2024-07-18T15:08:24.1936902Z",
        "activity": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v3-DataOperation",
              "code": "UPDATE"
            }
          ]
        },
        "entity": [
          {
            "role": "derivation",
            "what": {
              "reference": "FHIRCDSSyncAgent"
            }
          }
        ]
      },
      "request": {
        "method": "POST",
        "url": "Provenance"
      }
    }
  ]
}

Response value:

{
  "resourceType": "Bundle",
  "type": "batch-response",
  "entry": [
    {
      "resource": {
        "resourceType": "Provenance",
        "id": "287371be-0f0d-4295-ba26-c2f1900e88c4",
        "meta": {
          "versionId": "1",
          "lastUpdated": "2024-07-18T15:08:25.906+00:00"
        },
        "target": [
          {
            "reference": "Patient/f1fdbe3a-e266-4028-aa35-9c440daeeda4",
            "identifier": {
              "system": "Microsoft Cloud for Healthcare",
              "value": "{\"DataSource\":\"Microsoft Healthcare Writeback Data Source\",\"FHIRVersion\":\"2\",\"CDSETag\":\"2c27d21e-8ce5-4c0b-9f04-eecc6414b57e\",\"CDSReference\":\"contact/6ec787f4-1645-ef11-8409-000d3a8e806f\",\"SyncStatus\":\"Updated\",\"DateRecorded\":\"2024-07-18T15:08:24.1936902Z\",\"CDSContextUserId\":\"8e6fab4b-85e5-eb11-bacb-000d3a181fef\"}"
            }
          }
        ],
        "recorded": "2024-07-18T15:08:24.1936902+00:00",
        "activity": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v3-DataOperation",
              "code": "UPDATE"
            }
          ]
        },
        "agent": [
          {
            "who": {
              "reference": "Device/CDSSyncAgent"
            }
          }
        ],
        "entity": [
          {
            "role": "derivation",
            "what": {
              "reference": "FHIRCDSSyncAgent"
            }
          }
        ]
      },
      "response": {
        "status": "201",
        "location": "https://server.fhir.azurehealthcareapis.com/Provenance/287371be-0f0d-4295-ba26-c2f1900e88c4/_history/1",
        "etag": "W/\"1\"",
        "lastModified": "2024-07-18T15:08:25+00:00"
      }
    }
  ]
}