PPolyAI×AthenaOne (athenahealth)
Scheduling · New-Patient Intake · Insurance · Prescriptions · Safety-Net

Voice scheduling on AthenaOne — intake, real-time insurance, and the clinical line drawn.

How PolyAI authenticates to AthenaOne, identifies or registers a patient, confirms or finds the physician, re-scopes its variant, validates and verifies insurance in real time for the appointment type, routes prescription refill requests to clinical pools, 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.

OAuth 2.0 · Client Credentials · Proprietary REST New-patient intake · Demographic match · Patient create Native eligibility check + pVerify seam (fallback) Variants re-scoped per provider Per-field data provenance Prescription refills · eligibility gate · clinical routing
Overview

Integration model

PolyAI runs as a backend client of AthenaOne's proprietary REST API. Unlike Epic (FHIR + private operations) or Cerner (standard FHIR R4), AthenaOne exposes a comprehensive proprietary REST API with over 800 endpoints, organised by practice ID. Patient reads, scheduling writes, insurance management, and clinical chart access all use the same RESTful pattern: /v1/{practiceid}/…. AthenaOne also has a native real-time eligibility check endpoint, reducing (but not eliminating) the need for the pVerify seam. Insurance is read from the patient record, confirmed with the caller, validated via the native eligibility endpoint or pVerify before any write, and (when valid) written back provisionally.

The canonical booking sequence

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.

Reason & Safety-Net → ID Patient → Read Coverage → Confirm Physician (→ Find Physician) → Update Variants → Confirm Insurance (validate → provisional write) → Real-Time Benefit Check → Slot Negotiation → Schedule → Playback.

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 before writing it to AthenaOne; the live benefit check then runs after physician + variant so the rendering NPI and the service-type (appointment type) are both present.

Request path

No component requires a human logged into AthenaOne — correct for inbound telephony. The agent operates strictly in the administrative lane (see Scope & Compliance).

Caller (PSTN / SIP)
TelephonyTwilio · Five9 · Genesys · Amazon Connect · NICE
RuntimePolyAI dialog runtime
Flows · functions (conv.api) · variants · conv.state · deterministic readback · safety-net
Auth + transportOAuth 2.0 Client Credentials (AthenaOne) · pVerify OAuth2 (seam / fallback)
DataAthenaOne REST API (/v1/{practiceid}/…) · Native Eligibility · pVerify 270/271 (fallback seam)

Surface used by these flows

Resolved against the AthenaOne API documentation. All endpoints are proprietary REST — AthenaOne does not use FHIR for its primary scheduling and patient management APIs. The “Native Eligibility” endpoint provides real-time 270/271 checks directly through AthenaOne, reducing pVerify dependency.

Resource / serviceOperationRole in flowsAvailability
Patient SearchGET /patientsPatient match / demographic searchREST API
Patient Search (broadened)GET /patientsFallback patient match — name + DOB onlyREST API
Patient (create)POST /patientsCreate provisional new-patient recordREST API
Patient InsuranceGET /patients/{id}/insurancesRead insurance on file (payer + member ID)REST API
Insurance Eligibility (native)GET /insurances/{id}/eligibilityReal-time eligibility verification (270/271)REST API
EligibilitySummary (pVerify fallback)POSTFallback real-time eligibility when native unavailablepVerify seam
Patient Insurance (create)POST /patients/{id}/insurancesProvisional patient-reported coverage writeREST API
Chart EncountersGET /chart/{id}/encountersRecent / historical providerREST API
ProvidersGET /providersResolve / find provider + NPIREST API
Patient AppointmentsGET /patients/{id}/appointmentsLocate existing appointmentREST API
Open Appointment SlotsGET /appointments/openFind available time slotsREST API
Appointment BookPUT /appointments/{id}Book appointment (fill open slot with patient)REST API
Appointment CancelPUT /appointments/{id}/cancelCancel appointmentREST API
Appointment ReschedulePUT /appointments/{id}/rescheduleReschedule appointmentREST API
Appointments BookedGET /appointments/bookedList booked appointments (confirm flow)REST API
Appointment Check-inPUT /appointments/{id}/checkinConfirm / check-in (confirmation flow)REST API
Chart MedicationsGET /chart/{id}/medicationsRetrieve active medications (refill flow)REST API
DepartmentsGET /departmentsResolve department / locationREST API
Appointment TypesGET /appointmenttypesList configured appointment typesREST API
User Message / Inbox TasksPOSTSubmit refill request to clinical inboxREST API
i
AthenaOne uses a proprietary REST API rather than FHIR for scheduling. Open slots are found via GET /appointments/open and booked via POST /appointments/{id}/book — a simpler, more direct model than Epic's $find/$book or Cerner's two-step Schedule+Slot pattern. Available slots change in real time; cache for no more than 5–10 minutes.

