- FHIR
- API Specifications
- Build Apps
- Documentation
- App Developer Guidelines
- App Creation & Request Process Overview
- App Creation & Request Process Step-by-Step
- User Context
- Requesting a Listing in Showroom
- Designing an Efficient Application
- OAuth 2.0 Specification
- FHIR Tutorial
- App Default FHIR Version
- ID Types for FHIR APIs
- Sandbox Test Data
- Patient-Facing Apps Using FHIR
- Search Parameters
- FHIR Bulk Data Access Tutorial
- CDS Hooks Tutorial
- Troubleshooting
- Sex, Gender, & Names
- Vaccine Credentials
- Jump To
- Showroom
- open.epic
- Login
Log in with
or
Trusting CDS Clients
JWT Tokens
To enable your CDS service to authenticate the identity of the CDS client, CDS hooks use digitally signed JSON web tokens (JWTs). Each time a client transmits a request to your service which requires authentication, the request must include an authorization header presenting the JWT as a “Bearer” token, which contains the following fields:
Field | Description |
alg | The cryptographic string used to sign this JWT. The default is RSA SHA-384. |
jku | The URL to the JWK Set containing the public key(s). |
kid | The identifier of the key-pair used to sign this JWT. |
typ | Fixed value: "JWT". |
aud | Your CDS service’s endpoint. This must be manually configured by the health system. |
exp | The expiration timer for the authentication JWT. |
iat | The issue time of the JWT. |
iss | The URI of the JWT issuer, the FHIR endpoint of the organization. This must be manually configured. |
jti | A string value that uniquely identifies the JWT. |
nbf | Typically set to 5 minutes prior to the issue time of the JWT. |
sub | CDS hooks client ID. This must be manually configured. |
Header{ "alg": "RS384", "jku": "{{Base URL}}/api/epic/2019/Security/Open/PublicKeys/530013/530013", "kid": "d3bmo5HzW61TUgikHZH+A8Tx4UOXz2iOs4KvVU4eLY0=", "typ": "JWT"}Payload{ "aud": "https://example.com/savecdshooksrequest", "exp": 1708124873, "iat": 1708123973, "iss": "{{Base URL}}/api/FHIR/R4", "jti": "a42df6b7-2074-479a-b216-50eee1b09fb6", "nbf": 1708123673, "sub": "12345678-ce08-4ac7-ac0c-12345678"}
Install Considerations for the JWT Token
JWT authentication is configured in an External Endpoint Configuration record. The aud, iss, and sub claims are manually specified. These can be changed if your service requires a particular value.
- alg – This is typically RSA SHA-384
- aud – This is typically your CDS service’s endpoint
- iss – This is the FHIR server’s base url of the CDS Client
- sub – This is typically your CDS service’s client ID
To obtain the jku (JSON Web Key Set URL) from the installing organization, decode the JWT you receive in the “Authorization: Bearer” header, parse the jku claim from the JWT header, and verify the jku exists on your trusted allowlist of jku’s.
Make sure to not confuse the JWT you receive in the "Authorization: Bearer" header with the access token JWT you receive in the CDS Hooks request body. These two JWTs serve distinct purposes.
Feedback
When configuring your CDS Hooks service during implementation, you can choose to receive feedback immediately or to receive it in a batch. If you use the batch format, the interval at which you receive feedback is defined through configuration at the implementing organization. By default, feedback is sent to your CDS Hooks service endpoint with “/feedback” appended.
A UUID must be sent in the CDS Hooks service response to uniquely identify cards or suggestions. If a UUID is not sent for these fields, the CDS Hooks client does not trigger feedback because the feedback can't be associated with a particular card or suggestion the CDS Hooks service provided.
Acknowledgement reasons can be configured within Epic or sent from your CDS service. Each option has varying Epic configuration steps and a different feedback message. For acknowledgement reasons built in Epic, the health system will need to add the reasons to the CDS build and the details will be sent in the extension component of the feedback message. If you are dynamically sending acknowledgement reasons, build needs to be completed by the health system to map the value being sent to an Epic record. In this case, the feedback message will utilize the reason field. The two Overridden Cards below show examples of the reason component and the extension field being used.
Feedback Message Demonstrating Overridden Card with Reason
{"feedback": [{ "card": "123456", "outcome": "overridden", "outcomeTimestamp": "2022-05-19T19:44:04Z", "overrideReasons": { "reason": { "code": "contraindicated", "display": "bad", "system": "http: //example.org/cds-services/fhir/CodeSystem/override-reasons" }, "userComment": "User Entered Free Text"}}]}
Feedback Message Demonstrating Overridden Card with Extension
{"feedback": [{ "card": "123456", "outcome": "overridden", "outcomeTimestamp": "2022-05-19T19:44:04Z", "overrideReasons": { "extension": { "com.epic.cdshooks.feedback.overrideReason.reasonCategory": "45", "com.epic.cdshooks.feedback.overrideReason.reasonDisplay": "Does not meet criteria", "com.epic.cdshooks.feedback.overrideReason.reasonTitle": "Does not meet criteria" }, "userComment": "User Entered Free Text"}}]}
Feedback Message Demonstrating Accepted Suggestion
{"feedback": [{ "acceptedSuggestions": [{ "id": "replaceWithGUID" } ], "card": "123456", "outcome": "accepted", "outcomeTimestamp": "2022-05-19T19:48:34Z"}]}
Medication References
Beginning in the February 2024 version of Epic, medications referenced from MedicationRequest resources in the draftOrders context as part of the order-select and order-sign hooks will be included as a contained resource within the draftOrders context. This eliminates the need for additional roundtrips to the server to obtain medication codes.
Example Medication Reference
"context": { "patientId": "eXoGxqgBaJuNkuahMYmiDhg3", "encounterId": "eAJ9U5Zv9Vzeg4lBWxmAQcItP6nlidE0QacJVtVudEQ43", "userId": "PractitionerRole/e-QokEGUJIzyynNdkCFrs9w3", "draftOrders": { "resourceType": "Bundle", "type": "collection", "entry": [ { "resource": { "resourceType": "MedicationRequest", "id": "ez067mnwOAKP5z1.YJwRAsd9gCwdOzQ8wSrsM04QFoz882hxQZKBulF4smVj2SxHWfesiTZ1qsgBez8Rdeb2GpbWYuU.L0KkOqiZSgl2GBPFYUucdOKx53adK51FHbIL.9fyjChlCongwxq0kmbsAb63ITW14qpRUnm2l2PXADxvuolXYdkN80RBgyQwLK2O33", "status": "draft", "intent": "order", "category": [ { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/medicationrequest-category", "code": "inpatient", "display": "Inpatient" } ], "text": "Inpatient" } ], "priority": "routine", "medicationReference": { "reference": "Medication/eVBXvKwrWZIkPmaGwY.s1hQ3", "display": "DEXTROMETHORPHAN HBR 15 MG/5ML PO SYRP" }, "subject": { "reference": "Patient/eXoGxqgBaJuNkuahMYmiDhg3", "display": "Patient, Test" } } }, { "resource": { "resourceType": "MedicationRequest", "id": "ez067mnwOAKP5z1.YJwRAsfY.5YNxZJJDzDQrJbuKBDbIp.vKaSouyn36H4Tc6-z2y9h2OU5FqxVeqUHFJRpGe4BxmHoRsVJB9GLVkHUmLPX-LyD02h3sLRMgK9uFNRU73KWgj0Tmeqi8Y.vVgy-6vka7hpwQHl1zLGD2OaLJ9rJfzfKH89zl25piLYkeGQMz3", "status": "draft", "intent": "order", "category": [ { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/medicationrequest-category", "code": "inpatient", "display": "Inpatient" } ], "text": "Inpatient" } ], "priority": "routine", "medicationReference": { "reference": "Medication/emvpHliA4OaUxXJ4wp6N.Ig3", "display": "MERCAPTOPURINE 50 MG PO TABS" }, "subject": { "reference": "Patient/eXoGxqgBaJuNkuahMYmiDhg3", "display": "Patient, Test" } } }, { "resource": { "resourceType": "Medication", "id": "eVBXvKwrWZIkPmaGwY.s1hQ3", "identifier": [ { "use": "usual", "system": "urn:oid:1.2.840.114350.1.13.861.1.7.2.698288", "value": "2356" } ], "code": { "coding": [ { "system": "urn:oid:2.16.840.1.113883.6.253", "code": "6379" }, { "system": "urn:oid:2.16.840.1.113883.6.68", "code": "43102030501215" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "3289" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "102490" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "1090496" }, { "system": "urn:oid:2.16.840.1.113883.6.162", "code": "01592" } ], "text": "dextromethorphan syrup 15 mg/5mL" }, "form": { "coding": [ { "system": "urn:oid:1.2.840.114350.1.13.861.1.7.4.698288.310", "code": "SYRP", "display": "Syrup" } ], "text": "Syrup" }, "ingredient": [ { "itemCodeableConcept": { "coding": [ { "system": "urn:oid:2.16.840.1.113883.6.253", "code": "6379" }, { "system": "urn:oid:2.16.840.1.113883.6.68", "code": "43102030501215" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "3289" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "102490" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "1090496" }, { "system": "urn:oid:2.16.840.1.113883.6.162", "code": "01592" } ], "text": "dextromethorphan syrup 15 mg/5mL" }, "strength": { "numerator": { "value": 15, "unit": "MG/5ML" }, "denominator": { "value": 15, "unit": "MG/5ML" } } } ] } }, { "resource": { "resourceType": "Medication", "id": "emvpHliA4OaUxXJ4wp6N.Ig3", "identifier": [ { "use": "usual", "system": "urn:oid:1.2.840.114350.1.13.861.1.7.2.698288", "value": "10531" } ], "code": { "coding": [ { "system": "urn:oid:2.16.840.1.113883.6.253", "code": "28533" }, { "system": "urn:oid:2.16.840.1.113883.6.68", "code": "21300040000305" }, { "system": "urn:oid:2.16.840.1.113883.6.162", "code": "00597" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "103" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "197931" } ], "text": "mercaptopurine (PURINETHOL) tablet 50 mg" }, "form": { "coding": [ { "system": "urn:oid:1.2.840.114350.1.13.861.1.7.4.698288.310", "code": "TABS", "display": "Tablet" } ], "text": "Tablet" }, "ingredient": [ { "itemCodeableConcept": { "coding": [ { "system": "urn:oid:2.16.840.1.113883.6.253", "code": "28533" }, { "system": "urn:oid:2.16.840.1.113883.6.68", "code": "21300040000305" }, { "system": "urn:oid:2.16.840.1.113883.6.162", "code": "00597" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "103" }, { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "code": "197931" } ], "text": "mercaptopurine (PURINETHOL) tablet 50 mg" }, "strength": { "numerator": { "value": 50, "unit": "MG", "system": "http://unitsofmeasure.org", "code": "mg" }, "denominator": { "value": 50, "unit": "MG", "system": "http://unitsofmeasure.org", "code": "mg" } } } ] } } ] } }
Implementing CDS Hooks with an Epic Organization
When implementing your CDS service with an Epic organization, they will need certain pieces of information to complete their setup:
- Your CDS Hooks Client ID
- When registering your app, the website creates an app record in the Epic database and assigns your app production and non-production client IDs.
- The steps to register and receive your client IDs can be found in the App Request Process.
- Your CDS service’s endpoint
- Your service’s prefetch configuration, if applicable
- Expectations for JWT claims – aud, iss, and sub
- What workflow steps you expect to fire the hook
- During implementation, the organization’s analysts will configure this to trigger during appropriate workflows and will determine where in workflows the service should be invoked.
There are also pieces of information that you will need to receive from the organization:
- The FHIR iss of the client
- The jku (JSON Web Key Set URL)
For more information, refer to our Implementing a CDS Hooks App document.
Gotchas
Event Notification Streaming
CDS Hooks should be used only to trigger real-time, clinician-facing decision support. If your service never returns clinician-facing content, you should not use CDS Hooks.
If your use case requires notifications when an event occurs, you should use an event-based interface. For more information, refer to our interfaces document. If your use case requires context synchronization, you should use FHIRcast.
FHIR Version
When you register your CDS service with Epic’s authorization server infrastructure, the default FHIR version that you specify determines the FHIR version of resources in the CDS Hooks request, such as those in context or prefetch, as well as the specific fhirServer URL sent in the prefetch.
Required OAuth 2.0 Scopes
- Context.draftOrders is only sent to a CDS service that’s authorized for the OAuth 2.0 scopes corresponding to the CDS Hooks-specific FHIR order resource (for example, MedicationRequest (Unsigned Order)).
- Similarly, a CDS service must be authorized for scopes corresponding to any resources requested as part of prefetch.
Pre-Registration of Links and SMART Apps
As a security mechanism, SMART app link URLs returned within CDS Hooks cards must be pre-registered with the CDS client. SMART app URLs not pre-registered won't appear to the user.
We use cookies to improve our website.By accepting, you will receive these cookies from Epic on FHIR.Decline if you wish to use Epic on FHIR without these cookies.Read our privacy policy here.
Frequently Asked Questions (FAQs)
Contact
Terms of Use
Privacy Policy
1979 Milky Way, Verona, WI 53593
© 1979-2024 Epic Systems Corporation. All rights reserved.Protected by U.S. patents. For details visit www.epic.com/patents.
HL7®, FHIR® and the FLAME mark are the registered trademarks of HL7 and are used with the permission of HL7. The use of these trademarks does not constitute a product endorsement by HL7.
Epic, open.epic, and Epic on FHIR are trademarks or registered trademarks of Epic Systems Corporation.
Due to inactivity you will be logged out in 60 seconds.