How PolyAI authenticates to Epic, identifies or registers a patient, confirms or finds the physician, re-scopes its variant, validates and verifies insurance in real time for the visit type, and books. Every node shows the request/response contract and, for each field, exactly where the data is sourced — captured from the caller, carried in conv.state from a prior call, set as a deployment attribute, or taken from the telephony ANI.
PolyAI runs as a backend client of Epic's Interconnect FHIR server. Reads go through FHIR R4 resources; scheduling writes go through Epic's FHIR scheduling operations (Appointment.$find / $book) and the private (Class C) scheduling web services. New-patient intake adds EMPI duplicate-matching and Open-Scheduling record creation. Insurance is read from the FHIR Coverage resource, confirmed with the caller, validated against the payer before any write, and (when valid) written back provisionally — then a benefit check runs in real time, in-call against the payer via the pVerify eligibility seam.
Every booking is assembled from reusable building blocks in this order. Each block sources its inputs explicitly and writes named outputs to conv.state for the next block.
Coverage is read early so the payer is available to the in-network provider filter in Find Physician; the caller-facing confirm/update happens in its own step and validates the plan with the payer before writing it to Epic; the live benefit check then runs after physician + variant so the rendering NPI and the service-type (visit type) are both present.
No component requires a human logged into Epic — correct for inbound telephony. The agent operates strictly in the administrative lane (see Scope & Compliance).
Resolved against Epic_API_Documentation.md. "Public" = published FHIR/REST spec; "Private · C" = approved-vendor only (Vendor Services); "Open Scheduling" = sanctioned new-patient path; "pVerify seam" = the real-time eligibility integration to be wired in the pVerify pass.
| Resource / service | Operation | Role in flows | Availability |
|---|---|---|---|
| PatientLookup (2012) | POST (EMPI) | Patient match / EMPI duplicate check | Public |
| Patient.$match / Patient.Search | FHIR R4 | Fallback patient match | Public |
| Patient (create) · Open Scheduling | POST | Create provisional new-patient record | Open Scheduling |
| Coverage.Search | FHIR R4 | Read insurance on file (payer + member ID) | Public |
| EligibilitySummary (validation) | POST | Validate plan is real/active before write (org NPI) | pVerify seam |
| Coverage.Create | FHIR R4 (write) | Provisional patient-reported coverage update | Write · gated |
| EligibilitySummary (benefit) | POST | Real-time copay / PA check for the visit type | pVerify seam |
| Encounter.Search | FHIR R4 | Recent / historical provider | Public |
| PractitionerRole / Practitioner | FHIR R4 | Resolve / find provider + specialty + NPI | Public |
| Appointment.Search | FHIR R4 | Locate existing appointment | Public |
| Appointment.$find / $book | FHIR (open scheduling) | Slot search / open-scheduling book | Private · C |
| ScheduleAppointment (2019) | POST | Book / reschedule writer (established) | Private · C |
| CancelAppointment · ConfirmationResponse | POST | Cancel / confirm / acknowledge | Private · C |
| MedicationRequest.Search (Signed Medication Order) | FHIR R4 | Retrieve active prescriptions (refill flow) | Public |
| MedicationDispense.Search (Fill Status) | FHIR R4 | Dispense history / remaining refill count | Public |
| RelatedPerson.Search | FHIR R4 | Authorized representative verification | Public |
| Encounter.Search (Eligibility) | FHIR R4 | 12-month visit lookback for refill eligibility | Public |
| ReceiveCommunication3 | POST | Submit refill request to clinical pool (CAL record) | Private |
Appointment.$find / $book wrap the Schedule/Slot dance into a single deterministic call and reduce race conditions. A Slot tells you when something can happen, not whether it is clinically appropriate — appropriateness is handled by the configured visit type and Decision Tree, never by the agent.conv.state, not regenerated.conv.state from a prior dip, a deployment/variant attribute, or the telephony ANI.conv.set_variant() re-points persona, department and visit-type defaults the moment the provider is resolved.| Application | PolyAI |
| Prod Client ID | c6cc31b3-…-08f56ed57fa3 |
| SMART scope / FHIR | SMART V1 · R4 · system/* read + Coverage + scheduling |
| Grant | client_credentials + JWT assertion |
| Open Scheduling | Enabled per org (new-patient create) |
| pVerify (seam) | OAuth2 client_credentials; sub-account per NPI |
Written for both PolyAI deployment teams and prospective clients. It states PolyAI's operating position and the design rationale. It is not legal advice; final determination that a deployment is permissible in its jurisdiction rests with the customer's legal, compliance, and clinical leadership.
Identifying and registering patients, finding the right provider and visit type, confirming insurance, and booking are administrative functions — the same work a front-desk coordinator performs. They become the practice of medicine or nursing only when someone evaluates symptoms to determine clinical urgency or the type of care required. That boundary is the design.
The agent captures a reason-for-visit as an administrative label and maps it to an Epic-configured visit type using Epic's own Decision Tree / questionnaire mechanism — the same administrative mapping Epic ships for staff and patient self-scheduling. It does not interpret symptoms, rank severity, or select a specialty from a clinical presentation. "I need a cardiologist" or "my doctor referred me to dermatology" is administrative routing. "I have chest pain, what should I do?" is clinical — handled by the Safety-Net, not the agent.
Schmitt-Thompson protocols are the gold-standard telephone-triage decision support, used by the large majority of North American medical call centers — but they are physician-authored and administered by licensed nurses, peer-reviewed annually. PolyAI's decision is explicit: the agent does not run Schmitt-Thompson (or any) triage protocols and does not render dispositions. Where a caller introduces symptoms, the agent applies the Emergency Safety-Net and routes to the customer's licensed triage / clinical resource. Schmitt-Thompson stays with a licensed human.
New-patient registration and booking are administrative acts — automatable on the same basis as a human scheduler creating a chart and booking a visit — provided the interaction does not cross into symptom assessment or clinical triage. The flow collects identity and demographics, runs EMPI duplicate-matching, creates a provisional record (verified by staff at check-in), resolves an in-network provider, and books an administratively-mapped visit type. The reason-for-visit is a routing label, not a clinical finding. That is what lets the function drive down patient leakage without becoming clinical decision-making.
Confirming insurance, validating that a plan is real and active, and running a real-time benefit check are administrative (financial / registration) acts with no symptom content, so they sit fully inside scope. One bright-line rule governs them: the agent surfaces the payer's determination; it never makes one. It reads back "your plan is active and covers this visit, your copay is $40," or "the payer shows this plan as inactive — let me get you to billing." It does not deny coverage, decide medical necessity, or issue an adverse benefit determination. This keeps the function clear of AI adverse-determination restrictions — for example Texas S.B. 815 (effective Sept 2025), which prohibits utilization-review agents from using AI to make adverse determinations. Patient-reported coverage is validated with the payer before it is written, and even then is written provisional; the authoritative truth is set by the payer's 270/271 response and staff verification, not by the agent.
A conservative, customer-clinically-approved red-flag layer fronts every reason-for-visit. On a small set of unambiguous emergency cues — chest pain, difficulty breathing, stroke signs, severe bleeding, suicidal ideation — the agent stops the flow, instructs the caller to seek emergency care / dial 911, and warm-transfers to a designated clinical resource. It is tuned to over-escalate when uncertain. It is not triage: it assigns no disposition and no level of care — it removes the highest-risk interactions from the automated path entirely.
PolyAI provides the mechanics: the administrative flows, the reason→visit-type mapping, the escalation routing, the data lineage, and the eligibility seam. The health-system customer owns the clinical content: the emergency red-flag set, the escalation targets (nurse line, 911 guidance, warm transfer), the visit-type / Decision Tree configuration, and clinical governance.
Established-patient flows. Pick one; decisions fan out into labelled branches with their own terminals — loop-backs, CC handoffs, the continuing path. Click any node for utterances, request/response contracts with per-field data provenance, fallbacks, and capture strategy. New-patient intake has its own section. Click a building block to drill in.
The high-value, higher-care flow. A caller with no record wants to be seen. The agent runs the Safety-Net, matches against EMPI to avoid a duplicate, registers a provisional record only on no-match, takes insurance up front (so the provider search can filter in-network), validates the plan with the payer before writing it, finds a provider accepting new patients, re-scopes its variant, verifies benefits live, and books a new-patient visit type. The weight-bearing decisions — EMPI disposition, the Safety-Net, coverage validation, and the eligibility result — are explicit branches.
| Concern | Established patient | New patient |
|---|---|---|
| Record | Exists — resolve FHIR Patient ID | May not exist — EMPI match, then create only on no-match |
| Duplicate risk | Low | High — ambiguous match → data-stewardship handoff, never auto-create/merge |
| Insurance | On file → confirm, validate, update if changed | None on file → capture up front + validate before write (needed for in-network search) |
| Provider | Confirm the one they've seen | No history — directory search (specialty + location + accepting-new + network) |
| Visit type | Established visit types | New-patient visit types (longer; different codes) |
| Booking write | ScheduleAppointment (private) | Open Scheduling Appointment.$book |
Voice ASR makes some fields risky. These are the patterns PolyAI uses — validate against known values first, fall back to spelling only when needed, and treat reason-for-visit as an administrative label, never a clinical assessment.
Grouped by call flow. Each use case shows the APIs it needs, how many times each is called, and whether it costs anything beyond the standard EHR license. Expand any API for the full request/response contract with per-field data provenance.
Every API card carries four badges. Here’s what each one means.
Which system handles the API call.
| Epic | Call handled by Epic’s Interconnect server (FHIR R4 or proprietary). |
| pVerify | Call leaves the EHR and hits pVerify, a third-party eligibility clearinghouse. |
The API tier within that platform.
| Standard | Published API — FHIR R4 standard or “Epic Public” proprietary. No Vendor Services agreement required. Priced via flat annual subscription. |
| Private – Class C | Epic Private Technology (Class C). Requires enrollment in Epic’s Vendor Services program. Priced per-transaction under Epic’s Class A–G model (see below). |
| Clearinghouse | X12 270/271 transaction routed through pVerify. Separate vendor, separate contract, billed per-transaction. |
How the API is priced at runtime.
| Included | Flat annual subscription (per Production Directory, paid quarterly). Cost does not scale with call volume. |
| Per-Use | Per-transaction pricing. Each API call incurs a charge under Epic’s Class A–G model or pVerify’s clearinghouse rate. |
Expected calls per patient conversation.
| 1× | Called once per conversation. |
| 1× fallback | Called only if the primary lookup returns no results. |
| 1× cond. | Called conditionally (e.g., insurance changed, controlled substance, overdue patient). |
| 1–3× | May loop — e.g., slot negotiation when the caller requests different times. |
| 1× cond. | Red-tinted when the API is Per-Use — flags a per-transaction cost on each call. |
Epic prices Private API calls using a seven-tier marginal per-transaction model. The structure was disclosed in Epic’s court filing in Texas v. Epic (January 2026). Exact dollar amounts per class are shared under Vendor Services enrollment and are not publicly listed.
| Class | What falls here |
|---|---|
| Class A | Lowest tier. Read-only operations on data required for interoperability under USCDI / 21st Century Cures Act. |
| Class B | Low-cost tiers. Together with Class A, these three classes account for over 99% of all third-party API transactions. Common read/write operations and standard scheduling reads are expected here. |
| Class C | |
| Class D | Mid-to-upper tiers. Used for more complex operations. Exact API-to-class assignments are provided under Vendor Services enrollment. |
| Class E | |
| Class F | |
| Class G | Highest tier. Epic recorded zero Class G transactions in all of 2025 — effectively unused in practice. |
Appointment.$find, Appointment.$book, ScheduleAppointment, CancelAppointment, ConfirmationResponse, and Patient.Create (Open Scheduling) — are all per-transaction under this model. The specific class assignment for each endpoint (and therefore its per-call rate) is provided when you enroll in Vendor Services. Request the open.epic API Pricing Information summary for current rates.$find) may loop 1–3×, so a single patient interaction incurs roughly 3–6 Private API transactions. For volume planning, request your class assignments from Vendor Services and multiply by projected call volume.Model how many API transactions each use case generates per month. The estimator accounts for caller drop-off through the flow, multi-intent calls where the patient is already identified, and conditional steps that only fire in certain paths.
How many patient conversations per month will the PolyAI agent handle for each use case? These are intents — a single call may contain multiple intents (see Multi-Intent below).
What percentage of conversations complete the full flow (reach the final write/booking step)? Callers who abandon or hand off mid-flow still generate API calls for every step they reached.
What percentage of callers complete more than one task per call (e.g., book a new appointment and reschedule another)? When this happens, patient identification fires once per call, not per intent.
cond. fire only in certain paths (e.g., insurance changed, controlled substance, overdue patient) — estimated at 50% of the position-adjusted volume. fallback APIs (Patient.$match) fire only when the primary lookup returns zero results — estimated at 15%. These modifiers stack with the flow-position decay.OAuth 2.0 client_credentials with a signed JWT. No interactive login — correct for an inbound call where no clinician or patient can complete a browser consent. The same token serves read FHIR, the scheduling operations, and Open Scheduling writes. The pVerify eligibility seam uses its own OAuth2 token (covered in the pVerify pass).
| OAuth flow | Designed for | Voice-suitable? | Why |
|---|---|---|---|
| Backend Services Use | Server-to-server, no user present | Yes | JWT signed with a private key; Agent Studio auto-refreshes the token. |
| Clinician / EHR launch No | Apps launched inside Hyperspace | No | Needs a logged-in Epic user — impossible on an inbound call. |
| Patient (MyChart) No | Patient portal apps | No | Needs MyChart credentials + browser consent. (Some FHIR APIs also behave differently in a patient-facing context.) |
Build with Poly Agent Builder (non-technical) or the ADK (developers) — same dialog-native runtime. The data-lineage discipline below is what makes the deployment auditable.
Configure > Integrations > Epic. Submit the trusted-app request with the PolyAI Client ID; Epic approves via Vendor Services. Enable Open Scheduling for new-patient create. (pVerify provisioned separately in the pVerify pass.)
Configure > APIs: declare each endpoint with environment-specific base URLs and OAuth 2.0. Mark the private (Class C) operations requiring Epic approval, and the Coverage write scope.
Each function reads inputs from a declared source — caller capture, a conv.state value from a prior dip, a variant attribute, or ANI — calls conv.api.epic.<op>(...), and writes named results back to conv.state.
The moment Confirm/Find Physician resolves a provider, call conv.set_variant(specialty) and write provider / department / visit-type to conv.state so every downstream {{attr:…}}, slot search and write re-points.
Front every reason-for-visit with the customer-approved red-flag set; map reason→visit type via the Decision Tree; validate coverage with the payer before the Epic write; run the live benefit check after physician + variant. Keep clinical content as customer-owned configuration.
conv.api.pverify.* call is the integration to be wired in the pVerify pass. The Epic side (Coverage read + provisional write) is in-scope now; this node is drawn so the architecture is complete and the hook is unmistakable. It needs the rendering NPI + service type, which is why it runs after physician + variant \u2014 unlike the validation check.The reasoning behind each choice, so it holds up to clinical and technical review.
Surfaces that exist in the Epic ecosystem and could plausibly have been used here, with the reason each was set aside for this conversational, real-time, administrative use case. Confirm specifics against Epic_API_Documentation.md for a given instance.