RPM / RTM / CCM Reimbursement Calculator

Estimate reimbursement based on the CPT codes achieved or projected per patient per month.

Enter how many of each CPT code your team has achieved.

Tip: Each program’s CPT rows are in a section below—click the program name (e.g. Remote Patient Monitoring) to expand or collapse that table. Open the section you need to enter counts. The totals at the bottom always include all programs.

Total Claims
0
Total Reimbursement
$0.00
Project monthly & annual revenue based on # of enrolled patients per program.
Monthly Revenue iSum across all programs of (patients × average $ per patient per month) using the intensity selected above. Excludes one-time setup codes.
$0.00
Annual Revenue iMonthly Revenue × 12 months. Assumes stable enrollment and monthly billing throughout the year.
$0.00
Avg $ / Patient / Month iMonthly Revenue ÷ total patients enrolled across all programs. Useful for comparing your blended per-patient value against industry benchmarks.
$0.00
Adjust rates for "what-if" scenarios (e.g. your payer mix). Changes are saved in your browser only.

Tip: Rate rows are grouped by program—click the program heading to show or hide that program’s table. Use this to focus on one section at a time. Changes are kept in this browser only (see the note at the bottom).

* Overridden from default. Rates are saved in this browser only and do not affect other visitors or the site admin's settings.

Developer API

This calculator is designed to be embedded in another application (iframe or pop-up). Approved parent apps can push data in and receive live billing totals back out. All integration is origin-gated: only hosts on the admin allowlist at Settings → RPM / RTM / CCM Calc can send to or receive from the calculator.

Requirement — your domain must be whitelisted.
Every path below (URL prefill, inbound postMessage, and outbound postMessage) is rejected unless the calling origin's hostname is enabled on the admin allowlist at WP Admin → RPM / RTM / CCM Calc → Approved domains. Until your host is added there:
  • Page loads with no browser Origin / Referer that maps to an allowlisted host: all rrc_* prefills are ignored (treats the visit as a public viewer).
  • Inbound postMessage actions (setCounts, setProjection, setView, reset, ping) are silently dropped.
  • Outbound postMessage events (ready / update / pong) are never emitted to your window — no listener in your app will fire.

Push data into the calculator via URL query string

The calculator parses rrc_* query params on both the server (PHP) and the client (window.location.search). That means prefill still works even when a page cache, CDN, or optimizer strips query args before PHP ever sees them.

Security model (v1.4.7+): the calling app hostname is never read from the query string. It comes only from the browser-set Origin header, then Referer, or the rrc_calc_trusted_origin_host filter (reverse proxy). The legacy parameter rrc_domain is ignored if present. After load, the parent app can also establish the origin via postMessage (browser-validated event.origin).

Your domain must be whitelisted at WP Admin → RPM / RTM / CCM Calc → Approved domains. Prefill and outbound messaging unlock when the request’s trusted origin (or a later postMessage sender) matches an enabled allowlist entry.

Supported query parameters
Parameter Required? Type / allowed values Default What it does Example
rrc_<CPT> optional Non-negative integer. <CPT> must be 5 digits and part of the plugin catalog (RPM, RTM, CCM, PCM, BHI). Unknown or invalid codes are silently dropped. 0 Prefills the Per-Code Achieved input for one specific CPT code. Values accumulate with rrc_achieved; when both are present, the explicit rrc_<CPT> param wins for that code. rrc_99454=120
rrc_achieved optional Comma-separated list of CPT:count pairs, URL-encoded. Whitespace is tolerated; invalid segments are skipped silently. empty Compact alternative to rrc_<CPT>. Use it when you need to prefill many codes in one parameter (keeps the URL short and survives CDN query-arg limits better). rrc_achieved=99454:120,99457:80,99458:30
rrc_view optional One of code, patient, rates, api. Any other value is ignored. code Selects which tab is active on first render. code = Per-Code Achieved, patient = Per-Patient Projection, rates = Edit Rates (localStorage), api = Developer API docs. rrc_view=patient
rrc_readonly optional Truthy flag: any of 1, true, yes, on. Anything else = off. 0 (off) Locks the Per-Code numeric inputs and hides the Reset button. Ideal for dashboard embeds where the host app owns the state and the calculator is view-only. Tabs, tooltips, and projection mode remain interactive. rrc_readonly=1

