Every AI agent in healthcare needs to connect to EHR systems. But "connect to the EHR" actually means three distinct capabilities, each served by a different protocol. Understanding when to use FHIR APIs, CDS Hooks, or SMART on FHIR launch — and how they work together — is the foundation of any healthcare AI integration.

The Three Protocols: When to Use Which
Think of it this way: FHIR is the data access layer (read/write clinical data), CDS Hooks is the workflow trigger layer (react to clinical events), and SMART on FHIR is the app launch layer (embed your agent's UI inside the EHR).
FHIR R4 APIs: The Data Backbone
FHIR (Fast Healthcare Interoperability Resources) is the RESTful API standard for health data exchange. Under the 21st Century Cures Act, every certified EHR in the US must expose FHIR R4 APIs. This gives AI agents standardized access to:
- Patient demographics —
GET /fhir/Patient/12345 - Lab results & vitals —
GET /fhir/Observation?patient=12345&category=vital-signs - Diagnoses —
GET /fhir/Condition?patient=12345&clinical-status=active - Medications —
GET /fhir/MedicationRequest?patient=12345&status=active - Clinical notes —
GET /fhir/DocumentReference?patient=12345&type=clinical-note
# Python: FHIR client for AI agent data access
import requests
class FHIRClient:
def __init__(self, base_url: str, access_token: str):
self.base_url = base_url.rstrip("/")
self.headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/fhir+json"
}
def get_patient_context(self, patient_id: str) -> dict:
"""Fetch comprehensive patient context for AI agent processing."""
return {
"patient": self._get(f"Patient/{patient_id}"),
"conditions": self._search("Condition", {"patient": patient_id, "clinical-status": "active"}),
"medications": self._search("MedicationRequest", {"patient": patient_id, "status": "active"}),
"recent_vitals": self._search("Observation", {
"patient": patient_id, "category": "vital-signs",
"date": "ge" + get_date_days_ago(7), "_sort": "-date", "_count": "50"
}),
"recent_labs": self._search("Observation", {
"patient": patient_id, "category": "laboratory",
"date": "ge" + get_date_days_ago(30), "_sort": "-date", "_count": "100"
}),
"allergies": self._search("AllergyIntolerance", {"patient": patient_id}),
}
def _search(self, resource_type: str, params: dict) -> list:
resp = requests.get(f"{self.base_url}/{resource_type}", params=params, headers=self.headers)
bundle = resp.json()
return [entry["resource"] for entry in bundle.get("entry", [])]CDS Hooks: Workflow Triggers
FHIR gives you data access, but it doesn't tell you when to act. CDS Hooks solves this — it's an event-driven protocol that fires at clinical decision points in the EHR workflow:

