How to Automate Monthly Uptime Reports for Clients
Monthly Reports Are Your Maintenance Contract's Report Card
Even with a signed maintenance subscription in place, clients still ask: "What exactly are you doing each month?" Development work and WordPress updates are visible. Uptime monitoring and incident response are not — unless you show the numbers.
A monthly uptime report is the most direct way to make invisible work visible. "This month we held 99.97% uptime. One incident occurred, but we detected it before you did and restored service in 15 minutes" — that kind of statement justifies your retainer fee, reinforces trust, and raises the bar for cancellation.
The problem is scale. Building reports by hand is fine for five clients. Beyond that, it becomes a recurring drag at month-end. This guide shows how to pull uptime and incident data from Miterl's API and automate the reporting pipeline so you spend minutes, not hours, on this task.
Why Manual Reports Don't Scale
Client count and labor grow together
At 20–30 minutes per client, ten clients cost you three to five hours each month. Twenty clients eat a full day. When a late-month incident coincides with reporting week, you're fighting a fire and racing a deadline at the same time.
Manual transcription introduces errors
Copying numbers from a dashboard by hand means there's always a risk of a wrong month, a wrong monitor, or an off-by-one in a percentage. If a client questions a figure from last month, walking it back takes more time and credibility than the original error cost.
What automation changes
| Item | Manual | After Automation |
|---|---|---|
| Time per client | 20–30 min | Under 1 min |
| Transcription errors | Possible | Zero |
| Delivery timing | Depends on staff | 1st of each month, automatic |
| Impact of doubling clients | Work doubles | Virtually unchanged |
What Data Miterl Provides
Miterl stores uptime percentages and incident records for every monitor you configure. You can retrieve this data through the API and feed it directly into your report generation script — no dashboard tab-switching required.
The three data points most useful for client reports are:
- Rolling 30-day uptime (
uptime_30d): Percentage of time the monitor was up over the last 30 days - Incident list (
/api/v1/incidents): Start time, resolution time, and duration in seconds for each outage - Status page URL: A public page clients can check themselves at any time
Note that Miterl does not currently include a built-in "auto-send report" feature. The workflow described here uses the API to collect data and a script on your side to generate and deliver the report. That gives you full control over format, branding, and delivery channel.
Step 1: Get Your API Key and List Your Monitors
Generate an API key from the Miterl dashboard under Settings → API Keys. Then confirm your monitor IDs and current uptime figures.
# List all monitors with id, name, and 30-day uptime
curl -s "https://miterl.com/api/v1/monitors?per_page=100" \
-H "Authorization: Bearer YOUR_API_KEY" \
| jq -r '.data[] | "\(.id)\t\(.name)\t\(.uptime_30d)%"'
Sample output:
1 Client A — Corporate 99.97%
2 Client A — Careers 100.00%
3 Client B — E-commerce 99.83%
Step 2: Pull Calendar-Month Incident Data
uptime_30d covers a rolling 30-day window. For a calendar-month view (e.g., June 1–30), filter the incident list by resolution date.
# Fetch resolved incidents for monitor 1 in June 2026 and sum downtime
MONITOR_ID=1
YEAR=2026
MONTH=06
curl -s "https://miterl.com/api/v1/incidents?monitor_id=${MONITOR_ID}&status=resolved&per_page=100" \
-H "Authorization: Bearer YOUR_API_KEY" \
| jq --arg ym "${YEAR}-${MONTH}" '
[
.data[]
| select(.resolved_at | startswith($ym))
]
| {
count: length,
total_downtime_min: (map(.duration_seconds) | (add // 0) / 60 | round)
}
'
Sample output:
{
"count": 1,
"total_downtime_min": 9
}
To convert downtime minutes to an uptime percentage for a 30-day month:
# Example: 9 minutes of downtime in a 30-day month
downtime_min = 9
total_min = 30 * 24 * 60 # 43200 minutes
uptime_pct = (1 - downtime_min / total_min) * 100
print(f"Uptime: {uptime_pct:.4f}%")
# → Uptime: 99.9792%
For a quick reference on what common SLA thresholds (99.9%, 99.95%, 99.99%) allow in monthly downtime minutes, the "Uptime Percentage Calculator and Reference Guide" has the full conversion table.
Step 3: Collect All Client Data with a Shell Script
Store your monitor IDs and client names in a mapping, then loop through them to generate a combined report file.
#!/bin/bash
# monthly_report_collect.sh
# Usage: MONTH=2026-06 ./monthly_report_collect.sh
API_KEY="YOUR_API_KEY"
BASE_URL="https://miterl.com/api/v1"
MONTH="${MONTH:-$(date +%Y-%m)}"
declare -A MONITORS=(
[1]="Client A — Corporate"
[2]="Client A — Careers"
[3]="Client B — E-commerce"
)
echo "# ${MONTH} Monthly Uptime Report (auto-generated)"
echo ""
for MONITOR_ID in "${!MONITORS[@]}"; do
CLIENT_NAME="${MONITORS[$MONITOR_ID]}"
# Fetch 30-day rolling uptime
UPTIME=$(curl -s "${BASE_URL}/monitors/${MONITOR_ID}" \
-H "Authorization: Bearer ${API_KEY}" \
| jq -r '.data.uptime_30d // "N/A"')
# Fetch current-month incident summary
INCIDENT_DATA=$(curl -s "${BASE_URL}/incidents?monitor_id=${MONITOR_ID}&status=resolved&per_page=100" \
-H "Authorization: Bearer ${API_KEY}" \
| jq --arg ym "${MONTH}" '
[.data[] | select(.resolved_at | startswith($ym))]
| {count: length, total_min: (map(.duration_seconds) | (add // 0) / 60 | round)}
')
INCIDENT_COUNT=$(echo "$INCIDENT_DATA" | jq -r '.count')
DOWNTIME_MIN=$(echo "$INCIDENT_DATA" | jq -r '.total_min')
echo "## ${CLIENT_NAME}"
echo "- Rolling 30-day uptime: ${UPTIME}%"
echo "- Incidents this month: ${INCIDENT_COUNT}"
echo "- Total downtime: ${DOWNTIME_MIN} min"
echo ""
done
Run this script via cron on the first of each month, pipe the output to a Markdown or HTML template, and send it via your mail service of choice (SendGrid, Postmark, SES, etc.). That completes the automation loop.
Pairing Reports with a Status Page
A monthly email report is valuable on its own, but pairing it with a client-facing status page compounds the effect. When clients want to know if their site is up right now, they can check the status page instead of emailing you. That reduces reactive support traffic and positions you as the kind of agency that provides transparent, professional tooling.
Miterl's status pages are linked to your monitors and publicly accessible. Share the URL with your client at onboarding, and ask them to bookmark it.
For a full breakdown of what status pages cost to run and how to price them into your retainer, see "Status Page Cost and ROI for Agencies: A Pricing Breakdown".
Using Reports to Justify and Grow Retainer Fees
The strategic purpose of a monthly uptime report is to remind clients what they are paying for. In months with no incidents, "we maintained 99.99% uptime" is not a non-event — it is proof that the monitoring and maintenance infrastructure worked. Without a report, that month looks like nothing happened. With a report, it looks like a quiet, stable operation delivered on schedule.
Clients who cancel maintenance contracts most often cite a vague sense of not seeing value. A report converts that vague unease into a concrete record. Once a client has twelve months of uptime data in their inbox, your retainer becomes something they understand, not something they question.
For the broader business case for including monitoring in every maintenance contract, "Why Agencies Should Include Monitoring in Contracts" covers positioning, pricing, and common objections.
If you want to formalize uptime commitments with SLA targets in your contracts, "Automating SLA Reports for Maintenance Subscriptions" extends the approach above with calendar-month accuracy calculations and automated delivery.
What to Include in a Client Uptime Report
A minimal but effective report structure:
| Field | Example |
|---|---|
| Reporting period | June 1–30, 2026 |
| Monitored URL | https://example-client.com |
| Uptime (30-day rolling) | 99.97% |
| Incidents this month | 1 |
| Total downtime | 9 min |
| Status page URL | https://status.example-client.com |
| Upcoming maintenance | WordPress core update scheduled |
Keep it simple. The goal is not to impress clients with complexity — it is to give them a number they can feel good about. Charts and detailed logs add polish, but the core value is the uptime percentage and incident count.
Summary
Automating monthly uptime reports delivers three compounding benefits for agencies:
- Time savings: Eliminate the month-end data collection grind
- Trust building: Deliver a consistent, numbers-backed proof of work each month
- Revenue protection: Make the value of your retainer undeniable, reducing cancellations and supporting fee increases
Start with one or two clients. Pull their monitor data using the script above, format it into a simple email, and send it manually first to see how clients respond. Once the format feels right, automate the delivery and roll it out across your entire roster.