Deprecated: rrc_domain is not listed above because v1.4.7+ does not read it. Old bookmarks may still include &rrc_domain=…; it is ignored. Identity always comes from Origin / Referer (or postMessage after load).

Parsing rules, at a glance: values in rrc_* params are parsed as UTF-8 URL-decoded strings; negative numbers, non-numeric values, and unknown CPT codes are ignored; rrc_<CPT> overrides any conflicting entry in rrc_achieved; state is applied after the catalog is built so rate overrides stay intact; no cookie, session, or database write is performed by any rrc_* parameter.

Example URLs

1. Minimal prefill (single code). Open from your whitelisted app (so Origin / Referer is your app’s host):

https://your-wp-site.example/calculator/?rrc_99454=120

Replace older docs that used ...?rrc_domain=app.wellnessmetric.net&rrc_99454=120 — v1.4.7+ drops rrc_domain entirely, so the same scenario is: ...?rrc_99454=120 (your app host stays on the allowlist; the browser sends it, not the query string).

2. Full dashboard embed (read-only, Per-Code tab, multiple codes). Host app has already validated the numbers and just wants the calculator to render a snapshot:

https://your-wp-site.example/calculator/?rrc_view=code&rrc_readonly=1&rrc_achieved=99454:120,99457:80,99458:30

Breakdown: the app’s hostname must be on the allowlist (detected from the request, not the URL). rrc_view=code → open on the Per-Code Achieved tab. rrc_readonly=1 → lock the numeric inputs and hide Reset. rrc_achieved → prefill 99454 with 120, 99457 with 80, and 99458 with 30.

Same scenario, sample app.example.com + response body

Example path (replace your-wp-site.com and calculator-page with your real WordPress URL). activeDomain below is the trusted origin app.example.com:

https://your-wp-site.com/calculator-page/?rrc_view=code&rrc_readonly=1&rrc_achieved=99454:120,99457:80,99458:30

When the calculator loads inside an approved embedding (trusted Origin / Referer), it emits the same shape as the 5. Live response preview box. Below is a static example; dollar amounts use the built-in default rates (admin and per-domain overrides can change them). data.event is ready on first load and update on each recalculation. In a live message, the code array under each program normally includes every catalog CPT with count and subtotal — the trimmed JSON shows only the three codes with activity, plus the three program shells.

{
  "statusCode": 200,
  "resFlag": true,
  "type": "I",
  "msg": "calculator billing data returned successfully.",
  "data": {
    "source": "rpm-rtm-ccm-calculator",
    "event": "update",
    "currency": "$",
    "timestamp": "2026-04-24T15:00:00.000Z",
    "activeDomain": "app.example.com",
    "summary": {
      "totalClaims": 230,
      "totalAmount": 10146.70,
      "monthlyRevenue": 0.00,
      "annualRevenue": 0.00,
      "perPatientPerMonth": 0.00,
      "patients": 0
    },
    "data": [
      {
        "program": "RPM",
        "label": "Remote Patient Monitoring (RPM)",
        "codes": [
          { "code": "99454", "description": "Monthly review of RPM data (16+ days / 30)", "rate": 43.02, "count": 120, "subtotal": 5162.40 },
          { "code": "99457", "description": "Patient-provider communication, RPM data (20 min)", "rate": 47.87, "count": 80, "subtotal": 3829.60 },
          { "code": "99458", "description": "Additional 20 min RPM communication (add-on)", "rate": 38.49, "count": 30, "subtotal": 1154.70 }
        ],
        "totalClaims": 230,
        "totalAmount": 10146.70,
        "perPatientProjection": {
          "intensity": "typical",
          "track": "standard",
          "patients": 0,
          "monthlyRevenue": 0.00,
          "annualRevenue": 0.00,
          "perPatientPerMonth": 0.00
        }
      },
      {
        "program": "RTM",
        "label": "Remote Therapeutic Monitoring (RTM)",
        "codes": [],
        "totalClaims": 0,
        "totalAmount": 0.00,
        "perPatientProjection": { "intensity": "typical", "track": "msk", "patients": 0, "monthlyRevenue": 0.00, "annualRevenue": 0.00, "perPatientPerMonth": 0.00 }
      },
      {
        "program": "CCM",
        "label": "Chronic / Principal Care Management (CCM / PCM / BHI)",
        "codes": [],
        "totalClaims": 0,
        "totalAmount": 0.00,
        "perPatientProjection": { "intensity": "typical", "track": "standard", "patients": 0, "monthlyRevenue": 0.00, "annualRevenue": 0.00, "perPatientPerMonth": 0.00 }
      }
    ]
  }
}

