Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

FHIR API

The JHE FHIR server is served at FHIR/R5/ (the lowercase alias fhir/r5/ is also supported for backward compatibility).

Querying: JHE-native vs imported

Every search hits one store, selected by _source:

GET /FHIR/R5/Observation?patient=40001                                            # JHE-native (default)
GET /FHIR/R5/Condition?_source=https://jupyterhealth.org/fhir/fhir-source/90001    # one source
GET /FHIR/R5/Condition?_source:below=https://jupyterhealth.org/fhir/fhir-source/   # all imported

Filtering, sorting & counting

Search parameters (US Core) — the set available depends on the resource type:

TypeExamples
token?clinical-status=active · ?code=http://loinc.org|1234-5 · ?category=problem-list-item
date?recorded-date=ge2024-01-01 · ?date=le2024-12-31 (ge/le/gt/lt or a bare date)
string (starts-with)?name=nor matches “North Clinic” (case-insensitive)
reference?encounter=Encounter/abc · ?patient=40001

Sort with _sort (prefix - for descending):

GET /FHIR/R5/Observation?patient=40001&_sort=date          # by effective[x], oldest first
GET /FHIR/R5/Condition?patient=40001&_sort=-_lastUpdated    # most recently updated first

Count only with _summary=count:

// GET /FHIR/R5/Condition?patient=40001&_summary=count
{
  "resourceType": "Bundle",
  "type": "searchset",
  "total": 12,
  "entry": []
}

Working with OMH Observations

OMH Observations are the primary data type in JHE and are stored natively in the system. They are read and written as FHIR R5 resources.

Querying Observations

Patient-scoping parameters are optional — a paramless search returns everything you can access (a patient user’s own observations; a practitioner’s observations across all their organizations). When filtering by study (patient._has:Group:member:_id), results are additionally restricted to the study’s consented observation codes.

Query ParameterExampleDescription
patient._has:Group:member:_id30001Observations for patients enrolled in Study 30001
patient40001Observations for Patient 40001
patient.organization20001Observations for patients in Organization 20001
patient.identifierhttp://ehr.example.com|abc123Observations for the patient with that identifier
codehttps://w3id.org/openmhealth|omh:blood-pressure:4.0Filter by observation type
datege2024-01-01Filter by effective[x] time (ge/le/gt/lt)

Notes:

Examples:

# all blood-pressure observations for a patient
GET /FHIR/R5/Observation?patient=40001&code=https://w3id.org/openmhealth|omh:blood-pressure:4.0

# a study's observations, most recent effective time first
GET /FHIR/R5/Observation?patient._has:Group:member:_id=30001&_sort=-date

# newer than a given effective time (filters on effective[x] — see Effective Time below)
GET /FHIR/R5/Observation?patient=40001&date=gt2026-01-01

# an effective-time window (repeat = AND)
GET /FHIR/R5/Observation?patient=40001&date=ge2026-01-01&date=le2026-06-30

# two observation types at once (comma = OR)
GET /FHIR/R5/Observation?patient=40001&code=omh:blood-pressure:4.0,omh:heart-rate:2.0

