Free PDPM Rate Calculator for SNF Reimbursement
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.calculator-container {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 30px;
margin-bottom: 40px;
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
}
.calc-header {
text-align: center;
margin-bottom: 25px;
}
.calc-header h2 {
margin: 0;
color: #2c3e50;
}
.input-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 600;
font-size: 0.9rem;
color: #495057;
}
.form-group input, .form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 1rem;
box-sizing: border-box;
}
.form-group small {
display: block;
font-size: 0.8rem;
color: #6c757d;
margin-top: 3px;
}
.section-title {
grid-column: 1 / -1;
font-weight: bold;
color: #0056b3;
margin-top: 15px;
margin-bottom: 5px;
border-bottom: 2px solid #e9ecef;
padding-bottom: 5px;
}
.calc-btn {
grid-column: 1 / -1;
background-color: #0056b3;
color: white;
border: none;
padding: 15px;
font-size: 1.1rem;
font-weight: bold;
border-radius: 4px;
cursor: pointer;
width: 100%;
margin-top: 20px;
transition: background-color 0.2s;
}
.calc-btn:hover {
background-color: #004494;
}
.results-area {
margin-top: 30px;
background-color: #fff;
padding: 20px;
border-radius: 4px;
border: 1px solid #dee2e6;
display: none;
}
.result-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.result-row.total {
border-top: 2px solid #333;
border-bottom: none;
font-weight: bold;
font-size: 1.3rem;
color: #28a745;
margin-top: 10px;
}
.result-value {
font-family: monospace;
font-size: 1.1rem;
}
.article-content {
background-color: #fff;
padding: 20px;
margin-top: 40px;
}
.article-content h3 {
color: #2c3e50;
margin-top: 30px;
}
.info-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.info-table th, .info-table td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
.info-table th {
background-color: #f2f2f2;
}
@media (max-width: 768px) {
.input-grid {
grid-template-columns: 1fr;
}
}
Daily Reimbursement Breakdown
PT Component (Adj: 1.00):
$0.00
OT Component (Adj: 1.00):
$0.00
SLP Component:
$0.00
Nursing Component:
$0.00
NTA Component (Adj: 1.00):
$0.00
Non-Case Mix Base:
$0.00
Total Daily Rate:
$0.00
Understanding the Patient Driven Payment Model (PDPM)
The Patient Driven Payment Model (PDPM) is the Medicare Part A reimbursement classification system for Skilled Nursing Facilities (SNFs). Unlike previous models (RUG-IV) which were driven largely by therapy minutes, PDPM focuses on the patient's clinical characteristics to determine payment.
How to Use This PDPM Rate Calculator
This tool calculates the specific per diem rate for a given day of a patient's stay. Because PDPM utilizes a Variable Per Diem (VPD) adjustment, the payment rate changes depending on how long the patient has been in the facility.
- Select Geography: Base rates differ significantly between Urban and Rural facilities (CBSA designation).
- Enter Day of Stay: This is critical for calculating the VPD adjustment factors for PT, OT, and NTA components.
- Input Case-Mix Indices (CMI): Enter the CMI for each of the five components (PT, OT, SLP, Nursing, NTA). These are derived from the MDS assessment (HIPPS code).
- Verify Base Rates: The calculator pre-fills estimated FY 2024 Federal Base Rates, but you can adjust these if your fiscal year or facility-specific adjustments (like VBP) differ.
The 5 Components of PDPM
The total daily rate is the sum of five case-mix adjusted components plus a non-case-mix component:
- Physical Therapy (PT): Based on clinical category and functional status. Subject to VPD adjustment.
- Occupational Therapy (OT): Similar to PT, based on clinical category and functional score. Subject to VPD adjustment.
- Speech-Language Pathology (SLP): Based on swallowing disorders, mechanically altered diet, comorbidities, and cognitive status. Constant per diem.
- Nursing: Based on clinical complexity, depression score, and restorative nursing services. Constant per diem (uses RUG-IV categories like ES3, HDE2).
- Non-Therapy Ancillary (NTA): Based on the presence of comorbidities (e.g., HIV/AIDS, IV feeding). Points are summed to determine the group. Subject to VPD adjustment.
Variable Per Diem (VPD) Adjustment Schedule
PDPM reduces reimbursement for certain components over time to reflect the changing costs of care throughout a stay.
| Day of Stay |
PT / OT Adjustment Factor |
NTA Adjustment Factor |
| Days 1 – 3 |
1.00 |
3.00 |
| Days 4 – 20 |
1.00 |
1.00 |
| Days 21 – 27 |
0.98 |
1.00 |
| Days 28 – 34 |
0.96 |
1.00 |
| Days 98 – 100 |
0.76 |
1.00 |
Note: For PT and OT, the adjustment factor decreases by 0.02 every 7 days starting on Day 21.
// Initial Base Rates (Approx FY 2024 data for defaults)
// Users can override these in the input fields
var urbanRates = {
pt: 67.63,
ot: 63.04,
slp: 24.96,
nurs: 119.53,
nta: 88.22,
nonCase: 113.63
};
var ruralRates = {
pt: 76.99,
ot: 70.47,
slp: 31.95,
nurs: 114.19,
nta: 83.94,
nonCase: 115.42
};
function updateBaseRates() {
var geo = document.getElementById('geoLoc').value;
var rates = (geo === 'urban') ? urbanRates : ruralRates;
document.getElementById('ptBase').value = rates.pt;
document.getElementById('otBase').value = rates.ot;
document.getElementById('slpBase').value = rates.slp;
document.getElementById('nursBase').value = rates.nurs;
document.getElementById('ntaBase').value = rates.nta;
document.getElementById('nonCaseBase').value = rates.nonCase;
}
function calculatePDPM() {
// 1. Get Inputs
var day = parseInt(document.getElementById('dayOfStay').value);
var ptCmi = parseFloat(document.getElementById('ptCmi').value);
var otCmi = parseFloat(document.getElementById('otCmi').value);
var slpCmi = parseFloat(document.getElementById('slpCmi').value);
var nursCmi = parseFloat(document.getElementById('nursCmi').value);
var ntaCmi = parseFloat(document.getElementById('ntaCmi').value);
var ptBase = parseFloat(document.getElementById('ptBase').value);
var otBase = parseFloat(document.getElementById('otBase').value);
var slpBase = parseFloat(document.getElementById('slpBase').value);
var nursBase = parseFloat(document.getElementById('nursBase').value);
var ntaBase = parseFloat(document.getElementById('ntaBase').value);
var nonCaseBase = parseFloat(document.getElementById('nonCaseBase').value);
// Validation
if (isNaN(day) || day < 1) {
alert("Please enter a valid Day of Stay.");
return;
}
if (isNaN(ptCmi) || isNaN(otCmi) || isNaN(slpCmi) || isNaN(nursCmi) || isNaN(ntaCmi)) {
alert("Please enter all Case-Mix Indices (CMI). These can be found on your validation reports.");
return;
}
// 2. Calculate VPD Adjustments
var ptOtAdj = 1.00;
var ntaAdj = 1.00;
// PT/OT VPD Logic
if (day 1.0 – (1 * 0.02) = 0.98
// Day 28-34: (28-21)/7 = 1 -> 1.0 – (2 * 0.02) = 0.96
var cycles = Math.floor((day – 21) / 7) + 1;
ptOtAdj = 1.00 – (cycles * 0.02);
// Cap at reasonable minimum if necessary, though stay length is usually max 100
}
// NTA VPD Logic
if (day <= 3) {
ntaAdj = 3.00;
} else {
ntaAdj = 1.00;
}
// 3. Calculate Component Rates
// Formula: Base Rate * CMI * Adjustment
var ptRate = ptBase * ptCmi * ptOtAdj;
var otRate = otBase * otCmi * ptOtAdj;
var slpRate = slpBase * slpCmi; // No VPD for SLP
var nursRate = nursBase * nursCmi; // No VPD for Nursing
var ntaRate = ntaBase * ntaCmi * ntaAdj;
// Non-Case Mix is flat
var nonCaseRate = nonCaseBase;
// 4. Total
var totalRate = ptRate + otRate + slpRate + nursRate + ntaRate + nonCaseRate;
// 5. Display Results
document.getElementById('results').style.display = 'block';
// Display Adjustment Factors
document.getElementById('ptAdjDisplay').innerText = ptOtAdj.toFixed(2);
document.getElementById('otAdjDisplay').innerText = ptOtAdj.toFixed(2);
document.getElementById('ntaAdjDisplay').innerText = ntaAdj.toFixed(2);
// Display Dollar Amounts
document.getElementById('ptResult').innerText = "$" + ptRate.toFixed(2);
document.getElementById('otResult').innerText = "$" + otRate.toFixed(2);
document.getElementById('slpResult').innerText = "$" + slpRate.toFixed(2);
document.getElementById('nursResult').innerText = "$" + nursRate.toFixed(2);
document.getElementById('ntaResult').innerText = "$" + ntaRate.toFixed(2);
document.getElementById('nonCaseResult').innerText = "$" + nonCaseRate.toFixed(2);
document.getElementById('totalResult').innerText = "$" + totalRate.toFixed(2);
// Scroll to results
document.getElementById('results').scrollIntoView({behavior: 'smooth'});
}