Introduction
Welcome to the Open HealthHub Open API Hub! You can use our APIs to access the Open HealthHub Open API endpoints based on HL7 FHIR, which can interact with the Open HealthHub and SMART on FHIR applications for questionnaires, information and remote patient monitoring.
Open API overview
Open HealthHub's Open API hub is a core part of our mission to empower healthcare organizations to take back control over their own healthcare pathways and remote patient monitoring. Our APIs are designed to enable teams of any shape or size to build robust and secure integrations that help them customize and get the most value out of the Open HealthHub SMART on FHIR solutions Improve Designer, Improve Mobile app and Improve Connected Health.
Client libraries
We have language bindings in Shell, .NET, Java, JavaScript, PHP, Python and Ruby! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
For complete implementation please have a look at our FHIR Client Example Repository
Clients | |||||||
---|---|---|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Shell | Ruby | Python | PHP | JS | Java | C# | Go |
Get started
Welcome to the Open HealthHub Open API Hub! You can use our API's to access the Open HealthHub Open API endpoints based on FHIR, which can interact with the Open HealthHub hub for questionnaires, information and remote patient monitoring.
Step 1. Play and learn
Get familiar with our FHIR REST APIs, FHIR Client Example Repository and our example code here on this website. You can play with our sandbox with the listed credentials.
Learn more about FHIR via the following links:
Step 2. Get Credentials
To generate FHIR API credentials for the live environment:
- Request for an Open HealthHub API developer account.
- We will send your credentials.
- You can start using your credentials.
- Replace the sandbox credentials with your credentials.
- Replace the sandbox URL with the live URL.
For more information about authentication see our documentation
Step 3. Upload your public key
- Download and install the latest version of GPG command line tools for your operating system.
- Generate a GPG key pair.
- in your terminal/command prompt enter
gpg --expert --full-generate-key
- choose
ECC and ECC
for the kind of key,Curve 25519
for the kind of curve, choose default 0 (does not expire) for keys validity, choose a user ID to match your usecase, when choosing a passphrase remember that it will need to be provided every time the private key is used. - use
gpg --list-secret-keys --keyid-format=long
to view all keys - for the key you want to use, find the line that looks like
sec ed25519/9EB63F8FEEC4DEB8 2021-09-23 [SC]
take the key ID, in this case: 9EB63F8FEEC4DEB8 - run
gpg --armor --export <KEYID>
to export your key. You want to upload your public key that looks like:-----BEGIN PGP PUBLIC KEY BLOCK----- ..... -----END PGP PUBLIC KEY BLOCK-----
- run
gpg --armor --export-secret-key <KEYID>
to export your private key that looks like-----BEGIN PGP PRIVATE KEY BLOCK----- ..... -----END PGP PRIVATE KEY BLOCK-----
. Store this in a password manager/secret available only to your software for decrypting.
- in your terminal/command prompt enter
- Using our Binary resource upload your public key
Step 4. Get an Improve Designer account
You can design your own questionnaires and patient instructions which you can use for your app project using the Improve Designer.
- Register your own Improve Designer account or deliver your API key to one of your colleagues who has an Improve Designer account.
- Use the program credentials for your app project.
Step 5. Start your integration
Start building your own App project using our documentation and our example FHIR Client Example Repository.
Authentication
Retrieve the access token:
// Create Interceptor class that implements IClientInterceptor
@Override
public void interceptRequest(IHttpRequest theRequest) {
String token = getToken();
theRequest.addHeader(Constants.HEADER_AUTHORIZATION, (Constants.HEADER_AUTHORIZATION_VALPREFIX_BEARER + token));
}
private String getToken() {
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token"))
.POST(ofString("client_id=api-sandbox&client_secret=95810e52-4307-41f5-99a4-d873ab63b536&grant_type=client_credentials"))
.header("Content-Type", "application/x-www-form-urlencoded")
.build();
String response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()).body();
JsonObject respAsJson = JsonParser.parseString(response).getAsJsonObject();
String token = respAsJson.getAsJsonPrimitive("access_token").getAsString();
}
const headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Accept', 'application/json');
const urlencoded = new URLSearchParams();
urlencoded.append('client_id', 'api-sandbox');
urlencoded.append('client_secret', '95810e52-4307-41f5-99a4-d873ab63b536');
urlencoded.append('grant_type', 'client_credentials');
const requestOptions = {
method: 'POST',
headers: headers,
body: urlencoded,
redirect: 'follow'
};
const token = await fetch('https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token', requestOptions)
.then(response => response.json())
.then(result => result.access_token);
$ch = curl_init('https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => 'client_id=api-sandbox&client_secret=95810e52-4307-41f5-99a4-d873ab63b536&grant_type=client_credentials',
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded'
],
]);
$res = curl_exec($ch);
curl_close($ch);
$decoded_json = json_decode($res, true);
$token = $decoded_json['access_token'];
type TokenResponse struct {
Access_token string
}
func authenticate() string {
url := "https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token"
method := "POST"
payload := strings.NewReader("client_id=api-sandbox&client_secret=95810e52-4307-41f5-99a4-d873ab63b536&grant_type=client_credentials")
client := &http.Client{}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return ""
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return ""
}
defer res.Body.Close()
data := new(TokenResponse)
err = json.NewDecoder(res.Body).Decode(&data)
if err != nil {
fmt.Println(err)
return ""
}
return data.Access_token
}
# The ruby fhir client takes care of retrieving the token, if configured correctly as shown below
token=$(curl --location --request POST 'https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=api-sandbox' \
--data-urlencode 'client_secret=95810e52-4307-41f5-99a4-d873ab63b536' \
--data-urlencode 'grant_type=client_credentials' | jq -r '.access_token')
def get_token():
url = 'https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token'
response = requests.post(url,
f'client_id={api-sandbox}&client_secret={95810e52-4307-41f5-99a4-d873ab63b536}&grant_type=client_credentials',
headers={'Content-Type': 'application/x-www-form-urlencoded'}).json()
return response['access_token']
const string authUrl =
"https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token";
IEnumerable<KeyValuePair<string, string>> auth = new[]
{
new KeyValuePair<string, string>("client_id", "api-sandbox"),
new KeyValuePair<string, string>("client_secret", "95810e52-4307-41f5-99a4-d873ab63b536"),
new KeyValuePair<string, string>("grant_type", "client_credentials")
};
HttpClient http = new HttpClient();
HttpContent content = new FormUrlEncodedContent(auth);
HttpResponseMessage response = http.PostAsync(authUrl, content).Result;
return JsonConvert.DeserializeObject<Dictionary<string, string>>(
response.Content.ReadAsStringAsync().Result);
The
client_id
andclient_secret
need to be replaced with the id and secret for your clientAdding the API key and token to the request:
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
client.additional_headers = {'X-API-KEY': 'ad880601-b7e6-4d86-901d-b6fca96fc725'}
client.set_oauth2_auth('client_id', 'client_secret', 'https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/auth', 'https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token')
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4',
authorization=f'Bearer {get_token()}',
extra_headers={'x-api-key': 'ad880601-b7e6-4d86-901d-b6fca96fc725'}
)
# With shell, you can just pass the correct header with each request
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4" \
-H "X-API-KEY: ad880601-b7e6-4d86-901d-b6fca96fc725" \
-H "Authorization: Bearer $token"
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const requestObj = typeof request === 'string' ? {url: request} : request;
const parameterSeparator = requestObj.url.indexOf('?') === -1 ? '?' : '&';
requestObj.url = `${requestObj.url}${parameterSeparator}apikey=ad880601-b7e6-4d86-901d-b6fca96fc725`;
requestObj.headers = {
Authorization: `Bearer ${this.token}`
};
client.request(requestObj);
$ch = curl_init('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => array(
'X-API-Key: ' . self::API_KEY
),
CURLOPT_XOAUTH2_BEARER => $token,
CURLOPT_HTTPAUTH => CURLAUTH_BEARER
]);
req := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4", nil)
req.Header.Add("X-API-KEY", "ad880601-b7e6-4d86-901d-b6fca96fc725")
token := authenticate()
req.Header.Add("Authorization", "Bearer " + token)
@Interceptor
public class ApiKeyInterceptor {
@Hook(Pointcut.CLIENT_REQUEST)
public void addApiKey(IHttpRequest request) {
request.addHeader("X-API-KEY", "ad880601-b7e6-4d86-901d-b6fca96fc725");
}
}
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
client.registerInterceptor(new ApiKeyInterceptor());
client.registerInterceptor(new AuthorizationInterceptor());
public class ApiKeyMessageHandler : HttpClientHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("x-api-key", "ad880601-b7e6-4d86-901d-b6fca96fc725");
request.Headers.Add("Authorization", $"Bearer {_token}");
return await base.SendAsync(request, cancellationToken);
}
}
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4", settings, new ApiKeyMessageHandler());
Make sure to replace
api-key
with your personal API key.
Improve uses API keys and OpenID Connect to allow access to the API. You can register a new Improve API key at our developer portal.
Improve expects the API key and OpenID Connect access token to be included in all API requests to the server in a header, or as request parameter on the url.
For the sandbox environment this looks as follows:
- API key as header:
X-API-KEY: ad880601-b7e6-4d86-901d-b6fca96fc725
- API key as url parameter:
https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Appointment/1?apikey=ad880601-b7e6-4d86-901d-b6fca96fc725
- Access token header:
Authorization: Bearer <access_token_retrieved_from_oidc_server>
- OpenID Connect client_id:
api-sandbox
- OpenID Connect client_secret:
95810e52-4307-41f5-99a4-d873ab63b536
FHIR 4 API Reference
Overview
FHIR Resource | Open HealthHub entity |
---|---|
PlanDefinition | Program |
Questionnaire | Module |
CarePlan | Activated Program |
Questionnaire Reference + Status | Module + Participant Task |
QuestionnaireResponse | Module Response |
Times
Before going into detail with the exposed FHIR API's it's important to note that all dates and timestamps mentioned in these API's are in UTC. This means that any localisation of these dates and timestamps will need to happen on the client side. For exact details on how to fill these, we recommend looking into the FHIR documentation
Binary (Upload Key)
Upload public key
String publicKey = Base64.getEncoder().encodeToString(IOUtils.resourceToByteArray("sandbox.pub"));
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary"))
.POST(ofString(publicKey))
.header("Content-Type", "text/plain")
.header("Authorization", "Bearer " + getToken())
.header("x-api-key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
.build();
HttpResponse<Void> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.discarding());
HttpClient http = new HttpClient();
var publicKey = File.ReadAllBytes(Path.Combine(Directory.GetCurrentDirectory(), "sandbox.pub"));
var encodedKey = System.Convert.ToBase64String(publicKey);
var content = new ByteArrayContent(Encoding.ASCII.GetBytes(encodedKey));
content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain");
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthenticationUtil.authenticate());
http.DefaultRequestHeaders.Add("x-api-key", "ad880601-b7e6-4d86-901d-b6fca96fc725");
HttpResponseMessage response = http.PostAsync("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary", content).Result;
Console.Out.WriteLine(response.StatusCode);
publicKey, err := ioutil.ReadFile("sandbox.pub")
if err != nil {
return 0, err
}
pubKeysBytes := []byte(publicKey)
encodedBytes := []byte(b64.StdEncoding.EncodeToString(pubKeysBytes))
req, err := http.NewRequest("POST", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary", bytes.NewBuffer(encodedBytes))
if err != nil {
return 0, err
}
token := client.Authenticate()
req.Header.Add("Authorization", "Bearer "+token)
req.Header.Add("Content-Type", "text/plain")
req.Header.Add("X-API-KEY", "ad880601-b7e6-4d86-901d-b6fca96fc725")
resp, err := http.DefaultClient.Do(req)
const client = new Client();
const token = await client.getToken();
const request = {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
'Authorization': `Bearer ${token}`,
'X-API-KEY': 'ad880601-b7e6-4d86-901d-b6fca96fc725'
},
body: btoa(publicKey)
};
const promise = fetch('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary', request);
return promise.then(resp => {
return {responseStatus: resp.status, request};
});
$client = new FhirClient();
$keyASCII = file_get_contents(dirname(__FILE__) . 'sandbox.pub');
$encodedPubKey = base64_encode($keyASCII);
return $client->createRaw("Binary", $encodedPubKey, 'text/plain');
with open('sandbox.pub') as file:
key = file.read()
key_bytes = key.encode('ascii')
base64_bytes = base64.b64encode(key_bytes)
encoded_key = base64_bytes.decode('ascii')
token = get_token()
resp = requests.post(url='https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary',
data=encoded_key,
headers={'Content-Type': 'text/plain', 'Authorization': f'Bearer {token}', 'X-API-KEY': 'ad880601-b7e6-4d86-901d-b6fca96fc725'})
return resp
uri = URI('https://auth.openhealthhub.com/auth/realms/OpenHealthHub/protocol/openid-connect/token')
params = { 'client_id' => 'api-sandbox',
'client_secret' => '95810e52-4307-41f5-99a4-d873ab63b536',
'grant_type' => 'client_credentials' }
res = Net::HTTP.post_form(uri, params)
token = JSON.parse(res.body)['access_token']
file = open('sandbox.pub')
key = file.read
encoded_key = Base64.strict_encode64(key)
uri = URI('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary')
Net::HTTP.post(uri, encoded_key, { 'Content-Type' => 'text/plain',
'X-API-KEY' => 'ad880601-b7e6-4d86-901d-b6fca96fc725',
'Authorization' => 'Bearer ' + token })
base64Key=$(base64 -w 0 sandbox.pub)
curl -X POST "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary" -H "Content-Type: text/plain" -H "X-API-KEY: ad880601-b7e6-4d86-901d-b6fca96fc725" -H "Authorization: Bearer $token" --data-raw "$base64Key"
This endpoint can be used to upload your public key to Open HealthHub. This key will be used to encrypt patient data so you/your application can decrypt the patient data using your private key.
HTTP Request
POST https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Binary
The body of the post should be the base64 encoded version of the public key.
Request headers
Header | Value | Description |
---|---|---|
Content-Type | text/plain | the Content-Type should be text/plain |
CarePlan
Create CarePlan
curl -X POST "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan" -H "Content-Type: application/json" --data-binary "@careplan.json"
CarePlan carePlan = new CarePlan();
carePlan.setPeriod(new Period().setStart(Date.from(Instant.now())));
Patient patient = new Patient();
patient.setId("patient");
HumanName humanName = new HumanName();
humanName.setText("Test Patient");
patient.setName(Collections.singletonList(humanName));
ContactPoint email = new ContactPoint();
email.setSystem(ContactPoint.ContactPointSystem.EMAIL);
email.setValue("test@patient.ohh");
patient.addTelecom(email);
Identifier programPatientId = new Identifier();
programPatientId.setSystem("urn:oid:2.16.840.1.113883.2.4.99");
programPatientId.setValue("1234");
patient.addIdentifier(programPatientId);
carePlan.addContained(patient);
carePlan.setSubject(new Reference("#patient"));
carePlan.setInstantiatesCanonical(List.of(new CanonicalType("PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6")));
return client.create().resource(carePlan).execute();
var patient = new Patient
{
Id = "patient",
Identifier = new List<Identifier>
{
new Identifier
{
System = "urn:oid:2.16.840.1.113883.2.4.99",
Value = "1234"
}
},
Name = new List<HumanName> {new HumanName {Text = "Test Patient"}},
Telecom = new List<ContactPoint>
{
new ContactPoint
{
System = ContactPoint.ContactPointSystem.Email,
Value = "test@patient.ohh"
}
}
};
var carePlan = new CarePlan
{
Period = new Period(FhirDateTime.Now(), null),
Contained = new List<Resource>{patient},
Subject = new ResourceReference("#patient"),
InstantiatesCanonical = new List<string> { "PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6" }
};
var plan = client.Create(carePlan);
Console.Out.WriteLine(plan.InstantiatesCanonical.First());
}
const client = new Client();
return client.create({
resourceType: "CarePlan",
contained: [
{
resourceType: "Patient",
id: "patient",
identifier: [
{
system: "urn:oid:2.16.840.1.113883.2.4.99",
value: "1234"
}
],
name: [
{
text: "Test Patient"
}
],
telecom: [
{
system: "email",
value: "test@patient.ohh"
}
]
}
],
instantiatesCanonical: [
"https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6"
],
status: "active",
intent: "proposal",
subject: {
reference: "#patient"
},
period: {
start: "2021-03-16T13:32:37.430+01:00"
}
}
);
FhirClient.new
careplan = FHIR::CarePlan.new
careplan.period = FHIR::Period.new
careplan.period.start = Date.new(2021, 7, 9)
patient = FHIR::Patient.new
patient.id = 'patient'
patient_identifier = FHIR::Identifier.new
patient_identifier.system = 'urn:oid:2.16.840.1.113883.2.4.99'
patient_identifier.value = '1234'
patient.identifier = [patient_identifier]
patient.name = 'Test Patient'
patient_email = FHIR::ContactPoint.new
patient_email.system = 'email'
patient_email.value = 'test@patient.ohh'
patient.telecom = [patient_email]
careplan.contained = [patient]
careplan.instantiatesCanonical = 'PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6'
patient_reference = FHIR::Reference.new
patient_reference.reference = '#patient'
careplan.subject = patient_reference
FHIR::CarePlan.create(careplan)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
with open('careplan.json', 'r') as file:
careplan_json = json.load(file)
create_response = await client.execute ('CarePlan', method='post', data=careplan_json)
print(create_response)
file, err := os.Open("careplan/careplan.json")
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan", file)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
$client = new FhirClient();
$careplan = new FHIRCarePlan();
$patient = new FHIRPatient();
$patientName = new FHIRHumanName();
$patientName->setText('Test Patient');
$patientEmail = new FHIRContactPoint();
$telecomType = new FHIRContactPointSystem();
$telecomType->setValue('email');
$patientEmail->setSystem($telecomType)->setValue('test@patient.ohh');
$patientIdentifier = new FHIRIdentifier();
$patientIdentifier->setSystem('urn:oid:2.16.840.1.113883.2.4.99')->setValue('1234');
$patient->setId('patient')->addName($patientName)->addTelecom($patientEmail)->addIdentifier($patientIdentifier);
$careplan->addContained($patient);
$careplan->setSubject(new FHIRReference(['#patient']));
$careplan->setInstantiatesCanonical([new FHIRCanonical('PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6')]);
$period = new FHIRPeriod();
$period->setStart([new FHIRInstant('2021-03-16T13:32:37.430+01:00')]);
$careplan->setPeriod($period);
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($careplan)
]);
$res = curl_exec($ch);
curl_close($ch);
$createdCarePlan = new FHIRCarePlan(json_decode($res, true));
Update CarePlan
curl -X PUT "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/1" -H "Content-Type: application/json" --data-binary "@careplan.json"
CarePlan carePlan = new CarePlan();
carePlan.setId("1");
carePlan.setPeriod(new Period().setStart(Date.from(Instant.now())));
Patient patient = new Patient();
patient.setId("patient");
HumanName humanName = new HumanName();
humanName.setText("Test Patient");
patient.setName(Collections.singletonList(humanName));
ContactPoint email = new ContactPoint();
email.setSystem(ContactPoint.ContactPointSystem.EMAIL);
email.setValue("test@patient.ohh");
patient.addTelecom(email);
Identifier programPatientId = new Identifier();
programPatientId.setSystem("urn:oid:2.16.840.1.113883.2.4.99");
programPatientId.setValue("1234");
patient.addIdentifier(programPatientId);
carePlan.addContained(patient);
carePlan.setSubject(new Reference("#patient"));
carePlan.setInstantiatesCanonical(List.of(new CanonicalType("PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6")));
return client.update().resource(carePlan).execute();
var patient = new Patient
{
Id = "patient",
Identifier = new List<Identifier>
{
new Identifier
{
System = "urn:oid:2.16.840.1.113883.2.4.99",
Value = "1234"
}
},
Name = new List<HumanName> {new HumanName {Text = "Test Patient"}},
Telecom = new List<ContactPoint>
{
new ContactPoint
{
System = ContactPoint.ContactPointSystem.Email,
Value = "test@patient.ohh"
}
}
};
var carePlan = new CarePlan
{
Id = "1",
Period = new Period(FhirDateTime.Now(), null),
Contained = new List<Resource>{patient},
Subject = new ResourceReference("#patient"),
InstantiatesCanonical = new List<string> { "PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6" }
};
var plan = client.Update(carePlan);
Console.Out.WriteLine(plan.InstantiatesCanonical.First());
}
const client = new Client();
return client.update({
resourceType: "CarePlan",
id: "1",
contained: [
{
resourceType: "Patient",
id: "patient",
identifier: [
{
system: "urn:oid:2.16.840.1.113883.2.4.99",
value: "1234"
}
],
name: [
{
text: "Test Patient"
}
],
telecom: [
{
system: "email",
value: "test@patient.ohh"
}
]
}
],
instantiatesCanonical: [
"https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6"
],
status: "active",
intent: "proposal",
subject: {
reference: "#patient"
},
period: {
start: "2021-03-16T13:32:37.430+01:00"
}
}
);
FhirClient.new
careplan = FHIR::CarePlan.new
careplan.period = FHIR::Period.new
careplan.period.start = Date.new(2021, 7, 9)
patient = FHIR::Patient.new
patient.id = 'patient'
patient_identifier = FHIR::Identifier.new
patient_identifier.system = 'urn:oid:2.16.840.1.113883.2.4.99'
patient_identifier.value = '1234'
patient.identifier = [patient_identifier]
patient.name = 'Test Patient'
patient_email = FHIR::ContactPoint.new
patient_email.system = 'email'
patient_email.value = 'test@patient.ohh'
patient.telecom = [patient_email]
careplan.contained = [patient]
careplan.instantiatesCanonical = 'PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6'
patient_reference = FHIR::Reference.new
patient_reference.reference = '#patient'
careplan.subject = patient_reference
FHIR::CarePlan.partial_update(1, careplan)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
with open('careplan.json', 'r') as file:
careplan_json = json.load(file)
update_response = await client.execute ('CarePlan', method='put', data=careplan_json)
print(update_response)
file, err := os.Open("careplan/careplan.json")
if err != nil {
return nil, err
}
req, err := http.NewRequest("PUT", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/1", file)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
$client = new FhirClient();
$careplan = new FHIRCarePlan();
$careplan->setId("1");
$patient = new FHIRPatient();
$patientName = new FHIRHumanName();
$patientName->setText('Test Patient');
$patientEmail = new FHIRContactPoint();
$telecomType = new FHIRContactPointSystem();
$telecomType->setValue('email');
$patientEmail->setSystem($telecomType)->setValue('test@patient.ohh');
$patientIdentifier = new FHIRIdentifier();
$patientIdentifier->setSystem('urn:oid:2.16.840.1.113883.2.4.99')->setValue('1234');
$patient->setId('patient')->addName($patientName)->addTelecom($patientEmail)->addIdentifier($patientIdentifier);
$careplan->addContained($patient);
$careplan->setSubject(new FHIRReference(['#patient']));
$careplan->setInstantiatesCanonical([new FHIRCanonical('PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6')]);
$period = new FHIRPeriod();
$period->setStart([new FHIRInstant('2021-03-16T13:32:37.430+01:00')]);
$careplan->setPeriod($period);
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/1';
$ch = curl_init($url);
$body = json_encode($careplan);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => $body
]);
$res = curl_exec($ch);
curl_close($ch);
$updatedCarePlan = new FHIRCarePlan(json_decode($res, true));
Get CarePlan
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/3"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
CarePlan carePlan = client.read()
.resource(CarePlan.class)
.withId(3L)
.execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
var app = client.Read<CarePlan>("CarePlan/1");
Console.Out.WriteLine(app.Description);
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const carePlan = await client.request('CarePlan/1');
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
FHIR::CarePlan.read(3)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
carePlan = await client.resource('CarePlan').execute('1', 'GET')
req, err := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/1", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
unmarshaller, err := jsonformat.NewUnmarshaller(config.TimeZone, config.FhirVersion)
if err != nil {
return nil, err
}
bytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
unmarshal, err := unmarshaller.Unmarshal(bytes)
if err != nil {
return nil, err
}
unmarshal.(*r4pb.ContainedResource).GetCarePlan()
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/4?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$carePlan = new FHIRCarePlan(json_decode($res, true));
Delete CarePlan
curl -X DELETE "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/3"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
CarePlan carePlan = client.delete().resourceById("CarePlan", "1").execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
client.Delete("CarePlan/1");
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
await client.delete('CarePlan', 1);
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
FHIR::CarePlan.destroy(3)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
await client.resource('CarePlan').execute('1', 'DELETE')
req, err := http.NewRequest("DELETE", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/1", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/4';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CUSTOMREQUEST => 'DELETE'
]);
$res = curl_exec($ch);
curl_close($ch);
When a care plan is scheduled by a doctor via Open HealthHub the patient will be notified by email. They will receive a link and pin code to
access the program.
When a care plan is scheduled through a connected EHR system the link (with pin code) will be given in the CarePlan response and can then be
integrated where needed in the requesting application.
The link will be specified in an extension with url http://openhealthhub.com/fhir/StructureDefinition/improve-program-link
.
The APIs can be used to connect Open HealthHub to, for example, your EHR or scheduling software.
Retrieving a CarePlan
A CarePlan can be retrieved by its ID using a GET
request. The CarePlan will contain the following information:
- patient information (
subject
) - the PlanDefinition it has instantiated (
instantiatesCanonical
) status
, eitheractive
ordraft
, depending on whether the patient has accepted the invitation- Start and end date of the CarePlan (
period.start
andperiod.end
) - An
extension
containing the URL the patient needs to open the program as described above - Two
extensions
that contain the Customized Invite Mail text and image when set in the Improve Designer- The image uses extension url
http://openhealthhub.com/fhir/StructureDefinition/custom-invite-image
and is of type Attachment - The text uses extension url
http://openhealthhub.com/fhir/StructureDefinition/custom-invite-text
and is of type String
- The image uses extension url
Creating a CarePlan
For creating new CarePlan the following fields are required (on top of the FHIR requirements):
Field | Description | Example Value |
---|---|---|
subject.actor | There should be exactly one patient subject | |
subject.actor.name.text | The patient subject should have a name specified in the text field, other properties will be ignored. If no name present the email address of the patient will be used |
Test Patient |
subject.actor.telecom | The patient subject should have a telecom element of type 'email', if multiple email addresses are found the first one will be used | test@patient.ohh |
subject.actor.identifier.value | The patient should have a patient number, this should be identifiable by the system creating the care plan. | 564372819 |
subject.actor.identifier.system | The patient identifier, this should be the system of the healthcare institution. | urn:oid:2.16.840.1.113883.2.4.99 |
subject.actor.identifier.use | The patient identifier use. Only required when supplying more than 1 identifier. If you list more than 1 identifier there should be one and only one with use official . |
official, usual, secondary |
instantiatesCanonical | The instantiatesCanonical should hold a canonical URI according to FHIR specifications, Open Health Hub is a bit more lenient and accepts a reference to the PlanDefinition (i.e. Improve Program) for which the patient is invited | PlanDefinition/cca2eaf3-03a9-46c0-88c6-e0287917cea6 |
period.start | A start date (for details regarding the format refer to Times) should be entered when the patient can start the program. When retrieving a care plan we will always fill the end date. If no end date is known, the start date will be used. | 2021-03-16T13:32:37.430+01:00 |
activity | For our enterprise customers we support adding an activity to specify whether:
|
Updating a CarePlan
A CarePlan can be updated by sending a PUT
request with the updated CarePlan.
The CarePlan to update can be specified in 2 ways. The first is by setting the ID on the URL.
The second is by adding a patient.identifier
query parameter with one of the identifiers of the patient on the url.
There are some restrictions when updating a CarePlan:
- The CarePlan can only be updated when the patient has not completed any of the tasks in the program yet.
- When updating the patient's email address, the CarePlan will only be updated when the email address is not shared with other patients and when the email address does not belong to another user.
- When using the
patient.identifier
query:- If no CarePlan can be found using the query, a new CarePlan will be created
- If multiple CarePlans are found an error response with status
412
will be returned
Deleting a CarePlan
A CarePlan can be deleted by sending a DELETE
request.
The CarePlan to delete can be specified in 2 ways. The first is by setting the ID on the URL.
The second is by adding patient.identifier
and instantiates-canonical
query parameters with on the url. The patient.identifier
should
be one of the identifiers of the patient; the instantiates-canonical
should be a reference to the PlanDefinition as a complete URL (
e.g. https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/<ID>
) or a resource reference (e.g. PlanDefinition/<ID>
). If the query returns
multiple
results an error response with status 412
will be returned.
HTTP Request
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/<ID>
POST https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan
PUT https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/<ID>
PUT https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/?patient.identifier=<PatientIdentifierToken>
DELETE https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/<ID>
DELETE https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/CarePlan/?patient.identifier=<PatientIdentifierToken>&instantiates-canonical=<PlanDefinitionReference>
URL Parameters
Parameter | Description |
---|---|
ID | The ID of the CarePlan to retrieve |
PatientIdentifierToken | A token representing a patient identifier |
PlanDefinitionReference | A reference to the PlanDefinition (specified as: https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/<PlanDefinitionId> or PlanDefinition/<PlanDefinitionId> |
VitalSigns
Get Observation
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Observation/1"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
Observation observation = client.read()
.resource(Observation.class)
.withId(1)
.execute()
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
var obs = client.Read<Observation>("Observation/1");
Console.Out.WriteLine(obs.Category[0].Text);
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const observation = await client.request("Observation/1");
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
FHIR::Observation.read(1)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
obs = await client.resource('Observation').execute('1', 'GET')
print(obs.resource_type, obs.id)
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Observation/4?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$observation = new FHIRObservation(json_decode($res, true));
Search Observation
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Observation?identifier=identifier&device-name=devicename"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
Bundle observationBundle = client.search()
.forResource(Observation.class)
.where(Patient.IDENTIFIER.exactly().identifier("1234"))
.where(Device.DEVICE_NAME.matches().value("deviceName"))
.returnBundle(Bundle.class)
.execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
var obs = client.Read<Observation>("Observation/1");
Console.Out.WriteLine(obs.Category[0].Text);
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const bundle = await client.request("Observation?identifier=1234&device-name=testDevice");
const observations = bundle.entry.map(entry => entry.resource);
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
params = {
'identifier': '1234',
'device-name': 'testDevice'
}
FHIR::Observation.search(params)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
observations = await client.resources('Observation').search(identifier='identifier', device_name='devicename').fetch()
for o in observations:
print(o.as_json())
req, err := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Observation/1", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Observation?device-name=deviceName&identifier=1234?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$bundle = new FHIRBundle(json_decode($res, true));
Having accurate patient’s vital signs available whenever and wherever needed is crucial for medical professionals to provide the best care possible. Vital signs acquired via Improve Connected Health can be monitored on Improve Dashboard, but also added to, for example, the patient’s EHR file.
The APIs can be used to (automatically) add vital signs retrieved via Open HealthHub in any of the supported formats to your EHR system(s), or to integrate or create a different dashboard.
HTTP Request
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Observation/<ID>
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Observation/search?identifier=<PATIENT-NUMBER>&device-name=<DEVICE-NAME>
URL Parameters
Parameter | Description |
---|---|
ID | The ID of the Observation to retrieve |
PATIENT-NUMBER | the patient-number to retrieve measurements Observations for |
DEVICE-NAME | name of the device that the measurements were made with |
PlanDefinition
Get PlanDefinition
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
PlanDefinition planDefinition = client.read()
.resource(PlanDefinition.class)
.withId("57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca")
.execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/", settings);
var qr = client.Read<PlanDefinition>("PlanDefinition/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca");
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const resp = await client.request("PlanDefinition/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca");
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
FHIR::PlanDefinition.read('57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca')
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
response = await client.resource('PlanDefinition').execute('57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca', 'GET')
print(response)
req, err := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
unmarshaller, err := jsonformat.NewUnmarshaller(config.TimeZone, config.FhirVersion)
if err != nil {
return nil, err
}
bytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
unmarshal, err := unmarshaller.Unmarshal(bytes)
if err != nil {
return nil, err
}
unmarshal.(*r4pb.ContainedResource).GetPlanDefinition()
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$planDefinition = new FHIRPlanDefinition(json_decode($res, true));
Search PlanDefinition
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition?definition=Questionnaire/97f680b9-e397-4298-8c53-de62a284c806"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
Bundle bundle = client.search()
.forResource(PlanDefinition.class)
.where(PlanDefinition.DEFINITION.hasId("Questionnaire/97f680b9-e397-4298-8c53-de62a284c806"))
.returnBundle(Bundle.class)
.execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
var qr = client.Search<PlanDefinition>(new []{"definition=Questionnaire/97f680b9-e397-4298-8c53-de62a284c806"});
qr.Entry.ForEach(component => Console.WriteLine(component.FullUrl));
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const bundle = await client.request("PlanDefinition?definition=Questionnaire/97f680b9-e397-4298-8c53-de62a284c806");
const responses = bundle.entry.map(entry => entry.resource);
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
params = {
'definition': 'Questionnaire/97f680b9-e397-4298-8c53-de62a284c806'
}
FHIR::PlanDefinition.search(params)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
response = await client.resources('PlanDefinition').search(definition='Questionnaire/97f680b9-e397-4298-8c53-de62a284c806').fetch()
print(response)
req, err := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition?definition=Questionnaire/97f680b9-e397-4298-8c53-de62a284c806", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition?definition=Questionnaire/97f680b9-e397-4298-8c53-de62a284c806?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$bundle = new FHIRBundle(json_decode($res, true));
The program as created in Improve Designer.
This endpoint can be used to retrieve a PlanDefinition by id, or search using a small set of parameters.
HTTP Request
Get by ID
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition/<ID>
Search
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/PlanDefinition?definition=Questionnaire/<MODULE_UUID>&publisher=<PUBLISHER_NAME>
URL Parameters
Note that in case of search all parameters are optional, a search without parameters will return all resources that are accessible for your client.
Parameter | Description |
---|---|
ID | UUID of the PlanDefinition to retrieve |
MODULE_UUID | (optional) UUID of the Questionnaire that is part of this PlanDefinition |
PUBLISHER_NAME | (optional) name of the user that published the PlanDefinition |
Questionnaire
Get Questionnaire
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Questionnaire/781dc338-a932-4c0e-8c02-8d419fad4264"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
Questionnaire questionnaire = client.read()
.resource(Questionnaire.class)
.withId("781dc338-a932-4c0e-8c02-8d419fad4264")
.execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
var questionnaire = client.Read<Questionnaire>("Questionnaire/781dc338-a932-4c0e-8c02-8d419fad4264");
Console.Out.WriteLine(questionnaire.Description);
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const questionnaire = client.request("Questionnaire/781dc338-a932-4c0e-8c02-8d419fad4264");
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
FHIR::Questionnaire.read("781dc338-a932-4c0e-8c02-8d419fad4264")
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
questionnaire = await client.resource('Questionnaire').execute('781dc338-a932-4c0e-8c02-8d419fad4264', 'GET')
print(questionnaire.description)
req, err := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Questionnaire/781dc338-a932-4c0e-8c02-8d419fad4264", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
unmarshaller, err := jsonformat.NewUnmarshaller(config.TimeZone, config.FhirVersion)
if err != nil {
return nil, err
}
bytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
unmarshal, err := unmarshaller.Unmarshal(bytes)
if err != nil {
return nil, err
}
unmarshal.(*r4pb.ContainedResource).GetQuestionnaire()
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Questionnaire/781dc338-a932-4c0e-8c02-8d419fad4264?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$questionnaire = new FHIRQuestionnaire(json_decode($res, true));
Patients interact with healthcare professionals through questionnaires on Improve Mobile App. A Questionnaire can either be selected from Improve Library or custom made in Improve Designer. Improve Designer allows the user to specify custom codings for questions. These codings can be used to map data in this resource to existing data. The unfilled-out questionnaire is made available in FHIR format through this end-point. Generally the Questionnaire item components retrieved through this endpoint correspond to questions created in the Improve Designer. An exception to this is the readonly text items that are generated for the formulas defined in the Improve Designer. These are made so that even if a result slide is not defined (where the formula is mentioned as a sub item), the formula will still be in the questionnaire.
Formulas mostly follow mathjs syntax. There is exactly one exception to this, which is the variables. To clarify which QuestionnaireItem result is used in a formula,
the variables used in the formulas will be replaced by the linkId, surrounded by $
, of the QuestionnaireItem result that should replace the variable.
This linkId may be specified by using the Export label
field in Improve Designer and does not necessarily follow mathjs' syntax.
For example given answers: ```json { "some-long-link-id": 2, "something-else": 3 }
and formula $some-long-link-id$ * $something-else$
, the result should be 2 * 3
or when evaluated 6.
This endpoint retrieves a Questionnaire by id.
HTTP Request
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Questionnaire/<ID>
URL Parameters
Parameter | Description |
---|---|
ID | The ID of the Questionnaire to retrieve |
QuestionnaireResponse
Get QuestionnaireResponse
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
QuestionnaireResponse questionnaireResponse = client.read()
.resource(QuestionnaireResponse.class)
.withId("57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca")
.execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/", settings);
var qr = client.Read<QuestionnaireResponse>("QuestionnaireResponse/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca");
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const resp = await client.request("QuestionnaireResponse/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca");
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
FHIR::QuestionnaireResponse.read('57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca')
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
response = await client.resource('QuestionnaireResponse').execute('57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca', 'GET')
print(response)
req, err := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
unmarshaller, err := jsonformat.NewUnmarshaller(config.TimeZone, config.FhirVersion)
if err != nil {
return nil, err
}
bytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
unmarshal, err := unmarshaller.Unmarshal(bytes)
if err != nil {
return nil, err
}
unmarshal.(*r4pb.ContainedResource).GetQuestionnaireResponse()
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse/57a1f708-d9cf-4d8c-9f25-b5a450e7f0ca?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$questionnaireResponse = new FHIRQuestionnaireResponse(json_decode($res, true));
Search QuestionnaireResponse
curl "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse?patient.identifier=6226217e&based-on=97f680b9-e397-4298-8c53-de62a284c806"
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
Bundle bundle = client.search()
.forResource(QuestionnaireResponse.class)
.where(QuestionnaireResponse.BASED_ON.hasId("97f680b9-e397-4298-8c53-de62a284c806"))
.and(QuestionnaireResponse.PATIENT.hasChainedProperty(Patient.IDENTIFIER.exactly().identifier("6226217e")))
.returnBundle(Bundle.class)
.execute();
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
var qr = client.Search<QuestionnaireResponse>(new []{"patient.identifier=6226217e", "based-on=97f680b9-e397-4298-8c53-de62a284c806"});
qr.Entry.ForEach(component => Console.WriteLine(component.FullUrl));
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const bundle = await client.request("QuestionnaireResponse?based-on=PlanDefinition/97f680b9-e397-4298-8c53-de62a284c806&patient.identifier=6226217e");
const responses = bundle.entry.map(entry => entry.resource);
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
params = {
'based-on': 'PlanDefinition/97f680b9-e397-4298-8c53-de62a284c806',
'patient.identifier': '6226217e'
}
FHIR::QuestionnaireResponse.search(params)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
response = await client.resources('QuestionnaireResponse').search(based_on='PlanDefinition/97f680b9-e397-4298-8c53-de62a284c806', patient__identifier='6226217e').fetch()
print(response)
req, err := http.NewRequest("GET", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse?based-on=PlanDefinition/97f680b9-e397-4298-8c53-de62a284c806&identifier=6226217e", nil)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse?based-on=PlanDefinition/97f680b9-e397-4298-8c53-de62a284c806&patient.identifier=6226217e?_format=json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
$res = curl_exec($ch);
curl_close($ch);
$bundle = new FHIRBundle(json_decode($res, true));
The patient’s filled out questionnaire is immediately visible for the medical professional on Improve applications.
The APIs can be used to add responses to, for example, the patient’s EHR file, or can be used to integrate or create a different dashboard.
This endpoint can be used to retrieve a QuestionnaireResponse by id, or search using a small set of parameters. Note when using the search endpoint a Bundle containing the QuestionnaireResponses that match the search criteria will be returned.
The answers of the questionnaire will be encrypted using OpenPGP. Details on decrypting the response can be found in the Decrypting QuestionnaireResponse section.
HTTP Request
Get by ID
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse/<ID>
Search
GET https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/QuestionnaireResponse?based-on.instantiates-canonical=PlanDefinition/<PROGRAM_UUID>&questionnaire=Questionnaire/<MODULE_UUID>&patient.identifier=<PATIENT_ID>&_since=<SINCE_DATE>
URL Parameters
Note that in case of search all parameters are optional, a search without parameters will return all resources that are accessible for your client.
Parameter | Description |
---|---|
ID | UUID of the QuestionnaireResponse to retrieve |
PROGRAM_UUID | (optional) UUID of the program this Questionnaire response belongs to |
MODULE_UUID | (optional) UUID of the Questionnaire that was answered |
PATIENT_ID | (optional) the id of the patient that answered the questionnaire in FHIR Token format |
SINCE_DATE | (optional) QuestionnaireResponses that were entered after this date, in ISO 8601 format. For details refer to Times |
Decrypting QuestionnaireResponse
The decrypted JSON with all answers
{
"date_1": [
{
"value": "1981-07-29",
"codes": []
}
],
"photo_1": [
{
"value": "base64EncodedImage",
"codes": []
}
],
"hslider_1": [
{
"value": "5.5",
"codes": []
}
],
"vslider_1": [
{
"value": "-9",
"codes": []
}
],
"formula_1": [
{
"value": "-3.5",
"codes": []
}
],
"number_1": [
{
"value": "42",
"codes": []
}
],
"mchoice_1": [
{
"value": "Raspberry",
"codes": [{
"code": "7658-8",
"system": "https://fhir.loinc.org/CodeSystem/loinc",
"display": "Raspberry BasoBnd Ab Qn",
"version": "2.71"
}]
}
],
"mselect_1": [
{
"value": "Laptop",
"codes": []
},
{
"value": "Smartphone",
"codes": []
}
],
"boolean_1": [
{
"value": "1",
"codes": []
}
],
"open_2": [
{
"value": "It's the best questionnaire I've ever seen!",
"codes": []
}
]
}
The private key used to decrypt the examples from the sandbox
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js v4.10.10
Comment: https://openpgpjs.org
xYYEYQeklhYJKwYBBAHaRw8BAQdA7zkG2GrTERRlKqZRhbHEYARkzWjXt4Bj
RBx9PFEfwwb+CQMIwF4UP4mQC0bgQkxklm3EDi6SFHw1kfMzQ+gqpfaepGau
EPjpSqLN48gZJMznHK4UBe0xzu67OP6Y9UyT8SL2dj/gSVcku1MZvPZCEP2Y
Is0uU2FuZGJveCBBUEkyIDxlZGR5K3NhbmRib3gyQG9wZW5oZWFsdGhodWIu
Y29tPsKPBBAWCgAgBQJhB6SWBgsJBwgDAgQVCAoCBBYCAQACGQECGwMCHgEA
IQkQAyVBKg8H7ZgWIQSmxMhcFAXUQBd0uOYDJUEqDwftmLCiAQDVYGQ9eI+J
WL0PYwgrY7StV590qZar9S1dJvmGfkcGAgD/e/EBG7C5+Kd5KO2uCaS2q42B
HKzBUGVRYBjFQ8/SUQDHiwRhB6SWEgorBgEEAZdVAQUBAQdAum8OjYljCvYq
GCKW84Fub4/e/fp3l8dE/oZsrwArMwUDAQgH/gkDCJRAihNl5syQ4C/UKaHt
gM94KCfG48hvgIiOFrBp7ZBkNOl30H0r/mOLD6+BrvMFLHUG3H+OTIwsjDbc
Q5sHAE9tPVDXA98luvBQC/KNu2HCeAQYFggACQUCYQeklgIbDAAhCRADJUEq
DwftmBYhBKbEyFwUBdRAF3S45gMlQSoPB+2Y9IYBAMCPkUQO9r7Ot3nff45i
vThPkehhDk+MDb4zWW3xXVe7AP0ZXv6yBNGlsm2xFyGtVQH30nckhyBeKGcT
CEykt3SCBQ==
=X1eg
-----END PGP PRIVATE KEY BLOCK-----
Load private key:
gpg --import "../../sandbox.key"
privateKey = PGPainless.readKeyRing().secretKeyRing(ClientPerAnswerApplication.class.getResourceAsStream(PRIVATE_KEY_FILE));
keyRingProtector = SecretKeyRingProtector.unlockAllKeysWith(Passphrase.fromPassword(PRIVATE_KEY_PASSPHRASE), privateKey);
var privateKey = File.ReadAllBytes(Path.Combine(Directory.GetCurrentDirectory(), "sandbox.key"));
var pgp = new Openpgp();
pgp.Keys.Add(new Key(privateKey));
pgp.Keys[0].Passphrase = PgpPassphrase;
const keys = await openpgp.key.readArmored(PRIVATE_KEY_FILE);
const key = keys.keys[0];
await key.decrypt(PRIVATE_KEY_PASSPHRASE);
this.decryptedPrivateKey = key;
GPGME::Key.import(File.open('../../sandbox.key'))
gpg = gnupg.GPG()
with open('../../sandbox.key') as file:
gpg.import_keys(file.read(), passphrase='api-sandbox')
privateKey, err := ioutil.ReadFile("../sandbox.key")
$keyASCII = file_get_contents(dirname(__FILE__) . '/../../../../sandbox.key');
$gnupg = new gnupg();
$importKeyResult = $gnupg->import($keyASCII);
$fingerPrint = $importKeyResult['fingerprint'];
$gnupg -> adddecryptkey($fingerPrint, 'api-sandbox');
return $gnupg;
Determine if QuestionnaireResponse is encrypted
jq -r '.extension[] | select(.url="http://openhealthhub.com/StructureDefinition/encryptedAnswers") | .valueString'
boolean isEncryptedResponse(QuestionnaireResponse questionnaireResponse) {
return questionnaireResponse.getMeta()
.getProfile()
.stream()
.anyMatch(profile -> "http://openhealthhub.com/StructureDefinition/EncryptedQuestionnaireResponse".equals(profile.getValue()));
}
questionnaireResponse.Meta.Profile.Any(profile =>
"http://openhealthhub.com/StructureDefinition/EncryptedQuestionnaireResponse".Equals(profile));
isEncryptedResponse(resp) {
return resp.meta.profile.some(profile => profile === 'http://openhealthhub.com/StructureDefinition/EncryptedQuestionnaireResponse');
}
response.meta.profile.any? { |profile| profile == 'http://openhealthhub.com/StructureDefinition/EncryptedQuestionnaireResponse' }
encryptedProfile = 'http://openhealthhub.com/StructureDefinition/EncryptedQuestionnaireResponse'
def is_encrypted(resource: Resource):
encProfile = list(filter(lambda p: encryptedProfile == p, resource.meta.profile))
return len(encProfile) > 0
func isEncrypted(qr *questionnaire_response_go_proto.QuestionnaireResponse) bool {
for _, p := range qr.Meta.Profile {
if p.GetValue() == encryptedProfileUrl {
return true
}
}
return false
}
foreach ($resp->getMeta()->getProfile() as $profile) {
if ($profile->getValue() == 'http://openhealthhub.com/StructureDefinition/EncryptedQuestionnaireResponse') {
return true;
}
}
return false;
Decrypt a String value
gpg -d
String decryptValue(String value, String extensionUrl) {
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(value.getBytes(StandardCharsets.UTF_8)))
.decryptWith(keyRingProtector, privateKey)
.doNotVerify()
.build();
byte[] bytes = decryptionStream.readAllBytes();
decryptionStream.close();
return new String(bytes, StandardCharsets.UTF_8);
}
pgp.Decrypt();
var decrypted = pgp.OutputMessage;
async decryptValue(value) {
const messageObj = await openpgp.message.readArmored(value);
const result = await openpgp.decrypt({message: messageObj, privateKeys: [this.decryptedPrivateKey]});
return result.data;
}
crypto = GPGME::Crypto.new
crypto.decrypt(value, password: private_key_passphrase).to_s
dec = gpg.decrypt(encryptedAnswers[0].valueString)
print(dec)
message, err := helper.DecryptMessageArmored(string(privateKey), []byte("api-sandbox"), armored)
$gnupg->decrypt($value);
All answers in our QuestionnaireResponse are encrypted, so they can't be read unless you have the correct private key to decrypt the responses. The answers are encrypted in 2 separate ways.
Every answer is encrypted in the item -> answer field, using an extension with the prefix
http://openhealthhub.com/fhir/StructureDefinition/encrypted-
followed by the type of the answer (e.g. decimalType
, stringType
, attachment
).
Because decrypting all answers one-by-one can have a big impact on performance, we also emit all answers in an encrypted JSON object. This
is emitted in an extension at the top level of the QuestionnaireResponse with
url http://openhealthhub.com/StructureDefinition/encryptedAnswers
.
All answers are emitted as a JSON object with a value
property that contains the actual value of the answer. If the answer has codes
linked to it (as entered in Improve Designer), they will be put in a codes
array (see the mchoice_1
answer on the left). Most questionnaire
items will have a one-to-one match between their linkids and the ids for the answer value objects. For result questionnaire items
result_<result_index>_formula_<formula_index>
will be created to indicate first which item (result_<result_index>
) and second (formula_<formula_index>
)
which result sub-item the answer is for.
Finally all formula results will also be emitted as formula_<formula_id>
.
For decrypting, the private key shown on the right can be used (passphrase: api-sandbox
).
Some helper functions are displayed here to help you load the private key, determine if a QuestionnaireResponse is encrypted, and decrypt a value.
For a complete example please have a look at the FHIR QuestionnaireResponse Client Examples:
Language |
---|
C# |
Go |
Java |
JavaScript |
PHP |
Python |
Ruby |
shell |
Subscription
Create Subscription
curl -X POST 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Subscription' \
-H 'Content-Type: application/json' \
-D '{
"resourceType" : "Subscription",
"status": "requested",
"criteria": "Appointment?name=test",
"channel" : {
"type" : "rest-hook",
"endpoint" : "https://your-webhook/endpoint",
"header": ["Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"]
}
}'
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent()
.setType(Subscription.SubscriptionChannelType.RESTHOOK)
.setHeader(List.of(new StringType("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")))
.setEndpoint("https://your-webhook/endpoint");
Subscription subscription = new Subscription()
.setCriteria("Appointment?name=test")
.setStatus(Subscription.SubscriptionStatus.REQUESTED)
.setChannel(channel);
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
Subscription subscription = client.create()
.resource(subscription)
.execute();
// we use nuget package Hl7.Fhir.R4
var client = new FhirClient("https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4");
var resource = new Subscription
{
Status = Subscription.SubscriptionStatus.Requested,
Criteria = "QuestionnaireResponse",
Channel = new Subscription.ChannelComponent()
{
Type = Subscription.SubscriptionChannelType.RestHook,
Header = new List<string>{"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"}
}
};
var subscription = client.Create(resource);
Console.Out.WriteLine(subscription.Id);
const client = FHIR.client('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4');
const subscription = client.create({
resourceType: 'Subscription',
criteria: 'Appointment?name=test',
status: 'requested',
channel: {
type: 'rest-hook',
endpoint: 'https://your-webhook/endpoint',
header: ['Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8']
}
});
client = FHIR::Client.new('https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4')
FHIR::Model.client = client
subscription = FHIR::Subscription.new
subscription.criteria = 'Appointment?name=test'
subscription.status = 'requested'
subscription.channel = FHIR::Subscription::Channel.new
subscription.channel.type = 'rest-hook'
subscription.channel.endpoint = 'https://your-webhook/endpoint'
subscription.channel.header = ['Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8']
FHIR::Subscription.create(subscription)
client = AsyncFHIRClient(
'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4'
)
with open('subscription.json', 'r') as file:
subJson = json.load(file)
createResponse = await client.execute('Subscription', method='post', data=subJson)
print(createResponse)
file, err := os.Open("subscription/subscription.json")
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", "https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Subscription", file)
if err != nil {
return nil, err
}
req.Header.Add("X-API-Key", "ad880601-b7e6-4d86-901d-b6fca96fc725")
if method == "POST" {
req.Header.Add("Content-Type", "application/json")
}
response, err := http.DefaultClient.Do(req)
$subscription = new FHIRSubscription();
$status = new FHIRSubscriptionStatus(['requested']);
$subscription->setStatus($status);
$channel = new FHIRSubscriptionChannel();
$channelType = new FHIRSubscriptionChannelType();
$channelType->setValue('rest-hook')
$channel->setEndpoint('https://your-webhook/endpoint')->setType($channelType->setValue('rest-hook'))->addHeader(['Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8']);
$subscription->setCriteria('Appointment?name=test')->setChannel($channel);
$url = 'https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Subscription';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($subscription)
]);
$res = curl_exec($ch);
curl_close($ch);
$createdSubscription = new FHIRSubscription(json_decode($res, true));
The endpoint can be used to query and create Subscriptions that trigger a webhook request when a Resource that matches the criteria has been updated. The content of the webhook will be empty, so a query with the same criteria needs to be executed to get the actual data.
HTTP Request
POST https://api.openhealthhub.com/OpenHealthhub/fhir-sandbox/4/Subscription
Subscription fields
Field | Example value | Description |
---|---|---|
channel.type | rest-hook | the only allowed allowed channel type |
channel.headers | ["header1:value1", "header2:value2"] | custom headers to put on the webhook request |
channel.endpoint | http://yourserver:8080/yourPostEndpoint | the endpoint that the webhook should post to |
status | requested | the only allowed status |
payload | has to be empty | |
criteria | QuestionnaireResponse?based-on=21bf742e-5220-4b17-8eb8-241d20028de1 | for more info see subscription criteria and search |