# just the count
GET /FHIR/R5/Observation?patient=40001&_summary=count
// GET /FHIR/R5/Observation?patient._has:Group:member:_id=30001&code=https://w3id.org/openmhealth|omh:blood-pressure:4.0
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "resource": {
        "resourceType": "Observation",
        "id": "63416",
        "meta": {
          "lastUpdated": "2024-10-25T21:14:02.871132+00:00"
        },
        "identifier": [
          {
            "value": "6e3db887-4a20-3222-9998-2972af6fb091",
            "system": "https://ehr.example.com"
          }
        ],
        "status": "final",
        "subject": {
          "reference": "Patient/40001"
        },
        "device": {
          "reference": "Device/70001"
        },
        "code": {
          "coding": [
            {
              "code": "omh:blood-pressure:4.0",
              "system": "https://w3id.org/openmhealth"
            }
          ]
        },
        "valueAttachment": {
          "data": "eyJoZWFkZXIiOnsidXVpZCI6IjZlM2RiODg3LTRhMjAtMzIyMi05OTk4LTI5NzJhZjZmYjA5MSIsInNjaGVtYV9pZCI6eyJuYW1lc3BhY2UiOiJvbWgiLCJuYW1lIjoiYmxvb2QtcHJlc3N1cmUiLCJ2ZXJzaW9uIjoiNC4wIn0sInNvdXJjZV9jcmVhdGlvbl9kYXRlX3RpbWUiOiIyMDIxLTAzLTE0VDA5OjI1OjAwLTA3OjAwIn0sImJvZHkiOnsic3lzdG9saWNfYmxvb2RfcHJlc3N1cmUiOnsidmFsdWUiOjE0MiwidW5pdCI6Im1tSGcifSwiZGlhc3RvbGljX2Jsb29kX3ByZXNzdXJlIjp7InZhbHVlIjo4OSwidW5pdCI6Im1tSGcifSwiZWZmZWN0aXZlX3RpbWVfZnJhbWUiOnsiZGF0ZV90aW1lIjoiMjAyMS0wMy0xNFQwOToyNTowMC0wNzowMCJ9fX0=",
          "contentType": "application/json"
        }
      }
    },
    ...

Uploading Observations

Observations are uploaded as FHIR Batch Bundles via POST to the base endpoint.

