Introduction
This documentation is published by ZH Healthcare, Inc. (blueEHR) to meet the API documentation requirements of ONC §170.315(g)(10) — Standardized API for Patient and Population Services — as specified in the g(10) Certification Companion Guide (CCG).
blueEHR's FHIR API is powered by the EMR Direct Interoperability Engine. The API implements US Core FHIR Implementation Guide 6.1.0 and USCDI v3 as required by the ONC HTI-1 Final Rule.
GET https://sandbox-r4.interopengine.com:32540/.well-known/smart-configuration
Per the g(10) CCG, Health IT developers must document which US Core IG polymorphic data type choices ([x] elements) and Reference type choices are supported by their Health IT Module.
blueEHR's FHIR API supports US Core FHIR Implementation Guide 6.1.0 targeting USCDI version 3, as upgraded under the ONC HTI-1 Final Rule.
Supported Data Categories (USCDI v3)
| FHIR Resource | US Core Profile | USCDI v3 Data Class | Status |
|---|---|---|---|
| AllergyIntolerance | US Core AllergyIntolerance Profile | Allergies and Intolerances | Required |
| CarePlan | US Core CarePlan Profile | Care Plan | Required |
| CareTeam | US Core CareTeam Profile | Care Team Members | Required |
| Condition (Encounter Dx) | US Core Condition Encounter Diagnosis Profile | Encounter Diagnoses | Required |
| Condition (Problems) | US Core Condition Problems and Health Concerns Profile | Problems / Health Concerns | Required |
| Coverage | US Core Coverage Profile | Health Insurance Information | Required (HTI-1) |
| Device | US Core Implantable Device Profile | Unique Device Identifiers | Required |
| DiagnosticReport (Lab) | US Core DiagnosticReport Profile for Laboratory Results | Laboratory | Required |
| DiagnosticReport (Note) | US Core DiagnosticReport Profile for Report and Note Exchange | Clinical Notes | Required |
| DocumentReference | US Core DocumentReference Profile | Clinical Notes | Required |
| Encounter | US Core Encounter Profile | Encounter Information | Required (HTI-1) |
| Goal | US Core Goal Profile | Goals | Required |
| Immunization | US Core Immunization Profile | Immunizations | Required |
| MedicationDispense | US Core MedicationDispense Profile | Medication Dispensed | Required (HTI-1) |
| MedicationRequest | US Core MedicationRequest Profile | Medications | Required |
| Observation (Lab) | US Core Laboratory Result Observation Profile | Laboratory | Required |
| Observation (Vital Signs) | US Core Vital Signs Profile | Vital Signs | Required |
| Observation (Social History) | US Core Social History Profile | Social Determinants of Health | Required |
| Observation (Survey / SDOH) | US Core Simple Observation / Screening Assessment | SDOH | Required |
| Patient | US Core Patient Profile | Patient Demographics | Required |
| Procedure | US Core Procedure Profile | Procedures | Required |
| QuestionnaireResponse | US Core QuestionnaireResponse Profile | SDOH Screenings | Optional |
| RelatedPerson | US Core RelatedPerson Profile | Related Person | Required |
| ServiceRequest | US Core ServiceRequest Profile | Referral / Notes | Required (HTI-1) |
| Specimen | US Core Specimen Profile | Laboratory | Required (HTI-1) |
Polymorphic Data Type Choices Supported [x]
The following table documents the specific FHIR data type choices supported for each [x] element across US Core 6.1.0 profiles.
| Element | Supported Data Type Choice(s) |
|---|---|
AllergyIntolerance.onset[x] |
onsetDateTime, onsetAge, onsetPeriod, onsetRange, onsetString |
Condition.onset[x] |
onsetDateTime, onsetAge, onsetPeriod, onsetRange, onsetString |
Condition.abatement[x] |
abatementDateTime, abatementAge, abatementPeriod, abatementString |
DiagnosticReport.effective[x] |
effectiveDateTime, effectivePeriod |
Encounter.reasonReference[x] |
reasonReference (Condition, Procedure, Observation) |
Goal.start[x] |
startDate, startCodeableConcept |
Immunization.occurrence[x] |
occurrenceDateTime, occurrenceString |
MedicationDispense.medication[x] |
medicationCodeableConcept, medicationReference |
MedicationDispense.statusReason[x] |
statusReasonCodeableConcept, statusReasonReference |
MedicationRequest.medication[x] |
medicationCodeableConcept, medicationReference |
MedicationRequest.reported[x] |
reportedBoolean, reportedReference |
Observation.effective[x] |
effectiveDateTime, effectivePeriod, effectiveTiming, effectiveInstant |
Observation.value[x] |
valueQuantity, valueCodeableConcept, valueString, valueBoolean, valueInteger, valueRange, valueRatio, valueSampledData, valueTime, valueDateTime, valuePeriod |
Observation.component.value[x] |
valueQuantity, valueCodeableConcept, valueString, valueBoolean, valueInteger, valueRange, valueRatio, valueSampledData, valueTime, valueDateTime, valuePeriod |
Patient.deceased[x] |
deceasedBoolean, deceasedDateTime |
Patient.multipleBirth[x] |
multipleBirthBoolean, multipleBirthInteger |
Procedure.performed[x] |
performedDateTime, performedPeriod, performedString, performedAge, performedRange |
Provenance.occurred[x] |
occurredPeriod, occurredDateTime |
ServiceRequest.occurrence[x] |
occurrenceDateTime, occurrencePeriod, occurrenceTiming |
ServiceRequest.quantity[x] |
quantityQuantity, quantityRatio, quantityRange |
ServiceRequest.asNeeded[x] |
asNeededBoolean, asNeededCodeableConcept |
Specimen.collection.collected[x] |
collectedDateTime, collectedPeriod |
Specimen.collection.fastingStatus[x] |
fastingStatusCodeableConcept, fastingStatusDuration |
Coverage.subscribed[x] |
subscribedString, subscribedPeriod |
Timing.repeat.bounds[x] |
boundsDuration, boundsRange, boundsPeriod |
Reference Type Choices Supported
The following table documents the specific Reference target types supported for polymorphic Reference elements across US Core 6.1.0 profiles.
| Element | Supported Reference Target(s) |
|---|---|
AllergyIntolerance.patient |
Patient |
AllergyIntolerance.recorder |
Patient, Practitioner, PractitionerRole, RelatedPerson |
AllergyIntolerance.asserter |
Patient, Practitioner, PractitionerRole, RelatedPerson |
CarePlan.subject |
Patient |
CareTeam.subject |
Patient |
Condition.subject |
Patient |
Condition.encounter |
Encounter |
Condition.asserter |
Patient, Practitioner, PractitionerRole, RelatedPerson |
Coverage.subscriber |
Patient, RelatedPerson |
Coverage.beneficiary |
Patient |
Coverage.payor |
Patient, RelatedPerson, Organization |
DiagnosticReport.subject |
Patient |
DiagnosticReport.performer |
Practitioner, PractitionerRole, Organization, CareTeam |
DiagnosticReport.resultsInterpreter |
Practitioner, PractitionerRole, Organization, CareTeam |
DocumentReference.subject |
Patient |
DocumentReference.author |
Practitioner, PractitionerRole, Organization, Patient, Device, RelatedPerson |
Encounter.subject |
Patient |
Encounter.participant.individual |
Practitioner, PractitionerRole, RelatedPerson |
Goal.subject |
Patient |
Immunization.patient |
Patient |
MedicationDispense.subject |
Patient |
MedicationDispense.performer.actor |
Practitioner, PractitionerRole, Organization, Patient, Device, RelatedPerson |
MedicationRequest.subject |
Patient |
MedicationRequest.requester |
Patient, Practitioner, PractitionerRole, Organization, RelatedPerson, Device |
Observation.subject |
Patient, Group, Device, Location |
Observation.performer |
Practitioner, PractitionerRole, Organization, CareTeam, Patient, RelatedPerson |
Patient.generalPractitioner |
Organization, Practitioner, PractitionerRole |
Procedure.subject |
Patient |
Provenance.agent.who |
Practitioner, PractitionerRole, RelatedPerson, Patient, Device, Organization |
ServiceRequest.subject |
Patient, Group, Location, Device |
ServiceRequest.requester |
Practitioner, PractitionerRole, Organization, Patient, RelatedPerson, Device |
Specimen.subject |
Patient, Group, Device, Substance, Location |
HTI-1 Required FHIR Extensions (US Core 6.1.0)
The following FHIR extensions are newly required or updated under the ONC HTI-1 Final Rule and are supported on the Patient resource:
| Extension URL | Resource | Description | HTI-1 Status |
|---|---|---|---|
us-core-sex |
Patient | Sex for clinical use (replaces birthsex as primary) | New — Required |
us-core-genderIdentity |
Patient | Patient's gender identity | New — Required |
us-core-tribal-affiliation |
Patient | Tribal affiliation and enrolled/non-enrolled status | New — Required |
us-core-race |
Patient | Race (expanded value set in 6.1.0) | Updated |
us-core-ethnicity |
Patient | Ethnicity | Retained |
us-core-birthsex |
Patient | Birth sex (legacy; retained for backward compatibility) | Retained (legacy) |
us-core-interpreter-required |
Patient | Whether patient requires an interpreter | New |
Version Comparison: Previous vs. Current
| Component | Previous Version | Current Version | Change Driver |
|---|---|---|---|
| US Core FHIR IG | STU 3.1.1 | 6.1.0 | ONC HTI-1 Final Rule |
| USCDI | v1 | v3 | ONC HTI-1 Final Rule |
| SMART App Launch | 1.0.0 | 2.0 STU2 | ONC HTI-1 Final Rule |
| New Required Resources | N/A | Coverage, MedicationDispense, ServiceRequest, Specimen, Encounter (required), Media, Endpoint | US Core 6.1.0 / HTI-1 |
| Finer-Grained Scopes | Not supported | Supported (SMART v2) | SMART App Launch 2.0 STU2 |
blueEHR's FHIR API implements the SMART App Launch Framework 2.0 (STU2) scope model. Three scope context prefixes are supported, corresponding to the three access tiers required by ONC §170.315(g)(10):
| Prefix | Context | Grant Type Required |
|---|---|---|
| patient/ | Patient-authorized access (single patient context) | authorization_code |
| user/ | Clinician / user-authorized access | authorization_code |
| system/ | Backend system access — no active user session | client_credentials |
Both authorization_code and client_credentials grant types are enabled per g(10) certification requirements (see RFC 6749).
Patient and User Scopes — Supported Resource Types
The following scopes are supported for both patient/ and user/ context prefixes. SMART v2 permission suffixes: .rs = read + search; .r = read only; .s = search only. Wildcard patient/*.rs and user/*.rs are also supported.
| patient/ Scope | user/ Scope | FHIR Resource | US Core / USCDI v3 |
|---|---|---|---|
| patient/AllergyIntolerance.rs | user/AllergyIntolerance.rs | AllergyIntolerance | Required |
| patient/CarePlan.rs | user/CarePlan.rs | CarePlan | Required |
| patient/CareTeam.rs | user/CareTeam.rs | CareTeam | Required |
| patient/Condition.rs | user/Condition.rs | Condition | Required |
| patient/Coverage.rs | user/Coverage.rs | Coverage | Required (HTI-1) |
| patient/Device.rs | user/Device.rs | Device | Required |
| patient/DiagnosticReport.rs | user/DiagnosticReport.rs | DiagnosticReport | Required |
| patient/DocumentReference.rs | user/DocumentReference.rs | DocumentReference | Required |
| patient/Encounter.rs | user/Encounter.rs | Encounter | Required (HTI-1) |
| patient/Goal.rs | user/Goal.rs | Goal | Required |
| patient/Immunization.rs | user/Immunization.rs | Immunization | Required |
| patient/MedicationDispense.rs | user/MedicationDispense.rs | MedicationDispense | Required (HTI-1) |
| patient/MedicationRequest.rs | user/MedicationRequest.rs | MedicationRequest | Required |
| patient/Observation.rs | user/Observation.rs | Observation | Required |
| patient/Patient.rs | user/Patient.rs | Patient | Required |
| patient/Procedure.rs | user/Procedure.rs | Procedure | Required |
| patient/QuestionnaireResponse.rs | user/QuestionnaireResponse.rs | QuestionnaireResponse | Optional |
| patient/ServiceRequest.rs | user/ServiceRequest.rs | ServiceRequest | Required (HTI-1) |
| patient/Specimen.rs | user/Specimen.rs | Specimen | Required (HTI-1) |
| patient/Media.rs | user/Media.rs | Media | Required (HTI-1) |
| patient/Provenance.rs | user/Provenance.rs | Provenance | Required |
System Scopes (Backend / Bulk Data)
System scopes are used with the client_credentials grant type for backend services and bulk data export (§170.315(g)(10)(e)):
| Scope | Description |
|---|---|
| system/*.rs | Full read access to all authorized resources (bulk export) |
| system/Patient.rs | Patient-level bulk read |
| system/Group.rs | Group-level bulk read (population export) |
| system/[ResourceType].rs | Per-resource type system-level read/search |
client_credentials grant type and a registered backend client. Contact blueEHR to enable backend/system access for your application.OpenID Connect and Launch Scopes
| Scope | Description |
|---|---|
| openid | Enables OpenID Connect ID token return (RFC 8414) |
| fhirUser | Returns the authenticated user's FHIR resource URL in the ID token |
| launch | EHR-embedded (EHR Launch) context token |
| launch/patient | Standalone launch — requests patient selection at authorization |
| offline_access | Requests a long-lived refresh token for persistent access (see Section 4) |
Finer-Grained Scopes (HTI-1 Requirement)
SMART App Launch 2.0 STU2 introduces category-level access filters, required under the ONC HTI-1 Final Rule. These are enforced server-side automatically — the API applies a category filter to all matching queries when a finer-grained scope is granted.
| Finer-Grained Scope | Filters Access To |
|---|---|
| patient/Condition.rs?category=problem-list-item | Problem list conditions only |
| patient/Condition.rs?category=encounter-diagnosis | Encounter diagnoses only |
| patient/Condition.rs?category=health-concern | Health concern conditions only |
| patient/DiagnosticReport.rs?category=LAB | Laboratory diagnostic reports only |
| patient/DiagnosticReport.rs?category=http://loinc.org|LP29684-5 | Radiology reports only |
| patient/Observation.rs?category=laboratory | Lab result observations only |
| patient/Observation.rs?category=vital-signs | Vital sign observations only |
| patient/Observation.rs?category=social-history | Social history observations only |
| patient/Observation.rs?category=survey | Survey / SDOH screening observations only |
| patient/MedicationRequest.rs?category=inpatient | Inpatient medication requests only |
| patient/MedicationRequest.rs?category=community | Outpatient / community medication requests only |
GET https://sandbox-r4.interopengine.com:32540/.well-known/smart-configurationThis endpoint returns
scopes_supported, grant_types_supported, response_types_supported, and capabilities per SMART App Launch 2.0 STU2.
blueEHR's FHIR API enforces encrypted transport for all connections carrying ePHI in accordance with the HIPAA Security Rule (45 CFR §164.312(e)(2)(ii)) and ONC §170.315(g)(10).
Enforcement Method
| Layer | Policy |
|---|---|
| Minimum TLS Version | TLS 1.2 minimum. Connections attempting to negotiate TLS 1.0, TLS 1.1, SSL 3.0, or any earlier version are rejected at the transport layer before any data is exchanged. |
| Plaintext HTTP | All HTTP (port 80) connections to FHIR API endpoints are refused. No redirects are issued — the connection is terminated immediately without processing any request payload. |
| Backend Connection | The phiQuery connection from blueEHR's EHR system to the EMR Direct Interoperability Engine is also a TLS 1.2-only persistent socket. No PHI traverses any unencrypted channel at any layer. |
| Mutual TLS (mTLS) | Supported as an optional trust policy for backend client applications and dynamic client registration. Clients may be required to present a valid, trusted digital certificate for high-assurance connection establishment. |
| Certificate Validation | Server certificates are issued by a trusted certificate authority. Client applications must validate the full server certificate chain on every connection. Self-signed certificates are not accepted by the API server. |
Accepted Cipher Suites
The API server accepts TLS 1.2 cipher suites from the following approved categories per NIST SP 800-52 Rev. 2:
- ECDHE key exchange with forward secrecy (PFS)
- AES-128-GCM or AES-256-GCM authenticated encryption (AEAD)
- SHA-256 or SHA-384 for message authentication
The following cipher suites and protocols are explicitly not accepted: RC4, DES, 3DES, MD5-based cipher suites, NULL cipher suites, and export-grade ciphers.
FHIR Capability Statement Declaration
The CapabilityStatement.rest.security element declares transport-security support per the SMART on FHIR security extensions, confirming that TLS is required for all API access:
{
"resourceType": "CapabilityStatement",
"rest": [{
"security": {
"cors": true,
"service": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/restful-security-service",
"code": "SMART-on-FHIR"
}]
}],
"extension": [{
"url": "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris",
"extension": [
{ "url": "authorize", "valueUri": "https://sandbox-r4.interopengine.com:32540/authz" },
{ "url": "token", "valueUri": "https://sandbox-r4.interopengine.com:32540/token" },
{ "url": "register", "valueUri": "https://sandbox-r4.interopengine.com:32540/register" },
{ "url": "manage", "valueUri": "https://sandbox-r4.interopengine.com:32540/manage" },
{ "url": "revoke", "valueUri": "https://sandbox-r4.interopengine.com:32540/revoke" }
]
}]
}
}]
}
ONC §170.315(g)(10)(v)(A)(3) and SMART App Launch 2.0 STU2 require that the API support secure issuance of an initial refresh token to native applications. blueEHR's FHIR API implements this through the OAuth 2.0 Authorization Code Flow with PKCE (RFC 7636).
Authorization Code + PKCE Flow
Generate a Code Verifier and Challenge
The native app generates a cryptographically random code_verifier (43–128 characters) and computes:
code_challenge = BASE64URL(SHA-256(ASCII(code_verifier)))
code_challenge_method = S256
S256 method is accepted. The plain method is not supported.Authorization Request
The app redirects the user to the authorization endpoint. Include offline_access in the scope to request a refresh token:
GET https://sandbox-r4.interopengine.com:32540/authz
?response_type=code
&client_id=[registered_client_id]
&redirect_uri=[app_redirect_uri]
&scope=launch/patient openid fhirUser offline_access patient/*.rs
&state=[csrf_random_token]
&code_challenge=[code_challenge]
&code_challenge_method=S256
&aud=[FHIR base URL]
User Authentication and Consent
The user authenticates via blueEHR patient portal or provider portal credentials. The authorization server presents a consent screen listing the requested scopes. Upon approval, an authorization code is issued to the registered redirect_uri.
Token Exchange (with code_verifier)
The app exchanges the authorization code for tokens, proving possession by including the original code_verifier:
POST https://sandbox-r4.interopengine.com:32540/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=[authorization_code]
&redirect_uri=[app_redirect_uri]
&client_id=[registered_client_id]
&code_verifier=[original_code_verifier]
Token Response (includes Refresh Token)
The server validates the code_verifier against the stored code_challenge. If valid, it returns:
{
"access_token": "[jwt_access_token]",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "[opaque_refresh_token]",
"scope": "launch/patient openid fhirUser offline_access patient/*.rs",
"id_token": "[jwt_id_token]",
"patient": "[patient_fhir_id]"
}
The refresh_token is returned because offline_access was requested and approved.
Using the Refresh Token
When the access token expires (after 1 hour), obtain a new access token without requiring the user to re-authenticate:
POST https://sandbox-r4.interopengine.com:32540/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=[refresh_token]
&client_id=[registered_client_id]
Security Properties
| Property | Implementation |
|---|---|
| No client secret required | Native apps use PKCE S256 — no pre-shared secret needed |
| Authorization code binding | Code is cryptographically bound to the PKCE verifier — interception does not grant access without the verifier |
| Redirect URI validation | The redirect_uri must exactly match a URI pre-registered for the client_id |
| State parameter (CSRF) | Apps must include and validate the state parameter on the callback |
| Refresh token rotation | A new refresh token is issued on each token refresh; the previous token is immediately invalidated |
| Scope restriction | Refresh tokens are bound to the originally approved scopes; scope cannot be elevated at refresh |
| Access token lifetime | Access tokens expire after 1 hour (3600 seconds) |
Dynamic Client Registration (RFC 7591)
Native applications that support SMART Dynamic Client Registration may register with the authorization server at runtime without a pre-assigned client secret, using a trusted digital certificate or a signed software statement. This is the recommended approach for native apps distributed to multiple end-users, as each installation may register independently, receiving a unique client_id.
To enable Dynamic Client Registration for your application, contact bugsandsupport@bluebrix.health.
Relevant Standards
- SMART App Launch 2.0 STU2 — http://hl7.org/fhir/smart-app-launch/STU2/
- RFC 7636 — PKCE: rfc-editor.org/rfc/rfc7636
- RFC 6749 — OAuth 2.0: rfc-editor.org/rfc/rfc6749
- RFC 7591 — Dynamic Client Registration: rfc-editor.org/rfc/rfc7591
- RFC 7009 — Token Revocation: rfc-editor.org/rfc/rfc7009
- RFC 6750 — Bearer Token Usage: rfc-editor.org/rfc/rfc6750
- OpenID Connect Core 1.0: openid.net/specs/openid-connect-core-1_0.html
blueEHR's FHIR API supports the full USCDI v3 data set profiled in US Core 6.1.0. The following resources and capabilities are additionally available beyond the USCDI v3 mandatory baseline.
Additional Patient-Facing Resources
These resources are accessible via patient-context scopes and support individual patient queries, but are not part of the USCDI v3 required data class set:
| FHIR Resource | Profile Used | Description |
|---|---|---|
| QuestionnaireResponse | US Core QuestionnaireResponse Profile (optional in 6.1.0) | Patient-reported outcomes, SDOH screening instrument responses |
| Media | Base FHIR R4 (no US Core profile — HTI-1 required) | Clinical images and media referenced from DiagnosticReport or other clinical resources |
| RelatedPerson | US Core RelatedPerson Profile | Individuals related to the patient — emergency contacts, guardians, caregivers |
Additional Non-Patient-Specific Resources
Available to authorized user-context and system-context clients to support broader interoperability:
| FHIR Resource | Profile Used | Description |
|---|---|---|
| Practitioner | US Core Practitioner Profile | Provider directory information |
| PractitionerRole | US Core PractitionerRole Profile | Provider role, specialty, and organizational affiliation |
| Organization | US Core Organization Profile | Healthcare organization directory data |
| Location | US Core Location Profile | Facility and location information |
| Endpoint | Base FHIR R4 (HTI-1 required — referenced by US Core) | Technical connectivity information for organizations and practitioners |
| Provenance | US Core Provenance Profile | Data lineage and source attribution for all clinical records |
| Group | Base FHIR R4 | Patient population groupings — used for bulk data export ($export) |
| Binary | Base FHIR R4 | Raw document and attachment data (e.g., CCD / C-CDA documents via $docref) |
| Person | Base FHIR R4 | Cross-system patient matching and identity linking |
Additional Operations
| Operation | Endpoint | Description |
|---|---|---|
$docref |
POST https://sandbox-r4.interopengine.com:32540/DocumentReference/$docref |
Returns the patient's CCD (C-CDA on FHIR) document. Per US Core OperationDefinition http://hl7.org/fhir/us/core/OperationDefinition/docref. |
$export (System) |
GET https://sandbox-r4.interopengine.com:32540/$export |
Bulk FHIR export of all authorized patient data, per FHIR Bulk Data Access IG STU 1.0.1. |
$export (Group) |
GET https://sandbox-r4.interopengine.com:32540/Group/[id]/$export |
Bulk export of data for a defined patient population group. |
$export (Patient) |
GET https://sandbox-r4.interopengine.com:32540/Patient/$export |
Bulk export of all patient-level data. |
HTI-1 Extensions Beyond USCDI v1 Baseline
The following FHIR extensions are supported as required by US Core 6.1.0 and the ONC HTI-1 Final Rule. These represent an expansion beyond the prior USCDI v1 baseline that was previously implemented:
| Extension | Resource | Description | HTI-1 Status |
|---|---|---|---|
us-core-sex |
Patient | Biological sex for clinical use | New — Required |
us-core-genderIdentity |
Patient | Patient's gender identity | New — Required |
us-core-tribal-affiliation |
Patient | Tribal affiliation and enrolled/non-enrolled status | New — Required |
us-core-race |
Patient | Race (expanded value set in 6.1.0) | Updated |
us-core-ethnicity |
Patient | Ethnicity | Retained |
us-core-birthsex |
Patient | Birth sex (legacy; retained for backward compatibility) | Retained |
1. Permitted Use
Access to and use of the blueEHR FHIR API is permitted solely for the purposes of enabling lawful interoperability with patient health data as described in the published API documentation. Use of the API for any purpose not explicitly described in, or reasonably implied by, the official API documentation is prohibited.
2. No Reverse Engineering
Users of this API may not reverse engineer, disassemble, decompile, or attempt to derive the source code, underlying algorithms, or any non-public technical components of the API, its supporting infrastructure, or any associated software.
3. Compliance with Applicable Law
Users are solely responsible for ensuring that their applications and data-handling practices comply with all applicable federal and state laws and regulations, including but not limited to:
- HIPAA Privacy Rule (45 CFR Part 164, Subpart E)
- HIPAA Security Rule (45 CFR Part 164, Subpart C)
- HITECH Act
- ONC Information Blocking Rules (45 CFR Part 171)
- Applicable state privacy laws
4. Prohibited Uses
The following are expressly prohibited:
- Accessing, querying, storing, or transmitting PHI for any purpose not authorized under HIPAA and not consented to by the patient or their authorized representative
- Using the API to aggregate, sell, or market patient data without explicit patient consent and applicable legal authorization
- Attempting to access data beyond the scope of authorized patient records or authorized user roles
- Using the API in a manner that could impair, damage, or overload the API infrastructure or interfere with other authorized users
- Circumventing access controls, authentication mechanisms, or rate limits
5. Authentication and Access Credentials
API credentials (OAuth client IDs, client secrets, and certificates) are issued to specific registered applications. Credentials may not be shared between applications or transferred to third parties. Users must notify blueEHR immediately upon any actual or suspected unauthorized access to or compromise of their credentials.
6. Rate Limiting
API access is subject to rate limits based on practice size and allocated resources. Requests that consistently exceed allocated bandwidth may be throttled or temporarily blocked to protect service availability for all users. A HTTP 429 Too Many Requests response with a Retry-After header will be returned when rate limits are exceeded.
7. No Warranty
The blueEHR FHIR API and the underlying EMR Direct Interoperability Engine are provided "AS IS" without warranty of any kind, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, or non-infringement. blueEHR and EMR Direct do not warrant that the API will be uninterrupted, error-free, or free of harmful components.
8. Limitation of Liability
To the maximum extent permitted by applicable law, blueEHR's and EMR Direct's aggregate liability to any party arising out of or related to use of this API shall not exceed the amounts paid by that party for API access during the twelve (12) months preceding the claim. In no event shall blueEHR or EMR Direct be liable for indirect, incidental, special, exemplary, or consequential damages.
9. Non-Discrimination
blueEHR will not restrict access to the API, impose different terms, or otherwise discriminate against any lawful third-party application, technology, or developer in a manner inconsistent with 45 CFR §170.404(a)(1) (API Transparency Conditions — non-discrimination).
10. Modifications
blueEHR reserves the right to modify these Terms and Conditions at any time. Material changes will be communicated to registered developers with a minimum of 60 days notice, except where changes are required immediately to maintain security, comply with law, or address an emergency. Continued use of the API after the effective date of changes constitutes acceptance of the updated terms.
11. Governing Law
These Terms and Conditions are governed by and construed in accordance with the laws of the State of California, without regard to conflicts of law principles. Any disputes arising under these terms shall be resolved in the courts of competent jurisdiction located in California.
12. Contact
| Company | ZH Healthcare, Inc. (blueEHR) |
| Address | 4800 Hampden Lane, Suite 200, Bethesda, MD 20814 |
| Support Phone | +1-703-340-8065 |
| Sales Phone | +1-855-936-3367 |
| Support Email | bugsandsupport@bluebrix.health |
| Sales Email | marketing@bluebrix.health |
| Privacy Policy | blueehr.com/legal-documents/ |
Developer Reference
This section documents the technical API specification required for third-party application developers, including API syntax, function names, parameter data types, return structures, error handling, mandatory software requirements, and application registration details.
API Syntax
Base URL Structure
All FHIR API requests are made against a base FHIR R4 endpoint provided by blueEHR. Obtain your organization's specific base URL from the SMART configuration endpoint or by contacting blueEHR support.
https://sandbox-r4.interopengine.com:32540 = https://sandbox-r4.interopengine.com:32540
The base URL is used as the prefix for all resource and operation endpoints documented in this reference. The SMART discovery endpoint is always at:
GET https://sandbox-r4.interopengine.com:32540/.well-known/smart-configuration
GET https://sandbox-r4.interopengine.com:32540/metadata
HTTP Methods
| Method | Used For | Content-Type |
|---|---|---|
GET |
FHIR search, read, and capability queries | N/A (no request body) |
POST |
FHIR operations ($docref, $export), token endpoint, dynamic client registration | application/fhir+json or application/x-www-form-urlencoded |
Mandatory Request Headers
| Header | Required? | Value | Description |
|---|---|---|---|
Authorization |
Required | Bearer [access_token] |
OAuth 2.0 Bearer token obtained from the token endpoint. Must be included on every FHIR API request. |
Accept |
Required | application/fhir+json |
Declares the client accepts FHIR JSON responses. Requests without a valid Accept header may return HTTP 406. |
Content-Type |
Required (POST only) | application/fhir+json |
Required when sending a FHIR resource body (e.g., $docref operation). |
FHIR-Version |
Optional | 4.0 |
Explicitly requests FHIR R4. Defaults to R4 when omitted. |
Prefer |
Optional | respond-async |
Required for bulk export ($export) to initiate asynchronous processing per FHIR Bulk Data Access IG STU 1.0.1. |
Standard Response Headers
| Header | Type | Description |
|---|---|---|
Content-Type |
string | application/fhir+json; charset=UTF-8 on all FHIR responses |
ETag |
string | Version identifier for the returned resource (format: W/"[version_id]") |
Last-Modified |
HTTP-date | Timestamp of the last modification to the returned resource |
Location |
URI | Returned on successful resource creation; contains the resource's canonical URL |
X-Content-Type-Options |
string | nosniff — prevents MIME-type sniffing |
Content-Security-Policy |
string | CSP header enforced on all API responses |
Retry-After |
integer | Seconds to wait before retrying. Present on HTTP 429 (rate limit) responses only. |
General Request Syntax — Individual Resource Read
GET https://sandbox-r4.interopengine.com:32540/[ResourceType]/[logical-id]
Authorization: Bearer [access_token]
Accept: application/fhir+json
General Request Syntax — Resource Search
GET https://sandbox-r4.interopengine.com:32540/[ResourceType]?[search_parameter]=[value]&[parameter2]=[value2]
Authorization: Bearer [access_token]
Accept: application/fhir+json
Multiple parameters are combined with & (AND logic). Multiple values for the same parameter use comma separation (OR logic within that parameter). Example:
GET https://sandbox-r4.interopengine.com:32540/Observation?patient=12345&category=laboratory&date=ge2025-01-01&_count=50
Authorization: Bearer [access_token]
Accept: application/fhir+json
General Request Syntax — FHIR Operation (POST)
POST https://sandbox-r4.interopengine.com:32540/[ResourceType]/$[operation-name]
Authorization: Bearer [access_token]
Accept: application/fhir+json
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "[param-name]", "valueString": "[value]" }
]
}
Function Names and Operations
The following table enumerates every supported FHIR function (operation) by name, HTTP method, and endpoint pattern.
Capability and Discovery
| Function Name | Method | Endpoint | Description |
|---|---|---|---|
| capabilities | GET | https://sandbox-r4.interopengine.com:32540/metadata |
Returns the server's CapabilityStatement (FHIR R4). Declares all supported resources, search parameters, and operations. |
| smart-configuration | GET | https://sandbox-r4.interopengine.com:32540/.well-known/smart-configuration |
Returns the SMART App Launch configuration JSON, including OAuth endpoint URLs, supported scopes, and PKCE capabilities. |
Individual Resource Read
| Function Name | Method | Endpoint | Returns |
|---|---|---|---|
| read | GET | https://sandbox-r4.interopengine.com:32540/[ResourceType]/[id] |
Single FHIR resource by logical ID |
| vread | GET | https://sandbox-r4.interopengine.com:32540/[ResourceType]/[id]/_history/[vid] |
Specific version of a resource |
Resource Search Operations (by Resource)
| Function Name | Method | Endpoint | Scope Required |
|---|---|---|---|
| search-AllergyIntolerance | GET | https://sandbox-r4.interopengine.com:32540/AllergyIntolerance |
patient/AllergyIntolerance.rs |
| search-CarePlan | GET | https://sandbox-r4.interopengine.com:32540/CarePlan |
patient/CarePlan.rs |
| search-CareTeam | GET | https://sandbox-r4.interopengine.com:32540/CareTeam |
patient/CareTeam.rs |
| search-Condition | GET | https://sandbox-r4.interopengine.com:32540/Condition |
patient/Condition.rs |
| search-Coverage | GET | https://sandbox-r4.interopengine.com:32540/Coverage |
patient/Coverage.rs |
| search-Device | GET | https://sandbox-r4.interopengine.com:32540/Device |
patient/Device.rs |
| search-DiagnosticReport | GET | https://sandbox-r4.interopengine.com:32540/DiagnosticReport |
patient/DiagnosticReport.rs |
| search-DocumentReference | GET | https://sandbox-r4.interopengine.com:32540/DocumentReference |
patient/DocumentReference.rs |
| search-Encounter | GET | https://sandbox-r4.interopengine.com:32540/Encounter |
patient/Encounter.rs |
| search-Goal | GET | https://sandbox-r4.interopengine.com:32540/Goal |
patient/Goal.rs |
| search-Immunization | GET | https://sandbox-r4.interopengine.com:32540/Immunization |
patient/Immunization.rs |
| search-MedicationDispense | GET | https://sandbox-r4.interopengine.com:32540/MedicationDispense |
patient/MedicationDispense.rs |
| search-MedicationRequest | GET | https://sandbox-r4.interopengine.com:32540/MedicationRequest |
patient/MedicationRequest.rs |
| search-Observation | GET | https://sandbox-r4.interopengine.com:32540/Observation |
patient/Observation.rs |
| search-Patient | GET | https://sandbox-r4.interopengine.com:32540/Patient |
patient/Patient.rs |
| search-Procedure | GET | https://sandbox-r4.interopengine.com:32540/Procedure |
patient/Procedure.rs |
| search-QuestionnaireResponse | GET | https://sandbox-r4.interopengine.com:32540/QuestionnaireResponse |
patient/QuestionnaireResponse.rs |
| search-ServiceRequest | GET | https://sandbox-r4.interopengine.com:32540/ServiceRequest |
patient/ServiceRequest.rs |
| search-Specimen | GET | https://sandbox-r4.interopengine.com:32540/Specimen |
patient/Specimen.rs |
| search-Media | GET | https://sandbox-r4.interopengine.com:32540/Media |
patient/Media.rs |
| search-Provenance | GET | https://sandbox-r4.interopengine.com:32540/Provenance |
user/Provenance.rs |
Named FHIR Operations
| Function Name | Method | Endpoint | Description |
|---|---|---|---|
| $docref | POST | https://sandbox-r4.interopengine.com:32540/DocumentReference/$docref |
Generates and returns the patient's C-CDA document as a FHIR DocumentReference. Defined by US Core OperationDefinition. |
| $export (System) | GET | https://sandbox-r4.interopengine.com:32540/$export |
Initiates asynchronous bulk export of all authorized data. Requires Prefer: respond-async header and system/*.rs scope. |
| $export (Group) | GET | https://sandbox-r4.interopengine.com:32540/Group/[id]/$export |
Initiates bulk export for a defined patient population group. |
| $export (Patient) | GET | https://sandbox-r4.interopengine.com:32540/Patient/$export |
Initiates bulk export of all patient-level data. |
| $export-status | GET | [polling_location_from_export_response] |
Polls the status of an in-progress bulk export job. Returns 202 (in progress) or 200 (complete with file manifest). |
| $export-cancel | DELETE | [polling_location_from_export_response] |
Cancels an in-progress bulk export job. |
OAuth / Authorization Functions
| Function Name | Method | Endpoint | Description |
|---|---|---|---|
| authorize | GET | https://sandbox-r4.interopengine.com:32540/authz |
OAuth 2.0 authorization endpoint. Initiates user authentication and consent. Redirects to client redirect_uri with code or error. |
| token | POST | https://sandbox-r4.interopengine.com:32540/token |
OAuth 2.0 token endpoint. Exchanges authorization code for access/refresh tokens, or refreshes an existing access token. |
| register | POST | https://sandbox-r4.interopengine.com:32540/register |
Dynamic client registration endpoint (RFC 7591). Registers a new client application and returns client credentials. |
| revoke | POST | https://sandbox-r4.interopengine.com:32540/revoke |
Token revocation endpoint (RFC 7009). Revokes an access token or refresh token. |
| introspect | POST | https://sandbox-r4.interopengine.com:32540/introspect |
Token introspection endpoint (RFC 7662). Returns token metadata including active status, scope, and expiry. |
| manage | GET | https://sandbox-r4.interopengine.com:32540/manage |
Patient-facing authorization management portal. Allows patients to review and revoke granted application permissions. |
Search Parameters, Data Types, and Required/Optional Status
FHIR search parameter types: token = coded value or identifier (system|code); reference = resource reference (ResourceType/id); date = ISO 8601 date with optional prefix (eq, lt, gt, le, ge, ne, sa, eb, ap); string = text string (partial match by default); uri = exact URI match; quantity = numeric value with optional unit.
Common Parameters (All Resources)
| Parameter | Type | Required? | Description |
|---|---|---|---|
_id |
token | Optional | Filter by the resource's logical ID. Example: _id=abc123 |
_count |
integer | Optional | Maximum number of results per page. Default: 20. Maximum: 100. Example: _count=50 |
_sort |
string | Optional | Sort results by a named parameter. Prefix with - for descending. Example: _sort=-date |
_include |
string | Optional | Include referenced resources in the Bundle. Example: _include=MedicationRequest:medication |
_revinclude |
string | Optional | Include resources that reference the matched resource. Example: _revinclude=Provenance:target |
_elements |
string | Optional | Comma-delimited list of element names to return (partial response). Example: _elements=id,status,subject |
AllergyIntolerance Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose allergy records to retrieve. Example: patient=Patient/12345 |
clinical-status |
token | Optional | Filter by clinical status. Values: active, inactive, resolved |
date |
date | Optional | Date the allergy was recorded. Example: date=ge2024-01-01 |
code |
token | Optional | Allergy substance code. Example: code=http://www.nlm.nih.gov/research/umls/rxnorm|1049502 |
CarePlan Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose care plans to retrieve. |
category |
token | Required | Must be assess-plan. Example: category=assess-plan |
date |
date | Optional | Date range filter on the care plan period. Example: date=ge2024-01-01&date=le2025-12-31 |
status |
token | Optional | Values: draft, active, on-hold, revoked, completed, entered-in-error, unknown |
Condition Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose conditions to retrieve. |
category |
token | Optional | Values: problem-list-item, encounter-diagnosis, health-concern |
clinical-status |
token | Optional | Values: active, recurrence, relapse, inactive, remission, resolved |
code |
token | Optional | Condition code (ICD-10, SNOMED CT). Example: code=http://snomed.info/sct|73211009 |
onset-date |
date | Optional | Filter by onset date. Example: onset-date=ge2023-01-01 |
encounter |
reference | Optional | Filter conditions linked to a specific encounter. Example: encounter=Encounter/67890 |
DiagnosticReport Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose diagnostic reports to retrieve. |
category |
token | Optional | Report category. Values: LAB, http://loinc.org|LP29684-5 (radiology), http://loinc.org|LP7839-6 (pathology) |
code |
token | Optional | LOINC code for the report type. Example: code=http://loinc.org|58410-2 |
date |
date | Optional | Date the report was effective. Example: date=ge2024-06-01 |
status |
token | Optional | Values: registered, partial, preliminary, final, amended, corrected, appended, cancelled, entered-in-error |
DocumentReference Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose documents to retrieve. |
category |
token | Optional | Document category. Example: category=http://hl7.org/fhir/us/core/CodeSystem/us-core-documentreference-category|clinical-note |
type |
token | Optional | Document type (LOINC). Example: type=http://loinc.org|34133-9 (summarization of episode note / CCD) |
date |
date | Optional | Document creation date. Example: date=ge2024-01-01 |
period |
date | Optional | Time period the document covers. |
status |
token | Optional | Values: current, superseded, entered-in-error |
Encounter Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose encounters to retrieve. |
date |
date | Optional | Encounter period date range. Example: date=ge2024-01-01&date=le2025-01-01 |
class |
token | Optional | Encounter class. Example: class=AMB (ambulatory), IMP (inpatient), EMER (emergency) |
type |
token | Optional | Encounter type code (SNOMED CT / CPT). |
status |
token | Optional | Values: planned, arrived, triaged, in-progress, onleave, finished, cancelled, entered-in-error, unknown |
identifier |
token | Optional | Business identifier for the encounter. Example: identifier=http://hospital.example.org|ENC-2024-001 |
MedicationRequest Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose medication requests to retrieve. |
intent |
token | Required | Must be specified. Values: proposal, plan, order, original-order, reflex-order, filler-order, instance-order, option |
status |
token | Optional | Values: active, on-hold, cancelled, completed, entered-in-error, stopped, draft, unknown |
authoredon |
date | Optional | Date prescription was authored. Example: authoredon=ge2024-01-01 |
encounter |
reference | Optional | Filter by the prescribing encounter. |
Observation Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
patient |
reference | Required | Patient whose observations to retrieve. |
category |
token | Required | Observation category. Values: laboratory, vital-signs, social-history, survey, imaging, procedure, activity |
code |
token | Optional | LOINC or SNOMED code for the specific observation type. Example: code=http://loinc.org|8302-2 (body height) |
date |
date | Optional | Observation effective date/time. Example: date=ge2024-01-01 |
status |
token | Optional | Values: registered, preliminary, final, amended, corrected, cancelled, entered-in-error, unknown |
value-quantity |
quantity | Optional | Filter by numeric value. Example: value-quantity=gt100|http://unitsofmeasure.org|mg/dL |
Patient Search Parameters
| Parameter | Type | Required? | Description / Example |
|---|---|---|---|
_id |
token | Conditional | FHIR logical ID of the patient. Required when not using patient-context scopes. Example: _id=patient-12345 |
identifier |
token | Optional | Business identifier (MRN, etc.). Example: identifier=http://hospital.example.org/mrn|MRN-001 |
family |
string | Optional | Patient's family (last) name. Example: family=Smith |
given |
string | Optional | Patient's given (first) name. Example: given=John |
birthdate |
date | Optional | Date of birth. Example: birthdate=1980-01-15 |
gender |
token | Optional | Administrative gender. Values: male, female, other, unknown |
name |
string | Optional | Any part of the patient's name (given, family, prefix, suffix). |
$docref Operation Parameters
| Parameter | Type | Required? | Description | Return Type |
|---|---|---|---|---|
patient |
reference (id) | Required | The FHIR logical ID of the patient for whom the CCD is requested. | — |
start |
dateTime | Optional | Start of the period for the C-CDA document content. ISO 8601 format. | — |
end |
dateTime | Optional | End of the period for the C-CDA document content. | — |
type |
token (CodeableConcept) | Optional | Document type LOINC code. Defaults to 34133-9 (CCD). |
— |
on-demand |
boolean | Optional | If true, generates a new on-demand document. If false or omitted, returns existing document. |
Bundle (searchset) containing DocumentReference |
$export Operation Parameters
| Parameter | Type | Required? | Description |
|---|---|---|---|
_outputFormat |
string | Optional | Output format. Default and only supported value: application/fhir+ndjson |
_since |
instant | Optional | Only include resources last updated after this timestamp. ISO 8601 format. Example: _since=2024-01-01T00:00:00Z |
_type |
string | Optional | Comma-delimited list of resource types to export. If omitted, all authorized resource types are exported. Example: _type=Patient,Observation,MedicationRequest |
_elements |
string | Optional | Comma-delimited list of elements to include in each resource (partial export). Example: _elements=id,status,subject |
patient |
reference | Conditional | Required for Group-level export only. Specifies the patient(s) to include. |
Return Variables and Response Structures
FHIR Search Response — Bundle (searchset)
All search operations return a Bundle resource with type: "searchset". The top-level structure is:
| Field | Type | Always Present? | Description |
|---|---|---|---|
resourceType |
string | Yes | Always "Bundle" |
id |
string (id) | Yes | Server-assigned unique identifier for this Bundle |
meta.lastUpdated |
instant | Yes | ISO 8601 timestamp of when the Bundle was generated |
type |
string (code) | Yes | Always "searchset" for search responses |
total |
integer | Yes | Total number of matching records (may exceed page size if paginated) |
link |
array of objects | Yes | Pagination links. Each object has relation (string: "self", "next", "previous") and url (string: full URL for that page) |
entry |
array of objects | Conditional | Array of result entries. Empty array if no results found. Each entry contains fullUrl (string) and resource (object: the FHIR resource). |
entry[n].fullUrl |
URI | Yes (per entry) | Canonical URL of the individual resource |
entry[n].resource |
object (FHIR Resource) | Yes (per entry) | The FHIR resource object (e.g., Patient, Observation) |
entry[n].search.mode |
string (code) | Yes (per entry) | "match" for primary results; "include" for _include results |
Example Bundle (searchset) response structure:
{
"resourceType": "Bundle",
"id": "bundle-search-001",
"meta": { "lastUpdated": "2026-04-06T10:00:00Z" },
"type": "searchset",
"total": 47,
"link": [
{ "relation": "self", "url": "https://sandbox-r4.interopengine.com:32540/Observation?patient=12345&category=laboratory&_count=20" },
{ "relation": "next", "url": "https://sandbox-r4.interopengine.com:32540/Observation?patient=12345&category=laboratory&_count=20&_page=2" }
],
"entry": [
{
"fullUrl": "https://sandbox-r4.interopengine.com:32540/Observation/obs-001",
"resource": {
"resourceType": "Observation",
"id": "obs-001",
...
},
"search": { "mode": "match" }
}
]
}
Individual Resource Read Response
A direct read (GET https://sandbox-r4.interopengine.com:32540/[ResourceType]/[id]) returns the FHIR resource object directly — not wrapped in a Bundle:
| Field | Type | Description |
|---|---|---|
resourceType |
string | The FHIR resource type name (e.g., "Patient", "Observation") |
id |
string (id) | Logical ID of the resource (server-assigned) |
meta.versionId |
string | Version identifier for the resource |
meta.lastUpdated |
instant | Timestamp of last modification |
meta.profile |
array of URIs | US Core profile URLs the resource claims conformance with |
| Resource-specific fields | various | All mandatory (Must Support) elements per the applicable US Core 6.1.0 profile |
Token Endpoint Response
A successful POST to the token endpoint returns HTTP 200 with the following JSON body:
| Field | Type | Always Present? | Description |
|---|---|---|---|
access_token |
string (JWT) | Yes | Bearer token to use in the Authorization header for FHIR API requests |
token_type |
string | Yes | Always "Bearer" |
expires_in |
integer | Yes | Access token lifetime in seconds. Value: 3600 (1 hour) |
scope |
string | Yes | Space-delimited list of scopes actually granted (may be a subset of requested scopes) |
refresh_token |
string | Conditional | Present only when offline_access scope was requested and approved |
id_token |
string (JWT) | Conditional | Present only when openid scope was requested. Contains identity claims. |
patient |
string | Conditional | FHIR logical ID of the in-context patient. Present for patient-context launches. |
encounter |
string | Conditional | FHIR logical ID of the in-context encounter. Present for EHR launches with encounter context. |
fhirContext |
array | Conditional | Additional FHIR launch context resources (SMART 2.0 STU2 extension). |
Bulk Export — Initial Response (202 Accepted)
| Field | Type | Description |
|---|---|---|
| HTTP status | integer | 202 Accepted — export job initiated |
Content-Location header |
URI | Polling URL to check export status. Poll this URL to determine when the export is complete. |
Bulk Export — Completed Response (200 OK)
When polled and the export is complete, the status endpoint returns:
| Field | Type | Description |
|---|---|---|
transactionTime |
instant | Timestamp when the export was started (ISO 8601) |
request |
URI | The original $export request URL |
requiresAccessToken |
boolean | If true, the download URLs also require a Bearer token |
output |
array of objects | Array of export file descriptors. Each has type (string: resource type), url (string: NDJSON download URL), and count (integer: number of records) |
error |
array of objects | Any non-fatal errors encountered during export. Each has type ("OperationOutcome") and url (NDJSON file of OperationOutcome resources) |
SMART Configuration Response
The /.well-known/smart-configuration endpoint returns a JSON object with the following fields:
| Field | Type | Description |
|---|---|---|
issuer |
URI | Authorization server issuer identifier |
jwks_uri |
URI | JSON Web Key Set endpoint (public keys for token verification) |
authorization_endpoint |
URI | OAuth 2.0 authorization endpoint URL |
token_endpoint |
URI | OAuth 2.0 token endpoint URL |
registration_endpoint |
URI | Dynamic client registration endpoint URL (RFC 7591) |
scopes_supported |
array of strings | All scope values supported by this server |
response_types_supported |
array of strings | Supported OAuth response types. Value: ["code"] |
grant_types_supported |
array of strings | Supported grant types. Values: ["authorization_code", "client_credentials"] |
code_challenge_methods_supported |
array of strings | PKCE methods supported. Value: ["S256"] |
capabilities |
array of strings | SMART capabilities. Includes: launch-ehr, launch-standalone, client-public, client-confidential-symmetric, sso-openid-connect, context-banner, context-style, context-ehr-patient, context-ehr-encounter, permission-patient, permission-user, permission-offline, authorize-post |
Exceptions and Exception Handling
All errors are returned as FHIR OperationOutcome resources with an appropriate HTTP status code. Applications must handle all of the following HTTP status codes.
HTTP Error Status Codes
| HTTP Code | Status | Cause | Recommended Action |
|---|---|---|---|
400 |
Bad Request | Malformed request syntax, invalid parameter value, missing required parameter, or unsupported search parameter. | Parse the OperationOutcome issue[].details.text for the specific error. Correct the parameter and retry. |
401 |
Unauthorized | Missing or invalid Authorization header. Token is absent, expired, or malformed. | Obtain a new access token from the token endpoint (using refresh token if available, or re-authorize). |
403 |
Forbidden | Access token is valid but does not have the required scope for the requested resource or operation. | Request the appropriate scope during authorization. Do not retry without scope correction. |
404 |
Not Found | The requested resource does not exist, the resource ID is invalid, or the endpoint URL is incorrect. | Verify the resource ID and base URL. Check the CapabilityStatement to confirm the resource type is supported. |
405 |
Method Not Allowed | HTTP method (e.g., PUT, DELETE) not supported for this endpoint. | Use the correct HTTP method as documented in the Function Names section. |
406 |
Not Acceptable | The Accept header does not include application/fhir+json. |
Set Accept: application/fhir+json on all requests. |
410 |
Gone | The resource previously existed but has been deleted. | Do not retry for the same resource ID. Remove it from local cache. |
422 |
Unprocessable Entity | The request body is syntactically valid but semantically invalid (e.g., invalid FHIR resource structure, failed validation against a profile). | Review the OperationOutcome for validation error details. Correct the resource content and retry. |
429 |
Too Many Requests | Rate limit exceeded. The client has exceeded the request threshold for the allocated time window. | Read the Retry-After response header (integer, seconds). Wait for the indicated duration before retrying. Implement exponential backoff. |
500 |
Internal Server Error | Unexpected server error. | Log the error with the request details. Retry with exponential backoff (max 3 retries). If the issue persists, contact bugsandsupport@bluebrix.health with the id value from the OperationOutcome. |
501 |
Not Implemented | The requested operation or parameter is not implemented by this server. | Check the CapabilityStatement to verify support. Do not retry. |
503 |
Service Unavailable | Server is temporarily unavailable (maintenance or overload). | Retry after the duration indicated in the Retry-After header, if present. Implement exponential backoff. |
OperationOutcome Structure
All error responses return a FHIR OperationOutcome resource. Applications must never display the raw OperationOutcome to end users — log the details server-side and present a user-friendly message.
| Field | Type | Description |
|---|---|---|
resourceType |
string | Always "OperationOutcome" |
id |
string | Unique identifier for this error instance. Include in support requests. |
issue |
array | One or more issue objects describing the error(s) |
issue[].severity |
string (code) | Severity of this issue. Values: fatal, error, warning, information |
issue[].code |
string (code) | FHIR issue type code. Common values: invalid, security, login, not-found, too-costly, business-rule, exception, throttled |
issue[].details.text |
string | Human-readable description of the specific error. Do not expose directly to end users. |
issue[].diagnostics |
string | Additional diagnostic information (technical detail). For server-side logging only. |
issue[].expression |
array of strings | FHIRPath expression(s) identifying the element(s) that caused the issue (for validation errors) |
Example OperationOutcome (401 Unauthorized):
HTTP/1.1 401 Unauthorized
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"id": "err-20260406-001",
"issue": [
{
"severity": "error",
"code": "security",
"details": {
"text": "Access token is missing or has expired. Obtain a new access token and retry."
}
}
]
}
Example OperationOutcome (429 Rate Limit):
HTTP/1.1 429 Too Many Requests
Content-Type: application/fhir+json
Retry-After: 60
{
"resourceType": "OperationOutcome",
"id": "err-20260406-002",
"issue": [
{
"severity": "error",
"code": "throttled",
"details": {
"text": "Request rate limit exceeded. Please wait before retrying."
}
}
]
}
OAuth Error Responses
The authorization and token endpoints return OAuth 2.0 standard error responses (RFC 6749 §5.2) as JSON when an error occurs:
| Field | Type | Description |
|---|---|---|
error |
string | Error code. Values: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope, access_denied |
error_description |
string | Human-readable description of the error. For logging purposes only. |
error_uri |
URI | Optional URI pointing to additional error information. |
error_description values to end users. Log all errors server-side with the OperationOutcome id field for traceability.
Mandatory Software Components
The following software components are required in any application that integrates with blueEHR's FHIR API. All components must be current, actively maintained, and free of known critical vulnerabilities (CVE severity: High or Critical).
Required Components — All Applications
| Component | Requirement | Purpose |
|---|---|---|
| TLS 1.2-capable HTTP Client | Must support TLS 1.2 or higher. Must perform server certificate chain validation. Must not allow fallback to TLS 1.0/1.1 or plaintext HTTP. | All FHIR API requests and OAuth requests must be made over TLS 1.2+. HTTP connections are refused. |
| OAuth 2.0 Library with PKCE Support | Must support Authorization Code Flow with PKCE using the S256 challenge method (RFC 7636). Must support the state parameter for CSRF protection. Must handle token storage and refresh token rotation. |
Required for all patient-context and user-context (authorization_code) API access. |
| JSON Parser | Must support parsing of JSON per RFC 8259. Must handle deeply nested objects and large payloads (bulk export NDJSON files may be many megabytes). | All FHIR resources and responses are encoded as JSON (application/fhir+json). |
| JWT Library | Must support RS256 and ES256 signature verification. Must validate iss, aud, exp, iat, and nbf claims. Must retrieve and cache the JWKS from the server's jwks_uri. |
Required for verifying ID tokens (OpenID Connect) returned by the token endpoint. |
| Secure Storage / Keychain | Must use platform-native secure credential storage (e.g., iOS Keychain, Android Keystore, Windows Data Protection API, OS-level secrets manager). Tokens must never be stored in plaintext files, browser localStorage, or sessionStorage. | Secure storage of access tokens and refresh tokens. |
Required Components — Backend / System Applications
| Component | Requirement | Purpose |
|---|---|---|
| OAuth 2.0 Client Credentials Library | Must support the client_credentials grant type (RFC 6749 §4.4). Must support client_secret_basic or private_key_jwt token endpoint authentication. |
Required for backend/system-level (no user session) FHIR access and bulk data export. |
| NDJSON Parser | Must support streaming parse of Newline-Delimited JSON (NDJSON / application/fhir+ndjson) for processing bulk export output files. Must handle partial-line buffering for large files. | Bulk export ($export) output files are delivered as NDJSON. |
| Async HTTP Client | Must support long-polling for bulk export status. Must handle HTTP 202 (in-progress) responses correctly and retry polling at appropriate intervals (minimum 30 seconds between polls). | Bulk export is an asynchronous operation that may take minutes to complete. |
| X.509 Certificate / Private Key Management | Required only when using Dynamic Client Registration with client certificate authentication or mTLS. Certificate must be issued by a trusted CA. Private key must be stored in a hardware security module (HSM) or secure vault (e.g., AWS KMS, Azure Key Vault, HashiCorp Vault). | Mutual TLS and certificate-based client registration. |
Mandatory Software Configurations
Applications must be configured as specified below before they can successfully authenticate and interact with blueEHR's FHIR API.
TLS Configuration
| Configuration Item | Required Value | Notes |
|---|---|---|
| Minimum TLS version | TLS 1.2 |
TLS 1.0, TLS 1.1, and SSL are not accepted. Configure your HTTP client to refuse downgrade. |
| Certificate verification | Enabled (verify peer) |
Server certificate chain must be validated on every connection. Disabling certificate verification is not permitted. |
| Allowed cipher suites | ECDHE + AES-GCM + SHA-256/384 only | Configure your TLS client to disable RC4, DES, 3DES, MD5-based, and NULL cipher suites. |
| HTTPS-only | All requests over HTTPS | Do not construct or follow HTTP (non-TLS) redirect URLs for FHIR or OAuth endpoints. |
OAuth / PKCE Configuration
| Configuration Item | Required Value | Notes |
|---|---|---|
| PKCE code challenge method | S256 |
The plain method is not accepted. Must always generate a new random code_verifier per authorization request. |
code_verifier length |
43–128 characters | Generated using a cryptographically random source (e.g., SecureRandom, crypto.getRandomValues). Must use characters from: [A-Z a-z 0-9 - . _ ~] (unreserved URI characters per RFC 3986). |
| State parameter | Required — cryptographically random | Minimum 128 bits of entropy. Must be validated on callback — reject any callback where state does not match. |
| Redirect URI | Must be pre-registered with blueEHR | Must exactly match one of the registered redirect_uris for your client. For native apps, use a custom URI scheme (e.g., com.example.myapp:/callback) or a localhost loopback URL per RFC 8252. |
aud parameter |
FHIR base URL of the target server | Must be included in the authorization request. Protects against token mix-up attacks. |
| Token storage | Platform secure storage only | Never store tokens in cookies without HttpOnly + Secure + SameSite=Strict, localStorage, sessionStorage, or plaintext files. |
HTTP Request Configuration
| Configuration Item | Required Value | Notes |
|---|---|---|
Accept header |
application/fhir+json |
Must be set on all FHIR API requests. Omitting this header may result in HTTP 406. |
Content-Type header (POST) |
application/fhir+json or application/x-www-form-urlencoded |
Use application/fhir+json for FHIR operation requests; use application/x-www-form-urlencoded for OAuth token requests. |
| Request timeout | Minimum 30 seconds | Some FHIR searches may involve large result sets. Bulk export status polling uses a minimum 30-second interval. |
| Retry policy | Exponential backoff with jitter | On HTTP 429 or 503, wait for the Retry-After duration (or default 60 seconds) before retrying. Maximum 3 retries before surfacing the error. |
Bulk Export Configuration
| Configuration Item | Required Value | Notes |
|---|---|---|
Prefer header |
respond-async |
Must be included on all $export requests. Without it, the server will return HTTP 400. |
| Polling interval | Minimum 30 seconds between polls | Polling too frequently may trigger rate limiting. Use exponential backoff if 202 responses persist beyond expected duration. |
| NDJSON output format | application/fhir+ndjson |
Configure your NDJSON parser to process one JSON object per line. Files may be multiple gigabytes for large populations. |
Application Registration Requirements
All applications must be registered with blueEHR's authorization server before making any API requests. Registration can be performed via static (manual) registration or via the Dynamic Client Registration endpoint (RFC 7591). In both cases, the following attributes are required or conditionally required.
Required Registration Attributes — All Applications
| Attribute | Type | Required? | Description and Requirements |
|---|---|---|---|
client_name |
string | Required | Human-readable name of the client application. Displayed to the patient/user on the consent screen. Must accurately represent the application. Maximum 128 characters. |
redirect_uris |
array of URIs | Required | One or more pre-registered redirect URIs. The redirect_uri in authorization requests must exactly match one of these values. For native apps: use custom URI scheme (e.g., com.example.app:/callback) or loopback URL per RFC 8252. HTTPS required for web apps. HTTP on loopback only (127.0.0.1 or [::1]) is permitted for desktop apps. |
grant_types |
array of strings | Required | Grant types the client will use. Must include "authorization_code" for patient/user access. Must include "client_credentials" for system/bulk access. Must include "refresh_token" if offline_access will be requested. Example: ["authorization_code", "refresh_token"] |
response_types |
array of strings | Required | Must include "code" (Authorization Code flow). Value: ["code"] |
scope |
string | Required | Space-delimited list of all scopes the application may request. Registration must enumerate the maximum scope the application will ever request. Individual authorization requests may request a subset. Example: "launch/patient openid fhirUser offline_access patient/*.rs" |
token_endpoint_auth_method |
string | Required | How the client authenticates to the token endpoint. Values: "none" — public client using PKCE (native/SPA apps, no client secret); "client_secret_basic" — confidential client with client secret via HTTP Basic Auth; "private_key_jwt" — confidential client using signed JWT assertion. |
contacts |
array of email strings | Required | Contact email address(es) for the developer or organization responsible for the application. Used to notify of policy changes or security issues. |
Conditional Registration Attributes
| Attribute | Type | Condition | Description |
|---|---|---|---|
client_uri |
URI | Required if client_name is not self-explanatory | URL of the application's homepage. Must be HTTPS. Displayed on the consent screen to help users identify the application. |
logo_uri |
URI | Optional | URL of the application's logo image. Must be HTTPS. Displayed on the consent screen. |
policy_uri |
URI | Recommended | URL of the application's privacy policy. Must be HTTPS. Should describe how the application handles patient data. |
tos_uri |
URI | Recommended | URL of the application's Terms of Service. Must be HTTPS. |
jwks_uri |
URI | Required if token_endpoint_auth_method is private_key_jwt |
URL of the client's JSON Web Key Set (public keys). Must be HTTPS. Used to verify signed JWT client assertions at the token endpoint. |
jwks |
object (JWKS) | Alternative to jwks_uri for private_key_jwt |
Inline JSON Web Key Set. Use jwks_uri (preferred) for dynamic key rotation without re-registration. |
software_id |
string | Required for UDAP Dynamic Registration | Unique identifier for the software product (not the specific installation). Must be a UUID. Used to track multiple instances of the same application. |
software_version |
string | Recommended | Version string of the client software. Example: "2.4.1" |
Registration Response
On successful registration, the server returns HTTP 201 Created with the following JSON body:
| Field | Type | Description |
|---|---|---|
client_id |
string | The assigned OAuth client identifier. Use this value as client_id in all authorization and token requests. |
client_secret |
string | Present only for confidential clients (client_secret_basic auth method). Store securely. Never expose in client-side code or version control. |
client_id_issued_at |
integer (Unix timestamp) | Time the client ID was issued. |
client_secret_expires_at |
integer (Unix timestamp) | Time the client secret expires. Value 0 means the secret does not expire. Re-register before expiry. |
registration_access_token |
string | Token used to read or update this client registration via the registration management endpoint. |
registration_client_uri |
URI | URL of this client's registration record. Use with the registration_access_token to update registration details. |
| All submitted attributes | various | All submitted registration attributes are echoed back in the response for confirmation. |
Static Registration Process
For organizations that prefer manual (non-dynamic) registration, contact blueEHR with the following information:
- Application name and description
- Developer / organization contact email
- All redirect URIs the application will use
- Grant types required (
authorization_code,client_credentials,refresh_token) - Full list of scopes the application will request
- Token endpoint authentication method (
none,client_secret_basic, orprivate_key_jwt) - Application type:
web,native, orservice(backend) - Privacy policy URL and Terms of Service URL
