2026-06-13

How to Automate Monthly Uptime Reports for Clients

web agency report automation uptime maintenance contract API

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:

  1. Rolling 30-day uptime (uptime_30d): Percentage of time the monitor was up over the last 30 days
  2. Incident list (/api/v1/incidents): Start time, resolution time, and duration in seconds for each outage
  3. 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:

  1. Time savings: Eliminate the month-end data collection grind
  2. Trust building: Deliver a consistent, numbers-backed proof of work each month
  3. 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.

Start your free Miterl trial