// POST /FHIR/R5/
{
  "resourceType": "Bundle",
  "type": "batch",
  "entry": [
    {
      "resource": {
        "resourceType": "Observation",
        "status": "final",
        "code": {
          "coding": [
            {
              "system": "https://w3id.org/openmhealth",
              "code": "omh:blood-pressure:4.0"
            }
          ]
        },
        "subject": {
          "reference": "Patient/40001"
        },
        "device": {
          "reference": "Device/70001"
        },
        "identifier": [
          {
            "value": "6e3db887-4a20-3222-9998-2972af6fb091",
            "system": "https://ehr.example.com"
          }
        ],
        "valueAttachment": {
          "contentType": "application/json",
          "data": "eyJoZWFkZXIiOnsidXVpZCI6IjZlM2RiODg3LTRhMjAtMzIyMi05OTk4LTI5NzJhZjZmYjA5MSIsInNjaGVtYV9pZCI6eyJuYW1lc3BhY2UiOiJvbWgiLCJuYW1lIjoiYmxvb2QtcHJlc3N1cmUiLCJ2ZXJzaW9uIjoiNC4wIn0sInNvdXJjZV9jcmVhdGlvbl9kYXRlX3RpbWUiOiIyMDIxLTAzLTE0VDA5OjI1OjAwLTA3OjAwIn0sImJvZHkiOnsic3lzdG9saWNfYmxvb2RfcHJlc3N1cmUiOnsidmFsdWUiOjE0MiwidW5pdCI6Im1tSGcifSwiZGlhc3RvbGljX2Jsb29kX3ByZXNzdXJlIjp7InZhbHVlIjo4OSwidW5pdCI6Im1tSGcifSwiZWZmZWN0aXZlX3RpbWVfZnJhbWUiOnsiZGF0ZV90aW1lIjoiMjAyMS0wMy0xNFQwOToyNTowMC0wNzowMCJ9fX0="
        }
      },
      "request": {
        "method": "POST",
        "url": "Observation"
      }
    },
    ...

Effective Time

On upload, JHE lifts the OMH body.effective_time_frame out of the Base64 payload and onto indexed columns so observations can be queried by time. These columns are surfaced on read as FHIR R5 Observation.effective[x]. The valueAttachment.data blob remains the source of truth; the elevated values are a derived projection, so a missing or unrecognised time frame simply leaves the row without an effective[x] value.

A single point in time becomes effectiveDateTime; every OMH time_interval form becomes an effectivePeriod (start + end):

OMH effective_time_frame shapeExampleFHIR R5 output
date_time{ "date_time": "2026-07-18T09:30:00+09:00" }effectiveDateTime: "2026-07-18T09:30:00+09:00"
time_intervalstart + end{ "start_date_time": "…T09:00…", "end_date_time": "…T10:00…" }effectivePeriod: { start, end }
time_intervalstart + duration{ "start_date_time": "…T09:00…", "duration": { "value": 60, "unit": "min" } }effectivePeriod: { start, end } (end = start + duration)
time_intervalend + duration{ "end_date_time": "…T10:00…", "duration": { "value": 60, "unit": "min" } }effectivePeriod: { start, end } (start = end − duration)
time_intervaldate + part_of_day{ "date": "2026-07-18", "part_of_day": "morning" }effectivePeriod: { start, end } (the part-of-day window)

Notes:

Working with Patients, Practitioners, Organizations, Groups (Studies) and Devices (Data Sources)

These resources are read-only projections of JHE system entities — writes to them via FHIR are not supported (use the /api/v1/ REST API to manage these). All support the same patient-scoping query parameters.

Query ParameterExampleDescription
_has:Group:member:_id30001Resources belonging to patients in Study 30001
patient40001Resources belonging to Patient 40001
patient.organization20001Resources belonging to patients in Organization 20001
patient._has:Group:member:_id30001Resources belonging to patients enrolled in Study 30001
patient.identifierhttp://ehr.example.com|abc123Resources belonging to the patient with that identifier
identifierhttp://ehr.example.com|abc123Match the resource itself by identifier (Patient only)
family / given / nameSmithPatient name starts-with, case-insensitive (Patient only)
birthdatege1980-01-01Patient date of birth (Patient only)
// GET /FHIR/R5/Patient?_has:Group:member:_id=30001
{
  "resourceType": "Bundle",
  "type": "searchset",
  "entry": [
    {
      "resource": {
        "resourceType": "Patient",
        "id": "40001",
        "meta": {
          "lastUpdated": "2024-10-23T12:35:25.142027+00:00"
        },
        "identifier": [
          {
            "value": "fhir-1234",
            "system": "http://ehr.example.com"
          }
        ],
        "name": [
          {
            "given": ["Peter"],
            "family": "ThePatient"
          }
        ],
        "birthDate": "1980-01-01",
        "telecom": [
          {
            "value": "peter@example.com",
            "system": "email"
          },
          {
            "value": "347-111-1111",
            "system": "phone"
          }
        ]
      }
    },
    ...

The same scoping parameters apply to Group (Study), Device (Data Source), Organization, and Practitioner:

ResourceQueryReturns
Group (Study)GET /FHIR/R5/Group?patient._has:Group:member:_id=30001The study with ID 30001
Group (Study)GET /FHIR/R5/Group?patient=40001Studies Patient 40001 is enrolled in
Group (Study)GET /FHIR/R5/Group?patient.organization=20001Studies in Organization 20001
Device (Data Source)GET /FHIR/R5/Device?patient._has:Group:member:_id=30001Data sources used in Study 30001
Device (Data Source)GET /FHIR/R5/Device?patient=40001Data sources used in Patient 40001’s studies
Device (Data Source)GET /FHIR/R5/Device?patient.organization=20001Data sources in studies under Organization 20001
OrganizationGET /FHIR/R5/Organization?patient._has:Group:member:_id=30001The organization backing Study 30001
OrganizationGET /FHIR/R5/Organization?patient=40001Organizations Patient 40001 belongs to
OrganizationGET /FHIR/R5/Organization?patient.organization=20001Organization 20001
PractitionerGET /FHIR/R5/Practitioner?patient._has:Group:member:_id=30001Practitioners in Study 30001’s organization
PractitionerGET /FHIR/R5/Practitioner?patient=40001Practitioners in Patient 40001’s organizations
PractitionerGET /FHIR/R5/Practitioner?patient.organization=20001Practitioners in Organization 20001

Working with other resources

Any FHIR resource type not natively modeled in JHE (such as QuestionnaireResponse, Condition, or MedicationRequest) can be stored and retrieved via the auxiliary resource store. Before uploading, a patient must register a FHIR Source that identifies the upstream system the data originates from.

Step 1: Register a FHIR Source

POST /api/v1/fhir_sources
Authorization: Bearer WMSk9Te6QpENVxudxkRjeNBFlCf5pq
Content-Type: application/json
Accept: application/json
{
  "data_source": 70005,
  "label": "Neptune MyChart",
  "fhir_base_url": "https://fhir.neptune.org/api/FHIR/R4"
}

Response:

{
  "id": 90001,
  "patient": 40001,
  "dataSource": 70005,
  "label": "Neptune MyChart",
  "fhirBaseUrl": "https://fhir.neptune.org/api/FHIR/R4",
  "lastUpdated": "2026-06-07T04:11:52.577605Z"
}

The id returned (90001) is the FHIR Source ID used in subsequent requests.

Step 2: Upload the resource

Name the FHIR Source one of two ways (omit both → 400):

POST /FHIR/R5/QuestionnaireResponse
Authorization: Bearer WMSk9Te6QpENVxudxkRjeNBFlCf5pq
Content-Type: application/json
Accept: application/json
X-JHE-FHIR-Source-ID: 90001
{
  "resourceType": "QuestionnaireResponse",
  "status": "completed",
  "questionnaire": "Questionnaire/weekly-symptom-severity-vas",
  "subject": {
    "reference": "Patient/123"
  },
  "authored": "2026-05-28T14:30:00Z",
  "item": [
    {
      "linkId": "cough-severity",
      "answer": [{"valueInteger": 37}]
    },
    {
      "linkId": "dyspnea-severity",
      "answer": [{"valueInteger": 62}]
    },
    {
      "linkId": "fatigue-severity",
      "answer": [{"valueInteger": 48}]
    }
  ]
}

Response:

{
  "resourceType": "QuestionnaireResponse",
  "id": "2d50b34d-b33c-4f47-a5e8-595764d51f53",
  "status": "completed",
  "questionnaire": "Questionnaire/weekly-symptom-severity-vas",
  "subject": {
    "reference": "Patient/123"
  },
  "authored": "2026-05-28T14:30:00Z",
  "item": [
    {
      "linkId": "cough-severity",
      "answer": [{"valueInteger": 37}]
    },
    {
      "linkId": "dyspnea-severity",
      "answer": [{"valueInteger": 62}]
    },
    {
      "linkId": "fatigue-severity",
      "answer": [{"valueInteger": 48}]
    }
  ]
}

The id returned is a UUID assigned by JHE.

Step 3: Retrieve the resource

Retrieve by FHIR Source, by patient/study, or by resource ID. (The X-JHE-FHIR-Source-ID header is write-only — it is ignored on reads; select a source with _source instead.)

From one FHIR Source:

GET /FHIR/R5/QuestionnaireResponse?_source=https://jupyterhealth.org/fhir/fhir-source/90001

From all imported sources:

GET /FHIR/R5/QuestionnaireResponse?_source:below=https://jupyterhealth.org/fhir/fhir-source/

By patient or study (add any filter/sort from Filtering, sorting & counting):

GET /FHIR/R5/QuestionnaireResponse?patient=40001
GET /FHIR/R5/QuestionnaireResponse?patient._has:Group:member:_id=30001&status=completed&_sort=-date

By resource ID:

GET /FHIR/R5/QuestionnaireResponse/2d50b34d-b33c-4f47-a5e8-595764d51f53

All reads return a FHIR searchset Bundle (or a single resource for an ID lookup).