improved prior 8.2 fix
[openemr.git] / API_README.md
blobafee98ba36ccff950a228aa088818f2cdbcb7305
1 # OpenEMR REST API Documentation
3 ## REST API Table of Contents
4 - [Overview](API_README.md#overview)
5 - [Prerequisite](API_README.md#prerequisite)
6 - [Using API Internally](API_README.md#using-api-internally)
7 - [Multisite Support](API_README.md#multisite-support)
8 - [Authorization](API_README.md#authorization)
9     - [Scopes](API_README.md#scopes)
10     - [Registration](API_README.md#registration)
11         - [SMART on FHIR Registration](API_README.md#smart-on-fhir-registration)
12     - [Authorization Code Grant](API_README.md#authorization-code-grant)
13     - [Refresh Token Grant](API_README.md#refresh-token-grant)
14     - [Password Grant](API_README.md#password-grant)
15     - [Client Credentials Grant](API_README#client-credentials-grant)
16     - [Logout](API_README.md#logout)
17     - [More Details](API_README.md#more-details)
18 - [Standard API Documentation](API_README.md#standard-api-documentation)
19 - [Patient Portal API Documentation](API_README.md#patient-portal-api-documentation)
20 - [FHIR API Documentation (in FHIR_README.md)](FHIR_README.md#fhir-api-documentation)
21     - [Capability Statement (in FHIR_README.md)](FHIR_README.md#capability-statement)
22     - [Provenance (in FHIR_README.md)](FHIR_README.md#Provenance-resources)
23     - [BULK FHIR Exports (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
24         - [System Export (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
25         - [Patient Export (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
26         - [Group Export (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
27 - [For Developers](API_README.md#for-developers)
29 ## Overview
31 Easy-to-use JSON-based REST API for OpenEMR. FHIR is also supported, see FHIR API documentation [here](FHIR_README.md),
33 ## Prerequisite
35 Enable the Standard API service (/api/ endpoints) in OpenEMR menu: Administration->Globals->Connectors->"Enable OpenEMR Standard REST API"
37 ## Using API Internally
39 There are several ways to make API calls from an authorized session and maintain security:
41 -   See the script at tests/api/InternalApiTest.php for examples of internal API use cases.
43 ## Multisite Support
45 Multisite is supported by including the site in the endpoint. When not using multisite or using the `default` multisite site, then a typical path would look like `apis/default/api/patient`. If you are using multisite and using a site called `alternate`, then the path would look like `apis/alternate/api/patient`.
47 ## Authorization
49 OpenEMR uses OIDC compliant authorization for API. SSL is required and setting baseurl at Administration->Globals->Connectors->'Site Address (required for OAuth2 and FHIR)' is required. The listing of scopes can be found in below Scopes section.
51 ### Scopes
53 This is a listing of scopes:
54 - `openid` (Generic mandatory scope)
55 - `fhirUser`
56 - `online_access`
57 - `offline_access` (Will signal server to provide a refresh token)
58 - `launch`
59 - `launch/patient`
60 - `api:fhir` (fhir which are the /fhir/ endpoints)
61   - `patient/AllergyIntolerance.read`
62   - `patient/CarePlan.read`
63   - `patient/CareTeam.read`
64   - `patient/Condition.read`
65   - `patient/Device.read`
66   - `patient/DiagnosticReport.read`
67   - `patient/DocumentReference.read`
68   - `patient/Encounter.read`
69   - `patient/Goal.read`
70   - `patient/Immunization.read`
71   - `patient/Location.read`
72   - `patient/Medication.read`
73   - `patient/MedicationRequest.read`
74   - `patient/Observation.read`
75   - `patient/Organization.read`
76   - `patient/Patient.read`
77   - `patient/Person.read`
78   - `patient/Practitioner.read`
79   - `patient/Procedure.read`
80   - `patient/Provenance.read`
81   - `system/AllergyIntolerance.read`
82   - `system/CarePlan.read`
83   - `system/CareTeam.read`
84   - `system/Condition.read`
85   - `system/Coverage.read`
86   - `system/Device.read`
87   - `system/DiagnosticReport.read`
88   - `system/Document.read` (used for Bulk FHIR export downloads)
89   - `system/DocumentReference.read`
90   - `system/Encounter.read`
91   - `system/Goal.read`
92   - `system/Group.read`
93   - `system/Group.$export` (???)
94   - `system/Immunization.read`
95   - `system/Location.read`
96   - `system/Medication.read`
97   - `system/MedicationRequest.read`
98   - `system/Observation.read`
99   - `system/Organization.read`
100   - `system/Patient.read`
101   - `system/Patient.$export` (???)
102   - `system/Person.read`
103   - `system/Practitioner.read`
104   - `system/PractitionerRole.read`
105   - `system/Procedure.read`
106   - `system/Provenance.read`
107   - `system/*.$bulkdata-status` (???)
108   - `system/*.$export` (???)
109   - `user/AllergyIntolerance.read`
110   - `user/CarePlan.read`
111   - `user/CareTeam.read`
112   - `user/Condition.read`
113   - `user/Coverage.read`
114   - `user/Device.read`
115   - `user/DiagnosticReport.read`
116   - `user/DocumentReference.read`
117   - `user/Encounter.read`
118   - `user/Goal.read`
119   - `user/Immunization.read`
120   - `user/Location.read`
121   - `user/Medication.read`
122   - `user/MedicationRequest.read`
123   - `user/Observation.read`
124   - `user/Organization.read`
125   - `user/Organization.write`
126   - `user/Patient.read`
127   - `user/Patient.write`
128   - `user/Person.read`
129   - `user/Practitioner.read`
130   - `user/Practitioner.write`
131   - `user/PractitionerRole.read`
132   - `user/Procedure.read`
133   - `user/Provenance.read`
134 - `api:oemr` (user api which are the /api/ endpoints)
135   - `user/allergy.read`
136   - `user/allergy.write`
137   - `user/appointment.read`
138   - `user/appointment.write`
139   - `user/dental_issue.read`
140   - `user/dental_issue.write`
141   - `user/document.read`
142   - `user/document.write`
143   - `user/drug.read`
144   - `user/encounter.read`
145   - `user/encounter.write`
146   - `user/facility.read`
147   - `user/facility.write`
148   - `user/immunization.read`
149   - `user/insurance.read`
150   - `user/insurance.write`
151   - `user/insurance_company.read`
152   - `user/insurance_company.write`
153   - `user/insurance_type.read`
154   - `user/list.read`
155   - `user/medical_problem.read`
156   - `user/medical_problem.write`
157   - `user/medication.read`
158   - `user/medication.write`
159   - `user/message.write`
160   - `user/patient.read`
161   - `user/patient.write`
162   - `user/practitioner.read`
163   - `user/practitioner.write`
164   - `user/prescription.read`
165   - `user/procedure.read`
166   - `user/soap_note.read`
167   - `user/soap_note.write`
168   - `user/surgery.read`
169   - `user/surgery.write`
170   - `user/vital.read`
171   - `user/vital.write`
172 - `api:port` (patient api which are the /portal/ endpoints) (EXPERIMENTAL)
173   - `patient/encounter.read`
174   - `patient/patient.read`
176 ### Registration
178 Here is an example for registering a client. A client needs to be registered before applying for grant to obtain access/refresh tokens. Note: "post_logout_redirect_uris" is optional and only used if client wants a redirect to its own confirmation workflow.
180 Note that all scopes are included in this example for demonstration purposes. For production purposes, should only include the necessary scopes.
182 ```sh
183 curl -X POST -k -H 'Content-Type: application/json' -i https://localhost:9300/oauth2/default/registration --data '{
184    "application_type": "private",
185    "redirect_uris":
186      ["https://client.example.org/callback"],
187    "post_logout_redirect_uris":
188      ["https://client.example.org/logout/callback"],
189    "client_name": "A Private App",
190    "token_endpoint_auth_method": "client_secret_post",
191    "contacts": ["me@example.org", "them@example.org"],
192    "scope": "openid offline_access api:oemr api:fhir api:port user/allergy.read user/allergy.write user/appointment.read user/appointment.write user/dental_issue.read user/dental_issue.write user/document.read user/document.write user/drug.read user/encounter.read user/encounter.write user/facility.read user/facility.write user/immunization.read user/insurance.read user/insurance.write user/insurance_company.read user/insurance_company.write user/insurance_type.read user/list.read user/medical_problem.read user/medical_problem.write user/medication.read user/medication.write user/message.write user/patient.read user/patient.write user/practitioner.read user/practitioner.write user/prescription.read user/procedure.read user/soap_note.read user/soap_note.write user/surgery.read user/surgery.write user/vital.read user/vital.write user/AllergyIntolerance.read user/CareTeam.read user/Condition.read user/Coverage.read user/Encounter.read user/Immunization.read user/Location.read user/Medication.read user/MedicationRequest.read user/Observation.read user/Organization.read user/Organization.write user/Patient.read user/Patient.write user/Practitioner.read user/Practitioner.write user/PractitionerRole.read user/Procedure.read patient/encounter.read patient/patient.read patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Encounter.read patient/Immunization.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read"
193   }'
196 Response:
197 ```sh
199     "client_id": "LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA",
200     "client_secret": "j21ecvLmFi9HPc_Hv0t7Ptmf1pVcZQLtHjIdU7U9tkS9WAjFJwVMav0G8ogTJ62q4BATovC7BQ19Qagc4x9BBg",
201     "registration_access_token": "uiDSXx2GNSvYy5n8eW50aGrJz0HjaGpUdrGf07Agv_Q",
202     "registration_client_uri": "https:\/\/localhost:9300\/oauth2\/default\/client\/6eUVG0-qK2dYiwfYdECKIw",
203     "client_id_issued_at": 1604767861,
204     "client_secret_expires_at": 0,
205     "contacts": ["me@example.org", "them@example.org"],
206     "application_type": "private",
207     "client_name": "A Private App",
208     "redirect_uris": ["https:\/\/client.example.org\/callback"],
209     "token_endpoint_auth_method": "client_secret_post",
210     "scope": "openid offline_access api:oemr api:fhir api:port user/allergy.read user/allergy.write user/appointment.read user/appointment.write user/dental_issue.read user/dental_issue.write user/document.read user/document.write user/drug.read user/encounter.read user/encounter.write user/facility.read user/facility.write user/immunization.read user/insurance.read user/insurance.write user/insurance_company.read user/insurance_company.write user/insurance_type.read user/list.read user/medical_problem.read user/medical_problem.write user/medication.read user/medication.write user/message.write user/patient.read user/patient.write user/practitioner.read user/practitioner.write user/prescription.read user/procedure.read user/soap_note.read user/soap_note.write user/surgery.read user/surgery.write user/vital.read user/vital.write user/AllergyIntolerance.read user/CareTeam.read user/Condition.read user/Coverage.read user/Encounter.read user/Immunization.read user/Location.read user/Medication.read user/MedicationRequest.read user/Observation.read user/Organization.read user/Organization.write user/Patient.read user/Patient.write user/Practitioner.read user/Practitioner.write user/PractitionerRole.read user/Procedure.read patient/encounter.read patient/patient.read patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Encounter.read patient/Immunization.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read"
214 #### SMART on FHIR Registration
216 SMART Enabled Apps are supported.
218 SMART client can be registered at <website>/interface/smart/register-app.php. For example https://localhost:9300/interface/smart/register-app.php
220 After registering the SMART client, can then Enable it in OpenEMR at Administration->System->API Clients
222 After it is enabled, the SMART App will then be available to use in the Patient Summary screen (SMART Enabled Apps widget).
224 See this github issue for an example of a Smart App installation: https://github.com/openemr/openemr/issues/4148
226 ### Authorization Code Grant
228 This is the recommended standard mechanism to obtain access/refresh tokens. This is done by using an OAuth2 client with provider url of `oauth2/<site>`; an example full path would be `https://localhost:9300/oauth2/default`.
230 Note that a refresh token is only supplied if the `offline_access` scope is provided when requesting authorization grant.
232 ### Refresh Token Grant
234 Note that a refresh token is only supplied if the `offline_access` scope is provided when requesting authorization or password grant.
236 Example:
238 ```sh
239 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
240 -i 'https://localhost:9300/oauth2/default/token'
241 --data 'grant_type=refresh_token
242 &client_id=LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA
243 &refresh_token=def5020089a766d16...'
246 Response:
248 ```json
250   "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYn...",
251   "token_type": "Bearer",
252   "expires_in": 3599,
253   "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYnl1RkRp...",
254   "refresh_token": "def5020017b484b0add020bf3491a8a537fa04eda12..."
258 ### Password Grant
260 Recommend not using this mechanism unless you know what you are doing. It is considered far less secure than the standard authorization code method. Because of security implications, it is not turned on by default. It can be turned on at Administration->Globals->Connectors->'Enable OAuth2 Password Grant (Not considered secure)'.
262 Note that all scopes are included in these examples for demonstration purposes. For production purposes, should only include the necessary scopes.
264 Note that a refresh token is only supplied if the `offline_access` scope is provided when requesting password grant.
266 Example for `users` role:
267 ```sh
268 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
269 -i 'https://localhost:9300/oauth2/default/token'
270 --data 'grant_type=password
271 &client_id=LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA
272 &scope=openid%20offline_access%20api%3Aoemr%20api%3Afhir%20user%2Fallergy.read%20user%2Fallergy.write%20user%2Fappointment.read%20user%2Fappointment.write%20user%2Fdental_issue.read%20user%2Fdental_issue.write%20user%2Fdocument.read%20user%2Fdocument.write%20user%2Fdrug.read%20user%2Fencounter.read%20user%2Fencounter.write%20user%2Ffacility.read%20user%2Ffacility.write%20user%2Fimmunization.read%20user%2Finsurance.read%20user%2Finsurance.write%20user%2Finsurance_company.read%20user%2Finsurance_company.write%20user%2Finsurance_type.read%20user%2Flist.read%20user%2Fmedical_problem.read%20user%2Fmedical_problem.write%20user%2Fmedication.read%20user%2Fmedication.write%20user%2Fmessage.write%20user%2Fpatient.read%20user%2Fpatient.write%20user%2Fpractitioner.read%20user%2Fpractitioner.write%20user%2Fprescription.read%20user%2Fprocedure.read%20user%2Fsoap_note.read%20user%2Fsoap_note.write%20user%2Fsurgery.read%20user%2Fsurgery.write%20user%2Fvital.read%20user%2Fvital.write%20user%2FAllergyIntolerance.read%20user%2FCareTeam.read%20user%2FCondition.read%20user%2FCoverage.read%20user%2FEncounter.read%20user%2FImmunization.read%20user%2FLocation.read%20user%2FMedication.read%20user%2FMedicationRequest.read%20user%2FObservation.read%20user%2FOrganization.read%20user%2FOrganization.write%20user%2FPatient.read%20user%2FPatient.write%20user%2FPractitioner.read%20user%2FPractitioner.write%20user%2FPractitionerRole.read%20user%2FProcedure.read
273 &user_role=users
274 &username=admin
275 &password=pass'
278 Example for `patient` role:
279 ```sh
280 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
281 -i 'https://localhost:9300/oauth2/default/token'
282 --data 'grant_type=password
283 &client_id=LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA
284 &scope=openid%20offline_access%20api%3Aport%20api%3Afhir%20patient%2Fencounter.read%20patient%2Fpatient.read%20patient%2FAllergyIntolerance.read%20patient%2FCareTeam.read%20patient%2FCondition.read%20patient%2FEncounter.read%20patient%2FImmunization.read%20patient%2FMedicationRequest.read%20patient%2FObservation.read%20patient%2FPatient.read%20patient%2FProcedure.read
285 &user_role=patient
286 &username=Phil1
287 &password=phil
288 &email=heya@invalid.email.com'
291 Response:
293 ```json
295   "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYn...",
296   "token_type": "Bearer",
297   "expires_in": 3599,
298   "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYnl1RkRp...",
299   "refresh_token": "def5020017b484b0add020bf3491a8a537fa04eda12..."
303 ### Client Credentials Grant
305 This is an advanced grant that uses JSON Web Key Sets(JWKS) to authenticate and identify the client.  This credential grant is
306 required to be used for access to any **system/\*.$export** scopes.  API clients must register either web accessible JWKS URI that hosts
307 a RSA384 compatible key, or provide their JWKS as part of the registration. Client Credentials Grant access tokens are short
308 lived and valid for only 1 minute and no refresh token is issued.  Tokens are requested at `/oauth2/default/token`
309 To walk you through how to do this process you can follow [this guide created by HL7](https://hl7.org/fhir/uv/bulkdata/authorization/index.html).
311 ### Logout
313 A grant (both Authorization Code and Password grants) can be logged out (ie. removed) by url of `oauth2/<site>/logout?id_token_hint=<id_token>`; an example full path would be `https://localhost:9300/oauth2/default/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.
315 ### More Details
317 The forum thread that detailed development of Authorization and where questions and issues are addressed is here: https://community.open-emr.org/t/v6-authorization-and-api-changes-afoot/15450
319 More specific development api topics are discussed and described on the above forum thread (such as introspection).
321 ## Standard API Documentation
323 The Standard API is documented via Swagger. Can see this documentation (and can test it) by going to the `swagger` directory in your OpenEMR installation. The Standard API is documented there in the `standard` section. Can also see (and test) this in the online demos at https://www.open-emr.org/wiki/index.php/Development_Demo#Daily_Build_Development_Demos (clicking on the `API (Swagger) User Interface` link for the demo will take you there).
325 OpenEMR standard endpoints Use `https://localhost:9300/apis/default/api as base URI.`
327 Note that the `default` component can be changed to the name of the site when using OpenEMR's multisite feature.
329 _Example:_ `https://localhost:9300/apis/default/api/patient` returns a resource of all Patients.
331 The Bearer token is required for each OpenEMR 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](API_README.md#authorization) section.
333 Request:
335 ```sh
336 curl -X GET 'https://localhost:9300/apis/default/api/patient/1/medical_problem' \
337   -H 'Authorization: Bearer eyJ0b2tlbiI6IjAwNmZ4TWpsNWhsZmNPelZicXBEdEZVUlNPQUY5KzdzR1Jjejc4WGZyeGFjUjY2QlhaaEs4eThkU3cxbTd5VXFBeTVyeEZpck9mVzBQNWc5dUlidERLZ0trUElCME5wRDVtTVk5bE9WaE5DTHF5RnRnT0Q0OHVuaHRvbXZ6OTEyNmZGUmVPUllSYVJORGoyZTkzTDA5OWZSb0ZRVGViTUtWUFd4ZW5cL1piSzhIWFpJZUxsV3VNcUdjQXR5dmlLQXRXNDAiLCJzaXRlX2lkIjoiZGVmYXVsdCIsImFwaSI6Im9lbXIifQ=='
340 ## Patient Portal API Documentation
342 The Patient Portal API is documented via Swagger. Can see this documentation (and can test it) by going to the `swagger` directory in your OpenEMR 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://www.open-emr.org/wiki/index.php/Development_Demo#Daily_Build_Development_Demos (clicking on the `API (Swagger) User Interface` link for the demo will take you there).
344 This is under development and is considered EXPERIMENTAL.
346 Enable the Patient Portal API service (/portal/ endpoints) in OpenEMR menu: Administration->Globals->Connectors->"Enable OpenEMR Patient Portal REST API (EXPERIMENTAL)"
348 OpenEMR patient portal endpoints Use `https://localhost:9300/apis/default/portal as base URI.`
350 Note that the `default` component can be changed to the name of the site when using OpenEMR's multisite feature.
352 _Example:_ `https://localhost:9300/apis/default/portal/patient` returns a resource of the patient.
354 The Bearer token is required for each OpenEMR 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](API_README.md#authorization) section.
356 Request:
358 ```sh
359 curl -X GET 'https://localhost:9300/apis/default/portal/patient' \
360   -H 'Authorization: Bearer eyJ0b2tlbiI6IjAwNmZ4TWpsNWhsZmNPelZicXBEdEZVUlNPQUY5KzdzR1Jjejc4WGZyeGFjUjY2QlhaaEs4eThkU3cxbTd5VXFBeTVyeEZpck9mVzBQNWc5dUlidERLZ0trUElCME5wRDVtTVk5bE9WaE5DTHF5RnRnT0Q0OHVuaHRvbXZ6OTEyNmZGUmVPUllSYVJORGoyZTkzTDA5OWZSb0ZRVGViTUtWUFd4ZW5cL1piSzhIWFpJZUxsV3VNcUdjQXR5dmlLQXRXNDAiLCJzaXRlX2lkIjoiZGVmYXVsdCIsImFwaSI6Im9lbXIifQ=='
363 ## For Developers
365 -   For business logic, make or use the services [here](src/Services)
366 -   For controller logic, make or use the classes [here](src/RestControllers)
367 -   For routing declarations, use the class [here](_rest_routes.inc.php).
369 REST API endpoints are defined in the [primary routes file](_rest_routes.inc.php). The routes file maps an external, addressable
370 endpoint to the OpenEMR controller which handles the request, and also handles the JSON data conversions.
372 ```php
373 "POST /api/patient" => function () {
374     RestConfig::authorization_check("patients", "demo");
375     $data = (array) (json_decode(file_get_contents("php://input")));
376     $return = (new PatientRestController())->post($data);
377     RestConfig::apiLog($return, $data);
378     return $return;
382 At a high level, the request processing flow consists of the following steps:
385 JSON Request -> Controller Component -> Validation -> Service Component -> Database
388 The logical response flow begins with the database result:
391 Database Result -> Service Component -> Controller Component -> RequestControllerHelper -> JSON Response
394 The [RequestControllerHelper class](./src/RestControllers/RestControllerHelper.php) evaluates the Service Component's
395 result and maps it to a http response code and response payload. Existing APIs should be updated to utilize the
396 `handleProcessingResult` method as it supports the [Validator](./src/Validators/BaseValidator.php) components.
398 The [PatientRestController](./src/RestControllers/PatientRestController.php) may be used as a reference to see how APIs are
399 integrated with `RequestControllerHelper::handleProcessingResult` and the `Validator` components.
401 Finally, APIs which are integrated with the new `handleProcessingResult` method utilize a common response format.
403 ```json
405     "validationErrors": [],
406     "internalErrors": [],
407     "data": < data payload >
411 -   `validationErrors` contain "client based" data validation errors
412 -   `internalErrors` contain server related errors
413 -   `data` is the response payload, represented as an object/`{}` for single results or an array/`[]` for multiple results