Healthcare/Epic and Oracle Health
Vendor guide

Connecting to Epic and Oracle Health FHIR APIs from Python

The two EHR vendors covering most US hospitals expose FHIR R4 APIs behind SMART on FHIR authorization. What versions they support, how the auth flows work and the Python code to call them.

R4FHIR version both support
No R5on either platform
OAuth 2.0authorization
epic_read_patient.py
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class EpicReadPatient(Service):
    name = 'demo.ehr.epic-read-patient'

    def handle(self) -> 'None':

        # OAuth against Epic is configured on the
        # connection, tokens are managed for you
        client = self.fhir['FHIR.Epic']

        patient = client.get('Patient', 'eVgg3Buc6VmvyHU')

        family_name = patient.get_by_path('name.0.family')
        self.logger.info('Patient: %s', family_name)

Which FHIR version do Epic and Oracle Health support?

Both expose FHIR R4 production endpoints and neither supports R5 - a position mirrored across the major EHR vendors, as the FHIR versions page explains. Oracle Health (Cerner) deprecated its DSTU2 endpoints in December 2025, so R4 is the only version with continued support on these platforms.

Build on R4 and keep version assumptions out of the code - the connection definition holds the endpoint, the services hold the logic.

How does SMART on FHIR authorization work?

SMART on FHIR is OAuth 2.0 with healthcare conventions, and two flows matter. SMART App Launch is the user-facing flow - authorization code with PKCE - for apps that a clinician or patient launches, with the user's session defining what the app may see.

SMART Backend Services is the server-to-server flow - client credentials with a signed JWT assertion - for integration platforms that run without a user, which is the flow an integration layer uses. Your system is registered with the EHR, holds a key pair, and exchanges signed assertions for short-lived access tokens scoped to system-level resources.

FlowWho it is forGrant type
SMART App LaunchUser-facing apps launched from the EHR or a portalAuthorization code with PKCE
SMART Backend ServicesServer-to-server integrations without a userClient credentials with signed JWT

How do I authenticate to Epic from Python?

Register your application - Epic's vendor programs and Oracle's developer console both issue client credentials for production access. Then define an outgoing FHIR connection with an OAuth security definition - Zato obtains and refreshes the tokens, and the services only ever refer to the connection by name.

ehr_observations.py
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class ReadVitals(Service):
    name = 'demo.ehr.read-vitals'

    def handle(self) -> 'None':

        # The connection points at the EHR's R4 endpoint,
        # the OAuth definition is attached to it in the Dashboard
        client = self.fhir['FHIR.Epic']

        # Vital signs for one patient, most recent first
        observations = client.resources('Observation').search(
            patient = 'eVgg3Buc6VmvyHU',
            category = 'vital-signs',
        ).sort('-date').limit(20)

        for observation in observations.fetch():
            code_text = observation.get_by_path('code.text')
            value = observation.get_by_path('valueQuantity.value')
            self.logger.info('%s: %s', code_text, value)

The same service works against Oracle Health - only the connection name changes, e.g. self.fhir['FHIR.OracleHealth'], with that connection pointing at the Oracle R4 endpoint and with its own OAuth definition.

How do I read the CapabilityStatement first?

Every FHIR server describes itself at the metadata path - which resources it serves, which search parameters it supports, which auth endpoints to use. Reading it is the first request worth making against a new EHR endpoint, and path access pulls the details out of the deeply nested answer.

capability_statement.py
# The CapabilityStatement describes the server
capability = client.execute(path='metadata', method='get')

# The FHIR version the server declares
fhir_version = capability['fhirVersion']

# The OAuth endpoints, from the SMART security extension
rest = capability.get_by_path(['rest', 0])

self.logger.info('Server is on FHIR %s', fhir_version)

What does Zato do here and what does it not?

Zato is the FHIR client - it authenticates, reads and writes against the EHR's endpoints and integrates the results with everything else in your landscape. Registering the application is done in Epic's and Oracle's own programs (Epic's vendor services and open.epic, Oracle's Ignite APIs), and Zato does not host a FHIR server of its own - the EHR is the server.

Frequently asked questions

Backend integrations use system scopes - e.g. system/Patient.read or, in SMART 2.0 notation, system/Patient.rs - listing each resource type the integration touches. The EHR's app registration controls which scopes are grantable.

Yes - both vendors run public R4 sandboxes with test patients, and services written against a sandbox connection move to production by changing the connection definition, not the code.

Neither vendor exposes R5 endpoints - US regulation and US Core profiles standardize on R4, and the US Core roadmap moves from R4 directly to a planned R6 without adopting R5, so R4 is what production integrations target.

Both are R4, so the resource shapes match - differences concentrate in identifiers, extensions and supported search parameters. Keep those in configuration and per-connection lookups, and use path access with matchers instead of positional indexing.

Ready to connect to your EHR?

Get started with Zato and read your first Patient resource from Epic or Oracle Health in minutes.

Open source In Python