Your listener on window.addEventListener('message', ...) receives this object on event.data when the embedding origin and allowlist are valid. summary.totalAmount = 120×43.02 + 80×47.87 + 30×38.49. Per-patient fields stay at zero until you enter data on the Per-Patient Projection tab.

3. Open on the projection tab with no prefill (sales or onboarding demo):

https://your-wp-site.example/calculator/?rrc_view=patient

4. Mix compact and per-code forms. The explicit rrc_99454 wins over the value in rrc_achieved:

https://your-wp-site.example/calculator/?rrc_achieved=99454:100,99457:80&rrc_99454=150

Effective result: 99454 = 150, 99457 = 80.

your-wp-site.example is the WordPress host that serves the shortcode. Your app’s hostname (for allowlisting and data.activeDomain) is read from the browser Origin / Referer, not from a query parameter.

Push data into the calculator at runtime (postMessage)

Domain must be whitelisted. Inbound messages whose event.origin hostname is not on the admin allowlist are silently dropped — no error, no state change.

After the calculator is loaded (in an iframe or opened window), your app can send messages to drive it. The calculator only accepts messages whose event.origin hostname is on the allowlist.

Every inbound message must be an object with target: "rpm-rtm-ccm-calculator" and an action:

actionPayloadEffect
setCounts{ counts: { "99454": 120, ... } }Sets Per-Code input values, then recalculates. Codes not in the catalog are ignored.
setProjection{ projection: { intensity, tracks: {rpm, rtm, ccm}, patients: {RPM, RTM, CCM} } }Sets the Per-Patient tab intensity / track / patient counts, then recalculates.
setView{ view: "code"|"patient"|"rates"|"api" }Switches the active tab.
reset(none)Resets all counts on both tabs to 0.
ping(none)Triggers a fresh outbound response without changing state — useful right after load.

Push example:

// From your app (iframe is embedded on a page on your app origin):
var iframe = document.getElementById('rrc-iframe');
iframe.contentWindow.postMessage({
  target: 'rpm-rtm-ccm-calculator',
  action: 'setCounts',
  counts: { '99454': 120, '99457': 80, '99458': 30 }
}, 'https://your-wp-site.com');

Receive billing data from the calculator (postMessage)

Domain must be whitelisted. The outbound targetOrigin is strictly https://<activeDomain> where activeDomain is an entry from the admin allowlist. If your app's host isn't on the list, no message is ever dispatched to your window — your listener will never fire.

Every time the user edits inputs, the calculator emits a message to window.opener and window.parent using a strict targetOrigin of https://<activeDomain> (the allowlisted app host from the request or postMessage). Listen for it in your app:

window.addEventListener('message', function (event) {
  if (event.origin !== 'https://your-wp-site.com') return;
  var res = event.data;
  if (!res || !res.data || res.data.source !== 'rpm-rtm-ccm-calculator') return;
  if (res.resFlag !== true) {
    console.warn('Calculator error', res.msg);
    return;
  }
  // res.data is an object with meta + nested .data[] programs.
  console.log('event:', res.data.event, 'summary:', res.data.summary);
  res.data.data.forEach(function (program) {
    console.log(program.program, program.totalAmount, program.perPatientProjection);
  });
});

Response envelope (v1.4.0+) — the top level is strictly {statusCode, resFlag, type, msg, data}. All meta and the program array live inside data:

{
  "statusCode": 200,
  "resFlag": true,
  "type": "I",
  "msg": "calculator billing data returned successfully.",
  "data": {
    "source": "rpm-rtm-ccm-calculator",
    "event": "update",
    "currency": "$",
    "timestamp": "2026-04-24T12:34:56.789Z",
    "activeDomain": "app.example.com",
    "summary": {
      "totalClaims": 250,
      "totalAmount": 12345.67,
      "monthlyRevenue": 5000.00,
      "annualRevenue": 60000.00,
      "perPatientPerMonth": 100.00,
      "patients": 50
    },
    "data": [
      {
        "program": "RPM",
        "label": "Remote Patient Monitoring (RPM)",
        "codes": [
          { "code": "99453", "description": "RPM device set up", "rate": 19.32, "count": 0, "subtotal": 0.00 },
          { "code": "99454", "description": "Monthly review of RPM data (16+ days / 30)", "rate": 43.02, "count": 120, "subtotal": 5162.40 }
        ],
        "totalClaims": 120,
        "totalAmount": 5162.40,
        "perPatientProjection": {
          "intensity": "typical",
          "track": "standard",
          "patients": 50,
          "monthlyRevenue": 2500.00,
          "annualRevenue": 30000.00,
          "perPatientPerMonth": 50.00
        }
      },
      { "program": "RTM", "label": "Remote Therapeutic Monitoring (RTM)", "codes": [ /* ... */ ], "totalClaims": 0, "totalAmount": 0, "perPatientProjection": { /* ... */ } },
      { "program": "CCM", "label": "Chronic / Principal Care Management (CCM / PCM / BHI)", "codes": [ /* ... */ ], "totalClaims": 0, "totalAmount": 0, "perPatientProjection": { /* ... */ } }
    ]
  }
}
  • statusCode — HTTP-style code. 200 on success, 400 on validation error.
  • resFlagtrue if the payload is usable, false otherwise.
  • type"I" info / success, "E" error.
  • msg — human-readable status string.
  • data.source — always "rpm-rtm-ccm-calculator". Use this in your listener to filter out unrelated messages.
  • data.event"ready" (initial emit on load), "update" (user edit), "pong" (reply to ping), or "error" (inbound action failed).
  • data.currency — currency symbol the calculator was rendered with.
  • data.timestamp — ISO-8601 UTC timestamp.
  • data.activeDomain — the approved host the calculator is talking to, or null.
  • data.summary — cross-program totals.
  • data.data[] — always three entries in order: RPM, RTM, CCM. Programs your shortcode filtered out still appear with zero totals and empty codes.

Full working examples

Iframe embed + bi-directional messaging
<iframe id="rrc" width="100%" height="900"
        src="https://your-wp-site.com/calculator/?rrc_readonly=1&rrc_view=code"></iframe>

<script>
  var WP_ORIGIN = 'https://your-wp-site.com';
  var iframe    = document.getElementById('rrc');

  // Receive live totals.
  window.addEventListener('message', function (e) {
    if (e.origin !== WP_ORIGIN) return;
    var res = e.data;
    if (!res || !res.data || res.data.source !== 'rpm-rtm-ccm-calculator') return;
    document.getElementById('total').textContent = '$' + res.data.summary.totalAmount.toFixed(2);
  });

  // Push initial counts as soon as the iframe is ready.
  iframe.addEventListener('load', function () {
    iframe.contentWindow.postMessage({
      target: 'rpm-rtm-ccm-calculator',
      action: 'setCounts',
      counts: { '99454': 120, '99457': 80 }
    }, WP_ORIGIN);
  });
</script>
Pop-up window + deep-link
var url = 'https://your-wp-site.com/calculator/' +
          '?rrc_view=patient' +
          '&rrc_achieved=99454:120,99457:80,99458:30';
var pop = window.open(url, 'rrc', 'width=1000,height=900');

window.addEventListener('message', function (e) {
  if (e.origin !== 'https://your-wp-site.com') return;
  var res = e.data;
  if (!res || !res.data || res.data.source !== 'rpm-rtm-ccm-calculator') return;
  console.log('event:', res.data.event, 'summary:', res.data.summary);
  res.data.data.forEach(function (p) {
    console.log(p.program, p.totalAmount);
  });
});

Live response preview

This box shows the exact JSON payload the calculator is currently emitting. Edit the Per-Code or Per-Patient tabs and watch it update live.

{}

Tip: if the data.activeDomain field above is null, the page load had no allowlisted Origin/Referer (or cache hid it) and the parent has not yet sent a postMessage. Add your app’s hostname to WP Admin → RPM / RTM / CCM Calc → Approved domains and open the calculator from that app, or have your parent send {target:"rpm-rtm-ccm-calculator",action:"ping"} from an allowlisted origin.

RPM and RTM descriptions are sourced from telehealth.hhs.gov. CCM descriptions reflect CMS/AMA CPT guidance. Estimates are for planning only — actual reimbursement depends on payer, documentation, medical necessity, locality adjustments, and the current CMS Physician Fee Schedule. Verify all CPT code rules and rates before submitting claims.