
Implementation Guide: Auto-submit superbills to insurers on session completion
Step-by-step implementation guide for deploying AI to auto-submit superbills to insurers on session completion for Allied & Mental Health clients.
Hardware Procurement
Next-Generation Firewall / UTM Appliance
$250–$400 MSP distributor cost (Ingram Micro, D&H) / $500–$700 suggested resale including initial configuration
Provides NGFW with IDS/IPS, content filtering, SSL inspection, and site-to-site VPN for the practice network. Required for HIPAA Security Rule compliance — protects ePHI in transit between practice workstations and cloud-hosted EHR, clearinghouse, and payer portals. FortiGuard Security Services subscription adds threat intelligence, web filtering, and antivirus.
Next-Generation Firewall / UTM Appliance (Alternative)
$595–$800 MSP distributor cost / $900–$1,200 suggested resale with first-year Enterprise license
Cloud-managed alternative to FortiGate. Recommended if the practice already uses Meraki networking or if the MSP's RMM stack is Meraki-centric. Includes SD-WAN, content filtering, and Auto VPN. Annual license renewal provides ongoing MSP recurring revenue.
Wireless Access Point
$200–$350 MSP cost / $400–$550 suggested resale
VLAN-capable wireless access point for practice. Enables network segmentation: clinical devices on a secured VLAN, guest/patient Wi-Fi on an isolated VLAN. Managed centrally through the FortiGate.
Uninterruptible Power Supply
$180–$220 MSP cost / $280–$350 suggested resale with installation
Battery backup for firewall, network switch, and primary workstation. Ensures claim submissions in progress are not interrupted by power fluctuations. Provides 10–15 minutes of runtime for graceful shutdown or ride-through of brief outages.
Business Workstation
$500–$800 MSP cost per unit / $700–$1,100 suggested resale per unit
Modern business-class endpoint for front-desk billing staff. Must support TPM 2.0 for BitLocker full-disk encryption (HIPAA requirement). Only required if existing workstations are aging or lack TPM 2.0.
Managed Network Switch
$150–$250 MSP cost / $300–$400 suggested resale
8-port managed PoE switch for VLAN segmentation between clinical and administrative networks. Powers the FortiAP wirelessly. Managed through the FortiGate for unified security policy enforcement.
Software Procurement
SimplePractice Plus Plan (Primary EHR — Mental Health)
$99/month per provider. Additional providers at $59/month each. Claims at $0.25/claim. Client pays direct to SimplePractice.
All-in-one EHR, scheduling, telehealth, documentation, and insurance billing platform for mental health practices. The Plus plan includes electronic claim submission, ERA auto-posting, and superbill auto-generation. The built-in claims workflow handles the entire superbill→837P→clearinghouse→payer chain without external middleware.
TherapyNotes (Alternative EHR — Mental Health)
Solo: $69/month; Group: $79/month + $50/month per additional clinician. Claims at $0.14/claim, ERA at $0.14/claim. Client pays direct.
Strong alternative to SimplePractice with lower per-claim costs. After note completion, the To-Do list automatically creates a reminder to submit the electronic claim. Tighter integration of clinical notes with claim generation. Recommended when per-claim cost is a concern (high-volume practices).
Healthie Plus Plan (API-Enabled EHR — Allied Health / Custom Builds)
$129.99/month per provider (Plus plan). Group plans available at volume discounts. Client pays direct.
The only therapy/allied-health EHR with a full GraphQL API and webhook support. Required for Path B (custom integration) implementations. Webhooks fire on appointment status change, note signing, and other events — enabling automated claim submission through external middleware to any clearinghouse. Best choice for multi-disciplinary practices (dietitians, OTs, SLPs combined with therapists).
Kalix (Allied Health EHR — Dietitians, OTs, SLPs)
$30–$150/month depending on plan. Built-in clearinghouse at $15/month for unlimited claims. Client pays direct.
Purpose-built EHR for allied health professionals (registered dietitians, occupational therapists, speech-language pathologists). Includes built-in clearinghouse via Availity with unlimited claims and unlimited insurers. Simplest all-in-one option for non-mental-health allied practices.
Availity Essentials (Clearinghouse — Free Tier)
$0/month. Free for all providers. Widest payer connectivity (1M+ providers, $2.4T in claims/year).
Primary clearinghouse for claims submission and eligibility verification. Handles ANSI X12 837P formatting and routing to payers. Provides ERA (Electronic Remittance Advice) for payment reconciliation. Free tier is sufficient for most SMB practices. Used when the EHR's built-in clearinghouse does not support a required payer.
Stedi (API-First Clearinghouse — Custom Builds Only)
Free Basic plan with 100 free eligibility checks and claims/month. Paid plans from $2,000/month for higher volume. Client pays direct.
JSON-native, developer-friendly clearinghouse API. Required only for Path B custom integrations where the MSP is building direct API-to-clearinghouse pipelines. Provides real-time eligibility checks, claims submission, ERA retrieval, and payer enrollment via RESTful APIs. Not needed for Path A (native EHR auto-claim) implementations.
Keragon (HIPAA-Compliant Workflow Automation)
$99/month (billed annually). Higher tiers for more workflows. MSP can resell or client pays direct.
No-code healthcare automation middleware. Connects EHR webhooks (e.g., Healthie) to clearinghouse APIs (e.g., Stedi/Availity). Includes signed BAA, SOC 2 Type II compliance, encrypted data handling, and audit logging. Required only for Path B custom integrations. Not needed if using EHR's built-in auto-claim.
Microsoft 365 Business Premium
$22/user/month. MSP resells through CSP program at ~$18–$20/user cost. Suggested resale at $25–$30/user/month (bundled with management).
Provides Exchange Online email (HIPAA-compliant with BAA), Microsoft Intune MDM for endpoint management, Azure AD MFA, Microsoft Defender for Business endpoint protection, and Power Automate for workflow automation. Single platform covers email, device management, identity, and automation needs for the practice.
Huntress Managed EDR
$3–$5/endpoint/month MSP cost / $8–$12/endpoint suggested resale
Managed endpoint detection and response layered on top of Microsoft Defender. Provides 24/7 SOC monitoring, threat hunting, and incident response. Critical for HIPAA compliance — demonstrates active threat monitoring for endpoints handling ePHI.
Datto BCDR (or Axcient x360Recover)
$20–$50/device/month MSP cost / $40–$80/device suggested resale depending on retention and RTO requirements
HIPAA-compliant cloud backup with BAA. Backs up workstation configurations and any local data. AES-256 encryption at rest and in transit. Required for HIPAA Security Rule contingency planning requirements.
Cisco Umbrella (or DNSFilter)
$2–$4/user/month MSP cost / $5–$8/user suggested resale
DNS-layer security filtering. Blocks malicious domains, phishing sites, and command-and-control callbacks at the network layer. Additional security layer for endpoints accessing EHR and clearinghouse portals.
Prerequisites
- Business-class internet connection with minimum 25 Mbps down / 10 Mbps up and provider SLA (no residential connections)
- Practice must have a valid NPI (Type 1 for individual providers, Type 2 for group practice) registered with NPPES
- Each rendering provider must be credentialed and enrolled with target insurance payers (Aetna, BCBS, Cigna, UHC, etc.) — this is a clinical/administrative prerequisite, not an IT task
- Practice must have completed or be willing to complete payer ERA (Electronic Remittance Advice) and EFT (Electronic Funds Transfer) enrollment for each insurer — allow 2–6 weeks per payer
- Practice tax ID (EIN) and taxonomy codes must be current and match NPI registry entries exactly
- Signed Business Associate Agreements (BAAs) must be in place between the practice and: the MSP, the EHR vendor, the clearinghouse, and any middleware/automation platform
- HIPAA Security Risk Assessment must be completed (or scheduled) — this is a federal requirement and an MSP service opportunity
- All clinical staff must have individual EHR login credentials (no shared accounts) — HIPAA audit trail requirement
- Practice must have standardized clinical note templates that include required billing fields: session start/stop times, CPT code selection, ICD-10 diagnosis codes to highest specificity, and place of service
- Windows 10/11 Pro (for BitLocker) or macOS (for FileVault) on all endpoints — Windows Home editions cannot be used due to lack of BitLocker/GPO support
- TPM 2.0 chip required on all Windows workstations for BitLocker full-disk encryption
- Practice must designate a HIPAA Privacy Officer and Security Officer (can be the same person in small practices)
- If the practice treats substance use disorder (SUD) patients, a signed single TPO consent form compliant with 42 CFR Part 2 (updated February 2024) must be on file for each SUD patient before automated claim submission
Installation Steps
Step 1: Site Assessment and Security Baseline Audit
Perform an on-site or remote assessment of the practice's current IT environment. Document all existing hardware (workstations, network equipment, printers), software (current EHR, billing software, Office suite), internet connectivity, and security posture. Identify gaps against HIPAA Security Rule requirements. Catalog all insurance payers the practice bills to and verify ERA/EFT enrollment status for each. Review the last 90 days of claim submissions to identify rejection patterns and common errors.
# Run network scan to inventory all connected devices
nmap -sP 192.168.1.0/24 > practice_network_inventory.txt
# Check Windows endpoint encryption status (run on each workstation)
manage-bde -status C:- Navigate to https://www.ssllabs.com/ssltest/ from each workstation to verify TLS 1.2+ support
This step typically takes 2–4 hours on-site for a small practice. Use your MSP's standard HIPAA risk assessment template. Document findings in a formal report — this becomes the basis for the HIPAA Security Risk Assessment deliverable (billable at $1,500–$5,000). Pay special attention to any workstations running Windows Home editions or lacking TPM 2.0 — these must be upgraded or replaced.
Step 2: Network Infrastructure Deployment
Install and configure the HIPAA-compliant network infrastructure. Deploy the FortiGate 40F firewall (or Meraki MX67), configure VLANs for clinical vs. guest traffic, set up the FortiSwitch for wired connections, deploy the FortiAP for wireless, and connect the UPS. Configure firewall security policies: IDS/IPS enabled, SSL inspection for outbound traffic (with exceptions for EHR domains if certificate pinning is used), content filtering to block non-business categories, and DNS filtering.
config system interface
edit port1
set alias 'WAN'
set mode dhcp
set allowaccess ping https ssh
next
edit port2
set alias 'LAN-Clinical'
set ip 10.10.10.1 255.255.255.0
set allowaccess ping https ssh
set role lan
next
edit port3
set alias 'LAN-Guest'
set ip 10.10.20.1 255.255.255.0
set allowaccess ping
set role lan
next
end
# Enable IPS
config ips sensor
edit 'clinical-ips'
config entries
edit 1
set location server client
set severity high critical
set status enable
set action block
next
end
next
end
# Create VLAN for clinical network
config system dhcp server
edit 1
set interface port2
config ip-range
edit 1
set start-ip 10.10.10.100
set end-ip 10.10.10.200
next
end
set netmask 255.255.255.0
set gateway 10.10.10.1
set dns-server1 208.67.222.222
set dns-server2 208.67.220.220
next
end
# Configure firewall policy: Clinical LAN to Internet (HTTPS only to EHR/clearinghouse)
config firewall policy
edit 1
set name 'Clinical-to-Internet'
set srcintf port2
set dstintf port1
set srcaddr 'all'
set dstaddr 'all'
set action accept
set schedule 'always'
set service 'HTTPS' 'DNS'
set utm-status enable
set ips-sensor 'clinical-ips'
set ssl-ssh-profile 'certificate-inspection'
set av-profile 'default'
set webfilter-profile 'default'
set logtraffic all
set nat enable
next
endIf using Cisco Meraki MX67 instead, all configuration is done through the Meraki Dashboard (dashboard.meraki.com) — no CLI needed. Ensure the FortiGate firmware is updated to the latest stable release before configuring. Register the firewall with FortiCloud for remote management. Save the admin credentials in the MSP's password vault (e.g., IT Glue, Hudu). Configure SNMP or FortiCloud monitoring alerts to your RMM.
Step 3: Endpoint Hardening and MDM Enrollment
Secure all practice workstations per HIPAA requirements. Enable full-disk encryption (BitLocker on Windows, FileVault on macOS), enroll devices in Microsoft Intune MDM, enforce MFA on all user accounts, deploy Huntress EDR agent, and configure automatic OS and browser updates.
# Enable BitLocker via PowerShell (run as Administrator on each Windows workstation)
Enable-BitLocker -MountPoint 'C:' -EncryptionMethod XtsAes256 -UsedSpaceOnly -RecoveryPasswordProtector
# Get BitLocker recovery key and save to Azure AD
BackupToAAD-BitLockerKeyProtector -MountPoint 'C:' -KeyProtectorId ((Get-BitLockerVolume -MountPoint 'C:').KeyProtector | Where-Object {$_.KeyProtectorType -eq 'RecoveryPassword'}).KeyProtectorId
# Install Huntress agent (replace with your MSP's Huntress org key and account key)
# Download installer from Huntress dashboard
msiexec /i HuntressInstaller.msi ACCT_KEY="your_account_key" ORG_KEY="practice_name" /quiet
# Verify Huntress agent is running
Get-Service HuntressAgent | Select-Object Name, Status
# Configure Windows Update via PowerShell
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' -Name 'NoAutoUpdate' -Value 0
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' -Name 'AUOptions' -Value 4
# Enroll device in Intune (user will be prompted during next sign-in)
# Or push enrollment via Intune Autopilot if devices are new
Start-Process 'ms-device-enrollment:?mode=mdm'BitLocker recovery keys MUST be stored in Azure AD and in your MSP's documentation platform (IT Glue/Hudu). Never store recovery keys only on the local device. For macOS endpoints, enable FileVault via MDM profile in Intune. Configure Intune compliance policies to require encryption, require screen lock after 5 minutes, and block devices that fail compliance checks from accessing M365/EHR.
Step 4: Microsoft 365 Business Premium Configuration
Configure the practice's Microsoft 365 tenant for HIPAA compliance. Execute the Microsoft BAA (available in the M365 admin center under Settings > Org settings > Security & privacy), enable MFA for all users via Conditional Access, configure email encryption with Microsoft Purview, and set up Power Automate licenses for workflow automation if needed for Path B implementations.
# Connect to Microsoft 365 via PowerShell
Install-Module -Name Microsoft.Graph -Force
Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess','User.ReadWrite.All'
# Create Conditional Access policy requiring MFA for all users
$params = @{
displayName = 'Require MFA for all users'
state = 'enabled'
conditions = @{
users = @{ includeUsers = @('All') }
applications = @{ includeApplications = @('All') }
}
grantControls = @{
builtInControls = @('mfa')
operator = 'OR'
}
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $params- Navigate to: admin.microsoft.com > Settings > Org settings > Security & privacy > HIPAA BAA
- Accept the BAA and download a copy for records
The Microsoft HIPAA BAA is self-service in the M365 Admin Center — no sales call needed. Download a PDF copy and store it in the practice's compliance documentation. Ensure at least one break-glass admin account exists with MFA via hardware key (not SMS) in case of Authenticator app failures. Configure mail flow rules to auto-encrypt outbound emails containing PHI keywords.
Step 5: EHR Platform Selection and Account Setup
Based on the site assessment findings, select and set up the appropriate EHR platform. For most mental health solo/small group practices, SimplePractice Plus or TherapyNotes is recommended. For allied health (dietitians, OTs, SLPs), Kalix is recommended. For practices needing API customization, Healthie is the only viable option. Create the practice account, add all provider profiles with NPI, taxonomy codes, and credentials.
- SimplePractice signup: https://www.simplepractice.com/signup
- TherapyNotes signup: https://www.therapynotes.com/signup
- Healthie signup: https://www.gethealthie.com/signup
- Kalix signup: https://www.kalix.health/signup
If the practice already has an EHR, skip this step and proceed to Step 6 (configuring auto-claim within the existing platform). DO NOT migrate EHRs solely for this project unless the current platform cannot support electronic claims at all. EHR migration is a separate, larger project. For SimplePractice, the Plus plan ($99/mo) is required for insurance billing — Starter and Essential plans have limited claim functionality.
Step 6: Clearinghouse Enrollment and Payer Registration
Enroll the practice with the clearinghouse (built into most EHRs, or Availity/Office Ally for standalone). Then enroll each insurance payer for electronic claims submission (837P) and Electronic Remittance Advice (ERA/835). This is the longest step — individual payer enrollments can take 2–6 weeks. Start this step immediately and run it in parallel with other configuration work.
- For SimplePractice built-in clearinghouse: Navigate to: Settings > Insurance > Payer Setup
- Click 'Add Payer' and search by payer name or Payer ID
- Complete enrollment form for each payer (requires practice NPI, Tax ID, provider credentials)
- Submit ERA enrollment separately for each payer
- For Availity (standalone clearinghouse): Register at https://www.availity.com/Availity-Essentials-Registration
- Complete organization registration with NPI and Tax ID
- Add users and assign roles
- Submit payer-specific enrollment requests through Availity portal
Common Payer IDs for clearinghouse enrollment
ERA/EFT enrollment is separate from claims submission enrollment. The practice can submit claims electronically before ERA enrollment is complete, but will receive paper EOBs until ERA is active. Track each payer enrollment status in a spreadsheet — payers approve at different rates. Some payers (e.g., certain Medicaid MCOs) require additional credentialing steps. Confirm that the practice's NPI, Tax ID, and provider names match EXACTLY between the NPI registry (NPPES), the EHR, and the clearinghouse — mismatches are the #1 cause of enrollment rejections.
Step 7: Configure Superbill Templates and CPT/ICD-10 Code Libraries
Build standardized superbill templates in the EHR that auto-populate with the correct billing codes based on session type. Create CPT code favorites for the practice's most common services and ICD-10 diagnosis code favorites. Configure session-type-to-CPT-code mappings so clinicians only need to select the session type and the correct billing code is pre-populated.
90791 - Psychiatric Diagnostic Evaluation (intake, no medical services)
90792 - Psychiatric Diagnostic Evaluation WITH Medical Services (psychiatrists only)
90832 - Psychotherapy, 16-37 minutes
90834 - Psychotherapy, 38-52 minutes (most common)
90837 - Psychotherapy, 53+ minutes
90846 - Family psychotherapy without patient present
90847 - Family psychotherapy with patient present
90853 - Group psychotherapy
90785 - Interactive complexity add-on (use with 90832/90834/90837)
90839 - Psychotherapy for crisis, first 60 minutes
90840 - Psychotherapy for crisis, each additional 30 minutesModifier 95 - Synchronous audio-video telehealth
Modifier 93 or FQ - Audio-only telehealth
Place of Service 10 - Telehealth (patient at home)
Place of Service 02 - Telehealth (patient at qualifying facility)
Place of Service 11 - Office (in-person)97530 - Therapeutic activities (OT)
97110 - Therapeutic exercises (PT/OT)
92507 - Speech therapy treatment
97802 - Medical nutrition therapy initial (RD)
97803 - Medical nutrition therapy reassessment (RD)F41.1 - Generalized anxiety disorder
F41.0 - Panic disorder
F32.0 - Major depressive disorder, single episode, mild
F32.1 - Major depressive disorder, single episode, moderate
F33.0 - Major depressive disorder, recurrent, mild
F33.1 - Major depressive disorder, recurrent, moderate
F43.10 - Post-traumatic stress disorder, unspecified
F43.23 - Adjustment disorder with mixed anxiety and depressed mood
F90.0 - ADHD, predominantly inattentive type
F90.1 - ADHD, predominantly hyperactive type
F90.2 - ADHD, combined typeICD-10 codes must be coded to the highest level of specificity. F41 (anxiety disorder, unspecified) will be rejected by most payers — F41.1 (generalized anxiety disorder) is required. Work with the lead clinician to build the practice's top 20 diagnosis codes into favorites. For CPT 90834 vs 90837: the session must be documented with start and stop times. 90834 covers 38–52 minutes of psychotherapy; 90837 requires 53+ minutes. Incorrect time documentation is a top audit trigger. Configure the EHR note template to require start/stop time fields before the note can be signed.
Step 8: Enable Auto-Claim Generation on Note Signing
Configure the EHR to automatically generate and queue an insurance claim when a clinician signs/completes their session note. This is the core automation step. In most EHRs, this is a settings toggle or workflow rule — not custom code. The goal is: clinician signs note → system validates required fields → superbill auto-generates → claim auto-queues for submission → claim submits to clearinghouse within minutes or on the next batch cycle.
- SimplePractice Configuration — Step 1: Navigate to Settings > Billing > Insurance
- SimplePractice Configuration — Step 2: Under 'Claim Defaults', configure: Default Place of Service: 11 (Office) or 10 (Telehealth); Auto-generate claim when appointment is completed: ENABLE; Default billing provider for each clinician
- SimplePractice Configuration — Step 3: Under each Appointment Type, map to the corresponding CPT code
- SimplePractice Configuration — Step 4: Navigate to Settings > Billing > Clearinghouse
- SimplePractice Configuration — Step 5: Verify clearinghouse enrollment status shows 'Active' for each payer
- SimplePractice Configuration — Step 6: Under 'Claim Submission', set to 'Auto-submit' (if available) or 'Queue for batch'
- TherapyNotes Configuration — Step 1: Navigate to Billing & Insurance settings
- TherapyNotes Configuration — Step 2: Under 'Electronic Claims', enable electronic claim submission
- TherapyNotes Configuration — Step 3: Configure To-Do list notifications: after note is signed, auto-generate claim task
- TherapyNotes Configuration — Step 4: Set batch submission schedule (daily at 6 PM recommended)
- TherapyNotes Configuration — Step 5: Configure ERA auto-posting: Settings > ERA/EFT > Enable auto-posting
- Healthie Configuration (API Path) — Step 1: Navigate to Settings > Integrations > Webhooks
- Healthie Configuration (API Path) — Step 2: Create webhook for event: 'appointment.completed'
- Healthie Configuration (API Path) — Step 3: Set webhook URL to your Keragon workflow endpoint
- Healthie Configuration (API Path) — Step 4: See Custom AI Components section for the webhook handler specification
- TheraPlatform Configuration — Step 1: Navigate to Settings > Billing > Automation
- TheraPlatform Configuration — Step 2: Enable 'Automatically generate claims after session notes are signed'
- TheraPlatform Configuration — Step 3: Set submission method to 'Electronic'
- TheraPlatform Configuration — Step 4: Configure batch schedule or real-time submission
IMPORTANT: The auto-claim feature does NOT mean claims submit without any human review. Best practice is a 'generate and queue' model: claims are auto-generated when notes are signed, then a billing staff member reviews the queue once daily (5–10 minutes) before batch submission. This catches obvious errors (wrong CPT code, missing modifier) before they reach the payer. Configure the EHR to flag claims that fail validation rules (missing diagnosis, missing authorization number, etc.) and hold them for review rather than auto-submitting bad claims. SimplePractice and TheraPlatform support near-real-time auto-submission; TherapyNotes uses a batch model with manual review step.
Step 9: Configure ERA Auto-Posting and Denial Alerts
Set up Electronic Remittance Advice (ERA/835) auto-posting so that when insurance payments are received, they automatically post to the correct patient account in the EHR. Configure denial alerts so that rejected or denied claims trigger immediate notifications to billing staff for follow-up. This closes the revenue cycle loop.
SimplePractice ERA Configuration
TherapyNotes ERA Configuration
Daily Claims Monitoring Checklist
Common ERA denial reason codes to train staff on: CO-4 (procedure code inconsistent with modifier), CO-16 (claim lacks information), CO-29 (timely filing limit exceeded), CO-197 (precertification/authorization required), PR-1 (deductible), PR-2 (coinsurance), PR-3 (co-payment). If auto-posting is not available in the EHR tier, ERA files can be downloaded from the clearinghouse portal and manually imported. Auto-posting saves the billing team 30–60 minutes per day in a 5-provider practice.
Step 10: 42 CFR Part 2 Consent Verification Workflow (SUD Patients)
If the practice treats any substance use disorder (SUD) patients, configure a consent verification checkpoint in the claim submission workflow. Under the updated 42 CFR Part 2 (effective April 2024, compliance required by February 2026), a single TPO consent allows claims to flow through the normal pipeline. However, the system must verify that consent is on file before submitting claims containing SUD diagnosis codes.
- In the EHR, create a custom field or tag for SUD patients with field name: 'Part 2 TPO Consent Status' and options: 'Consent on File' / 'Consent Pending' / 'No Consent'
- SimplePractice: Use client tags or custom notes field
- TherapyNotes: Use client alerts or custom demographic field
- Healthie: Use custom form fields (accessible via API for automated checks)
- Document the consent in the patient record with: date consent was signed, scope (Treatment, Payment, and Healthcare Operations / TPO), expiration date (if any), and patient signature confirmation
# Configure a billing workflow rule:
# IF diagnosis code starts with F10-F19 (substance-related disorders)
# AND 'Part 2 TPO Consent Status' != 'Consent on File'
# THEN hold claim for manual review (do not auto-submit)The 2024 update to 42 CFR Part 2 significantly simplified consent management. A single consent for all TPO now covers claims submission, and Part 2 records no longer need to be segregated. However, if a patient has NOT signed a TPO consent, submitting a claim with SUD diagnosis codes is a federal violation. The hold-for-review workflow is a critical safety net. Not all practices treat SUD — if the practice does not, this step can be abbreviated to awareness training only.
Step 11: End-to-End Testing with Live Test Claims
Submit test claims through the complete pipeline to verify the automation works correctly. Start with a single payer (the practice's most common insurer), submit 3–5 test claims, verify receipt at the clearinghouse, monitor for acceptance/rejection, and verify ERA posting when payments arrive. Then expand to all enrolled payers.
Test claims are REAL claims submitted for REAL patient encounters — there is no 'sandbox' mode with most clearinghouses for production payer enrollment. Coordinate with the practice to identify 3–5 upcoming sessions to use as test cases. The intentional error test (Test 5) is critical: it verifies that the validation layer catches problems before they reach the payer. If bad claims pass through validation, tighten the EHR's required-fields configuration. Allow 2–3 weeks for the full test cycle (claim submission through ERA receipt).
Step 12: Staff Training and Workflow Documentation
Train all clinical and administrative staff on the new automated billing workflow. Clinicians must understand that signing their note now directly triggers a billing event — note quality and completeness are no longer just clinical concerns, they are revenue cycle events. Administrative/billing staff must understand the claim queue review process, denial management, and exception handling.
- No CLI commands — this is a training delivery step
Training Agenda (90-minute session)
Module 1: For Clinicians (45 minutes)
- How note signing triggers auto-claim generation
- Required fields that MUST be completed before signing: Session start and stop times (mandatory for 90832/90834/90837), CPT code selection (correct session duration mapping), ICD-10 diagnosis code (to highest specificity), Place of service (office vs telehealth), Telehealth modifiers (95 for video, FQ for audio-only)
- Common mistakes that cause claim rejections
- Timeline: notes should be signed within 24 hours of session
Module 2: For Billing Staff (45 minutes)
- Daily claim queue review process (10-minute morning routine)
- How to spot and fix common claim errors before submission
- Denial notification workflow and escalation
- ERA auto-posting verification
- Secondary claim submission process
- Patient responsibility collection workflow
- Monthly reconciliation report generation
Create a laminated quick-reference card for each clinician's desk/workspace with: (1) CPT code cheat sheet with time requirements, (2) top 10 ICD-10 codes for the practice, (3) telehealth modifier guide, (4) place-of-service code reference. Leave this physical artifact with the practice. Also create a 1-page 'What to do when a claim is denied' flowchart for billing staff. Schedule a 30-minute follow-up training session 2 weeks after go-live to address questions that arise from real-world use.
Custom AI Components
Healthie Webhook Claim Submission Workflow
Type: workflow
A deterministic automation workflow that triggers when a session note is signed in Healthie (via webhook), extracts the billing-relevant data via the Healthie GraphQL API, validates all required fields, formats the data for clearinghouse submission, and posts the claim to Stedi's Claims API (or routes to Availity). This component is ONLY needed for Path B implementations using Healthie as the EHR. Practices using SimplePractice, TherapyNotes, TheraPlatform, or Kalix should use the built-in auto-claim features instead.
Implementation:
# Healthie Webhook → Claim Submission Workflow
# Platform: Keragon (recommended) or Microsoft Power Automate
# Trigger: Healthie webhook event 'appointment.completed'Architecture
- Healthie Webhook (appointment.completed)
- → Keragon Workflow Engine
- → Step 1: Parse webhook payload, extract appointment_id
- → Step 2: Query Healthie GraphQL API for full appointment + patient + provider data
- → Step 3: Validate all required claim fields (fail-fast with alert if incomplete)
- → Step 4: Check 42 CFR Part 2 consent status (if SUD diagnosis)
- → Step 5: Map data to X12 837P field structure
- → Step 6: POST to Stedi Claims API (or format EDI for Availity)
- → Step 7: Log submission result and notify billing staff
Step 1: Healthie Webhook Configuration
Step 2: Healthie GraphQL Query (executed by Keragon HTTP node)
query GetAppointmentBillingData($appointmentId: ID!) {
appointment(id: $appointmentId) {
id
date
actual_duration
appointment_type {
name
cpt_code {
code
description
}
}
provider {
id
full_name
npi_number
tax_id
taxonomy_code
qualification
}
client {
id
first_name
last_name
date_of_birth
gender
address {
line1
line2
city
state
zip
}
insurance_authorizations {
id
authorization_number
insurance_plan {
payer_name
payer_id
member_id
group_number
plan_name
subscriber {
first_name
last_name
date_of_birth
relationship_to_patient
}
}
}
}
form_answer_groups {
form_answers {
label
answer
}
}
cpt_code {
code
description
}
icd_codes {
code
description
}
place_of_service {
code
name
}
modifiers
}
}Step 3: Validation Rules (Keragon conditional logic or custom function)
// all fields must pass before claim submission
// Validation function — all fields must pass before claim submission
function validateClaimData(appointment) {
const errors = [];
// Provider validation
if (!appointment.provider.npi_number) errors.push('Missing provider NPI');
if (!appointment.provider.tax_id) errors.push('Missing provider Tax ID');
// Patient validation
if (!appointment.client.first_name) errors.push('Missing patient first name');
if (!appointment.client.last_name) errors.push('Missing patient last name');
if (!appointment.client.date_of_birth) errors.push('Missing patient DOB');
// Insurance validation
const insurance = appointment.client.insurance_authorizations?.[0]?.insurance_plan;
if (!insurance) errors.push('No insurance plan on file');
if (!insurance?.member_id) errors.push('Missing insurance member ID');
if (!insurance?.payer_id) errors.push('Missing payer ID');
// Clinical validation
if (!appointment.cpt_code?.code) errors.push('Missing CPT code');
if (!appointment.icd_codes?.length) errors.push('Missing ICD-10 diagnosis code');
if (!appointment.place_of_service?.code) errors.push('Missing place of service');
// ICD-10 specificity check
appointment.icd_codes?.forEach(icd => {
if (icd.code.length < 4) {
errors.push(`ICD-10 code ${icd.code} lacks specificity — must be 4+ characters`);
}
});
// Time validation for time-based CPT codes
const timeBasedCodes = ['90832', '90834', '90837'];
if (timeBasedCodes.includes(appointment.cpt_code?.code)) {
if (!appointment.actual_duration) {
errors.push('Session duration required for time-based CPT code');
}
// Validate duration matches CPT code
const duration = appointment.actual_duration;
const cpt = appointment.cpt_code.code;
if (cpt === '90832' && (duration < 16 || duration > 37)) {
errors.push(`Duration ${duration}min does not match CPT 90832 (16-37 min)`);
}
if (cpt === '90834' && (duration < 38 || duration > 52)) {
errors.push(`Duration ${duration}min does not match CPT 90834 (38-52 min)`);
}
if (cpt === '90837' && duration < 53) {
errors.push(`Duration ${duration}min does not match CPT 90837 (53+ min)`);
}
}
return { isValid: errors.length === 0, errors };
}Step 4: 42 CFR Part 2 Consent Check
// evaluates SUD diagnosis codes and validates consent status before claim
// submission
// Check if any diagnosis codes are SUD-related (F10-F19)
function requiresPart2Consent(icdCodes) {
const sudRange = /^F1[0-9]/;
return icdCodes.some(icd => sudRange.test(icd.code));
}
// If SUD diagnosis, check consent status via Healthie custom field
// If consent not on file, HOLD claim and alert billing staff
if (requiresPart2Consent(appointment.icd_codes)) {
const consentStatus = appointment.client.form_answer_groups
?.find(g => g.form_answers.some(a => a.label === 'Part 2 TPO Consent Status'))
?.form_answers.find(a => a.label === 'Part 2 TPO Consent Status')?.answer;
if (consentStatus !== 'Consent on File') {
// HALT workflow — send alert, do not submit claim
return { action: 'HOLD', reason: '42 CFR Part 2 consent not confirmed for SUD patient' };
}
}Step 5 & 6: Submit to Stedi Claims API
// Map to Stedi Professional Claims (837P) format
const claimPayload = {
"tradingPartnerServiceId": insurance.payer_id,
"submitter": {
"organizationName": "Practice Name",
"contactInformation": {
"name": "Billing Department",
"phoneNumber": "5551234567"
}
},
"receiver": {
"organizationName": insurance.payer_name
},
"billing": {
"providerTaxId": appointment.provider.tax_id,
"npi": appointment.provider.npi_number,
"taxonomyCode": appointment.provider.taxonomy_code,
"providerName": {
"lastName": appointment.provider.full_name.split(' ').pop(),
"firstName": appointment.provider.full_name.split(' ')[0]
},
"address": {
"address1": "123 Practice St",
"city": "Anytown",
"state": "CA",
"zip": "90210"
}
},
"subscriber": {
"memberId": insurance.member_id,
"groupNumber": insurance.group_number,
"firstName": insurance.subscriber.first_name,
"lastName": insurance.subscriber.last_name,
"dateOfBirth": insurance.subscriber.date_of_birth,
"payerResponsibility": "primary"
},
"patient": {
"firstName": appointment.client.first_name,
"lastName": appointment.client.last_name,
"dateOfBirth": appointment.client.date_of_birth,
"gender": appointment.client.gender,
"address": {
"address1": appointment.client.address.line1,
"city": appointment.client.address.city,
"state": appointment.client.address.state,
"zip": appointment.client.address.zip
},
"relationshipToSubscriber": insurance.subscriber.relationship_to_patient
},
"claimInformation": {
"placeOfService": appointment.place_of_service.code,
"diagnosisCodes": appointment.icd_codes.map((icd, i) => ({
"code": icd.code,
"type": i === 0 ? "principal" : "other"
})),
"serviceLines": [{
"procedureCode": appointment.cpt_code.code,
"modifiers": appointment.modifiers || [],
"chargeAmount": getChargeAmount(appointment.cpt_code.code),
"units": 1,
"serviceDate": appointment.date,
"diagnosisPointers": ["1"]
}]
}
};
// POST to Stedi Claims API
const response = await fetch('https://healthcare.stedi.com/2024-04-01/claims', {
method: 'POST',
headers: {
'Authorization': `Bearer ${STEDI_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(claimPayload)
});
const result = await response.json();
console.log('Claim submission result:', result);Step 7: Logging and Notification
// Log to audit trail (Keragon provides built-in audit logging)
const logEntry = {
timestamp: new Date().toISOString(),
appointmentId: appointment.id,
patientId: appointment.client.id,
providerId: appointment.provider.id,
cptCode: appointment.cpt_code.code,
payerId: insurance.payer_id,
claimStatus: result.status,
claimId: result.claimId,
errors: result.errors || []
};
// Send notification based on result
if (result.status === 'accepted') {
// Send success summary to billing staff (daily digest recommended)
sendEmail({
to: 'billing@practice.com',
subject: `Claim Submitted: ${appointment.client.last_name} - ${appointment.date}`,
body: `Claim ${result.claimId} submitted successfully for ${appointment.cpt_code.code}.`
});
} else {
// Send immediate alert for failures
sendEmail({
to: 'billing@practice.com',
subject: `CLAIM ERROR: ${appointment.client.last_name} - ${appointment.date}`,
body: `Claim submission failed. Errors: ${result.errors.join(', ')}. Manual review required.`
});
}Keragon Workflow Configuration (No-Code Alternative)
If implementing in Keragon's no-code builder instead of custom code:
Claims Rejection Monitor and Alert Dashboard
Type: workflow
A daily automated workflow that queries the clearinghouse for claim status updates (277CA responses and 835 ERA responses), identifies rejected or denied claims, categorizes them by denial reason code, and sends a morning summary report to the billing team. This is a deterministic monitoring workflow that runs on a scheduled timer, not triggered by user action.
Implementation:
# Claims Rejection Monitor — Daily Scheduled Workflow
# Platform: Microsoft Power Automate (if using M365) or Keragon
# Schedule: Daily at 7:00 AM local timePower Automate Flow Definition
Trigger
- Type: Recurrence
- Frequency: Day
- Interval: 1
- Start time: 07:00 AM
- Time zone: Practice local time
Flow Steps
Step 1: Query Clearinghouse for Claim Status Updates
GET https://healthcare.stedi.com/2024-04-01/claim-responses
Headers:
Authorization: Bearer {STEDI_API_KEY}
Query Parameters:
updatedSince: {yesterday_date}T00:00:00Z
status: rejected,deniedStep 2: Parse and Categorize Rejections
// Categorize by denial reason for actionable reporting
const categories = {
'eligibility': [], // Patient not covered
'authorization': [], // Missing prior auth
'coding': [], // CPT/ICD mismatch, modifier issues
'data_quality': [], // Missing or invalid data fields
'timely_filing': [], // Past filing deadline
'duplicate': [], // Duplicate claim
'other': []
};
const reasonCodeMap = {
'1': 'eligibility', // Deductible
'2': 'eligibility', // Coinsurance
'3': 'eligibility', // Co-pay
'4': 'coding', // Procedure code inconsistent with modifier
'16': 'data_quality', // Claim lacks information
'18': 'duplicate', // Exact duplicate
'27': 'coding', // Expenses not covered
'29': 'timely_filing', // Filing limit exceeded
'50': 'data_quality', // Non-covered service
'96': 'data_quality', // Non-covered charge
'197': 'authorization' // Precertification required
};
rejectedClaims.forEach(claim => {
const category = reasonCodeMap[claim.reasonCode] || 'other';
categories[category].push({
claimId: claim.id,
patientName: claim.patientName,
dateOfService: claim.serviceDate,
cptCode: claim.procedureCode,
payerName: claim.payerName,
reasonCode: claim.reasonCode,
reasonDescription: claim.reasonDescription,
amount: claim.chargeAmount
});
});Step 3: Generate HTML Email Report
<h2>Daily Claims Status Report — {{currentDate}}</h2>
<h3>Summary</h3>
<table border='1' cellpadding='5'>
<tr><td><strong>Total Claims Submitted (yesterday)</strong></td><td>{{totalSubmitted}}</td></tr>
<tr><td><strong>Accepted</strong></td><td style='color:green'>{{totalAccepted}}</td></tr>
<tr><td><strong>Rejected/Denied</strong></td><td style='color:red'>{{totalRejected}}</td></tr>
<tr><td><strong>Clean Claim Rate</strong></td><td>{{cleanClaimRate}}%</td></tr>
<tr><td><strong>Total $ at Risk (rejected)</strong></td><td>${{totalAtRisk}}</td></tr>
</table>
<h3>Rejected Claims Requiring Action</h3>
{{#each categories}}
{{#if this.length}}
<h4>{{@key}} ({{this.length}} claims)</h4>
<table border='1' cellpadding='5'>
<tr><th>Patient</th><th>DOS</th><th>CPT</th><th>Payer</th><th>Reason</th><th>Amount</th></tr>
{{#each this}}
<tr>
<td>{{patientName}}</td>
<td>{{dateOfService}}</td>
<td>{{cptCode}}</td>
<td>{{payerName}}</td>
<td>{{reasonCode}}: {{reasonDescription}}</td>
<td>${{amount}}</td>
</tr>
{{/each}}
</table>
{{/if}}
{{/each}}
<h3>Action Required</h3>
<ul>
<li><strong>Coding errors:</strong> Review and correct CPT/ICD codes, resubmit within 24 hours</li>
<li><strong>Data quality:</strong> Check patient demographics and insurance info, correct and resubmit</li>
<li><strong>Authorization:</strong> Contact payer for retroactive authorization or appeal</li>
<li><strong>Eligibility:</strong> Verify patient coverage, consider secondary insurance or patient billing</li>
</ul>Step 4: Send Report
- To: billing@practice.com, practiceowner@practice.com
- CC: msp-healthcare-team@mspcompany.com (for MSP monitoring)
- Subject: "Daily Claims Report — {{currentDate}} — {{totalRejected}} claims need attention"
Step 5: Log Metrics for Monthly Trending
// Append to SharePoint list or Excel Online for monthly KPI tracking
const monthlyMetrics = {
date: currentDate,
totalSubmitted: totalSubmitted,
totalAccepted: totalAccepted,
totalRejected: totalRejected,
cleanClaimRate: cleanClaimRate,
totalRevenueSubmitted: totalRevenue,
totalRevenueAtRisk: totalAtRisk,
topDenialReason: getTopDenialReason(categories)
};
// Write to SharePoint list via Power Automate connectorKPI Targets
- Clean claim rate: >95% (industry benchmark)
- Average days to claim submission: <1 day (from session completion)
- Denial follow-up time: <48 hours
- Timely filing denials: 0 (auto-submission eliminates this category)
Superbill Field Completeness Validator
Type: integration
A real-time validation layer that runs within the EHR's note-signing workflow (or as a middleware check in Path B). Before any claim is generated, this validator checks that all 14 required superbill fields are present and correctly formatted. It prevents incomplete or malformed claims from entering the submission pipeline, directly improving the practice's clean claim rate.
Implementation:
# validation step before claim generation
# Superbill Field Completeness Validator
# This runs as a validation step BEFORE claim generation
# Implementation: JavaScript function in Keragon, or Power Automate expression setRequired Fields Specification (ANSI X12 837P)
const REQUIRED_FIELDS = [
{
field: 'provider.npi',
label: 'Rendering Provider NPI',
validate: (val) => /^\d{10}$/.test(val),
errorMsg: 'NPI must be exactly 10 digits'
},
{
field: 'provider.taxId',
label: 'Provider/Practice Tax ID (EIN)',
validate: (val) => /^\d{9}$/.test(val?.replace('-', '')),
errorMsg: 'Tax ID must be 9 digits (EIN format)'
},
{
field: 'provider.taxonomyCode',
label: 'Provider Taxonomy Code',
validate: (val) => /^\d{10}X$/.test(val),
errorMsg: 'Taxonomy code must be 10 digits followed by X'
},
{
field: 'patient.firstName',
label: 'Patient First Name',
validate: (val) => val && val.trim().length > 0,
errorMsg: 'Patient first name is required'
},
{
field: 'patient.lastName',
label: 'Patient Last Name',
validate: (val) => val && val.trim().length > 0,
errorMsg: 'Patient last name is required'
},
{
field: 'patient.dateOfBirth',
label: 'Patient Date of Birth',
validate: (val) => /^\d{4}-\d{2}-\d{2}$/.test(val) && new Date(val) < new Date(),
errorMsg: 'Valid DOB in YYYY-MM-DD format required'
},
{
field: 'insurance.memberId',
label: 'Insurance Member ID',
validate: (val) => val && val.trim().length >= 3,
errorMsg: 'Insurance member ID is required'
},
{
field: 'insurance.payerId',
label: 'Payer ID',
validate: (val) => val && val.trim().length >= 3,
errorMsg: 'Payer ID is required for electronic submission'
},
{
field: 'service.dateOfService',
label: 'Date of Service',
validate: (val) => /^\d{4}-\d{2}-\d{2}$/.test(val),
errorMsg: 'Date of service in YYYY-MM-DD format required'
},
{
field: 'service.cptCode',
label: 'CPT Procedure Code',
validate: (val) => /^\d{5}$/.test(val),
errorMsg: 'CPT code must be exactly 5 digits'
},
{
field: 'service.diagnosisCodes',
label: 'ICD-10 Diagnosis Code(s)',
validate: (val) => {
if (!Array.isArray(val) || val.length === 0) return false;
// Check specificity: minimum 4 characters (letter + 2 digits + dot or more)
return val.every(code => /^[A-Z]\d{2}\.\d{1,4}$/.test(code));
},
errorMsg: 'At least one ICD-10 code required, coded to highest specificity (e.g., F41.1, not F41)'
},
{
field: 'service.placeOfService',
label: 'Place of Service Code',
validate: (val) => ['02', '10', '11', '12', '20', '22', '49', '50', '53', '71', '72'].includes(val),
errorMsg: 'Valid place of service code required (common: 11=Office, 10=Telehealth Home, 02=Telehealth Facility)'
},
{
field: 'service.chargeAmount',
label: 'Charge Amount',
validate: (val) => typeof val === 'number' && val > 0,
errorMsg: 'Charge amount must be a positive number'
},
{
field: 'service.units',
label: 'Service Units',
validate: (val) => Number.isInteger(val) && val > 0,
errorMsg: 'Service units must be a positive integer (typically 1 for psychotherapy)'
}
];// CPT-to-duration cross-validation
const CPT_DURATION_RULES = {
'90832': { min: 16, max: 37, label: '16-37 minute psychotherapy' },
'90834': { min: 38, max: 52, label: '38-52 minute psychotherapy' },
'90837': { min: 53, max: 120, label: '53+ minute psychotherapy' }
};// Telehealth modifier validation
const TELEHEALTH_RULES = {
'10': { requiredModifiers: ['95', '93', 'FQ', 'GT'], label: 'Telehealth POS requires telehealth modifier' },
'02': { requiredModifiers: ['95', '93', 'FQ', 'GT'], label: 'Telehealth POS requires telehealth modifier' },
'11': { forbiddenModifiers: ['95', '93', 'FQ'], label: 'In-office POS should not have telehealth modifier' }
};function validateSuperbill(claimData) {
const results = { valid: true, errors: [], warnings: [] };
// Check each required field
REQUIRED_FIELDS.forEach(rule => {
const value = getNestedValue(claimData, rule.field);
if (!rule.validate(value)) {
results.valid = false;
results.errors.push({ field: rule.field, label: rule.label, message: rule.errorMsg, value: value });
}
});
// CPT-duration cross-validation
const cpt = claimData.service?.cptCode;
const duration = claimData.service?.duration;
if (CPT_DURATION_RULES[cpt] && duration) {
const rule = CPT_DURATION_RULES[cpt];
if (duration < rule.min || duration > rule.max) {
results.warnings.push({
field: 'service.duration',
message: `Duration ${duration}min may not match CPT ${cpt} (${rule.label}). Verify documentation.`
});
}
}
// Telehealth modifier validation
const pos = claimData.service?.placeOfService;
const modifiers = claimData.service?.modifiers || [];
if (TELEHEALTH_RULES[pos]) {
const rule = TELEHEALTH_RULES[pos];
if (rule.requiredModifiers) {
const hasRequired = modifiers.some(m => rule.requiredModifiers.includes(m));
if (!hasRequired) {
results.valid = false;
results.errors.push({ field: 'service.modifiers', message: rule.label });
}
}
if (rule.forbiddenModifiers) {
const hasForbidden = modifiers.some(m => rule.forbiddenModifiers.includes(m));
if (hasForbidden) {
results.warnings.push({ field: 'service.modifiers', message: rule.label });
}
}
}
return results;
}
// Helper: access nested object properties by dot-notation path
function getNestedValue(obj, path) {
return path.split('.').reduce((current, key) => current?.[key], obj);
}Integration Points
- Path A (Built-in EHR): This logic is handled natively by the EHR's claim validation engine. The MSP's role is to configure required fields in the EHR note templates so clinicians cannot sign incomplete notes.
- Path B (Custom API): Deploy this as a Keragon function node between the Healthie data extraction step and the Stedi claim submission step. Claims that fail validation are routed to an error queue and the billing team is alerted immediately.
Payer Enrollment Status Tracker
Type: workflow
A tracking workflow that monitors the status of ERA/EFT enrollment for each insurance payer. During initial setup, payer enrollments are the longest lead-time item (2–6 weeks per payer). This tracker ensures no payer falls through the cracks and provides visibility to both the MSP team and the practice's billing staff.
Implementation
SharePoint List Schema: 'Payer Enrollment Tracker'
PayerName
e.g., 'Aetna'
PayerID
e.g., '60054'
EnrollmentType
'837P Claims', 'ERA/835', 'EFT', 'Real-Time Eligibility'
SubmissionDate
Date enrollment request was submitted
ExpectedCompletionDate
SubmissionDate + 30 days (default)
Status
'Not Started', 'Submitted', 'Pending Payer', 'Active', 'Rejected', 'Resubmitted'
Notes
Free-form notes
LastCheckedDate
Date MSP last checked status
AssignedTo
MSP technician or billing staff member
Power Automate Flow: Weekly Enrollment Status Check Reminder
Trigger: Recurrence — Every Monday at 8:00 AM
Steps:
Email Template:
Subject: Payer Enrollment Status Update — {{count}} enrollments pending
The following payer enrollments are still pending:
{{#each pendingEnrollments}}
- {{PayerName}} ({{EnrollmentType}}): Submitted {{SubmissionDate}}, Status: {{Status}}
{{#if overdue}}⚠️ OVERDUE — expected by {{ExpectedCompletionDate}}{{/if}}
{{/each}}Action Required:
- Check clearinghouse portal for status updates
- Contact payer enrollment department for overdue items
- Update tracker with current status
Initial Population Script (run once during setup)
// run once during setup to pre-populate the payer enrollment tracker
// Common payers for mental health practices — pre-populate the tracker
const commonPayers = [
{ name: 'Aetna', id: '60054' },
{ name: 'Anthem BCBS', id: '00230' },
{ name: 'Cigna / Evernorth', id: '62308' },
{ name: 'UnitedHealthcare / Optum', id: '87726' },
{ name: 'Humana', id: '61101' },
{ name: 'Magellan Health', id: '77027' },
{ name: 'Medicare (local MAC)', id: 'VARIES' },
{ name: 'Medicaid (state MCO)', id: 'VARIES' },
{ name: 'Tricare', id: '99726' },
{ name: 'Beacon Health Options', id: '13551' }
];
// For each payer, create 3 enrollment rows: 837P, ERA, EFT
const enrollmentTypes = ['837P Claims', 'ERA/835', 'EFT'];
const rows = [];
commonPayers.forEach(payer => {
enrollmentTypes.forEach(type => {
rows.push({
PayerName: payer.name,
PayerID: payer.id,
EnrollmentType: type,
Status: 'Not Started',
SubmissionDate: null,
ExpectedCompletionDate: null,
Notes: '',
AssignedTo: 'MSP Technician'
});
});
});
// Bulk insert into SharePoint list via Power Automate or PnP PowerShellTesting & Validation
- NETWORK TEST: From a clinical workstation, run 'Test-NetConnection simplepractice.com -Port 443' (or the practice's EHR domain) and verify TLS 1.2+ connection. Repeat for the clearinghouse portal. All connections must show TcpTestSucceeded: True.
- ENCRYPTION TEST: Run 'manage-bde -status C:' on every Windows workstation and verify 'Protection Status: Protection On' and 'Encryption Method: XTS-AES 256'. On macOS, run 'fdesetup status' and verify FileVault is On.
- MFA TEST: Log out of the EHR and Microsoft 365 on a workstation. Log back in and verify that MFA is prompted (Authenticator app, not SMS). Repeat for each user account. Accounts that bypass MFA represent a compliance failure.
- FIREWALL TEST: Attempt to access a known-blocked website category (e.g., gambling) from the clinical VLAN and verify it is blocked. Then verify that the EHR, clearinghouse, and M365 portals are accessible. Test guest VLAN isolation by attempting to ping a clinical workstation from a guest-connected device — it should fail.
- SUPERBILL AUTO-GENERATION TEST: Have a clinician complete a test session note with all required fields (CPT 90834, ICD-10 F41.1, POS 11, start/stop times). Sign the note. Verify that a superbill/claim is automatically generated in the EHR's billing queue within 5 minutes of signing.
- INCOMPLETE NOTE REJECTION TEST: Have a clinician attempt to sign a note with a missing diagnosis code (or missing start/stop time for a time-based CPT code). Verify that the EHR prevents the note from being signed or flags the claim for review rather than auto-submitting it.
- TELEHEALTH MODIFIER TEST: Create a test session noted as telehealth (video). Verify the claim auto-populates with POS 10 and Modifier 95. Then create an audio-only session and verify POS 10 with Modifier FQ. Submit both through the clearinghouse and monitor for acceptance.
- CLEARINGHOUSE RECEIPT TEST: After submitting a test claim, log into the clearinghouse portal within 4 hours and verify the claim appears with status 'Accepted' or 'Forwarded to Payer'. If status shows 'Rejected', review the error code and correct the issue.
- ERA AUTO-POSTING TEST: After a test claim has been adjudicated by the payer (typically 7–21 days), verify that the ERA (835) is received by the clearinghouse and auto-posted to the patient's account in the EHR. The payment amount, patient responsibility (co-pay, deductible), and adjustment codes should all populate correctly.
- 42 CFR PART 2 CONSENT TEST: If the practice treats SUD patients, create a test claim with an F10-F19 diagnosis code for a patient WITHOUT a documented TPO consent. Verify the system holds the claim for manual review and alerts the billing team, rather than auto-submitting.
- END-TO-END TIMING TEST: Time the complete workflow from note signing to claim appearing in the clearinghouse queue. Target: less than 15 minutes for real-time systems (SimplePractice, TheraPlatform) or by end of same business day for batch systems (TherapyNotes).
- DENIAL ALERT TEST: If possible, submit a claim with a known issue (e.g., to a payer where the provider is not yet credentialed). Verify that the denial notification is received by billing staff via email within 24 hours of the clearinghouse processing the rejection.
- BACKUP RECOVERY TEST: Verify that Datto/Axcient backup is running successfully on all protected endpoints. Perform a test file restore to confirm backup integrity. Review backup logs in the RMM dashboard.
- HUNTRESS EDR TEST: Verify the Huntress agent is installed and reporting on all endpoints by checking the Huntress dashboard. Confirm the practice's endpoints appear in the correct organization. Run an EICAR test file to verify detection capability.
Client Handoff
The client handoff meeting should be a 90-minute session with both clinical leadership and billing/administrative staff present. Cover the following topics in order:
Maintenance
Ongoing MSP maintenance responsibilities for this implementation:
Weekly (15–30 minutes):
- Review the automated Claims Rejection Monitor report. Look for patterns: if a specific payer is rejecting >10% of claims, investigate whether it's a systemic issue (enrollment problem, code change, payer policy update).
- Check firewall logs and Huntress dashboard for security alerts on practice endpoints.
- Verify backup jobs completed successfully for all protected devices.
Monthly (1–2 hours):
- Review clean claim rate trending in the SharePoint KPI tracker. Target: >95% clean claim rate sustained month-over-month.
- Check for EHR platform updates or feature changes that could affect the auto-claim workflow. Apply any updates during a maintenance window.
- Review and rotate any service account passwords or API keys used in the automation workflows.
- Update FortiGate firmware and FortiGuard definitions if not set to auto-update.
- Verify all payer enrollments remain active — some payers require annual re-enrollment.
- Review Microsoft 365 Secure Score and address any new recommendations.
Quarterly (2–4 hours):
- Conduct a mini HIPAA compliance review: verify BAAs are current, review access logs for terminated employees, confirm encryption status on all endpoints, test backup restore procedures.
- Review CPT and ICD-10 code updates — CMS publishes annual updates effective January 1 and occasional mid-year corrections. Update EHR templates if codes change.
- Review payer fee schedule changes and update charge amounts in the EHR if applicable.
- Meet with practice billing manager to review revenue cycle KPIs and identify improvement opportunities.
Annually:
- Conduct full HIPAA Security Risk Assessment (billable engagement at $1,500–$5,000).
- Review and renew all BAAs.
- Review and update the practice's HIPAA policies and procedures.
- Conduct HIPAA workforce training for all staff (new and existing).
- Review firewall and endpoint hardware for end-of-life/end-of-support status.
- Review and renew FortiGuard, Huntress, backup, and M365 licenses.
- Verify that the practice's NPI and CAQH records are current.
Escalation Path:
- Tier 1 (billing staff): Handles individual claim corrections, patient insurance updates, ERA posting discrepancies.
- Tier 2 (MSP helpdesk): Handles EHR configuration issues, clearinghouse connectivity problems, payer enrollment issues, workstation/network problems.
- Tier 3 (MSP engineer): Handles firewall changes, API integration issues (Path B), security incidents, HIPAA breach response.
- Vendor escalation: EHR vendor support for platform bugs; clearinghouse support for EDI transmission failures; payer provider relations for enrollment issues.
SLA Considerations:
- Claims submission failures: 4-hour response during business hours (revenue impact).
- Security incidents: 1-hour response (HIPAA breach potential).
- Network/connectivity outages: 2-hour response (blocks all cloud-based workflows).
- Routine configuration requests: Next business day.
Alternatives
Path A: Native EHR Auto-Claim (Built-in Features Only)
Use the EHR's built-in auto-claim generation and clearinghouse submission without any external middleware, API integration, or custom development. The MSP configures the EHR's billing settings, enrolls payers, trains staff, and monitors results. This covers SimplePractice, TherapyNotes, TheraPlatform, Sessions Health, and Kalix — all of which have built-in claim submission pipelines.
Tradeoffs: LOWEST cost ($0 additional beyond EHR subscription), LOWEST complexity (configuration only, no code), FASTEST implementation (4–6 weeks). However, limited customization — you're constrained to whatever automation the EHR vendor has built. No external webhook triggers, no custom validation logic, no cross-platform data flow. If the EHR's built-in workflow has a gap (e.g., no auto-submit, only auto-generate-and-queue), the workaround is manual batch submission by billing staff (adds 5–10 minutes/day). RECOMMENDED for 80% of practices — solo practitioners and small groups with straightforward billing workflows.
Path B: Healthie API + Keragon + Stedi (Custom Integration)
Use Healthie's GraphQL API and webhooks to detect session completion, Keragon as HIPAA-compliant middleware to orchestrate the workflow, and Stedi's Claims API for clearinghouse submission. This provides fully automated, real-time claim submission with custom validation, 42 CFR Part 2 consent checks, and rich error handling — all configurable by the MSP.
Tradeoffs: HIGHER cost (~$250–$500/month additional for Keragon + Stedi beyond the EHR), MODERATE-HIGH complexity (requires developer resources for initial build, 8–12 weeks timeline), but provides MAXIMUM flexibility and automation. Custom validation logic can catch errors that built-in EHR validation misses. Supports complex multi-site, multi-provider, multi-payer scenarios. Best for practices with 5+ providers, high claim volume (200+ claims/month), or specific customization requirements. Requires ongoing developer maintenance for API version updates.
Path C: Microsoft Power Automate + EHR Manual Export
For EHRs without APIs or built-in auto-claim (legacy systems), use Power Automate to monitor a shared folder or email inbox for exported superbill files, parse them, and route them to a clearinghouse portal via browser automation (UI flows) or API. This is a bridge solution for practices that cannot or will not switch EHRs.
Tradeoffs: MODERATE cost (Power Automate included in M365 Business Premium; may need Premium connectors at $15/user/month), HIGH complexity and FRAGILITY (UI-based automation breaks when the clearinghouse portal UI changes), MODERATE implementation time (6–8 weeks). This approach is inherently brittle — it relies on screen scraping or file watching rather than proper API integration. Recommended ONLY as a temporary bridge while the practice plans an EHR migration. Not suitable as a permanent solution.
Path D: Outsourced Medical Billing Service
Instead of automating in-house billing, the practice outsources claims submission to a third-party medical billing company (e.g., Practice Solutions, Therapy Brands billing services, or a local billing company). The clinicians complete notes, and the billing company handles superbill generation, claim submission, denial management, and payment posting.
Tradeoffs
- ZERO technology implementation required from the MSP (no middleware, no API work).
- The MSP's role is limited to providing the secure network and HIPAA compliance infrastructure.
- Cost is typically 5–10% of collections (for a practice collecting $500K/year, that's $25K–$50K/year in billing fees).
- MORE expensive than in-house automation long-term but LOWER risk and FASTER to implement (can be operational in 1–2 weeks once the billing company is contracted).
- Best for practices that have no billing staff and no desire to manage billing internally.
- The MSP loses the claims monitoring and EHR administration managed service revenue opportunity but retains all security/compliance/infrastructure revenue.
Alternative EHR: TheraPlatform with Built-in Auto-Claim
TheraPlatform offers the lowest entry price ($39/month Basic, $69/month Pro) with built-in claim automation that can be configured to automatically generate and submit claims after session notes are signed. It includes telehealth, scheduling, and documentation in addition to billing. Good alternative for extremely budget-conscious practices.
Tradeoffs: LOWEST EHR cost in the market for auto-claim capability. $0.25/claim transaction fee (same as SimplePractice). However, smaller user community means fewer online resources and peer support. Less polished UX compared to SimplePractice. Limited third-party integrations. No public API for custom builds. Recommended when budget is the primary constraint and the practice needs basic auto-claim without customization.
Want early access to the full toolkit?