Where the platform earns its place

  • Deterministic readback — confirmed values (DOB, slot, provider, copay) are templated from conv.state, not regenerated.
  • Stateful data lineage — every API field is sourced explicitly: caller capture, conv.state from a prior dip, a deployment/variant attribute, or the telephony ANI.
  • Validated, real-time insurance — the plan is checked via AthenaOne's native eligibility endpoint (or pVerify as fallback) before it's written; the agent reports the payer's result, it never adjudicates.
  • Variants re-scoped per providerconv.set_variant() re-points persona, department and appointment-type defaults the moment the provider is resolved.
  • Administrative-only by design — the agent schedules and verifies; it does not triage. The Safety-Net removes emergencies from the automated path.

App registration

ApplicationPolyAI
Prod Client IDpolyai-prod-…
API versionv1 · Proprietary REST · Practice-scoped
Grantclient_credentials (secret or JWT-based)
Token endpointhttps://api.platform.athenahealth.com/oauth2/v1/token
Scopeathena/service/Athenanet.MDP.*
pVerify (fallback seam)OAuth2 client_credentials; when native eligibility insufficient
Scope & Compliance

Why intake & insurance are in scope — and where the clinical line is

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.

Operating principle

The agent performs administrative patient-access work. It does not assess symptoms, judge urgency, or decide what care a patient needs — and it never adjudicates coverage.

Identifying and registering patients, finding the right provider and appointment 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.

1 · The administrative / clinical line

The agent captures a reason-for-visit as an administrative label and maps it to a configured appointment type using the practice's own appointment-type configuration in AthenaOne. 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.

2 · Schmitt-Thompson: referenced, not executed

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.

3 · Why new-patient intake is permissible as an administrative function

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 duplicate-matching, creates a provisional record (verified by staff at check-in), resolves an in-network provider, and books an administratively-mapped appointment 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.

The test PolyAI applies: if a step requires clinical judgement about the patient's condition, it does not belong in the automated path. Routing by stated preference, referral, or administrative reason-code is in scope; deciding what is wrong with the patient, or how urgent it is, is out.

4 · Insurance verification — report, never adjudicate

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 before it is written, and even then is written provisional; the authoritative truth is set by the payer's response and staff verification, not by the agent.

5 · The Emergency Safety-Net — the controlling guardrail

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.

6 · Roles, ownership & sign-off

PolyAI provides the mechanics: the administrative flows, the reason→appointment-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 appointment-type configuration, and clinical governance.

!
This document states PolyAI's operating position and design rationale. It is not legal advice. Each deployment should be reviewed and signed off by the customer's counsel and clinical leadership before go-live, and the administrative/clinical boundary recorded in the SOW.
Interactive Call Flows

Branch logic, fallbacks, and the API at every node

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.

Use Case · Leakage Reduction

Booking a brand-new patient — intake, insurance, no triage

The high-value, higher-care flow. A caller with no record wants to be seen. The agent runs the Safety-Net, matches against existing records 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 before writing it, finds a provider accepting new patients, re-scopes its variant, verifies benefits live, and books a new-patient appointment type.

Why this differs from scheduling an existing patient

ConcernEstablished patientNew patient
RecordExists — resolve Patient IDMay not exist — demographic match, then create only on no-match
Duplicate riskLowHigh — ambiguous match → data-stewardship handoff, never auto-create/merge
InsuranceOn file → confirm, validate, update if changedNone on file → capture up front + validate before write (needed for in-network search)
ProviderConfirm the one they've seenNo history — directory search (specialty + location + accepting-new + network)
Appointment typeEstablished appointment typesNew-patient appointment types (longer; different codes)
Booking writePOST /appointments/{id}/bookPOST /appointments/{id}/book (same endpoint)
Three states, not two. “New to this provider but already in the system” is still an established record (skip create). “New to the health system” is the registration path. The demographic match tells them apart deterministically, before any write.
Voice Data-Capture Playbook

Handling the hard-to-capture data points

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.

API Reference

APIs by use case — cost, frequency & data source

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.

Badge Definitions

Every API card carries four badges. Here’s what each one means.

Platform

Which system handles the API call.

