> For the complete documentation index, see [llms.txt](https://docs.appmixer.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appmixer.com/connector-configuration/epic.md).

# Epic (on FHIR)

### 1. Create an Epic on FHIR account

Sign up at <https://fhir.epic.com> and log in to the developer portal.

### 2. Register an app

Go to **Build Apps** → **Create** and fill in:

* **Application Name**: anything you want.
* **Application Audience**: `Clinicians or Administrative Users` (the connector uses `user/*.read` SMART scopes).
* **SMART on FHIR Version**: `R4`.
* **Redirect URI**: depends on your environment, usually in the following format: `https://api.qa.appmixer.com/auth/epic/callback`

### 3. Select Incoming APIs

This is the most important step. Epic authorizes each FHIR interaction separately — for every resource there is a `.Read` **and** a `.Search` API, often split further by use-case category. If a `.Search` API is missing, the corresponding connector component fails with `403 insufficient_scope` even though authentication succeeds.

Select **all `(R4)` variants** (ignore DSTU2 and STU3) of both `.Read` and `.Search` for the resources below. The table shows which connector component depends on which API:

| Connector component                                                      | Required Incoming APIs (R4)                                                                                                                          |
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| GetAppointment, NewAppointment, UpdatedAppointment, CancelledAppointment | `Appointment.Read`, `Appointment.Search` — select all R4 variants                                                                                    |
| FindPatients, GetPatient                                                 | `Patient.Read`, `Patient.Search`                                                                                                                     |
| FindConditions                                                           | `Condition.Read (Problems)`, `Condition.Search (Problems)` — select all other `Condition.*` R4 variants too (Encounter Diagnosis, Health Concern, …) |
| FindVitalSigns                                                           | `Observation.Read (Vitals)`, `Observation.Search (Vitals)`                                                                                           |
| FindLabResults                                                           | `Observation.Read (Labs)`, `Observation.Search (Labs)`                                                                                               |
| FindSmokingHistory                                                       | `Observation.Read (Social History)`, `Observation.Search (Social History)` (a.k.a. Smoking History)                                                  |
| GetMedication                                                            | `Medication.Read`                                                                                                                                    |
| FindMedicationRequests, GetMedicationRequest                             | `MedicationRequest.Read (Orders)`, `MedicationRequest.Search (Orders)` — select all `MedicationRequest.*` R4 variants                                |
| FindProcedures, GetProcedure                                             | `Procedure.Read`, `Procedure.Search` — select all R4 variants (Surgeries, Orders, …)                                                                 |
| FindCarePlans                                                            | `CarePlan.Read (Longitudinal)`, `CarePlan.Search (Longitudinal)`                                                                                     |
| FindGoals                                                                | `Goal.Read (Patient)`, `Goal.Search (Patient)`                                                                                                       |
| FindImmunizations                                                        | `Immunization.Read`, `Immunization.Search`                                                                                                           |
| FindDiagnosticReports, GetDiagnosticReport                               | `DiagnosticReport.Read (Results)`, `DiagnosticReport.Search (Results)`                                                                               |
| FindDocumentReferences                                                   | `DocumentReference.Read (Clinical Notes)`, `DocumentReference.Search (Clinical Notes)`                                                               |
| FindDevices                                                              | `Device.Read (Implants)`, `Device.Search (Implants)`                                                                                                 |
| MakeApiCall                                                              | whatever APIs the called endpoint requires — the component sends arbitrary authorized FHIR requests                                                  |

The exact labels can differ slightly between Epic portal versions — when in doubt, select every `(R4)` variant of the resource.

#### Alphabetical checklist

The Epic UI lists available APIs alphabetically. Work through this list top to bottom (all items are the `(R4)` variants):

```
Appointment.Read (Appointments) (R4)
Appointment.Read (Prior Auth) (R4)
Appointment.Search (Appointments) (R4)
Appointment.Search (Prior Auth) (R4)
CarePlan.Read (Longitudinal) (R4)
CarePlan.Search (Longitudinal) (R4)
Condition.Read (Problems) (R4)
Condition.Search (Problems) (R4)
Device.Read (Implants) (R4)
Device.Search (Implants) (R4)
DiagnosticReport.Read (Results) (R4)
DiagnosticReport.Search (Results) (R4)
DocumentReference.Read (Clinical Notes) (R4)
DocumentReference.Search (Clinical Notes) (R4)
Goal.Read (Patient) (R4)
Goal.Search (Patient) (R4)
Immunization.Read (R4)
Immunization.Search (R4)
Medication.Read (R4)
MedicationRequest.Read (Orders) (R4)
MedicationRequest.Search (Orders) (R4)
Observation.Read (Labs) (R4)
Observation.Read (Social History) (R4)
Observation.Read (Vitals) (R4)
Observation.Search (Labs) (R4)
Observation.Search (Social History) (R4)
Observation.Search (Vitals) (R4)
Patient.Read (R4)
Patient.Search (R4)
Procedure.Read (Orders) (R4)
Procedure.Read (Surgeries) (R4)
Procedure.Search (Orders) (R4)
Procedure.Search (Surgeries) (R4)
```

If a label from the list does not exist exactly (e.g. `Observation.Search (Smoking History) (R4)` instead of `Social History`), pick the closest `(R4)` variant of the same resource and interaction.

{% hint style="info" %}
The connector requests these SMART on FHIR scopes during authentication: `openid`, `fhirUser` and `user/<Resource>.read` for Patient, Condition, Observation, Medication, MedicationRequest, Procedure, CarePlan, Goal, Immunization, DiagnosticReport, DocumentReference, Device and Appointment. The `.read` scope covers both the read and search interaction — whether a search call is actually allowed is controlled purely by the Incoming APIs selected above, not by the scope string. No connector configuration change is needed when you add more APIs to the app.
{% endhint %}

### 4. Client ID and client secret

After saving the app, Epic shows a **Non-Production Client ID** and a **Production Client ID**. Use the non-production ID against the Epic sandbox (`https://fhir.epic.com/interconnect-fhir-oauth`).

{% hint style="warning" %}
Changes on fhir.epic.com — creating an app, generating a client secret, adding Incoming APIs — are **not effective immediately**. Propagation to the sandbox typically takes tens of minutes and can take up to 12 hours. Until then the token endpoint returns `invalid_client` (unknown app / secret) or searches return `403 insufficient_scope` (missing APIs).

Additionally, Epic freezes the granted permissions at authorization time. After adding Incoming APIs to an existing app, **users must re-authenticate** — refreshing the access token is not enough, existing tokens (including refreshed ones) keep returning `403 insufficient_scope`.
{% endhint %}

If you generate a client secret, Epic requires HTTP Basic authentication at the token endpoint (the connector handles this automatically). Without a secret the app acts as a public client — this works in the sandbox, but Epic may not issue a refresh token, so users must re-authenticate when the access token expires (1 hour).

#### Set `clientId` and `clientSecret` into Appmixer Backoffice

The last step is to configure the client ID and client secret in the Appmixer Backoffice for `appmixer:epic`.

### Going to production

The public sandbox (`fhir.epic.com`) is only for development. Real patient data lives in the Epic instances of individual healthcare organisations — there is no central production API. Going live means:

1. **Mark the app "Ready for Production"** on fhir.epic.com. This activates the **Production Client ID** (so far you have been using the non-production one).
2. **Get activated by each healthcare organisation.** For apps with the `Clinicians or Administrative Users` audience (this connector — `user/*.read` scopes) the gatekeeper is the Epic customer, not Epic itself. Each organisation typically requires a business agreement and a **HIPAA Business Associate Agreement (BAA)**, runs its own security & privacy review, and then activates your Production Client ID in their Epic environment, including the list of allowed APIs (their counterpart of your Incoming APIs selection). Epic's paid **Vendor Services** program (successor of App Orchard) and the Connection Hub/Showroom listing make this process smoother when distributing to multiple customers, but do not replace per-organisation activation.
3. **Point the connector at the organisation's endpoints.** Every Epic customer hosts its own FHIR and OAuth endpoints (see the public endpoint directory on [open.epic.com](https://open.epic.com)). Configure in the Appmixer Backoffice for `appmixer:epic`:
   * `clientId` / `clientSecret` — the Production Client ID (and secret, if issued).
   * `epicFhirBaseUrl` — the organisation's FHIR R4 base URL, e.g. `https://ehr.hospital.org/interconnect-prd/api/FHIR/R4`.
   * `epicOauthBaseUrl` — optional. When omitted, the connector derives it from `epicFhirBaseUrl` using Epic's standard interconnect layout (`…/api/FHIR/R4` → `…/oauth2`). Set it explicitly only when the organisation uses a non-standard layout.
4. **Users authenticate with their clinical (EHR) credentials** of that organisation. What they can see in patient charts is governed by their Epic user role and the APIs the organisation enabled — the connector never grants more access than the organisation allows. Existing accounts must re-authenticate after any endpoint or app change.
5. **Compliance.** Once real PHI flows through Appmixer, the deployment itself must satisfy HIPAA requirements (BAA between you and the customer, encryption, audit logging, data retention). Plan this on the deployment side; no connector change is involved.

A practical rollout path: pilot with one partner organisation against their **non-production environment** first (every Epic customer has TST/POC instances — an intermediate step between the public sandbox and production), then request production activation.

### Sandbox test logins

Epic provides test users for the sandbox, e.g. provider login `FHIR` / `EpicFhir11!`. Test patient: Camila Lopez (`erXuFYUfucBZaryVksYEcMg3`). See <https://fhir.epic.com/Documentation?docId=testpatients> for the full list.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.appmixer.com/connector-configuration/epic.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