patient-view— Clinician opens a patient chart (use for: risk scores, care gap alerts)order-sign— Clinician is about to sign an order (use for: drug interaction warnings, duplicate order alerts)order-select— Clinician selects an order (use for: formulary alternatives, cost information)medication-prescribe— Medication is being prescribed (use for: dosage suggestions, safety guardrails)encounter-start/encounter-discharge— Visit begins or ends (use for: screening reminders, discharge checklists)
# Express.js: CDS Hooks service endpoint
const express = require("express");
const app = express();
// Discovery endpoint - tells the EHR what hooks you support
app.get("/cds-services", (req, res) => {
res.json({
services: [{
id: "readmission-risk",
hook: "patient-view",
title: "30-Day Readmission Risk Score",
description: "AI-powered readmission prediction using clinical + social determinants",
prefetch: {
patient: "Patient/{{context.patientId}}",
conditions: "Condition?patient={{context.patientId}}&clinical-status=active",
encounters: "Encounter?patient={{context.patientId}}&date=ge{{now-180d}}&_sort=-date"
}
}]
});
});
// Hook handler - receives context, returns cards
app.post("/cds-services/readmission-risk", async (req, res) => {
const { context, prefetch } = req.body;
const patientId = context.patientId;
// AI agent processes patient data
const riskScore = await calculateReadmissionRisk(prefetch);
const cards = [];
if (riskScore > 0.7) {
cards.push({
summary: `HIGH readmission risk: ${Math.round(riskScore * 100)}%`,
detail: "Patient has 3+ ED visits in 6 months, active CHF, and polypharmacy (8 medications). Consider transitional care referral.",
indicator: "critical",
source: { label: "Nirmitee Readmission AI" },
suggestions: [{
label: "Refer to Transitional Care",
actions: [{ type: "create", description: "Transitional care referral",
resource: { resourceType: "ServiceRequest", status: "draft",
code: { text: "Transitional Care Management" }}}]
}]
});
}
res.json({ cards });
});SMART on FHIR: Embedded Applications
When your AI agent needs a user interface inside the EHR — a dashboard, an interactive form, or a detailed analysis view — SMART on FHIR provides the launch framework. It handles OAuth 2.0 authentication and passes the EHR context (which patient, which encounter, which user) to your app.
Two launch modes:
- EHR Launch: User clicks your app icon inside Epic/Cerner. The EHR sends a
launchparameter containing the context. Your app exchanges it for patient/encounter IDs via OAuth. - Standalone Launch: Your app launches outside the EHR (e.g., a mobile app). The user authenticates and selects a patient. Used for patient-facing apps and backend services.
# Python: SMART on FHIR launch handler
from flask import Flask, redirect, request, session
import requests, secrets
app = Flask(__name__)
@app.route("/launch")
def smart_launch():
"""Handle EHR Launch - receives launch context from the EHR."""
iss = request.args["iss"] # FHIR server URL
launch = request.args["launch"] # Launch context token
# Discover auth endpoints from the FHIR server
metadata = requests.get(f"{iss}/metadata").json()
auth_url = extract_auth_url(metadata)
token_url = extract_token_url(metadata)
session["token_url"] = token_url
session["fhir_url"] = iss
state = secrets.token_urlsafe(32)
session["state"] = state
# Redirect to authorization with SMART scopes
params = {
"response_type": "code",
"client_id": "your-smart-app-id",
"redirect_uri": "https://your-app.com/callback",
"scope": "launch patient/*.read user/Patient.read openid fhirUser",
"launch": launch,
"state": state,
"aud": iss,
}
return redirect(f"{auth_url}?" + urlencode(params))How All Three Work Together
In a real AI agent deployment, you typically use all three protocols:
- CDS Hooks triggers your agent when a clinician opens a chart or signs an order
- FHIR APIs fetch the patient data your agent needs for processing (often via prefetch in the hook request)
- SMART Launch opens your agent's detailed UI when the clinician wants more than a card summary
Example flow: Clinician opens a patient chart → patient-view CDS Hook fires → your agent queries FHIR for vitals/labs/conditions → AI model calculates sepsis risk → returns a CDS Card with the score → clinician clicks "View Details" → SMART app launches showing the full risk analysis with contributing factors.
EHR-Specific Considerations
Epic
- Supports CDS Hooks natively since 2020; register via Epic App Market (formerly App Orchard)
- FHIR R4 endpoint:
https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4/ - Requires Epic-specific SMART app review and certification (6-12 months)
- Supports
patient-view,order-sign,order-selecthooks; limitedencounter-dischargesupport
Oracle Health (Cerner)
- Full CDS Hooks specification support via Millennium platform
- FHIR R4 endpoint varies by site; supports the full CDS Hooks hook catalog
- Open API program with shorter certification timeline than Epic (3-6 months)
- SMART on FHIR v2 support with PKCE
For a deeper dive into FHIR API implementation, see our US Core implementation guide. For OAuth security specifics, read our healthcare API security guide. And for event-driven alternatives to CDS Hooks, explore FHIR Subscriptions for AI agents.
At Nirmitee, we build EHR integrations for AI agent platforms using all three protocols. If you need help connecting your AI to Epic, Cerner, or other EHR systems, let's talk.
Struggling with healthcare data exchange? Our Healthcare Interoperability Solutions practice helps organizations connect clinical systems at scale. We also offer specialized Agentic AI for Healthcare services. Talk to our team to get started.