AthenaOneCall handled by the AthenaOne proprietary REST API server.
pVerifyCall leaves the EHR and hits pVerify, a third-party eligibility clearinghouse (fallback).

Class

The API tier within that platform.

REST APIStandard AthenaOne proprietary REST endpoint. Included with the athenahealth subscription. No per-call fees; no vendor-gated tier system.
ClearinghouseX12 270/271 transaction routed through pVerify. Separate vendor, separate contract.

Cost

How the API is priced at runtime.

IncludedIncluded with athenahealth subscription. No per-call fees. Cost does not scale with call volume.
Per-UsePer-transaction pricing (pVerify clearinghouse only).

Multiplier

Expected calls per patient conversation.

Called once per conversation.
1× fallbackCalled 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.

AthenaOne API Pricing Model

Unlike Epic (which uses a seven-tier Class A–G per-transaction model for Private APIs) or Cerner (which bundles everything under the Millennium Platform license), AthenaOne uses a subscription-based model where API access is included with the athenahealth service subscription.

No per-transaction fees for AthenaOne APIs. All endpoints — patient search, appointment booking, insurance management, clinical chart access — are included with the athenahealth subscription. The only per-use costs come from external integrations like pVerify clearinghouse transactions (when used as a fallback to the native eligibility check).
i
Native eligibility vs pVerify. AthenaOne provides a built-in real-time eligibility check via GET /insurances/{id}/eligibility that performs a 270/271 transaction natively. This reduces pVerify dependency to a fallback role — pVerify is only needed when the native check is insufficient (e.g., specific benefit detail not returned, non-EDI payer, or practice preference). This is a significant cost advantage over Epic and Cerner deployments.
Usage Estimator

Estimate API call volume from projected conversations

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.

Monthly Conversation Volume

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).

Completion Rate

What percentage of conversations complete the full flow (reach the final write/booking step)?

0% 100% 70%

Multi-Intent Rate

What percentage of callers complete more than one task per call?

0% 50% 15%

Estimated API Calls per Month

Enter conversation volumes above to see estimated API call counts.

How the estimator works

Flow-position decay. Not every caller reaches the end of the flow. The completion rate models a linear drop-off.
Multi-intent deduction. When a caller handles two tasks in one call, the agent identifies the patient once.
i
Note for AthenaOne. All AthenaOne REST API calls are Included — no per-call fees. The only Per-Use costs are pVerify clearinghouse transactions (fallback eligibility checks). Volume planning is primarily about capacity and rate limits, not transaction billing.
Authentication

OAuth 2.0 — Client Credentials

OAuth 2.0 client_credentials with either a client secret or a signed JWT assertion. No interactive login — correct for an inbound call where no clinician or patient can complete a browser consent. The same token serves all AthenaOne REST API calls. The pVerify eligibility seam (when used as fallback) uses its own OAuth2 token.

Token flow

Why client credentials — not patient or clinician OAuth

OAuth flowDesigned forVoice-suitable?Why
Client Credentials UseServer-to-server, no user presentYesClient ID + secret (or JWT); Agent Studio auto-refreshes the token.
Authorization Code NoUser-facing apps with browser redirectNoNeeds a browser consent screen — impossible on an inbound call.
Patient Portal NoPatient-facing portal appsNoNeeds patient portal credentials + browser consent.
Implementation

Wiring AthenaOne into PolyAI Agent Studio

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.

From integration request to live agent

1

Enable AthenaOne API access

Configure > Integrations > AthenaOne. Register the application via the athenahealth Marketplace / developer portal; production access requires athenahealth approval. Configure practice ID(s) and OAuth credentials. (pVerify provisioned separately as fallback.)

2

Define API operations

Configure > APIs: declare each endpoint with environment-specific base URLs and OAuth 2.0. All operations use the proprietary REST API — no FHIR or vendor-gated tiers. Configure insurance write and eligibility check endpoints.

3

Write data-dip functions with explicit lineage

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.athena.<op>(...), and writes named results back to conv.state.

4

Re-scope the variant on provider resolution

The moment Confirm/Find Physician resolves a provider, call conv.set_variant(specialty) and write provider / department / appointment-type to conv.state so every downstream {{attr:…}}, slot search and write re-points.

5

Wire the Safety-Net + eligibility

Front every reason-for-visit with the customer-approved red-flag set; map reason→appointment type via the configured type mapping; validate coverage via native eligibility (or pVerify fallback) before writing; run the live benefit check after physician + variant. Keep clinical content as customer-owned configuration.

Python New Patient Intake — demographic match, then create-on-no-match (with lineage)

