φ(ai) PHI AI

Connected systems

Every system this platform can talk to, and what each will actually do. One row per vendor: the profile its connector runs on, whether it has been checked against that profile, what it holds of the corpus, and — for the nine that sell one — the separately-licensed write path and the stub it plugs into. This was three screens saying different parts of the same thing.

Which of these are wired as sources and targets for a run is decided on Orchestration; this screen is the catalogue, not the selection.

18
systems connected
each built from that vendor's own published specification
18
accept writes by default
on the API their certification requires them to publish
9
sell a write path
separately licensed — stubs below
17
publish bulk export
the only way to read a population at once

The catalogue

A vendor is not a system. A network runs two Epics — one per hospital it merged with — and they are different stores, with different charts and different identifiers for the same person. Add as many instances of a vendor as this deployment actually has.

A vendor's install base does not grow because you deployed another copy of it: adding a third Epic re-divides Epic's charts three ways. That vendor's stores are rebuilt on the spot; the other systems are untouched, and the corpus still totals 188,111.

Sorted as the sidebar orders them. A vendor's posture is read from its profile and never typed here, so this table cannot disagree with what a run actually does.

SystemAuthenticationBulk exportWrites by default Commercial path
Northside Health (Epic) source target SMART Backend Services — RS384-signed JWT client assertion; public key registered with the client ID yes 10 types
write path licensed at this site
Epic write APIs, licensed per health system holdings →
Mercy Regional (Epic) SMART Backend Services — RS384-signed JWT client assertion; public key registered with the client ID yes 10 types
write path licensed at this site
Epic write APIs, licensed per health system holdings →
Lakeshore Medical (Oracle Health) SMART Backend Services with MANDATORY explicit system/<Resource>.read scopes — wildcard scopes are not supported yes 10 types
write path licensed at this site
contact Oracle Health (Cerner) ↗
no published write path — ask the vendor
holdings →
Valley Care (Oracle Health) SMART Backend Services with MANDATORY explicit system/<Resource>.read scopes — wildcard scopes are not supported yes 10 types
write path licensed at this site
contact Oracle Health (Cerner) ↗
no published write path — ask the vendor
holdings →
Bayside Clinics (athenahealth) OAuth2 client credentials — client ID and client secret (no JWT assertion) yes 10 types
write path licensed at this site
contact athenahealth ↗
no published write path — ask the vendor
holdings →
Harbor Family Medicine (athenahealth) OAuth2 client credentials — client ID and client secret (no JWT assertion) yes 10 types
write path licensed at this site
contact athenahealth ↗
no published write path — ask the vendor
holdings →
Riverbend Family Care (eClinicalWorks) SMART Backend Services JWT assertion yes 10 types
write path licensed at this site
FHIR Create/Update APIs (V12.0.2+) holdings →
Saint Anne's Hospital (MEDITECH Expanse) SMART Backend Services JWT assertion yes 10 types
write path licensed at this site
contact MEDITECH Expanse ↗
no published write path — ask the vendor
holdings →
Cedar Park Physicians (NextGen) SMART Backend Services JWT assertion no 10 types
write path licensed at this site
NextGen Enterprise APIs (proprietary) holdings →
Coastal Dermatology (ModMed) SMART Backend Services — ES384-signed JWT client assertion (EC P-384 key, public JWKS registered on the app); explicit system/<Resource>.rs scopes REQUIRED on every token request; no client secret on this grant yes 10 types
write path licensed at this site
EMA Proprietary API holdings →
Fairview Health (Altera) SMART Backend Services — private-key JWT client assertion verified against the JWKS URL registered on a System-type app; the token request must carry a scope (Altera's own example is system/*.read); signing algorithm not documented by the vendor yes 10 types
write path licensed at this site
Unity API (proprietary, bidirectional) holdings →
Pinehurst Primary Care (Greenway) SMART Backend Services — ES384-signed JWT client assertion (EC P-384 key pair published at a JWKS URL registered on the Developer Platform; no client secret); the token request carries explicit system/<Resource>.read scopes yes 10 types
write path licensed at this site
GAPI (Greenway API, proprietary) holdings →
Summit Medical Group (Veradigm) SMART Backend Services — RSA-signed JWT client assertion (RS384) against a JWKS you host; Veradigm requires RSA 2048 keys with a kid, syncs the JWKS nightly, and documents no client secret for System apps yes 10 types
write path licensed at this site
Unity API (proprietary, bidirectional) holdings →
Elmwood Pediatrics (Practice Fusion) SMART Backend Services — signed JWT client assertion (RS384 or ES384, kid required, public key at a JWKS URL registered on the PDS API Portal); no client secret; explicit per-type system/<Resource>.read scopes required, limited to what the practice administrator authorized in the EHR yes 10 types
write path licensed at this site
contact Practice Fusion ↗
no published write path — ask the vendor
holdings →
Cornerstone Rural Hospital (TruBridge) SMART Backend Services — private_key_jwt client assertion against a JWKS URL given at registration (RS256/RS384/ES256/ES384 accepted; PHI AI signs RS384); TruBridge equally documents client_secret_basic/post. scope is REQUIRED in the token request — one explicit system/<Resource>.read per ingested type yes 10 types
write path licensed at this site
contact TruBridge ↗
no published write path — ask the vendor
holdings →
Grant County Medical Center (MEDHOST) SMART Backend Services — private_key_jwt client assertion signed RS384 or ES384; public key served from a JWK Set URL registered on the app (set with each facility for production); no client secret for service clients yes 10 types
write path licensed at this site
MEDHOST Interoperability package holdings →
Willow Behavioral Health (Netsmart) SMART Backend Services — Private Key JWT (Netsmart's recommended grant; JWK Set URI registered with the app) or client secret, both documented; explicit system/<Resource> scopes required on every token request; one app registration per tenant yes 10 types
write path licensed at this site
contact Netsmart ↗
no published write path — ask the vendor
holdings →
Vista Eye & Skin (Nextech) SMART Backend Services (system app) — RS384- or ES384-signed JWT client assertion against sts.mypatientvisit.com; public key served from a registered TLS 1.2 JWK Set URL; explicit system/<Resource>.read scopes in the token request; 15-minute tokens with no refresh tokens; one client ID per practice on a single multi-tenant base URL yes 10 types
write path licensed at this site
Practice+ / Select write APIs holdings →

Connection settings

The primary source and target, and the endpoint each is reached on. The signing keypair and client secret never enter this screen — they are referenced by file path on the server, mounted read-only, exactly as the platform does it.

Source EMR — where records are ingested from

AuthenticationSMART Backend Services — RS384-signed JWT client assertion; public key registered with the client ID
Bulk exportGroup-level Bulk Data Export only; requires a Group FHIR ID from Epic; rate-limited to once per 24 hours per group and client; every kickoff is a full re-extract
Write surfaceDocumentReference create only, and only where the health system has licensed and enabled that write API (write APIs are enabled per resource and per flavor by each health system); no general FHIR create for historical clinical resources; MedicationRequest is read/search only over FHIR REST (order suggestions exist only as CDS Hooks); conditional create not documented — a confirmed run needs --allow-duplicates
CredentialsThe signing keypair / client secret never enters this screen — it is referenced by file path on the server, mounted read-only, exactly as the platform does it.

Target EMR — where signed write-backs are delivered

Write posture for Epic: DocumentReference create only, and only where the health system has licensed and enabled that write API (write APIs are enabled per resource and per flavor by each health system); no general FHIR create for historical clinical resources; MedicationRequest is read/search only over FHIR REST (order suggestions exist only as CDS Hooks); conditional create not documented — a confirmed run needs --allow-duplicates. Nothing is written without a human signature (see the Signature queue), and a capability the vendor does not expose is refused, never approximated.
Saving re-renders the vendor seams and is audited.

Commercial write paths

Wiring one of these is the add-on work. If you need help obtaining or implementing a vendor's commercial path, contact phi-ai@ryangomez.nyc.
These sites have bought their write paths. A vendor's certified API is what it publishes to everybody, and for most of them that is read-only — the write path is sold separately. Every connected system here is set up as a site that licensed one, signed the agreement and registered its keys, because that is what a running deployment looks like and a demonstration where nothing moves teaches nothing. Revoke any licence in the table below to see what a site sees before it has bought anything: the same run, refusing.
3
FHIR, switched on by contract
5
A different API entirely
1
A commercial gate, not a new API
6
vendors selling no write path
Oracle Health (Cerner), athenahealth, MEDITECH Expanse, Practice Fusion, TruBridge, Netsmart

FHIR, switched on by contract

The same endpoints, with create and update enabled per contract. Try the standard writer first — it may simply work once the scopes are granted.

eClinicalWorks

FHIR FHIR Create/Update APIs (V12.0.2+)

eClinicalWorks FHIR Create/Update, sold as a contracted add-on.

What to obtaineClinicalWorks documents Create/Update APIs from V12.0.2 onward, but as a contracted add-on rather than a default capability: the practice must be on a supporting version and the interface has to be arranged with eClinicalWorks.
Who to askinterop@eclinicalworks.com
How to buy it https://fhir.eclinicalworks.com/ecwopendev/ ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py ECLINICALWORKS.write_notes
docs/EMR_CONNECTORS.md, eClinicalWorks chapter
Refuses withConnectorNotConfigured

The nearest thing here to a drop-in: it is still FHIR, on the same
endpoints, with create and update enabled per contract. An implementer
with the contract may find that the standard EMRWriter simply works
once the scopes are granted - try that before writing anything here.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — EClinicalWorksWriteAddOn
class EClinicalWorksWriteAddOn(CommercialConnector):
    """eClinicalWorks FHIR Create/Update, sold as a contracted add-on.

    The nearest thing here to a drop-in: it is still FHIR, on the same
    endpoints, with create and update enabled per contract. An implementer
    with the contract may find that the standard EMRWriter simply works
    once the scopes are granted - try that before writing anything here.
    """

    vendor_key = "eclinicalworks"
    product = "FHIR Create/Update APIs (V12.0.2+)"
    is_fhir = True
    how_to_obtain = (
        "eClinicalWorks documents Create/Update APIs from V12.0.2 onward, but as a contracted "
        "add-on rather than a default capability: the practice must be on a supporting version and "
        "the interface has to be arranged with eClinicalWorks."
    )
    contact = "interop@eclinicalworks.com"
    sources = ("core/fhir/emr_profiles.py ECLINICALWORKS.write_notes",
               "docs/EMR_CONNECTORS.md, eClinicalWorks chapter")

MEDHOST

FHIR MEDHOST Interoperability package

MEDHOST - a licence gate rather than a different API.

What to obtainThe FACILITY must purchase and activate the Interoperability package - it is a licence the customer holds, not something an integrator can buy on their behalf. Without it there is no API access to patient health information at all.
Who to askMEDHOST — via the facility's account team
How to buy it https://www.medhost.com/ehr/interoperability/ ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py MEDHOST.write_notes
MEDHOST costs-and-considerations workbook
Refuses withConnectorNotConfigured

"Customers must purchase and activate the MEDHOST Interoperability
package to use API access to patient health information." The facility
buys it, not the integrator; without it there is no API access at all,
read or write.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — MedhostInteroperabilityPackage
class MedhostInteroperabilityPackage(CommercialConnector):
    """MEDHOST - a licence gate rather than a different API.

    "Customers must purchase and activate the MEDHOST Interoperability
    package to use API access to patient health information." The facility
    buys it, not the integrator; without it there is no API access at all,
    read or write.
    """

    vendor_key = "medhost"
    product = "MEDHOST Interoperability package"
    is_fhir = True
    how_to_obtain = (
        "The FACILITY must purchase and activate the Interoperability package - it is a licence the "
        "customer holds, not something an integrator can buy on their behalf. Without it there is no "
        "API access to patient health information at all."
    )
    contact = "MEDHOST — via the facility's account team"
    sources = ("core/fhir/emr_profiles.py MEDHOST.write_notes",
               "MEDHOST costs-and-considerations workbook")

Nextech

FHIR Practice+ / Select write APIs

Nextech's writable surface - narrow, and per product.

What to obtainAccess is arranged through Nextech's connection request form and a client login. What can be written depends on the product: Select/NexCloud documents DocumentReference create only, gated by a write scope; Practice+ on STU3 adds Patient, Appointment and PaymentReconciliation.
Who to asknextech.com/developers-portal — connection request form
How to buy it https://www.nextech.com/developers-portal ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py NEXTECH.write_notes
nextechsystems.github.io/practiceplusapidocspub (STU3 reference)
Refuses withConnectorNotConfigured

Select/NexCloud publishes exactly one create (DocumentReference, gated
by a write scope); Practice+ on STU3 writes Patient, Appointment,
DocumentReference and PaymentReconciliation. Different products, so a
connector must know which one the practice runs.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — NextechPracticePlus
class NextechPracticePlus(CommercialConnector):
    """Nextech's writable surface - narrow, and per product.

    Select/NexCloud publishes exactly one create (DocumentReference, gated
    by a write scope); Practice+ on STU3 writes Patient, Appointment,
    DocumentReference and PaymentReconciliation. Different products, so a
    connector must know which one the practice runs.
    """

    vendor_key = "nextech"
    product = "Practice+ / Select write APIs"
    is_fhir = True
    how_to_obtain = (
        "Access is arranged through Nextech's connection request form and a client login. What can "
        "be written depends on the product: Select/NexCloud documents DocumentReference create only, "
        "gated by a write scope; Practice+ on STU3 adds Patient, Appointment and PaymentReconciliation."
    )
    contact = "nextech.com/developers-portal — connection request form"
    sources = ("core/fhir/emr_profiles.py NEXTECH.write_notes",
               "nextechsystems.github.io/practiceplusapidocspub (STU3 reference)")

A different API entirely

Not FHIR. Implementing this is writing a new client against the vendor's own protocol, not adjusting a FHIR one.

Altera Digital Health

not FHIR Unity API (proprietary, bidirectional)

Altera's Unity API - bidirectional, proprietary, not FHIR.

What to obtainUnity is sold under Altera's Integrator membership tiers and sits outside FHIR entirely - demographics, appointments and financial data go through it. Membership and the Unity documentation come with the agreement.
Who to askADP@alterahealth.com (Altera Developer Program)
How to buy it https://marketplace.alterahealth.com/Developers ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py ALTERA.write_notes
developer.adpstg.ahcentral.com ProcessOverview — 'limited to read-only access and not write-backs'
Refuses withConnectorNotConfigured

Altera states its FHIR API is "limited to read-only access and not
write-backs". Unity is the write path, sold on Integrator membership
tiers, and it is a different protocol: implementing this is writing a
Unity client, not adjusting a FHIR one.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — AlteraUnity
class AlteraUnity(CommercialConnector):
    """Altera's Unity API - bidirectional, proprietary, not FHIR.

    Altera states its FHIR API is "limited to read-only access and not
    write-backs". Unity is the write path, sold on Integrator membership
    tiers, and it is a different protocol: implementing this is writing a
    Unity client, not adjusting a FHIR one.
    """

    vendor_key = "altera"
    product = "Unity API (proprietary, bidirectional)"
    is_fhir = False
    how_to_obtain = (
        "Unity is sold under Altera's Integrator membership tiers and sits outside FHIR entirely - "
        "demographics, appointments and financial data go through it. Membership and the Unity "
        "documentation come with the agreement."
    )
    contact = "ADP@alterahealth.com (Altera Developer Program)"
    sources = ("core/fhir/emr_profiles.py ALTERA.write_notes",
               "developer.adpstg.ahcentral.com ProcessOverview — 'limited to read-only access and not write-backs'")

Veradigm

not FHIR Unity API (proprietary, bidirectional)

Veradigm's Unity API - the same product family as Altera's.

What to obtainUnity is a proprietary API on Veradigm's Integrator tiers - a second client, not this profile. It is the only documented route to Veradigm Practice Management data.
Who to askVeradigm Connect — developer.veradigm.com
How to buy it https://veradigm.com/veradigm-connect/ ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py VERADIGM.write_notes
developer.veradigm.com ProcessOverview — 'limited to read-only access'
Refuses withConnectorNotConfigured

Veradigm documents its FHIR API as read-only, and says developers
"must utilize Unity to read or write patient demographic, appointment,
or financial data". It is also the only route to Veradigm Practice
Management.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — VeradigmUnity
class VeradigmUnity(CommercialConnector):
    """Veradigm's Unity API - the same product family as Altera's.

    Veradigm documents its FHIR API as read-only, and says developers
    "must utilize Unity to read or write patient demographic, appointment,
    or financial data". It is also the only route to Veradigm Practice
    Management.
    """

    vendor_key = "veradigm"
    product = "Unity API (proprietary, bidirectional)"
    is_fhir = False
    how_to_obtain = (
        "Unity is a proprietary API on Veradigm's Integrator tiers - a second client, not this "
        "profile. It is the only documented route to Veradigm Practice Management data."
    )
    contact = "Veradigm Connect — developer.veradigm.com"
    sources = ("core/fhir/emr_profiles.py VERADIGM.write_notes",
               "developer.veradigm.com ProcessOverview — 'limited to read-only access'")

Greenway Health

not FHIR GAPI (Greenway API, proprietary)

Greenway's GAPI - proprietary, and different per product.

What to obtainGAPI 'supports reads and writes across a variety of clinical and financial data elements' and is reached through a different portal from the FHIR API. Its calls and data structures differ between Intergy and Prime Suite, so a deployment needs the one its practice runs.
Who to askdevelopers.greenwayhealth.com
How to buy it https://developers.greenwayhealth.com/developer-platform ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py GREENWAY.write_notes
developers.greenwayhealth.com api-an-overview — 'read operations only at the present time'
Refuses withConnectorNotConfigured

Greenway's own description is the warning: "a Proprietary API with
separate and distinct API calls and data structures for each of our
EHR products". Intergy and Prime Suite differ, so this is realistically
two implementations, and the subclass should not pretend otherwise.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — GreenwayGAPI
class GreenwayGAPI(CommercialConnector):
    """Greenway's GAPI - proprietary, and different per product.

    Greenway's own description is the warning: "a Proprietary API with
    separate and distinct API calls and data structures for each of our
    EHR products". Intergy and Prime Suite differ, so this is realistically
    two implementations, and the subclass should not pretend otherwise.
    """

    vendor_key = "greenway"
    product = "GAPI (Greenway API, proprietary)"
    is_fhir = False
    how_to_obtain = (
        "GAPI 'supports reads and writes across a variety of clinical and financial data elements' "
        "and is reached through a different portal from the FHIR API. Its calls and data structures "
        "differ between Intergy and Prime Suite, so a deployment needs the one its practice runs."
    )
    contact = "developers.greenwayhealth.com"
    sources = ("core/fhir/emr_profiles.py GREENWAY.write_notes",
               "developers.greenwayhealth.com api-an-overview — 'read operations only at the present time'")

ModMed

not FHIR EMA Proprietary API

ModMed's EMA Proprietary API - CREATE/READ/SEARCH/UPDATE, for a fee.

What to obtainOffered 'for a fee' through the synapSYS Marketplace, with a technical review before a vendor is 'permitted to gain access to their first customer's production system'. Rate limited at 1,250 calls per minute per API key. EMA and Practice Management only - not gGastro.
Who to asksynapsys@modmed.com
How to buy it https://www.modmed.com/what-we-do/integrations/synapsys/developers/ ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py MODMED.write_notes
portal.api.modmed.com — Proprietary API; Mandatory Disclosures PDF ('for a fee')
Refuses withConnectorNotConfigured

Note the product boundary: EMA and Practice Management only. ModMed
states it "will not be able to support gGastro customers", so a
gGastro practice has no write path here at all and the stub should
refuse rather than try.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — ModMedProprietary
class ModMedProprietary(CommercialConnector):
    """ModMed's EMA Proprietary API - CREATE/READ/SEARCH/UPDATE, for a fee.

    Note the product boundary: EMA and Practice Management only. ModMed
    states it "will not be able to support gGastro customers", so a
    gGastro practice has no write path here at all and the stub should
    refuse rather than try.
    """

    vendor_key = "modmed"
    product = "EMA Proprietary API"
    is_fhir = False  # FHIR-shaped, but a separate product with its own auth and limits
    how_to_obtain = (
        "Offered 'for a fee' through the synapSYS Marketplace, with a technical review before a "
        "vendor is 'permitted to gain access to their first customer's production system'. Rate "
        "limited at 1,250 calls per minute per API key. EMA and Practice Management only - not gGastro."
    )
    contact = "synapsys@modmed.com"
    sources = ("core/fhir/emr_profiles.py MODMED.write_notes",
               "portal.api.modmed.com — Proprietary API; Mandatory Disclosures PDF ('for a fee')")

NextGen Healthcare

not FHIR NextGen Enterprise APIs (proprietary)

NextGen's proprietary Enterprise APIs, behind the developer portal.

What to obtainThe full developer guides sit behind NextGen's developer portal registration; no system/backend flow or Enterprise-level $export is publicly documented, so the terms have to come from the agreement rather than from a public page.
Who to askNextGen developer portal
How to buy it https://www.nextgen.com/developer-program ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py NEXTGEN.write_notes
Refuses withConnectorNotConfigured

The public NextGen surface documents a patient-oauth token endpoint and
no system/backend flow; the Enterprise APIs and full developer guides
sit behind registration. An implementer needs that access before this
can be written honestly.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — NextGenEnterprise
class NextGenEnterprise(CommercialConnector):
    """NextGen's proprietary Enterprise APIs, behind the developer portal.

    The public NextGen surface documents a patient-oauth token endpoint and
    no system/backend flow; the Enterprise APIs and full developer guides
    sit behind registration. An implementer needs that access before this
    can be written honestly.
    """

    vendor_key = "nextgen"
    product = "NextGen Enterprise APIs (proprietary)"
    is_fhir = False
    how_to_obtain = (
        "The full developer guides sit behind NextGen's developer portal registration; no "
        "system/backend flow or Enterprise-level $export is publicly documented, so the terms have "
        "to come from the agreement rather than from a public page."
    )
    contact = "NextGen developer portal"
    sources = ("core/fhir/emr_profiles.py NEXTGEN.write_notes",)

A commercial gate, not a new API

The API is one this platform already speaks. What is missing is the licence and the app registration, not the code.

Epic

FHIR Epic write APIs, licensed per health system

Epic - not a separate API, a per-health-system licence.

What to obtainWriting back is realistically limited to attaching documents to a chart, and even that requires the specific write API to be licensed and enabled for that health system - write APIs are enabled per resource and per flavour by each organisation, not once for Epic.
Who to askthe health system's Epic team, via open.epic.com registration
How to buy it https://vendorservices.epic.com/ ↗
The vendor's own page. Terms, tiers and eligibility are theirs to state, and they change them without telling us.
Stated by
core/fhir/emr_profiles.py EPIC.write_notes
open.epic.com/DeveloperResources
Refuses withConnectorNotConfigured

Epic's write APIs are FHIR and the standard writer speaks them. What
gates them is commercial: the specific write API must be licensed and
enabled for that health system, per resource and per flavour. So this
stub exists to carry the explanation, not a different protocol.

The stub, as it is written in the platform
core/fhir/commercial/vendors.py — EpicLicensedWrite
class EpicLicensedWrite(CommercialConnector):
    """Epic - not a separate API, a per-health-system licence.

    Epic's write APIs are FHIR and the standard writer speaks them. What
    gates them is commercial: the specific write API must be licensed and
    enabled for that health system, per resource and per flavour. So this
    stub exists to carry the explanation, not a different protocol.
    """

    vendor_key = "epic"
    product = "Epic write APIs, licensed per health system"
    is_fhir = True
    how_to_obtain = (
        "Writing back is realistically limited to attaching documents to a chart, and even that "
        "requires the specific write API to be licensed and enabled for that health system - write "
        "APIs are enabled per resource and per flavour by each organisation, not once for Epic."
    )
    contact = "the health system's Epic team, via open.epic.com registration"
    sources = ("core/fhir/emr_profiles.py EPIC.write_notes",
               "open.epic.com/DeveloperResources")

Extending the platform yourself

The contract is deliberately small — three methods and a refusal that explains itself. Adding a vendor is filling in authenticate, capabilities and create, not learning a framework. In plain English:

  1. Find out what you are actually dealing with. Read the vendor's own developer site, not a summary of it. The question to answer is whether writes go over FHIR at all.
  2. Work out which of the three kinds you have — the three headings above. That decides whether you are turning something on, writing a new client, or signing a licence.
  3. Buy or sign the thing. Every path here has a commercial step, and no amount of code substitutes for it. The contact above is the vendor's own.
  4. Write the connector in core/fhir/commercial/vendors.py, replacing the stub's refusal with real calls. Keep the refusal for everything the contract does not cover — a delivery that silently went nowhere is worse than one that failed loudly.
  5. Tell the platform what you learned. Register it, and record what the live endpoint actually accepted in a CommercialCapability — the vendor's sales material is a planning aid; the running integration is the fact.

The full guide ships with the software as docs/EXTENDING_CONNECTORS.md, and every claim on this page carries the vendor page it came from. Where a vendor's material does not say something — a base URL, an auth scheme, a resource list — the stub says it does not know rather than inventing a plausible value.

Streaming feeds — the continuous half

A connected system is not only something a run reads from and writes to: some of them keep delivering. Orchestration runs a batch — wire it, scope it, preflight it, execute it, and it finishes. A feed never finishes; it is a standing subscription carrying admissions, discharges and results as they happen. Both are properties of the same connection, which is why they are on one screen. Batch movement lives on Orchestration; what a run did is in the run ledger.

Inbound — feeds arriving

Real-time feeds beside the batch pipeline — admissions and discharges, lab results, claims remittances. Streaming has no clean-run boundary, so each partition keeps its own checkpoint with explicit gap accounting, never sharing the bulk pipeline's watermark. A gap is surfaced loudly rather than interpolated.

0
events today across all feeds
0
partitions under checkpoint discipline
0
open gaps — surfaced, not interpolated

Partitions

FeedPartitionCheckpoint Latest offsetLag Events todayLast eventState
Why two disciplines. The bulk pipeline has a clean-run boundary and a watermark; a stream has neither — only per-partition offsets and the honesty to account for every one. The gapped partition above holds its checkpoint until the missing offsets are recovered or the loss is formally accepted and recorded; it does not skip ahead.

Source EMR lookup — pull one patient now

Between bulk runs, new patients exist at the source that PHI AI has not seen. Search the source EMR directly and import an individual patient over the per-patient read path — the same path bulk-less vendors force for entire populations.

No match at the source or in PHI AI. The search itself was audited — a lookup is an identity search wherever it runs.

An individual import runs read → encrypt → store → index for one patient and lands in your session's sandbox: the patient appears in Patients & charts, the import is audited (ingest.patient_imported), and the next reconciliation on the Bulk import manager counts them.

Outbound — feeds leaving

Data leaving in real time — ADT notifications to community providers, results to the patient portal, claims to the clearinghouse, measure submissions. Each outbound feed tracks what the destination has acknowledged against what has been produced; the difference is held and accounted, never dropped, and a feed can be paused by governance without losing its place.

5,110
deliveries today across all feeds
182
held for retry — queued and accounted, not dropped
5
outbound feeds under acknowledgment discipline

Outbound feeds

FeedDestinationAcknowledged ProducedHeld TodayLast deliveryState
ADT notifications (CMS Condition of Participation) Community providers via HIE 6,621,401 6,621,401 0 1,188 13:58 healthy
Results to patient portal Patient portal 3,310,221 3,310,221 0 3,301 13:59 healthy
Claims 837 submissions Clearinghouse 441,207 441,389 182 206 11:02 held
Clearinghouse rejecting since 11:02 (certificate rotation on their side). 182 submissions HELD with retry - held means queued and accounted, never dropped; nothing is re-generated or skipped.
Quality-measure submission (eCQM) Payer portal 8,812 8,812 0 3 09:15 healthy
Event notifications to researchers De-identified event bus 99,120 99,120 0 412 13:57 paused
Paused by governance: purpose-of-use review of a new subscriber in progress. A paused feed accumulates sequence, it does not leak.
Outbound is governed like inbound. A held feed retries against the destination without regenerating or skipping; a paused feed is a governance decision that accumulates sequence rather than leaking; and nothing in a de-identified event feed carries identifiers — the pause in the table above is a purpose-of-use review doing its job.