HealtheIntent API Workshop
Course Objective
This course will teach you how to consume Population Health concepts using the Cerner HealtheIntent APIs. First, you will learn to authenticate your API calls using OAuth1 and to use HealtheRecord person search and patient data retrieval services. Next, you will retrieve registry and measure outcomes with the HealtheRegistries API, and learn how to filter the outcomes in the response.
Click here to take you to the HealtheIntent slide deck.
Prerequisites
- The examples will be in
Ruby
. If you are not familiar with ruby, don’t worry! The ruby quickstart guide will help you get started. - For this workshop we will be using a VM built by Cerner. Follow these instructions to install the VM:
- Download and install VirtualBox.
- Download Cerner Ubuntu Virtual machine.
- Launch VirtualBox and click
File
→Import Appliance
. - Select the downloaded cerner_ubuntu_16_04-1.0.0.ova file, click on
continue
. - Keep the default settings and click on
import
. - Select the virtual machine on the left pane.
- Click the
Settings
button in the top menu. - Click
Network
in the Settings window. - Under Advanced Options, make sure
Cable connected
is selected.
Introduction to HealtheIntent APIs
URI Structure
HealtheIntent is a multi-tenant platform and it follows an URI pattern.
https://{client}.{solution}.healtheintent.com
{client}
=> The tenant identifier.{solution}
=> The solution identifier
For this workshop we will be using the cernerdemo
client. So the URI structure will look like:
https://cernerdemo.{solution}.healtheintent.com
To make calls to your production client, you would replace cernerdemo
with your client mnemonic.
Authentication and Authorization
HealtheIntent‘s APIs use the two-legged (or B2B) OAuth 1.0a based authentication workflow. For detailed documentation on how to authenticate against Cerner services, please see the documentation we have for Authentication.
Authentication using the cerner-oauth1a Gem
For the purpose of this workshop, we will be using the cerner-oauth1a
gem to request an OAuth token. cerner-oauth1a
supports functionality to return an Authorization
header, which we will use in our REST calls.
Creating Authorization header using cerner-oauth1a gem
require 'cerner/oauth1a'
auth_header = Cerner::OAuth1a::AccessToken.request(consumer_key: 'consumer_key', consumer_secret: 'consumer_secret', oauth_url: 'URL for OAuth provider').get_authorization_header
Exercise 1
Create an OAuth Authorization
header using the given credentials.
Note The Authorization
header created as part of this exercise will be used in the later exercises.
Authorization
The system account we will be using has already been created. It has permissions to access HealtheRecord, HealtheRegistries, and Data Syndication services. You used the credentials (the consumer_key and consumer_secret) for that account to create the OAuth token.
Note We will be disabling this account at the end of this workshop. To request a new system account to pursue further development against our platform, follow the instructions here.
Request Headers
The following headers must be set before you can call the HealtheIntent APIs:
Authorization
must be set according to the structure of the Authorization header documented here.Accept
must be set toapplication/json
.
HealtheRecord
The Cerner longitudinal record, HealtheRecord, is designed to provide an organized, coherent representation of the aggregated clinical data for a member. We will use HealtheRecord to demonstrate how to authenticate your REST calls and how to use the APIs.
Detailed API documentation for HealtheRecord can be found here
We will be using the httparty gem as our HTTP client for the purpose of this workshop.
Person Search
This API is used for searching among the people in a population. You can also refine your search using query parameters.
Person search API: GET /api/populations/{population_id}/people
We will be using the following population id for all our exercises: 1424e81d-8cea-4d6b-b140-d6630b684a58
Exercise 2
require 'httparty'
# psssst... remember to substitute the population id in the URL
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/{population_id}/people', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
Retrieve a list of people from the given population. You will need to use the Authorization
header created in the previous exercise.
How many people do you have in your population?
The unformatted response object is hard to read, so let’s make it look pretty by using pretty_generate!
require 'json'
puts JSON.pretty_generate(response)
Click here for the answer
The answer is 111971 (total_results attribute gives your the result).
Click here for the answer
The answer is 111971 (total_results attribute gives your the result).Exercise 3
query_parameters = {
'date_of_birth' => '1972-01-22',
'q' => 'butler'
}
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response)
We need to find the person ID for Tammy Butler, whose birthdate is 1972-01-22
.
Click here for the answer
Person ID for Tammy Butler is 6faf92f6-f3d3-4e0e-b633-48a45df383db
Click here for the answer
Person ID for Tammy Butler is 6faf92f6-f3d3-4e0e-b633-48a45df383dbPerson Demographics
We just found the person_id for Tammy Butler. Now let’s learn a little more about her using the Person Demographics API.
Person demographic API: GET /api/populations/{population_id}/people/{person_id}
Exercise 4
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/{person_id}', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Find out Tammy Butler’s insurance plan name and how long has she been in the same plan.
Click here for the answer
Her plan name is Healthe and she has been on the same plan since 2015-09-06.
Click here for the answer
Her plan name is Healthe and she has been on the same plan since 2015-09-06.Medications
Time to check out the Medications currently prescribed to Tammy.
Medication groups API: GET /api/populations/{population_id}/people/{person_id}/medication_groups
Exercise 5
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/{person_id}/medication_groups', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Find out all the medications that Tammy has been prescribed. How many medications has she been prescribed?
Click here for the answer
12
Click here for the answer
12Allergies
Before we prescribe any new medications to Tammy, let’s check out what she is allergic to.
Allergen groups API: GET /api/populations/{population_id}/people/{person_id}/allergen_groups
Exercise 6
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/{person_id}/allergen_groups', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Find out if Tammy is allergic to anything.
Click here for the answer
Tammy is allergic to penicillin.
Click here for the answer
Tammy is allergic to penicillin.Conditions
Now it’s time to see all the conditions Tammy has. We can use the conditions_groups resource to find them.
Conditions groups API: GET /api/populations/{population_id}/people/{person_id}/condition_groups
Exercise 7
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/{person_id}/condition_groups', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Take a look at all the conditions Tammy has. How many conditions does she have?
Click here for the answer
She has 12 conditions.
Click here for the answer
She has 12 conditions.Procedures
Let’s check out all the procedures we know about for Tammy. The Procedure_groups API consolidates procedures for easier viewing.
Procedure groups API: GET /api/populations/{population_id}/people/{person_id}/procedure_groups
Exercise 8
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/{person_id}/procedure_groups', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Find out all the procedures Tammy has undergone.
Click here for the answer
Tammy has undergone ‘Abdomen Ultrasound’, ‘Foot Exam’, and ‘Laparoscopy’.
Click here for the answer
Tammy has undergone ‘Abdomen Ultrasound’, ‘Foot Exam’, and ‘Laparoscopy’.Bonus Questions
Exercise 9
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/vaccine_groups', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/vaccine_groups/F8BD9284FBC0082BE043902F47AAB2CA/immunizations', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Find out when Tammy was vaccinated against polio.
Hint
You will need to call “/api/populations/{population_id}/people/{person_id}/vaccine_groups” first to figure out the “vaccine_group_id” for polio.
Hint
You will need to call “/api/populations/{population_id}/people/{person_id}/vaccine_groups” first to figure out the “vaccine_group_id” for polio. Click here for the answer
The answer is ‘2009-01-05’ and ‘2010-04-12’.
Click here for the answer
The answer is ‘2009-01-05’ and ‘2010-04-12’.Exercise 10
response = HTTParty.get('https://cernerdemo.record.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/provider_relationships', headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
Find out the total number of healthcare providers for Tammy.
Hint
You will have to use the provider_relationships API. The answer is 17.
Hint
You will have to use the provider_relationships API. The answer is 17.HealtheRegistries
A registry is an aggregation of an organization’s patients who share a particular clinical characteristics.
Detailed API documentation for HealtheRegistries can be found here
Person Registries Summaries
Person Registries summary lets you fetch a person’s registry data using the HealtheIntent person id.
Person Registries summary API: GET api/populations/{population_id}/people/{person_id}/registries
Exercise 11
require 'httparty'
# psssst... remember to create the authorization header
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries',headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
MARA risk score is a metric that is used to gauge a patient’s cost of care to the hospital. Average risk score for a person is 1. The cost of care will be more expensive for a patient with a higher risk score.
Using Tammy Butler’s person_id from the previous exercise fetch her registry. What is the MARA score for Tammy?
Click here for the answer
The MARA score is 0.05
Click here for the answer
The MARA score is 0.05Exercise 12
query_parameters = {fields: 'mara_total_risk_score'}
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries',headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response)
Now using the query parameters filter the response so that you only get the mara score
Hint
Use the “fields” query parameter to filter the mara_total_risk_score field.
Hint
Use the “fields” query parameter to filter the mara_total_risk_score field.Exercise 13
query_parameters = { measures_status_filter: 'due' }
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries',headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response)
As Tammy’s primary care provider you want to know all the measures that are due.
Fetch her registry and find out all the measures that are due under Adult Wellness program.
Hint
Use the “measures_status_filter” query parameter to filter only those measures that are due.
Hint
Use the “measures_status_filter” query parameter to filter only those measures that are due. Click here for the answer
These are the measures that are due are “Alcohol Use Screening”, “Blood Pressure Measurement”, “Body Mass Index Follow-Up Plan”, “Cervical Cancer Screening” “Influenza Vaccination - Full Season”, and “Influenza Vaccination - Partial Season”.
Click here for the answer
These are the measures that are due are “Alcohol Use Screening”, “Blood Pressure Measurement”, “Body Mass Index Follow-Up Plan”, “Cervical Cancer Screening” “Influenza Vaccination - Full Season”, and “Influenza Vaccination - Partial Season”.Person Measure Component Group
Supporting facts for a measure can be fetched using the component group API.
Person Measure Component Group API: GET api/populations/{population_id}/people/{person_id}/registries/{program_id}/measures/{fqn}/componentGroup
fqn is the fully qualified name of the measure (its identifier), example is cernerstandard.adultwellness.org2014.clinical/body-mass-index
. And program_id is the HealtheIntent program id to which the corresponding measure belongs to, example is cernerdemo.adultwellness.org.clinical.cernerdemo-adult-wellness
.
Exercise 14
response = HTTParty.get( 'http://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/6faf92f6-f3d3-4e0e-b633-48a45df383db/registries/cernerdemo.diabetes.org.clinical.cernerdemo-diabetes/measures/cernerstandard.diabetesmellitus.org2014.clinical%2Fbp-measurement/componentGroup' ,headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Let’s take a look at what Tammy’s last measured blood pressure is. Fetch supporting facts for cernerstandard.diabetesmellitus.org2014.clinical/bp-measurement
measure from cernerdemo.diabetes.org.clinical.cernerdemo-diabetes
program.
Hint
The “/” in the measure needs to be changed to “%2F”.
Hint
The “/” in the measure needs to be changed to “%2F”. Click here for the answer
Blood Pressure 112/60 mmHg.
Click here for the answer
Blood Pressure 112/60 mmHg.Bonus questions
Exercise 15
response = HTTParty.get( 'http://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/programs' ,headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
Retrieve all the programs for the population.
Hint
Need to use the Programs API: “GET api/populations/{population_id}/programs”.
Hint
Need to use the Programs API: “GET api/populations/{population_id}/programs”.Exercise 16
response = HTTParty.get('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/programs/cernerdemo.asthma.org.clinical.cernerdemo-asthma-care',headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
How many measures does the cernerdemo.asthma.org.clinical.cernerdemo-asthma-care
program have?
Hint
Need to use the Programs API: “GET /populations/{population_id}/programs/{program_id}” to retrieve a single program.
Hint
Need to use the Programs API: “GET /populations/{population_id}/programs/{program_id}” to retrieve a single program. Click here for the answer
cernerdemo.asthma.org.clinical.cernerdemo-asthma-care program has 6 measures.
Click here for the answer
cernerdemo.asthma.org.clinical.cernerdemo-asthma-care program has 6 measures.Exercise 17
request_body = { person_ids: ['ae3a2060-1261-43a3-a42b-013b0d700fca', 'a6facde2-b5b3-41e0-b939-3d9c87b258c9', '6faf92f6-f3d3-4e0e-b633-48a45df383db'],
program_ids: [ 'cernerdemo.adultwellness.org.clinical.cernerdemo-adult-wellness']
}
query_parameters = { measures_status_filter: 'due' }
response = HTTParty.post('https://cernerdemo.registries.healtheintent.com/api/populations/1424e81d-8cea-4d6b-b140-d6630b684a58/people/registries', headers: {'Authorization' => <auth_header>}, body: request_body, query: query_parameters)
Stephanie (ae3a2060-1261-43a3-a42b-013b0d700fca), Jason (a6facde2-b5b3-41e0-b939-3d9c87b258c9) and Tammy (6faf92f6-f3d3-4e0e-b633-48a45df383db) are coming in today for a checkup. Fetch their registries and find out what measures are due for their Cerner adult wellness program. The program id for “Cerner adult wellness” is cernerdemo.adultwellness.org.clinical.cernerdemo-adult-wellness
.
Hint
Need to use the Multiple People registries API: “POST /populations/{population_id}/people/registries” to retrieve multiple registries. You will also have to use the “measures_status_filter” query parameter.
Hint
Need to use the Multiple People registries API: “POST /populations/{population_id}/people/registries” to retrieve multiple registries. You will also have to use the “measures_status_filter” query parameter. Click here for the answer
The measures due for Stephanie, Jason, and Tammy are 11, 9, and 6 respectively.
Click here for the answer
The measures due for Stephanie, Jason, and Tammy are 11, 9, and 6 respectively.Readmission Risk
The Readmission Risk API can be used to determine how likely a patient is of being readmitted based on the Cerner Readmission algorithm.
Detailed API documentation for Readmission Risk can be found here
Person Lookup
This endpoint is used to lookup a HealtheIntent person ID from a particular data partition and person ID from the data partition source.
Person lookup API: POST /api/populations/{population_id}/data_partitions/{data_partition_id}/persons
Prerequisites
In order to look up a HealtheIntent person ID, you must first have the id of the source data partition and the person id from that source data partition.
Cerner Millennium Demo partition id: 8dee150d-505f-4635-b009-1bef63d7cf5a
The readmissions API also uses a different population than the other APIs we have worked with.
Readmissions population id: 0a9cc467-094c-403a-84d0-35604e1e418c
Person IDs from the Cerner Millennium Demo partition:
3614281
1427933
2235926
Exercise 18
response = HTTParty.post('https://cernerdemo.programs.healtheintent.com/api/populations/0a9cc467-094c-403a-84d0-35604e1e418c/data_partitions/8dee150d-505f-4635-b009-1bef63d7cf5a/persons',
headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>, 'Content-Type' => 'application/json'},
body: {values: ['3614281', '1427933', '2235926']}.to_json)
puts JSON.pretty_generate(response)
Lookup the HealtheIntent person IDs for the people in the Cerner Millennium data partition.
Click here for the answer
You should get back the following IDs: 0230b3ec-a541-3da1-bb60-4710f0446237, 06c3415b-deb5-3bbd-a6f4-f2293894758d, and 0655eafe-a71e-3b55-8258-2a51f43b14fc
Click here for the answer
You should get back the following IDs: 0230b3ec-a541-3da1-bb60-4710f0446237, 06c3415b-deb5-3bbd-a6f4-f2293894758d, and 0655eafe-a71e-3b55-8258-2a51f43b14fcReadmission Risk Score
Now that you have the HealtheIntent person IDs for the people from exercise 1 you can look up their actual risk scores. This endpoint actually allows looking up a history of risk scores for a person, but by default returns the most recent risk score. We will return to the historical risk scores later.
The risk score for a person is shown under the stratification
of the response. The possible values are LOW
, MODERATE
, and HIGH
.
Readmission Risk Score API: GET /api/populations/{population_id}/readmission_risk/{person_id}
Exercise 19
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/0a9cc467-094c-403a-84d0-35604e1e418c/readmission_risk/0655eafe-a71e-3b55-8258-2a51f43b14fc',
headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
What is the age of the person with a HIGH
risk score?
Hint
The age can be found in the risk_factors array under the field named age_in_years
Hint
The age can be found in the risk_factors array under the field named age_in_years Click here for the answer
The person with a HIGH risk score is age 85
Click here for the answer
The person with a HIGH risk score is age 85Exercise 20
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/0a9cc467-094c-403a-84d0-35604e1e418c/readmission_risk/06c3415b-deb5-3bbd-a6f4-f2293894758d',
headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
What is the age of the person with a MODERATE
risk score?
Hint
The age can be found in the risk_factors array under the field named age_in_years
Hint
The age can be found in the risk_factors array under the field named age_in_years Click here for the answer
The person with a MODERATE risk score is age 40
Click here for the answer
The person with a MODERATE risk score is age 40Exercise 21
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/0a9cc467-094c-403a-84d0-35604e1e418c/readmission_risk/0230b3ec-a541-3da1-bb60-4710f0446237',
headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>})
puts JSON.pretty_generate(response)
What is the age of the person with a LOW
risk score?
Hint
The age can be found in the risk_factors array under the field named age_in_years
Hint
The age can be found in the risk_factors array under the field named age_in_years Click here for the answer
The person with a LOW risk score is age 73
Click here for the answer
The person with a LOW risk score is age 73Exercise 22
query_parameters = {
'start_version' => '0',
'end_version' => '20161117'
}
response = HTTParty.get('https://cernerdemo.programs.healtheintent.com/api/populations/0a9cc467-094c-403a-84d0-35604e1e418c/readmission_risk/0655eafe-a71e-3b55-8258-2a51f43b14fc',
headers: {'Accept' => 'application/json', 'Authorization' => <auth_header>}, query: query_parameters)
puts JSON.pretty_generate(response)
As mentioned previously, the readmission risk endpoint returns only the latest risk score by default. Now we will use it to look up historical risk scores for a person. In order to do this the start_version
and end_version
query parameters can be used to provide a range. Despite the name these query parameters actually take in dates in the format YYYYMMDDhhmm
in UTC.
What is the comorbidity_index
for very first risk score of the person with a HIGH
risk score?
Hint
0 can be used for the start_version query param and today’s date can be used for the end_version query param
Hint
0 can be used for the start_version query param and today’s date can be used for the end_version query param Click here for the answer
The comorbidity_index on the very first risk score is 2
Click here for the answer
The comorbidity_index on the very first risk score is 2Readmission Risk Score List
The readmission risk score list endpoint can be used to get the risk score for multiple people in a single call. Unlike the singular risk score endpoint, this endpoint uses a POST
with the person IDs included in the post body.
Readmission Risk Score List API: POST /api/populations/{population_id}/readmission_risk
Exercise 23
response = HTTParty.post('https://cernerdemo.programs.healtheintent.com/api/populations/0a9cc467-094c-403a-84d0-35604e1e418c/readmission_risk',
headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json', 'Authorization' => <auth_header>},
body: {empi_ids: ['0655eafe-a71e-3b55-8258-2a51f43b14fc', '06c3415b-deb5-3bbd-a6f4-f2293894758d', '0230b3ec-a541-3da1-bb60-4710f0446237']}.to_json)
puts JSON.pretty_generate(response)
Get the readmission risk score for all 3 persons at once.