new_patient_intake.py def new_patient_intake(conv, flow): # caller-captured this turn: name, dob; phone seeded from ANI r = conv.api.athena.patient_search(params={ "firstname": conv.state.first_name, # src: caller capture "lastname": conv.state.last_name, # src: caller capture "dob": conv.state.dob, # src: caller capture "homephone": conv.state.phone}) # src: ANI cands = r.json().get("patients", []) if r.status_code==200 else [] if not cands: # fallback: name + DOB only cands = _broadened_search(conv) grade = match_confidence(cands, conv) # strong / none / ambiguous if grade == "strong": conv.state.patient_id = cands[0]["patientid"] # → conv.state (stateful) return flow.goto_step("Verify Identity") if grade == "ambiguous": return conv.functions.handoff("data_stewardship") # never auto-create/merge reg = conv.api.athena.patient_create(json=_demographics(conv)) # provisional conv.state.patient_id = reg.json()["patientid"] # → conv.state flow.goto_step("Confirm Insurance")

Native Validate Coverage — AthenaOne native eligibility check (org NPI)

validate_coverage.py def validate_coverage(conv, flow): # runs BEFORE insurance write. Uses native AthenaOne eligibility. # Falls back to pVerify if native check insufficient. ins_id = conv.state.insurance_id res = conv.api.athena.insurance_eligibility( insurance_id=ins_id, params={"patientid": conv.state.patient_id}) if res.json().get("eligibilitystatus") == "Eligible": _write_provisional(conv, flow) # NOW the write is safe flow.goto_step("Next") elif res.json().get("eligibilitystatus") == "Ineligible": conv.say(_report_result(res)) conv.functions.handoff("billing") # no write else: # unknown / error → pVerify fallback _pverify_fallback(conv, flow)
i
Native eligibility advantage: AthenaOne performs 270/271 checks directly, so the pVerify seam serves as a fallback rather than the primary path. This reduces per-transaction costs compared to Epic and Cerner deployments where pVerify is always required.
Prescription Refills & Renewals

Refill requests, eligibility checks, and clinical pool routing

The agent checks the patient's active medications, computes remaining refills, verifies visit eligibility (12-month lookback), and routes the request to the appropriate clinical pool. Controlled substances require an in-person visit. The agent never dispenses, adjudicates, or overrides — it routes.

Prescription refill logic

ScenarioAgent actionAPI surface
Refills remaining on fileDirect caller to their pharmacy — no request submittedGET /chart/{id}/medications (read)
No refills remaining — visit within 12 monthsSubmit refill request to clinical poolPOST User Message / Inbox Task
No refills remaining — no visit in 12 monthsSchedule a visit and submit refill requestGET /appointments/open + POST /appointments/{id}/book + POST message
Controlled substanceSchedule in-person visit; submit request with HIGH priorityPOST /appointments/{id}/book + POST message (priority: urgent)
Clinical question about medicationTransfer to staffNo API — CC handoff
!
Authorized representative gate: because refill requests involve sharing medication details (PHI), the agent verifies the caller's identity before sharing any medication information. AthenaOne does not expose a dedicated RelatedPerson/authorized-representative endpoint via the REST API — representative verification relies on the practice's configured privacy rules and staff handoff when the caller is not the patient. [NEEDS VALIDATION] Confirm whether AthenaOne exposes guardian/proxy data via the patient record or a separate endpoint.

Remaining-refill calculation

refill_calc.py def remaining_refills(conv, patient_id): # Step 1: get active medications from the chart meds = conv.api.athena.chart_medications(patient_id=patient_id) med_list = meds.json().get("medications", []) # Step 2: for the selected medication, check refill info # AthenaOne returns refill data within the medication record selected = _find_medication(med_list, conv.state.medication_name) refills_remaining = selected.get("refillsallowed", 0) - selected.get("refillsfilled", 0) conv.state.refills_remaining = max(0, refills_remaining) return conv.state.refills_remaining
i
[NEEDS VALIDATION] The exact field names for refill count within AthenaOne's GET /chart/{id}/medications response should be confirmed against the current API documentation. The medication record structure may use different field names than shown above.
Additional Considerations

Choices we made — and the ones we deliberately did not

The reasoning behind each choice, so it holds up to clinical and technical review.

Roads not taken

API endpoints & interfaces we deliberately did not choose

Surfaces that exist in the AthenaOne ecosystem and could plausibly have been used here, with the reason each was set aside for this conversational, real-time, administrative use case.