Back to all insights
Care Management 9 min read

Replacing Excel in CCM/PCM: Billing Compliance and Invoicing

Move CCM/PCM off Excel: time tracking built for CMS billing rules, invoices generated from CPT paycode counts, and the RBAC and audit trail behind them.

What Is CCM/PCM Software?

Chronic Care Management (CCM) and Principal Care Management (PCM) are CMS-reimbursed care management services with monthly time thresholds. CCM (CPT 99490) requires at least 20 minutes of clinical staff time per calendar month for patients with two or more chronic conditions. PCM requires at least 30 minutes per calendar month (99424/99426 cover the first 30 minutes) for a single high-risk condition expected to last at least 3 months. That time goes to care plan discussions, coordination across providers, and tracking patient outcomes.

The operational challenge for CCM/PCM companies is not the clinical work. It's the administrative infrastructure: tracking time per patient, managing large staff rosters, allocating patients to coordinators, generating audit-defensible documentation, and — for scaling companies — doing all of this across a multi-tenant SaaS platform serving multiple health systems. The CCM/PCM Operations Platform case study shows this infrastructure in a live operation; the care management operations software page covers building it.

Generic SaaS tools handle some of this, but companies managing hundreds of coordinators and thousands of patients consistently hit their ceiling. This is the gap that custom CCM/PCM operations software fills.

Requirement 1: Role-Based Access Control (RBAC)

A CCM/PCM platform serves multiple roles with fundamentally different data access needs:

  • Care coordinators: See their assigned patient roster, log time, view and update care plans
  • Managers: See team performance metrics, reassign patients, approve timesheets, flag escalations
  • Billing staff: Access billable minutes per patient, generate monthly billing documentation, flag billing exceptions
  • Administrators: Full platform access, user management, tenant configuration

RBAC must be enforced at the API layer, not just the UI. A care coordinator whose frontend doesn't show the admin panel should also receive a 403 from the API if they attempt to call admin endpoints directly.

# RBAC middleware in FastAPI
from functools import wraps
from fastapi import HTTPException, Depends

def require_role(*allowed_roles: str):
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, current_user=Depends(get_current_user), **kwargs):
            if current_user.role not in allowed_roles:
                raise HTTPException(
                    status_code=403,
                    detail=f"Role '{current_user.role}' is not authorized for this endpoint"
                )
            return await func(*args, current_user=current_user, **kwargs)
        return wrapper
    return decorator

@app.get("/admin/users")
@require_role("admin")
async def list_all_users():
    ...

@app.get("/manager/team-metrics")
@require_role("admin", "manager")
async def get_team_metrics():
    ...

Requirement 2: Time Tracking With Immutable Audit Trail

CMS reimbursement for CCM and PCM depends on documented time that meets the monthly thresholds, alongside required elements such as patient consent and a care plan. CMS prescribes those documentation elements, not a time-log format — so the rules below are audit-defensible practice rather than CMS requirements. The time tracking module should:

  • Record start and stop times precisely, using server-side timestamps
  • Categorize time by activity type (care plan review, provider coordination, patient call, medication management)
  • Prevent retroactive editing without a complete audit trail
  • Generate monthly summaries per patient that show how each time threshold was met

The audit trail requirement is the engineering constraint most teams underestimate. You cannot allow time log records to be deleted — only flagged as erroneous and superseded by corrected entries. Every mutation to the time log table needs an immutable record:

CREATE TABLE time_log_entries (
    id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    patient_id    UUID NOT NULL REFERENCES patients(id),
    coordinator_id UUID NOT NULL REFERENCES users(id),
    tenant_id     UUID NOT NULL REFERENCES tenants(id),
    activity_type VARCHAR(50) NOT NULL,
    started_at    TIMESTAMPTZ NOT NULL,
    ended_at      TIMESTAMPTZ NOT NULL,
    duration_secs INTEGER GENERATED ALWAYS AS
                  (EXTRACT(EPOCH FROM (ended_at - started_at))::INTEGER) STORED,
    is_void       BOOLEAN DEFAULT FALSE,
    void_reason   TEXT,
    voided_by     UUID REFERENCES users(id),
    created_at    TIMESTAMPTZ DEFAULT NOW()
    -- No updated_at — records are immutable. Corrections create new rows.
);

