Legal and certification information

Register an app

Mira EMR patient and population APIs

Developer: Mira Technologies, Inc. Product: Mira EMR, version 1.0.

This page covers three API capabilities:

Hosts: Mira EMR is https://miraemr.com. The FHIR server for the development stage is https://fhir-dev.mirahealth.care (its CapabilityStatement and SMART configuration); the production FHIR server's address is published before production opens. Each practice's own FHIR base URL is published in the service base URL Bundle (§2).


1. Terms of use

  1. Who may use the APIs. Patients and their authorized representatives may use any app they choose to reach their own records. Healthcare organizations that use Mira EMR (the "API Information Sources") may use the APIs and may authorize other apps to reach their population data.

  2. No fees.

    • Mira charges no fee to patients or to app developers to register an app or to call these APIs.
    • Any fee Mira charges a customer for deploying the APIs is stated in our mandatory disclosures, per §170.404(a)(3).
  3. Use. Apps must:

    • use the APIs as documented here
    • keep their credentials confidential
    • request only the scopes they need
    • not attempt to reach data their user is not authorized to see

    Mira does not require app developers to sign a business associate agreement to serve a patient's chosen app. Mira does not vet patient-chosen apps for security beyond the registration steps in §3.

  4. Rights. Mira grants the rights needed to develop, test, market and distribute apps that use these APIs. Those rights do not depend on fees, exclusivity, non-compete terms, or reciprocal data sharing (§170.404(a)(4)).

  5. Changes. Mira gives registered developers and customers advance notice of changes to the APIs, and reasonable time to update, except where a security issue requires faster action.

  6. Support. support@mirahealth.care. We answer within 2 business days.

2. Service base URLs (§170.404(b)(2))

Every customer organization whose FHIR API is live is published, free of charge and with no sign-in, as a FHIR R4 Bundle (type: collection) of Organization and Endpoint resources:

The Bundle is generated from the live configuration. It is served with Cache-Control: public, max-age=300, so a change (a customer going live or changing its endpoint) shows within 5 minutes.

