eMedicalPractice REST API Documentation
REST API Table of Contents
Overview
This document is intended for application developers, integration engineers and clients who wants to integrate with eMedicalPractice. It describes how the eMedicalPractice Health IT Module implements FHIR API requirements, including supported US Core IG elements, API registration, OAuth2/SMART on FHIR security models, refresh token issuance, TLS enforcement, and all disclosures required.
prerequisite
Enable the standard api service (/api/ endpoints) in after login to your portal see the emedicalpractice menu and go to : siteadmin->Fhir Setup->"enable emedicalpractice standard rest api"
Authorization
eMedPractice uses OIDC compliant authorization for API. SSL is required and setting baseurl at SiteAdmin->FhirSetup->'Site Address (required for OAuth2 and FHIR)' is required.
Scopes
This is a listing of scopes:
Note: For Smart app version 2 Scope should be of type (*).rs instead of (*).read
openid(Generic mandatory scope)fhirUseremailprofileonline_accessoffline_access(Will signal server to provide a refresh token)launchlaunch/patientapi:fhir(fhir which are the /fhir/ endpoints)- Patient (USCDI V2)
patient/AllergyIntolerance.rspatient/CarePlan.rspatient/CareTeam.rspatient/Condition.rspatient/Coverage.rspatient/Device.rspatient/DiagnosticReport.rspatient/Document.rspatient/DocumentReference.rspatient/DocumentReference.$docrefpatient/Encounter.rspatient/Goal.rspatient/Immunization.rspatient/Location.rspatient/MedicationRequest.rspatient/Medication.rspatient/Observation.rspatient/Organization.rspatient/Patient.rspatient/Person.rspatient/Practitioner.rspatient/Procedure.rspatient/Provenance.rspatient/ServiceRequest.rspatient/Coverage.rspatient/MedicationDispense.rspatient/Specimen.rspatient/RelatedPerson.rs
patient/Condition.rs?category=http://hl7.org/fhir/us/core/CodeSystem/condition-category|health-concernpatient/Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|encounter-diagnosispatient/Condition.rs?category=http://terminology.hl7.org/CodeSystem/condition-category|problem-list-itempatient/Observation.rs?category=http://hl7.org/fhir/us/core/CodeSystem/us-core-category|sdohpatient/Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|social-historypatient/Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|laboratorypatient/Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|surveypatient/Observation.rs?category=http://terminology.hl7.org/CodeSystem/observation-category|vital-signs
- Patient (USCDI V1)
patient/AllergyIntolerance.readpatient/CarePlan.readpatient/CareTeam.readpatient/Condition.readpatient/Coverage.readpatient/Device.readpatient/DiagnosticReport.readpatient/Document.readpatient/DocumentReference.readpatient/DocumentReference.$docrefpatient/Encounter.readpatient/Goal.readpatient/Immunization.readpatient/Location.readpatient/MedicationRequest.readpatient/Medication.readpatient/Observation.readpatient/Organization.readpatient/Patient.readpatient/Person.readpatient/Practitioner.readpatient/Procedure.readpatient/Provenance.read
- EHR (USCDI V2)
user/AllergyIntolerance.rsuser/CarePlan.rsuser/CareTeam.rsuser/Condition.rsuser/Coverage.rsuser/Device.rsuser/DiagnosticReport.rsuser/Document.rsuser/DocumentReference.rsuser/DocumentReference.$docrefuser/Encounter.rsuser/Goal.rsuser/Immunization.rsuser/Location.rsuser/MedicationRequest.rsuser/Medication.rsuser/Observation.rsuser/Organization.rsuser/Organization.writeuser/Patient.rsuser/Patient.writeuser/Person.rsuser/Practitioner.rsuser/Practitioner.writeuser/PractitionerRole.rsuser/Procedure.rsuser/Provenance.rs
- EHR (USCDI V1)
user/AllergyIntolerance.readuser/CarePlan.readuser/CareTeam.readuser/Condition.readuser/Coverage.readuser/Device.readuser/DiagnosticReport.readuser/Document.readuser/DocumentReference.readuser/DocumentReference.$docrefuser/Encounter.readuser/Goal.readuser/Immunization.readuser/Location.readuser/MedicationRequest.readuser/Medication.readuser/Observation.readuser/Organization.readuser/Organization.writeuser/Patient.readuser/Patient.writeuser/Person.readuser/Practitioner.readuser/Practitioner.writeuser/PractitionerRole.readuser/Procedure.readuser/Provenance.read
- Multi-Patient (USCDI V2)
system/AllergyIntolerance.rssystem/CarePlan.rssystem/CareTeam.rssystem/Condition.rssystem/Coverage.rssystem/Device.rssystem/DiagnosticReport.rssystem/Document.rssystem/DocumentReference.rssystem/DocumentReference.$docrefsystem/Encounter.rssystem/Goal.rssystem/Group.rssystem/Group.$exportsystem/Immunization.rssystem/Location.rssystem/MedicationRequest.rssystem/Medication.rssystem/Observation.rssystem/Organization.rssystem/Patient.rssystem/Patient.$exportsystem/Person.rssystem/Practitioner.rssystem/PractitionerRole.rssystem/Procedure.rssystem/Provenance.rssystem/*.$bulkdata-statussystem/*.$export
- Multi-Patient (USCDI V1)
system/AllergyIntolerance.readsystem/CarePlan.readsystem/CareTeam.readsystem/Condition.readsystem/Coverage.readsystem/Device.readsystem/DiagnosticReport.readsystem/Document.readsystem/DocumentReference.readsystem/DocumentReference.$docrefsystem/Encounter.readsystem/Goal.readsystem/Group.readsystem/Group.$exportsystem/Immunization.readsystem/Location.readsystem/MedicationRequest.readsystem/Medication.readsystem/Observation.readsystem/Organization.readsystem/Patient.readsystem/Patient.$exportsystem/Person.readsystem/Practitioner.readsystem/PractitionerRole.readsystem/Procedure.readsystem/Provenance.readsystem/*.$bulkdata-statussystem/*.$export
- Patient (USCDI V2)
Supported Resources Table
| Resource Type | US Core Profile(s) | Interactions | Search Parameters | revInclude / Notes |
|---|---|---|---|---|
| AllergyIntolerance | us-core-allergyintolerance | read, search-type, history-instance | clinical-status, patient | revInclude: Provenance:target |
| CarePlan | us-core-careplan | read, search-type, history-instance | category, date, patient, status | revInclude: Provenance:target |
| CareTeam | us-core-careteam | read, search-type, history-instance | patient, status | revInclude: Provenance:target |
| Condition (LIMITED: category=health-concern — certification-only) | us-core-condition; us-core-condition-encounter-diagnosis; us-core-condition-problems-health-concerns | read, search-type, history-instance | category clinical-status, patient, onset-date, code | revInclude: Provenance:target |
| Coverage | us-core-coverage | read, search-type | patient | revInclude: Provenance:target |
| Device | us-core-implantable-device | read, search-type, history-instance | patient, type | revInclude: Provenance:target |
| DiagnosticReport | us-core-diagnosticreport-lab; us-core-diagnosticreport-note | create, read, search-type, history-instance | status, patient, category, code, date | revInclude: Provenance:target |
| DocumentReference (CERT-ONLY: specific categories) | us-core-documentreference | create, read, search-type, history-instance | _id, status, patient, categorytype, date, period | revInclude: Provenance:target |
| Encounter | us-core-encounter | read, search-type, history-instance | _id, class, date, identifier, patient, status, type | revInclude: Provenance:target |
| Goal | us-core-goal | read, search-type, history-instance | lifecycle-status, patient, target-date | revInclude: Provenance:target |
| Group | (Bulk export support) | export operation | — | Supports Group-level $export |
| Immunization | us-core-immunization | read, search-type, history-instance | patient, status, date | revInclude: Provenance:target |
| Location | us-core-location | read, search-type, history-instance | name, address, address-city, address-state, address-postalcode | — |
| Medication (read-only) | us-core-medication | read, history-instance | — | read-only |
| MedicationDispense | us-core-medicationdispense | read, search-type | status, type, patient | revInclude: Provenance:target |
| MedicationRequest (CERT-ONLY) | us-core-medicationrequest | read, search-type, history-instance | status, intent, patient, encounter, authoredon | include: MedicationRequest:medication; revInclude: Provenance:target |
| Observation | US Core Observation Profiles (vital signs, labs, imaging, survey, social-history, SDOH, etc.) | read, search-type, history-instance | status, category, code, date, patient | revInclude: Provenance:target; supports wide set of US Core observation profiles |
| Organization | us-core-organization | read, search-type, history-instance | name, address | — |
| Patient | us-core-patient | read, search-type, history-instance | _id, birthdate, family, gender, given, identifier, name | revInclude: Provenance:target; supports patient-level $export |
| Practitioner | us-core-practitioner | read, search-type, history-instance | name, identifier | — |
| PractitionerRole | us-core-practitionerrole | read, search-type, history-instance | specialty, practitioner | searchInclude: endpoint, practitioner |
| Procedure | us-core-procedure | read, search-type, history-instance | status, patient, date, code | revInclude: Provenance:target |
| Provenance | us-core-provenance | read, history-instance | — | Used for tracking origin of records |
| ServiceRequest | us-core-servicerequest | read | status, patient, category, code, authored, _id | revInclude: Provenance:target; required parameters supported |
| Specimen (CERT-ONLY) | us-core-specimen | read, search-type | _id, patient | Certification-only: Not available to production clients |
| RelatedPerson | us-core-relatedperson | read, search-type | _id, patient | revInclude: Provenance:target |
Registration
A client needs to be registered before applying for grant to obtain access/refresh tokens. A client can register by going to the url https://service.emedpractice.com/admin/fhirclientregistration.aspx.
SMART on FHIR Registration
SMART Enabled Apps are supported.
SMART client can be registered at https://service.emedpractice.com/admin/fhirclientregistration.aspx. For Registration Click Here and fill the form.
After registering the SMART client, A request is generated which has to be approved by eMedicalPractice.
After it is approved, the SMART App will then be available to use in the Patient portal screen (SMART Enabled Apps widget).
Authorization Code Grant
This is the recommended standard mechanism to obtain access/refresh tokens. This is done by using an OAuth2 client with url of connect/<authorize>; an example full path would be https://stage.emedpractice.com:8080/connect/authorize. Standard OAUTH2 clients will retrieve the authorize URL from the FHIR /metadata endpoint, but if you are building your own client you can access the metadata or go directly to the https://stage.emedpractice.com:8181/fhir/r4/metadata endpoint.
Note that a refresh token is only supplied if the offline_access scope is provided when requesting authorization grant.
You will need to pass the scopes you are requesting, the redirect_uri (must be one that was registered at the time of your client registration), and a state parameter which can be any value. Once authorization has finished the browser will be redirected to the URL specified in redirect_uri with an encrypted code value and the state value sent in the initial authorize request.
Example GET (this must be done in a browser):
GET /connect/authorize?client_id=yi4mnmVadpnqnJiOigkcGshuG-Kayiq6kmLqCJsYrk4&response_type=code&scope=launch%2Fpatient%20openid%20fhirUser%20offline_access%20patient%2FAllergyIntolerance.read%20patient%2FCarePlan.read%20patient%2FCareTeam.read%20patient%2FCondition.read%20patient%2FDevice.read%20patient%2FDiagnosticReport.read%20patient%2FDocumentReference.read%20patient%2FEncounter.read%20patient%2FGoal.read%20patient%2FImmunization.read%20patient%2FLocation.read%20patient%2FMedication.read%20patient%2FMedicationRequest.read%20patient%2FObservation.read%20patient%2FOrganization.read%20patient%2FPatient.read%20patient%2FPractitioner.read%20patient%2FProcedure.read%20patient%2FProvenance.read&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcallback&state=9512151b-e5ca-cb4b-1ddc-aaf4cd8c6ecc
The client application must then make a request for an access token by hitting the /token endpoint. Note the redirect_uri MUST match what what was sent in /authorize endpoint. If your application is registered as a public application you must include the client_id in the POST request. If you are registered as a confidential app you must use HTTP Basic Authentication where the client_id is your username and the password is your client_secret. HTTP Basic Authentication follows the algorithm of base64_encode(username:client_secret). Note that this mechanism should ONLY be used over an encrypted protocol such as TLS to prevent leaking your client_secret more inormation here.
Example Public Application POST
curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
'https://stage.emedpractice.com:8080/connect/token'
--data 'grant_type=authorization_code&client_id=yi4mnmVadpnqnJiOigkcGshuG-Kayiq6kmLqCJsYrk4&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcallback&code=def50...'
Example Private Application POST
curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Authorization: Basic c3Z2TThFX1hISEhYUmtoZzUyeWoyNjdIOEYwQnpmT09pRmE4aUZBT290WTptbzZpZEFPaEU0UVYxb0lacUR5YTFHR1JHVGU5VDQzNWpzeTlRbWYxV2NiVFQ4NXhuZW5VdUpaUFR0bUZGT1QxVkhmYjZiclVvWWZ2Znd2NTFQejFldw==' \
'https://stage.emedpractice.com:8080/connect/token' \
--data 'grant_type=authorization_code&client_id=yi4mnmVadpnqnJiOigkcGshuG-Kayiq6kmLqCJsYrk4&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcallback&code=def50...'
Refresh Token Grant
Note that a refresh token is only supplied if the offline_access scope is provided when requesting authorization or password grant.
Example:
curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
-i 'https://stage.emedpractice.com:8080/connect/token'
--data 'grant_type=refresh_token
&client_id=LnjqojXXjFYe5j2Jp9m9UnmuxOnMg0VodEJj3yE8_OA
&refresh_token=def5020089a766d16...'Response:
{
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYn...",
"token_type": "Bearer",
"expires_in": 3599,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYnl1RkRp...",
"refresh_token": "def5020017b484b0add020bf3491a8a537fa04eda12..."
}Client Credentials Grant
This is an advanced grant that uses JSON Web Key Sets(JWKS) to authenticate and identify the client. This credential grant is
required to be used for access to any system/*.$export scopes. API clients must register either web accessible JWKS URI that hosts
a RSA384 compatible key, or provide their JWKS as part of the registration. Client Credentials Grant access tokens are short
lived and valid for only 1 minute and no refresh token is issued. Tokens are requested at /connect/token.
Logout
A grant (both Authorization Code and Password grants) can be logged out (ie. removed) by url of https://stage.emedpractice.com:8080/authorize/logout?id_token_hint=<id_token>. Optional: post_logout_redirect_uri and state parameters can also be sent; note that post_logout_redirect_uris also needs to be set during registration for it to work.
Standard API Documentation
The Standard API is documented via Swagger. Can see this documentation (and can test it) by going to the swagger directory in your eMedicalPractice installation. The Standard API is documented there in the standard section. (clicking on the API (Swagger) User Interface link for the demo will take you there)..
eMedicalPractice standard endpoints Use https://stage.emedpractice.com:8080/fhir/r4as base URI.
Example: https://stage.emedpractice.com:8080/fhir/r4/patient returns a resource of all Patients.
The Bearer token is required for each eMedicalPractice API request, and is conveyed using an Authorization header. Note that the Bearer token is the access_token that is obtained in the above Authorization section.
Request:
curl -X GET 'https://stage.emedpractice.com:8080/fhir/r4/patient/1' \
-H 'Authorization: Bearer eyJ0b2tlbiI6IjAwNmZ4TWpsNWhsZmNPelZicXBEdEZVUlNPQUY5KzdzR1Jjejc4WGZyeGFjUjY2QlhaaEs4eThkU3cxbTd5VXFBeTVyeEZpck9mVzBQNWc5dUlidERLZ0trUElCME5wRDVtTVk5bE9WaE5DTHF5RnRnT0Q0OHVuaHRvbXZ6OTEyNmZGUmVPUllSYVJORGoyZTkzTDA5OWZSb0ZRVGViTUtWUFd4ZW5cL1piSzhIWFpJZUxsV3VNcUdjQXR5dmlLQXRXNDAiLCJzaXRlX2lkIjoiZGVmYXVsdCIsImFwaSI6Im9lbXIifQ=='Patient Portal API Documentation
The Patient Portal API is documented via Swagger. Can see this documentation (and can test it) by going to the swagger directory in your eMedicalPractice installation. The Patient Portal API is documented there in the standard-patient section. Can also see (and test) this in the online demos at https://stage.emedpractice.com:8181/swagger/index.html (clicking on the API (Swagger) User Interface link for the demo will take you there). Make sure to set your client api registration's redirect_uris to be <eMedicalPractice base URI>/swagger/oauth2-redirect.html.
Enable the Patient Portal API service (/portal/ endpoints) in eMedicalPractice menu: Administration->Globals->Connectors->"Enable eMedicalPractice Patient Portal REST API (EXPERIMENTAL)"
eMedicalPractice patient portal endpoints Use https://patientportal.emedpractice.com/patientlogin.aspx as base URI.
Note that the default component can be changed to the name of the site when using eMedicalPractice's multisite feature.
Example: https://stage.emedpractice.com:8080 returns a resource of the patient.
The Bearer token is required for each eMedicalPractice API request, and is conveyed using an Authorization header. Note that the Bearer token is the access_token that is obtained in the above Authorization section.
Security
- eMedicalPractice adminstrators / installers should ensure that the API is protected using an end to end encryption protocol such as TLS
- Password Grant SHOULD be turned off for any kind of production use as it has a number of security problems
- Setting the Admin -> Globals -> OAuth2 App Manual Approval Settings to be 'Manual Approval' prevents any OAuth2 application from accessing the API without manual approval from an administrator. This is the most secure setting. However, in the USA jurisdiction that must comply with CEHRT, patient standalone apps must be approved within 48 hours of a patient requesting access in order to avoid pentalities under the Information Blocking Provisions from ONC. EHR administrators are not allowed to vet a patient's choice of an app as long as the app complies with eMedicalPractice's OAuth2 security requirements. If an app requests user/* or system/* scopes, administrators can vet an application and request additional information / security on an app by app basis. Leaving the setting at the default will auto-approve any patient standalone app.
- Public apps (ones that can't securely store a secret) MUST implement the PKCE standard specified in RFC 7636. Confidential apps are still highly encouraged to implement PKCE to mitigate forms of MITM attacks such as multiple native app devices registering for the same custom url scheme used as the OAUTH2 redirect_uri in the authorization_code grant.
TLS 1.2 or higher enforcement
Enforcement statement: All public FHIR API and Auth endpoints enforce TLS 1.2 or higher.
Client registration, onboarding & app vetting
Registration URL: /admin/fhirclientregistration.aspx
Onboarding steps
- Create developer account (email verification and basic dev details).
- Register application with name, description, redirect URIs, scopes, and privacy policy URL.
- Provide contact and support info.
- Declare API usage and testing plan (sandbox vs production).
- Agree to API Terms & Conditions.
- Undergo manual approval for system-level scopes (if requested).
App vetting criteria
Apps requesting system-level or sensitive scopes must provide:
- Business justification
- Data flow diagram
- Privacy policy and security controls
- Penetration test summary (for high-risk access)
- Need to provide KYC (If needed)
Mandatory client requirements & recommended secure practices
To integrate with eMedPractice, client applications MUST:
- Support only HTTPS withTLS 1.2 or higher.
- Use Authorization Code with PKCE for native apps.
- Store secrets securely (e.g., OS-keystore, secure enclave) for confidential clients.
- Use exact redirect URIs registered during onboarding; no wildcards unless preapproved.
- Publish a privacy policy and adhere to data handling rules.
Rate limits, SLA & operational policies
Default public rate limits (subject to change):
- 5 requests per minute per client
SLA: Target 95% uptime. Scheduled maintenance windows will be published in advance.
For Developers
The OpenAPI/Swagger spec is the source of truth for endpoint signatures and example payloads. This section explains conventions and provides examples developers need beyond Swagger. REST API endpoints are defined endpoint to the eMedicalPractice controller which handles the request, and also handles the JSON data conversions.
Base URLs & versioning
- FHIR base:
https://emedpractice.com:8181/fhir/r4 - Auth base:
https://stage.emedpractice.com:8080/connect/authorize - Versioning policy: Major FHIR version changes use separate base paths; minor changes will be backward-compatible whenever possible.
"POST https://fhirbackup.emepractice.com:8443/fhir/r4/patient" => function () {
RestConfig::authorization_check("patients", "demo");
$data = (array) (json_decode(file_get_contents("php://input")));
$return = (new PatientRestController())->post($data);
RestConfig::apiLog($return, $data);
return $return;
}At a high level, the request processing flow consists of the following steps:
JSON Request -> Controller Component -> Validation -> Service Component -> Database
The logical response flow begins with the database result:
Database Result -> Service Component -> Controller Component -> RequestControllerHelper -> JSON Response
Error model
We return FHIR OperationOutcome resources for FHIR operation errors. For OAuth/auth errors, we follow RFC6749 and RFC6750 error formats.
{
"resourceType": "OperationOutcome",
"issue": {
"severity": "error",
"code": "invalid",
"details": { "text": "Invalid date parameter" }
}
}
validationErrorscontain "client based" data validation errorsinternalErrorscontain server related errorsdatais the response payload, represented as an object/{}for single results or an array/[]for multiple results