Requirement 3: Intelligent Patient Assignment

As a CCM/PCM company scales, patient-to-coordinator assignment becomes a significant operational problem. A coordinator who leaves has their entire roster orphaned. A new coordinator needs a calibrated caseload, not a random batch of the most complex patients.

Intelligent assignment logic accounts for:

  • Current coordinator caseload (patient count + total risk score)
  • Patient complexity (number of chronic conditions, engagement history)
  • Coordinator capacity and specialization
  • Geographic or time zone alignment

At scale, this becomes a scoring and recommendation engine rather than a manual assignment tool. Historical data on coordinator performance and patient engagement can be used to optimize assignments algorithmically — flagging patients who are likely to miss their monthly time threshold and proactively reassigning them.

Requirement 4: HIPAA-Compliant Multi-Tenant Architecture

If multiple covered entities use the same platform instance (the SaaS model), each customer is a separate covered entity and their patient data must be isolated at the database layer, not just the application layer.

The standard PostgreSQL pattern uses row-level security (RLS):

-- Tenant isolation enforced at the DB level
ALTER TABLE patients ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON patients
    USING (tenant_id = current_setting('app.current_tenant_id')::UUID);

-- Set at connection time from the application session
SET LOCAL app.current_tenant_id = '3f47a9b2-...';

With RLS enabled, even if application code has a bug that forgets to filter by tenant_id, the database will silently return only the current tenant's rows. This satisfies the HIPAA data isolation requirements that hospital security audits verify and also ensures that a multi-tenant breach scenario is structurally prevented at the storage layer.

Each tenant also requires a separate signed HIPAA BAA — the architecture enforces isolation, but the legal agreement still needs to exist per customer relationship.

Requirement 5: Monthly Billing Documentation

Monthly CCM and PCM billing is far easier to defend with a generated summary of each patient's care management activities for the month. CMS prescribes documentation elements (consent, care plan, time thresholds), not a format, so the following is audit-defensible practice. The system should:

  • Aggregate time logs by patient and calendar month
  • Confirm the program's time threshold is met — 20 minutes for CCM, 30 minutes for PCM — and flag exceptions
  • Generate a structured PDF summarizing consent status, the care plan reference, and time by activity
  • Timestamp and digitally identify the generating user
  • Store the document immutably (no post-generation edits)

PDF generation in a Python/FastAPI backend is handled with WeasyPrint or ReportLab, with generated files stored in a KMS-encrypted S3 bucket. The document cannot be deleted — only superseded by a regeneration with an audit record.

The EHR Integration Layer

CCM/PCM platforms that pull care plan data directly from hospital EHR systems (Epic, Cerner) need an EHR integration middleware layer between the platform and the EHR. The CCM/PCM application should not make direct FHIR API calls to Epic — it should call an internal middleware API that handles authentication, FHIR profile mapping, and error handling.

This separation also means the CCM/PCM platform doesn't need to go through Epic's app review (Vendor Services and Showroom, formerly App Orchard) directly — only the middleware service does. See the Epic App Orchard approval guide for what that process involves.

Build vs. Buy

Off-the-shelf CCM platforms work well for companies managing a few hundred patients with a small, stable team. Once you cross ~500 patients or have specific workflows the template doesn't support, per-seat licensing costs and workflow rigidity become real constraints.

Custom-built CCM/PCM software has a fixed build cost and zero ongoing per-seat licensing. For a company at scale, the economics improve dramatically over time — and you own the IP. The Practice Management vs. EHR explainer covers the broader build-vs-buy framing for healthcare operations software.

The Custom Practice Management service includes full CCM/PCM platform architecture — RBAC, time tracking, multi-tenant SaaS conversion, and monthly billing documentation.

CMS time thresholds last reviewed 2026-09-25. Source: CMS MLN909188, Chronic Care Management Services.

Related Service

Custom CCM, PCM & RPM Operations Software

Deep-dive into our engineering approach, capabilities, and technical specifications.

View Engineering Specs →
SA

Written by Sheharyar Amin

Founder & Lead Engineer, Opexia