3. Registering an app (§170.404(b)(1))

  1. Register online at https://miraemr.com/developers/register (no sign-in). The form asks for:

    • the practice the app will connect to (the practices listed in §2)
    • app name, your organization, a contact name and email, your website
    • who uses the app: patients, clinicians or practice staff, or a back-end system
    • redirect URIs (https; http://localhost for development), and whether to register a SMART on FHIR client (required for a patient app)
    • for a SMART client, optionally your key set URL (jwksUri, https) for private_key_jwt
    • what the app does with the data
    • acceptance of these terms

    Registration is free. You may also email support@mirahealth.care with the same details.

  2. Authenticity verification. The practice's administrator, in Mira, confirms your identity and contact (for example a reply from an address on your own domain, and a working website). The decision is made within 10 business days of registration; Mira shows the administrator the due date. The same steps apply to every developer.

  3. Credentials. When the registration is activated, Mira issues the credentials within 5 business days of verification (normally at once):

    • Patient apps get a SMART client only. A patient app reaches a record only when that patient signs in and authorizes it (§4, §5.1); it never receives a key to the practice's records.
    • Provider and back-end apps get a Mira API key mira_<client id>.<secret> for §5. It reads every patient of that practice, so the administrator activates it as an explicit authorization of practice-wide access. It is shown once to the administrator, who sends it to your contact email; Mira keeps only a SHA-256 fingerprint. A lost key is revoked and a new registration made.
    • When you asked for one, a SMART client (client_id and client_secret) on the practice's FHIR server (§4) with your redirect URIs (and key set URL). A back-end SMART client reads every patient of the practice except restricted charts, read only, and the status and files of its own bulk exports (§4); Mira proves it can obtain a token before reporting it ready. If the FHIR server cannot take the registration at that moment, it stays on the administrator's work list with the 5-business-day deadline until it is completed.

    A declined registration is told why. An administrator can revoke a key at any time; the next call with it is refused.

  4. A healthcare organization that uses Mira EMR may also enable an app for its own users through the same screen.

4. (g)(10) Standardized API for patient and population services (FHIR R4)

This section is the (g)(10) API documentation required by §170.315(g)(10)(viii): the API syntax and function names (§4.4 to §4.6), the required and optional parameters with their data types and the return variables with their types and structures (§4.3 to §4.6), exceptions and their handling (§4.7), the software components and configuration an app needs (§4.2), and what an app needs to register with the authorization server (§3 and §4.3). The machine-readable source of the same facts is the live CapabilityStatement (§4.1).

Below, [base] stands for a practice's FHIR base URL. On the development stage every practice's base is https://fhir-dev.mirahealth.care/fhir/R4; the production FHIR server's address is published before production opens. Each practice's base is also in the service base URL Bundle (§2). The base URL answers only API requests (with a token); open its CapabilityStatement to read it in a browser.

4.1 Endpoints, capability statement and conformance

DocumentLink (development stage)
CapabilityStatement (GET [base]/metadata)https://fhir-dev.mirahealth.care/fhir/R4/metadata
SMART configurationhttps://fhir-dev.mirahealth.care/fhir/R4/.well-known/smart-configuration (also at the host root: https://fhir-dev.mirahealth.care/.well-known/smart-configuration)
OpenID Connect configurationhttps://fhir-dev.mirahealth.care/.well-known/openid-configuration
Signing keys (JWKS) for id_tokenhttps://fhir-dev.mirahealth.care/.well-known/jwks.json
Service base URL Bundle (§2)https://miraemr.com/api/v1/api-access/service-base-urls
Sign-in page the authorize endpoint sends users tohttps://fhir-login-dev.mirahealth.care

The CapabilityStatement needs no token. It names the server software (Medplum 5.2.3), FHIR version 4.0.1, the JSON format, every resource type with its supported profiles, interactions and search parameters, the Group $export operation, and the OAuth endpoints (in rest.security). It instantiates the US Core server and Bulk Data CapabilityStatements.

StandardVersionSpecification
HL7 FHIRR4 (4.0.1)FHIR R4: RESTful API, Search, Bundle, OperationOutcome, CapabilityStatement
US Core Implementation Guide6.1.0 (USCDI v3)US Core 6.1.0 and its server CapabilityStatement; each profile is linked in §4.5
SMART App Launch2.0.0SMART App Launch 2.0.0: App Launch, Scopes and launch context, Backend Services, Token introspection, Conformance
Bulk Data Access1.0.1 (STU 1)Bulk Data Access 1.0.1: Export request flow; the operations are linked in §4.6
OAuth 2.0 and relatedRFCsRFC 6749 (OAuth 2.0), RFC 6750 (bearer tokens), RFC 7636 (PKCE), RFC 7523 (private_key_jwt), RFC 7662 (introspection)
ONC test method§170.315(g)(10)Standardized API for patient and population services

4.2 Software components and configuration

What Mira runs.

What an app needs.

4.3 Authorization (SMART App Launch 2.0.0)

Endpoints. These are API endpoints, not pages: each answers only the request shown. They are also listed in the SMART configuration.

FunctionHTTP syntax (development stage)Notes
AuthorizeGET or POST https://fhir-dev.mirahealth.care/oauth2/authorizeOpened in the user's browser. Sends the user to the sign-in page, then back to redirect_uri
TokenPOST https://fhir-dev.mirahealth.care/oauth2/tokenBody application/x-www-form-urlencoded
Token introspectionPOST https://fhir-dev.mirahealth.care/oauth2/introspectBody token={access or refresh token}. The caller authenticates as the client the token was issued to
UserInfo (OpenID Connect)GET https://fhir-dev.mirahealth.care/oauth2/userinfoAuthorization: Bearer {access_token}
Sign out and revoke the app's accessGET https://fhir-dev.mirahealth.care/oauth2/logoutAuthorization: Bearer {access_token}. Revokes the sign-in, so its access and refresh tokens stop working. There is no RFC 7009 revocation endpoint

Authorization request (GET [authorize]?…, or the same fields form-encoded in a POST). Every parameter is a string.

ParameterTypeRequiredValue
response_typestringyescode
client_idstringyesYour client_id
redirect_uristring (URL)yesExactly one of your registered redirect URIs
scopestring (scopes separated by spaces)yesSee Scopes below
statestringyesAn unguessable value; returned unchanged
audstring (URL)yesThe FHIR base URL, https://fhir-dev.mirahealth.care/fhir/R4. Another server is refused (invalid_request)
code_challengestring (base64url SHA-256 of the verifier)yesPKCE challenge
code_challenge_methodstringyesS256
launchstringEHR launch onlyThe launch value Mira passed to your launch URL
noncestringnoOpenID Connect nonce, echoed in the id_token

Success redirects to {redirect_uri}?code={code}&state={state}. An error after the client and redirect URI are known redirects to {redirect_uri}?error={code}&error_description={text}&state={state} (for example invalid_request or unsupported_response_type).

Token request (POST [token], Content-Type: application/x-www-form-urlencoded).

GrantParameters (all strings)
Authorization codegrant_type=authorization_code, code, redirect_uri, code_verifier; a public client also sends client_id. A confidential client authenticates as below
Refreshgrant_type=refresh_token, refresh_token; a confidential client authenticates as below
Client credentials (back-end, bulk)grant_type=client_credentials, scope (system/ scopes); client authentication as below
Client authenticationclient_secret_basic (Authorization: Basic base64(client_id:client_secret)), client_secret_post (client_id and client_secret in the body), or private_key_jwt (client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer and client_assertion, a JWT signed with your registered key per SMART Backend Services)

Token response (200 application/json):

FieldTypeWhen
access_tokenstring (JWT)Always. Send it as Authorization: Bearer {access_token}
token_typestringAlways Bearer
expires_ininteger (seconds)Always. The access token's lifetime
scopestring (space-separated)Always. The scopes granted, which may be fewer than requested: the patient chooses which to grant
id_tokenstring (JWT)When openid and fhirUser were granted. Signed RS256; keys at the JWKS URL (§4.1)
refresh_tokenstringWhen offline_access or online_access was granted
patientstring (Patient id)When the token has a patient context (patient launch, patient account, or an EHR launch with a patient)
encounterstring (Encounter id)When an EHR launch carried a visit
need_patient_bannerbooleanAlways. true when there is a patient context
smart_style_urlstring (URL)Always. https://fhir-dev.mirahealth.care/fhir/R4/.well-known/smart-styles.json

The server also returns project, profile and fhirContext (Medplum fields); apps can ignore them. A refused token request answers 400 with {"error": string, "error_description": string}, for example {"error":"invalid_request","error_description":"Invalid client"}; invalid_grant means the code or refresh token was already used, expired or revoked.

Token introspection response (200 application/json): active (boolean). An active token adds scope (string), client_id (string), sub (string), iss (string), iat and exp (integer, seconds since 1970) and patient (string, when there is a patient context). An unknown, expired or revoked token answers {"active": false}.

Scopes. SMART v1 and v2 syntax are both accepted (the SMART configuration lists permission-v1 and permission-v2).

ScopeForm
Resource scopes, v1patient/{Type}.read, user/{Type}.read, system/{Type}.read (also .write, .*), for one resource type or *. Example: patient/Observation.read
Resource scopes, v2patient/{Type}.rs, user/{Type}.rs, system/{Type}.rs and the other c r u d s combinations, for one resource type or *. Example: patient/*.rs
Granular scopes, v2 (Condition)patient/Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|encounter-diagnosis, …|problem-list-item, and patient/Condition.rs?category=http://hl7.org/fhir/us/core/CodeSystem/condition-category|health-concern (also with user/)
Granular scopes, v2 (Observation)patient/Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory, …|vital-signs, …|social-history, …|survey, …|procedure (clinical tests), and patient/Observation.rs?category=http://hl7.org/fhir/us/core/CodeSystem/us-core-category|sdoh (also with user/)
Launch contextlaunch (EHR launch), launch/patient (standalone patient launch)
Identityopenid, fhirUser
Refreshoffline_access, online_access

Sign-in accounts. A patient or clinician signs in on the FHIR server's own sign-in page with an account Mira creates on the practice's request; the FHIR server emails an invitation to set a password. Mira EMR has no self-service screen for this yet. A patient account reads only that patient's own record; a clinician account reads every patient of the practice except restricted charts, read only.

Launches.

Refresh tokens.

Registration. Apps register through §3. What the authorization server needs: the redirect URIs (https; http://localhost for development), whether the app is a patient app, a clinician app or a back-end system, and optionally a key set URL (jwksUri, https) for private_key_jwt. Mira issues the client_id and client_secret (§3, step 3).

4.4 Requests and responses

Functions. The API's functions are the FHIR RESTful interactions and one operation:

FunctionHTTP syntaxReturns
capabilitiesGET [base]/metadata200 CapabilityStatement (no token needed)
readGET [base]/{Type}/{id}200 the resource
vreadGET [base]/{Type}/{id}/_history/{versionId}200 that version of the resource
historyGET [base]/{Type}/{id}/_history200 Bundle of type history
searchGET [base]/{Type}?{parameters}, or POST [base]/{Type}/_search with the parameters form-encoded in the body200 Bundle of type searchset
$exportGET [base]/Group/{id}/$export, GET [base]/Patient/$export, GET [base]/$export202 and a status URL (§4.6)

Send on every request: Authorization: Bearer {access_token} and Accept: application/fhir+json. Responses are application/fhir+json. The API is read only for apps: the create, update, patch and delete interactions the CapabilityStatement lists are refused.

Parameter data types (FHIR search parameter types):

TypeSyntaxExample
reference{id} or {Type}/{id}patient=6f0c9a8e-2c3b-4f7e-9a51-0d2b8c7e1a44
token{system}|{code}, or {code} alonecategory=http://terminology.hl7.org/CodeSystem/observation-category|laboratory
dateYYYY, YYYY-MM, YYYY-MM-DD or a dateTime, with an optional prefix eq, gt, lt, ge or le; repeat the parameter for a rangedate=ge2026-01-01&date=le2026-06-30
stringtext; matches values that start with it, ignoring casename=riv
numberinteger_count=50

Several values of one parameter separated by commas match any of them (status=active,completed). No US Core search below uses a composite parameter.

Search results. A search returns a Bundle:

FieldTypeNotes
resourceTypestringBundle
typecodesearchset
link[]{relation: string, url: string}self, and next while there are more pages. Follow next until it is absent
entry[].fullUrlstring (URL)The resource's absolute URL
entry[].resourceresourceA resource of the searched type, or a Provenance added by _revinclude
entry[].search.modecodematch for a result, include for a resource added by _revinclude

No match returns 200 with no entries. _revinclude=Provenance:target adds each result's US Core Provenance (author and author organization). _count sets the page size.

Document content. A DocumentReference (and a report-type DiagnosticReport) holds its document in content[].attachment.url (presentedForm[].url), an address on Mira EMR of the form https://{Mira EMR host}/fhir-binary/{documentId}. Fetch it with GET and the same Authorization: Bearer token; it returns the document's bytes with its own content type. It serves only documents the token may read.

What a patient token reads. A patient-context token reads that patient's own record. On the current server software (Medplum 5.2.3), patient/ scopes reach only resources in the patient's compartment, so a patient app cannot read the Practitioner or Organization resources a record refers to; a clinician (user/) or back-end (system/) token can.

4.5 Supported resources and searches

The US Core 6.1.0 resources Mira sends for USCDI v3, and the searches each supports. Every search below is a SHALL or SHOULD search of the US Core server CapabilityStatement, and every parameter in it is in the live CapabilityStatement's list for that resource (checked 2026-10-22). The read row links the profile every returned resource conforms to; the resources in a search's Bundle conform to the same profile.

AllergyIntolerance

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/AllergyIntolerance/{id}id (id, in the path)AllergyIntolerance (US Core AllergyIntolerance)
searchGET [base]/AllergyIntolerance?patient={id}patient (reference)Bundle (searchset) of AllergyIntolerance
searchGET [base]/AllergyIntolerance?patient={id}&clinical-status={token}patient (reference), clinical-status (token)Bundle (searchset) of AllergyIntolerance

Optional on every search: _count (number), _revinclude=Provenance:target (string).

CarePlan

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/CarePlan/{id}id (id, in the path)CarePlan (US Core CarePlan)
searchGET [base]/CarePlan?patient={id}&category={token}patient (reference), category (token)Bundle (searchset) of CarePlan
searchGET [base]/CarePlan?patient={id}&category={token}&status={token}patient (reference), category (token), status (token)Bundle (searchset) of CarePlan
searchGET [base]/CarePlan?patient={id}&category={token}&date={date}patient (reference), category (token), date (date)Bundle (searchset) of CarePlan
searchGET [base]/CarePlan?patient={id}&category={token}&status={token}&date={date}patient (reference), category (token), status (token), date (date)Bundle (searchset) of CarePlan

Optional on every search: _count (number), _revinclude=Provenance:target (string).

CareTeam

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/CareTeam/{id}id (id, in the path)CareTeam (US Core CareTeam)
searchGET [base]/CareTeam?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of CareTeam
searchGET [base]/CareTeam?patient={id}&role={token}patient (reference), role (token)Bundle (searchset) of CareTeam

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Condition

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Condition/{id}id (id, in the path)Condition (US Core Condition Encounter Diagnosis or US Core Condition Problems and Health Concerns)
searchGET [base]/Condition?patient={id}patient (reference)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&category={token}patient (reference), category (token)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&recorded-date={date}patient (reference), recorded-date (date)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&asserted-date={date}patient (reference), asserted-date (date)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&onset-date={date}patient (reference), onset-date (date)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&abatement-date={date}patient (reference), abatement-date (date)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&clinical-status={token}patient (reference), clinical-status (token)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&code={token}patient (reference), code (token)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&category={token}&clinical-status={token}patient (reference), category (token), clinical-status (token)Bundle (searchset) of Condition
searchGET [base]/Condition?patient={id}&category={token}&encounter={id}patient (reference), category (token), encounter (reference)Bundle (searchset) of Condition

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Coverage

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Coverage/{id}id (id, in the path)Coverage (US Core Coverage)
searchGET [base]/Coverage?patient={id}patient (reference)Bundle (searchset) of Coverage

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Device

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Device/{id}id (id, in the path)Device (US Core Implantable Device)
searchGET [base]/Device?patient={id}patient (reference)Bundle (searchset) of Device
searchGET [base]/Device?patient={id}&type={token}patient (reference), type (token)Bundle (searchset) of Device
searchGET [base]/Device?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of Device

Optional on every search: _count (number), _revinclude=Provenance:target (string).

DiagnosticReport

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/DiagnosticReport/{id}id (id, in the path)DiagnosticReport (US Core DiagnosticReport for Laboratory Results Reporting or US Core DiagnosticReport for Report and Note Exchange)
searchGET [base]/DiagnosticReport?patient={id}patient (reference)Bundle (searchset) of DiagnosticReport
searchGET [base]/DiagnosticReport?patient={id}&category={token}patient (reference), category (token)Bundle (searchset) of DiagnosticReport
searchGET [base]/DiagnosticReport?patient={id}&code={token}patient (reference), code (token)Bundle (searchset) of DiagnosticReport
searchGET [base]/DiagnosticReport?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of DiagnosticReport
searchGET [base]/DiagnosticReport?patient={id}&category={token}&date={date}patient (reference), category (token), date (date)Bundle (searchset) of DiagnosticReport
searchGET [base]/DiagnosticReport?patient={id}&code={token}&date={date}patient (reference), code (token), date (date)Bundle (searchset) of DiagnosticReport

Optional on every search: _count (number), _revinclude=Provenance:target (string).

DocumentReference

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/DocumentReference/{id}id (id, in the path)DocumentReference (US Core DocumentReference)
searchGET [base]/DocumentReference?_id={id}_id (token)Bundle (searchset) of DocumentReference
searchGET [base]/DocumentReference?patient={id}patient (reference)Bundle (searchset) of DocumentReference
searchGET [base]/DocumentReference?patient={id}&type={token}patient (reference), type (token)Bundle (searchset) of DocumentReference
searchGET [base]/DocumentReference?patient={id}&category={token}patient (reference), category (token)Bundle (searchset) of DocumentReference
searchGET [base]/DocumentReference?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of DocumentReference
searchGET [base]/DocumentReference?patient={id}&category={token}&date={date}patient (reference), category (token), date (date)Bundle (searchset) of DocumentReference
searchGET [base]/DocumentReference?patient={id}&type={token}&period={date}patient (reference), type (token), period (date)Bundle (searchset) of DocumentReference

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Encounter

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Encounter/{id}id (id, in the path)Encounter (US Core Encounter)
searchGET [base]/Encounter?_id={id}_id (token)Bundle (searchset) of Encounter
searchGET [base]/Encounter?patient={id}patient (reference)Bundle (searchset) of Encounter
searchGET [base]/Encounter?identifier={token}identifier (token)Bundle (searchset) of Encounter
searchGET [base]/Encounter?patient={id}&date={date}patient (reference), date (date)Bundle (searchset) of Encounter
searchGET [base]/Encounter?patient={id}&type={token}patient (reference), type (token)Bundle (searchset) of Encounter
searchGET [base]/Encounter?patient={id}&class={token}patient (reference), class (token)Bundle (searchset) of Encounter
searchGET [base]/Encounter?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of Encounter
searchGET [base]/Encounter?patient={id}&location={id}patient (reference), location (reference)Bundle (searchset) of Encounter
searchGET [base]/Encounter?patient={id}&discharge-disposition={token}patient (reference), discharge-disposition (token)Bundle (searchset) of Encounter

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Goal

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Goal/{id}id (id, in the path)Goal (US Core Goal)
searchGET [base]/Goal?patient={id}patient (reference)Bundle (searchset) of Goal
searchGET [base]/Goal?patient={id}&target-date={date}patient (reference), target-date (date)Bundle (searchset) of Goal
searchGET [base]/Goal?patient={id}&description={token}patient (reference), description (token)Bundle (searchset) of Goal
searchGET [base]/Goal?patient={id}&lifecycle-status={token}patient (reference), lifecycle-status (token)Bundle (searchset) of Goal

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Immunization

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Immunization/{id}id (id, in the path)Immunization (US Core Immunization)
searchGET [base]/Immunization?patient={id}patient (reference)Bundle (searchset) of Immunization
searchGET [base]/Immunization?patient={id}&date={date}patient (reference), date (date)Bundle (searchset) of Immunization
searchGET [base]/Immunization?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of Immunization

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Location

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Location/{id}id (id, in the path)Location (US Core Location)
searchGET [base]/Location?name={string}name (string)Bundle (searchset) of Location
searchGET [base]/Location?address={string}address (string)Bundle (searchset) of Location
searchGET [base]/Location?address-city={string}address-city (string)Bundle (searchset) of Location
searchGET [base]/Location?address-state={string}address-state (string)Bundle (searchset) of Location
searchGET [base]/Location?address-postalcode={string}address-postalcode (string)Bundle (searchset) of Location

Optional on every search: _count (number).

MedicationDispense

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/MedicationDispense/{id}id (id, in the path)MedicationDispense (US Core MedicationDispense)
searchGET [base]/MedicationDispense?patient={id}patient (reference)Bundle (searchset) of MedicationDispense
searchGET [base]/MedicationDispense?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of MedicationDispense
searchGET [base]/MedicationDispense?patient={id}&status={token}&type={token}patient (reference), status (token), type (token)Bundle (searchset) of MedicationDispense

Optional on every search: _count (number), _revinclude=Provenance:target (string).

MedicationRequest

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/MedicationRequest/{id}id (id, in the path)MedicationRequest (US Core MedicationRequest)
searchGET [base]/MedicationRequest?patient={id}&intent={token}patient (reference), intent (token)Bundle (searchset) of MedicationRequest
searchGET [base]/MedicationRequest?patient={id}&intent={token}&status={token}patient (reference), intent (token), status (token)Bundle (searchset) of MedicationRequest
searchGET [base]/MedicationRequest?patient={id}&intent={token}&encounter={id}patient (reference), intent (token), encounter (reference)Bundle (searchset) of MedicationRequest
searchGET [base]/MedicationRequest?patient={id}&intent={token}&authoredon={date}patient (reference), intent (token), authoredon (date)Bundle (searchset) of MedicationRequest

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Observation

Profiles: Laboratory Result, Clinical Result, Screening and Assessment, Smoking Status, Occupation, Pregnancy Status, Pregnancy Intent, Sexual Orientation, Vital Signs, Blood Pressure, BMI, Body Height, Body Weight, Body Temperature, Head Circumference, Heart Rate, Respiratory Rate, Pulse Oximetry, Pediatric BMI for Age, Pediatric Weight for Height, Pediatric Head Occipital-frontal Circumference Percentile.

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Observation/{id}id (id, in the path)Observation (one of the profiles above)
searchGET [base]/Observation?patient={id}&category={token}patient (reference), category (token)Bundle (searchset) of Observation
searchGET [base]/Observation?patient={id}&code={token}patient (reference), code (token)Bundle (searchset) of Observation
searchGET [base]/Observation?patient={id}&category={token}&date={date}patient (reference), category (token), date (date)Bundle (searchset) of Observation
searchGET [base]/Observation?patient={id}&code={token}&date={date}patient (reference), code (token), date (date)Bundle (searchset) of Observation
searchGET [base]/Observation?patient={id}&category={token}&status={token}patient (reference), category (token), status (token)Bundle (searchset) of Observation

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Organization

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Organization/{id}id (id, in the path)Organization (US Core Organization)
searchGET [base]/Organization?name={string}name (string)Bundle (searchset) of Organization
searchGET [base]/Organization?address={string}address (string)Bundle (searchset) of Organization

Optional on every search: _count (number).

Patient

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Patient/{id}id (id, in the path)Patient (US Core Patient)
searchGET [base]/Patient?_id={id}_id (token)Bundle (searchset) of Patient
searchGET [base]/Patient?identifier={token}identifier (token)Bundle (searchset) of Patient
searchGET [base]/Patient?name={string}name (string)Bundle (searchset) of Patient
searchGET [base]/Patient?birthdate={date}&name={string}birthdate (date), name (string)Bundle (searchset) of Patient
searchGET [base]/Patient?gender={token}&name={string}gender (token), name (string)Bundle (searchset) of Patient
searchGET [base]/Patient?birthdate={date}&family={string}birthdate (date), family (string)Bundle (searchset) of Patient
searchGET [base]/Patient?family={string}&gender={token}family (string), gender (token)Bundle (searchset) of Patient
searchGET [base]/Patient?death-date={date}&family={string}death-date (date), family (string)Bundle (searchset) of Patient

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Practitioner

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Practitioner/{id}id (id, in the path)Practitioner (US Core Practitioner)
searchGET [base]/Practitioner?name={string}name (string)Bundle (searchset) of Practitioner
searchGET [base]/Practitioner?identifier={token}identifier (token)Bundle (searchset) of Practitioner
searchGET [base]/Practitioner?_id={id}_id (token)Bundle (searchset) of Practitioner

Optional on every search: _count (number).

Procedure

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Procedure/{id}id (id, in the path)Procedure (US Core Procedure)
searchGET [base]/Procedure?patient={id}patient (reference)Bundle (searchset) of Procedure
searchGET [base]/Procedure?patient={id}&date={date}patient (reference), date (date)Bundle (searchset) of Procedure
searchGET [base]/Procedure?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of Procedure
searchGET [base]/Procedure?patient={id}&code={token}&date={date}patient (reference), code (token), date (date)Bundle (searchset) of Procedure

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Provenance

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Provenance/{id}id (id, in the path)Provenance (US Core Provenance)

RelatedPerson

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/RelatedPerson/{id}id (id, in the path)RelatedPerson (US Core RelatedPerson)
searchGET [base]/RelatedPerson?_id={id}_id (token)Bundle (searchset) of RelatedPerson
searchGET [base]/RelatedPerson?patient={id}patient (reference)Bundle (searchset) of RelatedPerson
searchGET [base]/RelatedPerson?name={string}name (string)Bundle (searchset) of RelatedPerson
searchGET [base]/RelatedPerson?patient={id}&name={string}patient (reference), name (string)Bundle (searchset) of RelatedPerson

Optional on every search: _count (number), _revinclude=Provenance:target (string).

ServiceRequest

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/ServiceRequest/{id}id (id, in the path)ServiceRequest (US Core ServiceRequest)
searchGET [base]/ServiceRequest?patient={id}patient (reference)Bundle (searchset) of ServiceRequest
searchGET [base]/ServiceRequest?_id={id}_id (token)Bundle (searchset) of ServiceRequest
searchGET [base]/ServiceRequest?patient={id}&category={token}patient (reference), category (token)Bundle (searchset) of ServiceRequest
searchGET [base]/ServiceRequest?patient={id}&code={token}patient (reference), code (token)Bundle (searchset) of ServiceRequest
searchGET [base]/ServiceRequest?patient={id}&status={token}patient (reference), status (token)Bundle (searchset) of ServiceRequest
searchGET [base]/ServiceRequest?patient={id}&category={token}&authored={date}patient (reference), category (token), authored (date)Bundle (searchset) of ServiceRequest
searchGET [base]/ServiceRequest?patient={id}&code={token}&authored={date}patient (reference), code (token), authored (date)Bundle (searchset) of ServiceRequest

Optional on every search: _count (number), _revinclude=Provenance:target (string).

Specimen

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Specimen/{id}id (id, in the path)Specimen (US Core Specimen)
searchGET [base]/Specimen?_id={id}_id (token)Bundle (searchset) of Specimen
searchGET [base]/Specimen?patient={id}patient (reference)Bundle (searchset) of Specimen

Optional on every search: _count (number).

Group (bulk export)

One Group per practice: every patient of the practice except restricted charts. It has no US Core profile.

InteractionHTTP syntaxRequired parameters (type)Returns
readGET [base]/Group/{id}id (id, in the path)Group
searchGET [base]/GroupnoneBundle (searchset) of Group: the practice's one Group
$exportGET [base]/Group/{id}/$exportsee §4.6see §4.6

4.6 Bulk Data Access 1.0.1 ($export)

OperationKick-off syntaxExportsOperationDefinition
Group exportGET [base]/Group/{id}/$exportThe practice's patients and their data, with the Practitioner, Organization and Location resources that data refers to. Declared in the CapabilityStatementgroup-export
Patient exportGET [base]/Patient/$exportEvery patient the client may read, with their data. A patient's own token exports only that patient's recordpatient-export
System exportGET [base]/$exportEvery resource the client may readexport

Authorization. A back-end client (client_credentials with private_key_jwt or its client secret, §4.3) with a system/ read scope, for example system/*.rs or system/*.read. The practice's Group excludes restricted charts. A patient token may not use Group export.

Kick-off request. Headers Accept: application/fhir+json, Prefer: respond-async and Authorization: Bearer {access_token}.

ParameterTypeRequiredSupported
_outputFormatstringnoAccepted; the output is always NDJSON (application/fhir+ndjson), whatever the value
_sinceinstant (YYYY-MM-DDThh:mm:ss[.sss]Z or with an offset)noYes, on all three. Only resources changed at or after _since are exported, including the Practitioner, Organization and Location resources a group export adds
_typestring: resource types separated by commasnoYes, on all three. Only those resource types are exported
_typeFilterstring: a FHIR search, for example Observation?category=laboratorynoPatient and system export only; a group export with _typeFilter answers 400

Kick-off response. 202 Accepted with the header Content-Location: https://fhir-dev.mirahealth.care/fhir/R4/bulkdata/export/{exportId}, the status URL. A refused request answers 4xx with an OperationOutcome (§4.7).

Status request. GET {Content-Location} with Authorization: Bearer {access_token}. A client reads only its own exports.

Cancelling a running export (DELETE {Content-Location}) is not available to clients registered through Mira.

Completion manifest.

FieldTypeValue
transactionTimestring (FHIR instant)When the export started; use it as the next _since
requeststring (URL)The kick-off request URL
requiresAccessTokenbooleanfalse: the file URLs are signed and expire, so download them without the access token
output[]array of {type: string, url: string}One entry per file: type is the resource type (for example Patient), url the file's signed URL
error[]array of {type: string, url: string}Files of OperationOutcome resources for anything that could not be exported; empty when nothing failed

The server also returns a deleted array (a Bulk Data 2.0 field); Bulk Data 1.0.1 clients can ignore it.

{
	"transactionTime": "2026-10-22T15:00:00.000Z",
	"request": "https://fhir-dev.mirahealth.care/fhir/R4/Group/{id}/$export",
	"requiresAccessToken": false,
	"output": [
		{"type": "Patient", "url": "https://fhir-dev.mirahealth.care/storage/…"},
		{"type": "Condition", "url": "https://fhir-dev.mirahealth.care/storage/…"}
	],
	"error": []
}

File request. GET {output[].url} with no Authorization header returns 200 and the file in NDJSON: one FHIR resource, as JSON, per line, all of the file's type.

4.7 Errors and exception handling

FHIR API. Every error is an HTTP status code with a FHIR OperationOutcome body (application/fhir+json):

FieldTypeValue
resourceTypestringOperationOutcome
issue[]arrayOne or more issues
issue[].severitycodeerror (or fatal, warning, information)
issue[].codecodeThe FHIR issue type, for example login, forbidden, not-found, invalid, processing
issue[].details.textstringA plain-language message
issue[].expression[]stringThe parameter or element at fault, when there is one
extension[] (tracing)objectThe request's requestId; quote it to support
{
	"resourceType": "OperationOutcome",
	"id": "unauthorized",
	"issue": [{"severity": "error", "code": "login", "details": {"text": "Unauthorized"}}]
}
HTTPWhenWhat the app should do
400Invalid search or parameter (an unknown parameter, a malformed value, _typeFilter on a group export)Fix the request; do not retry it unchanged
401Missing, expired, revoked or invalid access tokenUse the refresh token for a new access token, or authorize again; then retry
403The token's scopes or the account's access rules refuse the request (including any write); or the firewall limit (§4.8)Do not retry; request the scope the call needs
404No such resource, or a resource the token may not read (the same answer for both)Treat as not found
410The resource was deletedRemove your copy
429Too many sign-in attempts (§4.8)Wait a minute, then retry
5xxServer errorRetry with backoff; quote the requestId to support

Bulk export: 202 while running, then 200 with the manifest (§4.6).

Authorization server. The token and introspection endpoints answer errors as {"error": string, "error_description": string} (§4.3). The authorize endpoint returns its errors to the app's redirect_uri as error, error_description and state query parameters; when the client_id or redirect_uri itself is invalid, it shows an error page instead of redirecting.

4.8 Limits

Sign-in allows 5 attempts per minute per address (429 Too Many Requests). The token endpoint takes at most 300 requests per 5 minutes per address; past that the firewall answers 403.

5. (g)(7) patient selection and (g)(9) all data request

Mira EMR serves these two APIs itself, under https://miraemr.com/api/v1/api-access. Version: v1. A breaking change gets a new path version and the notice in §1.5.

5.1 Authentication and app configuration

Send one credential as Authorization: Bearer <credential> on every request. A request with an access_token query parameter is refused (400). There are no cookies; browser apps may call cross-origin (CORS *, preflight answered).

CredentialHow you get itWhat it reaches
Mira API key mira_<client id>.<secret>Registration (§3)Every patient of the one practice it was registered for, both endpoints. Issued to provider and back-end apps only. Only an active key works
SMART access token from the practice's FHIR server (/oauth2/token, §4): authorization_code with PKCE for a patient-facing or clinician app, client_credentials (private_key_jwt or client_secret_basic) for a back-end app§3 or the practiceA patient-context token (patient launch): that patient only. Any other token: the practice whose FHIR project registered the client; and in every case only the patients and resources the token's own FHIR access policy shows it. Scopes: a Patient read scope for §5.2 (system/Patient.rs, user/Patient.read, patient/*.rs …); for §5.3, an unconstrained read of every resource the CCD carries, in practice patient/*.rs, user/*.rs or system/*.rs. A constrained scope (…?category=…) never authorizes a whole resource type

Software you need: any HTTPS client (TLS 1.2 or later) that can set a header, parse JSON (§5.2) and save XML (§5.3). For SMART tokens, a SMART App Launch 2.0 client library (§4). Responses are never cached (Cache-Control: no-store).

Results never cross practices. With a SMART token, Mira asks the FHIR server, as that token, which of the matching patients it may see (§5.2) and whether it may read the patient and every resource type of the CCD (§5.3); anything refused is left out or refused. A restricted chart (a confidential chart the practice limits to named staff) is reachable only by the patient's own token.

5.2 (g)(7) Patient selection: GET /api/v1/api-access/patients

Returns the Mira patient id (the token for §5.3) of every patient of the practice who matches and whom the credential may reach.

Query parameters. Provide either identifier, or name with birthdate.

ParameterFormatRule
identifier<system>|<value>, for example https://mirahealth.care/fhir/sid/mrn/<organizationId>|12345Exact match. Systems: the practice's MRN system https://mirahealth.care/fhir/sid/mrn/<organizationId> and the Mira patient id https://mirahealth.care/fhir/sid/patient-id. Any other system matches nothing
nametext, 1–100 characters: family or family,givenFamily name: exact, ignoring case and accents. Given name: matches the start of the first name, ignoring case and accents
birthdateYYYY-MM-DDExact date. Required with name
_countinteger 1–50, default 20Page size
pageopaque cursor from nextNext page

Only charts the CCD (§5.3) can be produced for are listed: a merged chart is not, and neither is a chart with no date of birth or of a minor (the patient record export Mira serves today is for adults).

Response 200 application/json:

{
	"patients": [
		{
			"id": "6f0c9a8e-2c3b-4f7e-9a51-0d2b8c7e1a44",
			"identifier": [
				{"system": "https://mirahealth.care/fhir/sid/mrn/<organizationId>", "value": "12345"},
				{"system": "https://mirahealth.care/fhir/sid/patient-id", "value": "6f0c9a8e-2c3b-4f7e-9a51-0d2b8c7e1a44"}
			],
			"name": {"family": "Rivera", "given": ["Ana"]},
			"birthDate": "1971-04-05",
			"sex": "female"
		}
	],
	"total": 1,
	"next": null
}
FieldTypeNotes
patients[].idstring (UUID)Pass to §5.3
patients[].identifier[]{system: string, value: string}MRN (when the chart has one) and the Mira patient id
patients[].name{family: string, given: string[]}Legal name
patients[].birthDatestring YYYY-MM-DD
patients[].sexfemale | male | other | unknown
totalintegerMatches on this page and after
nextstring | nullCursor for page

No match returns 200 with "patients": [], not 404.

5.3 (g)(9) All data request: GET /api/v1/api-access/patients/{id}/ccd

Returns a C-CDA R2.1 Continuity of Care Document (Companion Guide R4.1, USCDI v3) for one patient: every USCDI data class Mira holds for the patient, as section narrative and discrete entries, in one document.

ParameterWhereFormatRule
idpathUUID from §5.2Must be a patient the credential may reach
startqueryYYYY-MM-DDOptional. Inclusive start of the date range
endqueryYYYY-MM-DDOptional. Inclusive end of the date range

Date semantics.

What the practice withholds. The document is the same record the practice releases to the patient in its patient portal: an item the practice has held from release (for example under a HIPAA or state-law restriction), a result not yet released, and a visit note not yet released are left out.

Response 200 application/xml. A single ClinicalDocument:

Headers: Content-Type: application/xml; charset=utf-8, Content-Disposition: attachment; filename="ccd-<id>.xml", Cache-Control: no-store.

5.4 Errors

Every error is JSON: {"error": {"code": "<code>", "message": "<plain words>"}}. Every response of §5.2 and §5.3 carries an X-Request-Id header.

HTTPcodeWhen
400invalid_requestMissing or malformed parameter; name without birthdate; a bad date; start after end; a patient id that is not a UUID; an access_token query parameter
401invalid_tokenMissing, expired, unknown or revoked credential (with header WWW-Authenticate: Bearer error="invalid_token")
403insufficient_scopeThe token lacks the scope, a patient token asked for another patient, or the FHIR server's access rules refuse the patient to the token
404not_foundNo such patient for this credential. The same answer is given whether the patient does not exist, belongs to another practice, or is not visible
406not_acceptable§5.3 called with an Accept other than application/xml, text/xml, application/* or */*
429rate_limitedMore than 600 requests per minute per client on one Mira server (each server counts separately); Retry-After gives the seconds to wait
500server_errorUnexpected failure. Retry with backoff; quote the response's X-Request-Id to support
503unavailableThe FHIR server cannot check the SMART token or its access right now; Retry-After is set when the token itself could not be checked

5.5 Specifications

5.6 Example

GET /api/v1/api-access/patients?identifier=https%3A%2F%2Fmirahealth.care%2Ffhir%2Fsid%2Fmrn%2F<org>%7C12345 HTTP/1.1
Host: miraemr.com
Authorization: Bearer mira_0b8a…_c1.Yc3…

GET /api/v1/api-access/patients/6f0c9a8e-2c3b-4f7e-9a51-0d2b8c7e1a44/ccd?start=2026-01-01&end=2026-06-30 HTTP/1.1
Host: miraemr.com
Authorization: Bearer mira_0b8a…_c1.Yc3…
Accept: application/xml
curl -H "Authorization: Bearer $MIRA_API_KEY" \
  "https://miraemr.com/api/v1/api-access/patients?name=Rivera,Ana&birthdate=1971-04-05"
curl -H "Authorization: Bearer $MIRA_API_KEY" -o ccd.xml \
  "https://miraemr.com/api/v1/api-access/patients/<id>/ccd?start=2026-01-10&end=2026-01-10"

6. Security