On this page — 10 sections
EMR connections — API & bulk export, per vendor
This platform's EMR connectivity was designed specifically against each vendor's published documentation. Every seam the integration screens enforce — auth flows, bulk-export limits, write surfaces — was taken from the vendor's own developer documentation, and this page carries the inline references. Where a capability could not be verified on a vendor's public pages, that is stated as recorded uncertainty rather than assumed; the full research record lives in the repository's docs/EMR_CONNECTORS.md, which cites the same sources.
1. The standards baseline
All six connectors build on the same published standards, referenced throughout the vendor chapters below:
- HL7 FHIR R4 — the resource model every vendor's certified API exposes.
- SMART App Launch: Backend Services — the unattended system-to-system authorization profile, built on RFC 7523 (JWT client assertions).
- FHIR Bulk Data Access IG — the $export kickoff / status / NDJSON pattern the bulk import manager implements.
- US Core — the USCDI profile set the certified vendor surfaces target, required by the ONC certification criterion (§170.315(g)(10)) that obliges certified EMRs to offer standardized patient and population services.
2. Epic
Primary sources: open.epic.com/DeveloperResources and fhir.epic.com.
As a source — API
- Federated, not central: every Epic health system runs its own instance and its own FHIR base URL; production data never transits anything Epic operates. The connector's base URL is per-deployment configuration, and Epic issues separate non-production and production client IDs — the sandbox ID works only against fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4/.
- Registration: a Backend Services app at fhir.epic.com, with the public key hosted at a JWK Set URL — per Epic's JWK Set documentation, static key uploads have not been accepted for new sandbox registrations since August 2025. Each health system separately syncs the client ID to their instance and signs Epic's API subscription agreement before production.
- Auth (Epic OAuth 2.0 documentation): signed JWT client assertion — RS384, iss=sub=client ID, aud=token endpoint, unique jti, exp ≤ 5 minutes. No client secret exists in this flow, and the documented token request carries no scope parameter — Epic derives the grant from the app registration. The platform refuses a configured client secret on Epic deployments because it would be inert.
As a source — bulk export
Reference: fhir.epic.com — Bulk Data documentation (cited again in core/fhir/bulk_client.py's own docstring):
- Group-level export only. Epic's own words: "Epic supports only the Group Export operation. We do not support _since or other bulk data operations at this time." No system-level export, no incremental mode — every run is a full re-extract of the Group's scope, which is why the import manager treats every run as the whole population and why the watermark rule exists.
- The Group FHIR ID is not discoverable through any API — it is provisioned with the health system during registration, which is why it is a configuration field on Source & target EMRs.
- Rate-limited to once per 24 hours per group and client ID by default — the exact refusal the bulk import manager enforces before a kickoff ever reaches the vendor.
As a target — writes
- Two-step, signature-gated delivery: stage, human signs, commit — with AI-assisted provenance recorded on the written resource. "DocumentReference create" is several distinct Epic APIs with separate per-health-system enablement (per the fhir.epic.com API catalog), so the install enumerates each flavor individually.
- MedicationRequest is read/search only over FHIR REST — order-shaped writes exist only as CDS Hooks "unsigned order" suggestions inside Epic's own workflow. The signature queue's blocked metformin draft is this fact enforced, not styling.
3. Oracle Health (Cerner)
Primary sources — the Millennium Platform APIs documentation on docs.oracle.com (fhir.cerner.com now redirects there): the FHIR R4 API overview, the authorization framework, and the Bulk Data Access API.
As a source — API
- Registration: system apps through the Oracle Health developer console; the health system's tenant enables them. Registration issues a system account, and JWT auth takes a preregistered JWKS via System Account Management.
- Auth — two documented modes: OAuth2 client credentials with the secret in an RFC 2617 Basic header, or a signed JWT client assertion — which the authorization framework calls "the appropriate mode of authentication for Bulk Data Access". The platform uses the JWT mode because population ingestion wants $export.
- Every scope must be requested explicitly (system/Patient.read system/Observation.read …) — Oracle's documentation is explicit that wildcard scopes are unsupported. This is the sharpest contrast with Epic, whose backend token request takes no scope parameter at all; a missing scope fails at the resource, which is why the platform verifies conformance per-resource.
- Base URL is tenant-scoped: fhir-ehr.cerner.com/r4/{tenant-id}/… — one deployment's base URL can never reach another tenant's data.
As a source — bulk export
Documented in the Bulk Data Access API; requires the JWT auth mode; group-level availability is tenant configuration — confirmed per tenant before scheduling.
As a target — writes
Oracle publishes create endpoints for several types (Patient, Condition, DocumentReference POST operations are in the R4 docs). Conditional-create (If-None-Exist) support could not be re-verified on the current public pages — recorded as uncertainty, to be confirmed per tenant before designing re-runnable delivery around it.
4. athenahealth
Primary source: docs.athenahealth.com (FHIR R4 API).
- As a source — API: OAuth2 client credentials with a client secret — the one profiled vendor whose documented flow is a secret rather than a signed JWT, and the reason the platform's secret-based auth path exists at all (it is refused for every other vendor). Base URLs are practice-scoped; apps are enabled per practice through the athenahealth Marketplace.
- As a source — bulk export: supported through the documented FHIR APIs; confirm per practice. Rate limits are tighter than the other targets — plan extract windows accordingly.
- As a target — writes: through the combination of proprietary and FHIR APIs documented on docs.athenahealth.com; confirmed per practice before any delivery is scheduled.
5. eClinicalWorks
Primary source: the eClinicalWorks FHIR developer portal (Cures Act / g(10) APIs).
- As a source — API: SMART Backend Services with asymmetric private-key JWT — the portal's own words: "Backend Services uses Asymmetric (Private Key JWT) Authentication", public key registered as a JWKS. Same client-assertion flow as Epic; no client secret. Read APIs cover the USCDI v1–v3 surface; confirm against the practice's CapabilityStatement.
- As a source — bulk export: the portal documents backend (single-patient) and bulk (multiple-patient) FHIR APIs. Availability for a specific practice may still require contracting — confirmed before a migration is planned around $export. Vendor-documented ceiling of 250 calls per minute per base URL (FHIR, authorize and token endpoints, effective October 2025).
- As a target — writes: eCW documents FHIR Create/Update APIs (V12.0.2+: Patient, Encounter, MedicationRequest, Immunization, DocumentReference variants, Coverage, ServiceRequest) but as a contracted add-on arranged through interop@eclinicalworks.com — not a default capability. Until a contract says otherwise, the platform delivers as files for their own migration tooling.
6. MEDITECH
Primary sources: the Greenfield Workspace resources page and the API explorer at greenfield.meditech.com. Much of the technical detail sits behind the portal login, so this chapter is explicit about vendor-confirmed versus certification-baseline facts.
- As a source — API: registration through the Greenfield Workspace (no self-service public sandbox). Auth is recorded as SMART Backend Services as the ONC g(10) certification baseline — the public pages do not spell out the token request, and the platform's profile says so in its notes rather than pretending confirmation. Verified from the public explorer: operations live under …/v2/uscore/R4/, and the surface is US Core FHIR R4 for USCDI data — the narrowest published surface of the six, which is why the platform's profile is deliberately the narrowest to match.
- As a source — bulk export: verified as documented — "Bulk Data" is a topic in the Greenfield explorer, and MEDITECH appears in the SMART team's registry of bulk-data implementations.
- As a target — writes: Greenfield describes the patient-access APIs as view-only; no general FHIR create is publicly documented. The platform delivers as files unless the health system's MEDITECH contacts confirm a write path.
7. NextGen Healthcare
Primary sources: nextgen.com/api and the NextGen Enterprise regulatory page; the full developer guides sit behind developer.nextgen.com onboarding.
- Which product: this connector targets NextGen Enterprise (base URLs shaped fhir.nextgen.com/nge/prod/fhir-api-r4/…) — not NextGen Office, a separate small-practice product with a different API and auth model.
- As a source — API: registration through the developer portal, enabled per practice. Publicly documented auth is the Patient Access authorization-code flow; no system/backend flow is publicly documented — the profile records SMART Backend Services as the g(10) baseline expectation and flags it as requiring confirmation through the portal. Published resources are USCDI/US Core R4; the broader list must be confirmed against the practice's CapabilityStatement.
- As a source — bulk export: recorded as not available until proven otherwise. Nothing public documents an Enterprise-level $export. ONC g(10) obliges the certified stack to offer population services, so it likely exists behind the portal — but this platform records what is verifiable, and the bulk scheduler refuses to run against this profile until the flag is corrected with evidence from the gated docs or a real instance's CapabilityStatement. This is the refusal the export managers surface when NextGen is the target.
- As a target — writes: no bulk write surface; any write capability is confirmed per practice before relying on it.
8. SSO & authentication capabilities, system by system
Two different kinds of sign-on meet at this platform, and they must never be confused: system-to-system SSO — how the platform itself authenticates to an EMR to move records — and user-facing SSO — how a person signs into the platform (your organization's IdP, or a SMART launch from inside the EMR). This section covers both, per vendor.
| System | System-to-system auth | Credential artifact | Token lifetime | Scope model | User-facing SMART launch |
|---|---|---|---|---|---|
| Epic | SMART Backend Services — RS384-signed JWT client assertion | RSA private key; public half at your JWK Set URL — no secret exists | Access token ≤ 60 min (assertion exp ≤ 5 min, single-use jti) | system/*.read honored; write scopes enabled per-resource and per-flavor, per health system | Yes — EHR launch and standalone; the platform accepts Epic as a launch issuer on the allowlist |
| Oracle Health | SMART Backend Services — JWT assertion (documented path for bulk); client-credentials-with-secret also documented | RSA private key (JWT mode) or client secret (basic mode) | Short-lived bearer token | Explicit scopes only — every system/<Resource>.read requested by name; wildcards unsupported | Yes — SMART on FHIR launch supported |
| athenahealth | OAuth2 client credentials | Client ID + client secret — the one profiled vendor whose flow is a secret | Short-lived bearer token | Scoped per API registration | Yes — SMART launch per its g(10) surface |
| eClinicalWorks | SMART Backend Services — JWT assertion, same asymmetric model as Epic | RSA private key; no secret | Short-lived bearer token | System scopes per registration | Per g(10) certification surface |
| MEDITECH | SMART Backend Services (g(10) baseline; token request flagged for portal confirmation) | RSA private key | Short-lived bearer token | System scopes per registration | Per g(10) certification surface |
| NextGen | SMART Backend Services (g(10) baseline; backend flow flagged for portal confirmation) | RSA private key | Short-lived bearer token | System scopes per registration | Per g(10) certification surface |
| The platform itself (users) | Reverse-proxy SSO (your IdP: SAML/OIDC in front), SMART launch from the EMR, or local accounts as the fallback | Held by your IdP — the platform stores a credential only in local-accounts mode | Your IdP's session policy; platform sessions are signed cookies | Roles asserted by your identity source of truth; the platform enforces, it does not own them | — |
9. Two systems, two SSO configurations — source and target
Topology first — and the default is one system. By default the source system is the target system: the platform ingests from your EMR and signed documentation writes back to that same chart of legal record. This is fully configurable, in three shapes:
- One system (default): a single EMR serves both roles. Even here the platform keeps two registrations against the same system — a read/bulk registration for ingestion and a write-scoped registration for delivery — because directional least privilege does not stop mattering when the endpoints coincide.
- Split source and target: read from one system, deliver to another — the migration and exchange configuration the rest of this section details.
- Many to many: the platform supports multiple sources and multiple targets at once — a health system ingesting from several EMRs and delivering to several destinations. Every connection carries its own vendor profile, its own registration and keypair, and its own token lifecycle; nothing below is shared across connections. The demonstration shows a single source-target pair for clarity.
A deployment usually talks to two EMRs at once: the source it ingests from and the target it delivers to. These are managed as two fully independent SSO configurations — the Source & target EMRs screen holds a separate vendor, base URL and client ID for each side, and nothing is shared between them:
- Separate registrations, always. Source and target are distinct app registrations with distinct client IDs — even when both sides are the same vendor (an Epic-to-Epic migration is still two registrations). The two sides need different scopes, and a registration that can do both jobs is a violation of least privilege waiting for a leaked key.
- Separate keypairs, separate rotation. Each registration gets its own RSA keypair and its own JWK Set URL. Rotating the source key cannot interrupt deliveries; rotating the target key cannot stall ingestion. A private key is never reused across registrations, environments, or vendors.
- Directional least privilege. The source registration requests read and bulk-export scopes only; the target registration requests exactly the enumerated write scopes the delivery needs (per-resource and per-flavor on Epic) and nothing else. Neither credential can do the other side's job, so a compromise of one is contained by construction.
- Separate token lifecycles. Tokens are acquired, cached and expired per system. A source token is never presented to the target, and the assertion's aud claim binds each token request to its own system's token endpoint — a captured assertion cannot be replayed against the other side.
- Failure isolation. A target-side auth outage holds deliveries (accumulating, accounted) without touching ingestion; a source-side outage fails runs visibly while deliveries continue. Refusals and failures name which system's authentication was involved.
- Mixed vendors are the normal case. Ingesting from Epic while delivering to Oracle Health means RS384 assertions on one side and explicit per-resource scopes on the other; the vendor profiles apply each system's rules independently, so each side honors its own vendor's seams.
- User SSO is a third, separate plane. The IdP that signs your people in shares nothing with either system registration: system-to-system credentials can never mint a human session, and a human session can never authorize a system-to-system call. Three planes, three credential stores, no crossings.
10. How the platform enforces what the documentation says
- Vendor profiles encode each documented seam — auth flow, scope behavior, bulk capability, write surface — and the schedulers, export managers and auth code select behavior from the profile, never from optimism.
- The conformance probe checks a live instance's CapabilityStatement against the profile before first ingest, because a tenant's actual surface can be narrower than the vendor's documentation.
- Refusals carry the vendor's seam: a second Epic bulk kickoff inside 24 hours, an Oracle request missing an explicit scope, a bulk export aimed at NextGen — each refuses with the documented limit named, and the refusal is recorded.
- Uncertainty is recorded as uncertainty. Where a vendor's public pages do not confirm a capability (MEDITECH's token request, NextGen's backend flow, Oracle's conditional create), the profile says so — and the platform behaves conservatively until a real instance or gated documentation proves otherwise.
Vendor documentation moves. When this page and a vendor's current published documentation disagree, the vendor's page wins — file the discrepancy against docs/EMR_CONNECTORS.md, which records the review dates behind every claim above. Companions: API details for the token flows as implemented, and Setup & deployment for the registration steps in sequence.