Guide
Get clinical history for a patient
Retrieve diagnoses, procedures, fills and labs, then query them.
Patient Histories retrieves a patient’s diagnoses, procedures, prescription fills and lab results from their claims.
It is independent of Site Sonar. Site Sonar tells you where a patient was seen; Patient Histories tells you what happened there. Turn on either, both or neither.
Turn on retrieval
Set patientHistories on the patient body you send to
POST /v0/companies/{companyId}/projects/{projectId}/patients:
curl https://api.hermeshealth.ai/v0/companies/COMPANY_ID/projects/PROJECT_ID/patients \
-X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jane",
"lastNames": [
"Doe"
],
"dateOfBirth": "1990-04-12",
"sex": "female",
"zipCodes": [
"94110",
"02139"
],
"patientHistories": true
}'
import requests
response = requests.post(
"https://api.hermeshealth.ai/v0/companies/COMPANY_ID/projects/PROJECT_ID/patients",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"firstName": "Jane",
"lastNames": [
"Doe",
],
"dateOfBirth": "1990-04-12",
"sex": "female",
"zipCodes": [
"94110",
"02139",
],
"patientHistories": True,
},
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.hermeshealth.ai/v0/companies/COMPANY_ID/projects/PROJECT_ID/patients", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
"firstName": "Jane",
"lastNames": [
"Doe"
],
"dateOfBirth": "1990-04-12",
"sex": "female",
"zipCodes": [
"94110",
"02139"
],
"patientHistories": true
}),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();
Omitting the flag means off.
Turn it on for a patient you already created
Send the flag to
PATCH /v0/companies/{companyId}/projects/{projectId}/patients/{patientId}/search-level:
curl https://api.hermeshealth.ai/v0/companies/COMPANY_ID/projects/PROJECT_ID/patients/PATIENT_ID/search-level \
-X PATCH \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"patientHistories": true
}'
import requests
response = requests.patch(
"https://api.hermeshealth.ai/v0/companies/COMPANY_ID/projects/PROJECT_ID/patients/PATIENT_ID/search-level",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"patientHistories": True,
},
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.hermeshealth.ai/v0/companies/COMPANY_ID/projects/PROJECT_ID/patients/PATIENT_ID/search-level", {
method: "PATCH",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
"patientHistories": true
}),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const data = await response.json();
Patch semantics: an omitted flag keeps its current value, where an omitted flag
on create means off. This will not turn siteSonar off.
Get the identity right
Both products match claims against who the patient was at the time of care,
so the same two fields matter. lastNames needs maiden and prior names, and
zipCodes needs the ZIPs where the patient lived when treated, not now. A thin
result has the same causes, covered in
Find where a patient was treated.
If the project’s
purposerequires an authorization, retrieval does not run until one is uploaded and approved.
Know when it finished
The patientHistories flag changes from true to false when the run
finishes. Poll the patient and read patient.patientHistories from the
response (the flag sits inside its patient object), or subscribe a webhook to
patient / columnChanged on that column. See
Receive webhook events.
A run that fails does not clear the flag; it is retried quietly, so a patient
can sit at patientHistories: true for longer than one run normally takes.
Read the data
Five tables carry what the retrieval found. All take the same query syntax — see Query large tables.
| Route | Holds |
|---|---|
POST /v0/diagnoses/browse | Diagnoses recorded against a visit |
POST /v0/procedures/browse | Procedures performed |
POST /v0/prescription-fills/browse | Prescriptions filled |
POST /v0/lab-accessions/browse | Lab orders |
POST /v0/lab-results/browse | Results against those orders |
Scope to one patient
Every one of them takes the same filter:
{
"where": {
"patient": { "id": [{ "equals": "<patient_id>" }] },
"project": { "id": [{ "equals": "<project_id>" }] }
}
}
Filter through the joined entity, not an ID column on the root:
patient.id, notdiagnosis.patientId. An unknown key is accepted and ignored, so the wrong one returns200with rows you did not ask for.
Export it
Send Accept: text/csv and omit take to stream every matching row as CSV.
That is the intended path for a bulk extract; aggregate and total are
dropped from CSV output.
Show it to your own users
Embed the read-only UI rather than rendering browse rows yourself — see Embed clinical data. These schemas change as claims coverage expands, and the iframe absorbs that. The browse routes are the right tool for server-to-server querying and exports.
Next steps
- Query large tables: filter, sort and aggregate these tables.
- Embed clinical data: show the results to your users without building the UI.