API Documentation

The MyUpMonitor API lets you programmatically manage monitors, incidents, status pages, and notifications. Available on Business and Enterprise plans.

Base URL

https://myupmonitor.com/api

Rate Limits

PlanLimit
Free30 req/min
Pro100 req/min
Business1,000 req/min
Enterprise1,000 req/min

Rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After

Authentication

Create an API key in Dashboard → Settings → API Keys. Include it as a Bearer token:

Authorization: Bearer mum_your_api_key_here
AUTH All API endpoints
curl -H "Authorization: Bearer mum_your_key" \
  https://myupmonitor.com/api/monitors

API Key Scopes

API keys can be scoped to limit access. Keys with no scopes have full access (backwards compatible). Create scoped keys via POST /api/keys with a scopes array.

Available Scopes

ScopeGrants Access To
monitors:readList and view monitors
monitors:writeCreate, update, delete monitors
incidents:readList and view incidents
incidents:writeCreate, update, delete incidents
notifications:readList notification channels
notifications:writeCreate, update, delete channels
account:readView account info
status-pages:readList and view status pages
status-pages:writeCreate, update status pages
reports:readView SLA and weekly reports
POST/api/keysCreate a scoped API key
{
  "name": "CI/CD Read-Only",
  "scopes": ["monitors:read", "incidents:read"]
}

// Response (raw key shown once):
{
  "key": { "id": "uuid", "name": "CI/CD Read-Only", "scopes": ["monitors:read", "incidents:read"] },
  "rawKey": "mum_..."
}

Keys with empty scopes: [] or no scopes field have full access. A scoped key trying to access an endpoint outside its scopes receives 403 Forbidden.

Monitors

GET /api/monitors List all monitors
// Response
[
  {
    "id": "uuid",
    "website": "https://example.com",
    "check_type": "http",
    "interval_seconds": 60,
    "active": true,
    "last_status": 200,
    "uptime_24h": 99.95,
    "avg_response_ms": 245
  }
]
POST /api/monitors Create a monitor
curl -X POST /api/monitors \
  -H "Authorization: Bearer mum_key" \
  -H "Content-Type: application/json" \
  -d '{"website":"https://example.com","check_type":"http","interval_seconds":60}'
GET/api/monitors/:idGet monitor details
PUT/api/monitors/:idUpdate a monitor
DELETE/api/monitors/:idDelete a monitor
GET /api/monitors/:id/status?period=24h Status history
// Response
{
  "uptime_percent": 99.95,
  "avg_response_ms": 245,
  "total_checks": 1440,
  "incidents": 1,
  "history": [
    { "timestamp": "2026-03-25T10:00:00Z", "status": 200, "response_ms": 230, "region": "us-east" }
  ]
}

Periods: 24h, 7d, 30d

Monitor Check Types

When creating a monitor, set check_type to one of the following. Each type accepts different parameters.

TypeDescriptionExtra Fields
httpHTTP(S) status checkhttp_keyword, http_keyword_negate, response_time_threshold_ms
sslSSL certificate expiryAlerts at 30/14/7/1 days before expiry
tcpTCP port connectivitytcp_port (required, 1-65535)
dnsDNS record monitoringdns_record_type (A/AAAA/MX/TXT/CNAME), dns_expected_value
heartbeatDead man's switchReturns heartbeat_token — ping /api/heartbeat/:token to report health
apiMulti-step API checksapi_check_steps (JSON array of steps)
POST/api/monitorsDNS monitor example
{
  "url": "example.com",
  "check_type": "dns",
  "dns_record_type": "A",
  "dns_expected_value": "93.184.216.34",
  "interval_seconds": 600
}
POST/api/monitorsHTTP with keyword assertion
{
  "url": "https://example.com",
  "check_type": "http",
  "http_keyword": "Welcome",
  "http_keyword_negate": false,
  "response_time_threshold_ms": 2000,
  "interval_seconds": 300
}
POST/api/monitorsMulti-step API check
// api_check_steps is a JSON string containing an array of steps:
// Each step: name, method, url, headers, body, assertions, extract
//
// Step fields:
//   assertions: [{type: "status", value: "200"},
//                {type: "body_contains", value: "ok"},
//                {type: "json_path", path: "data.id", value: "123"}]
//   extract: {"token": "data.access_token"} (dot-notation JSON path)
//
// Variables from extract are available in later steps as {{token}}

Steps run sequentially with fail-fast. SSRF protection on all step URLs.

Escalation Policies

Define multi-step alert escalation chains. If nobody acknowledges an alert, it escalates to the next tier of channels.

GET/api/escalation-policiesList escalation policies
POST/api/escalation-policiesCreate escalation policy
{
  "name": "Production Alerts",
  "steps": [
    { "delayMinutes": 0, "channelIds": ["slack-channel-id"] },
    { "delayMinutes": 5, "channelIds": ["pagerduty-channel-id"] },
    { "delayMinutes": 15, "channelIds": ["email-channel-id"] }
  ]
}

Step 1 fires immediately. Subsequent steps fire if no acknowledgment within the delay.

POST/api/alerts/:id/acknowledgeAcknowledge an active escalation

Stops further escalation for this alert. Recovery auto-acknowledges.

DELETE/api/escalation-policies/:idDelete policy (unlinks from monitors)

Incidents

GET/api/incidentsList incidents

Query params: monitor_id, active=true

POST/api/incidentsCreate manual incident
{
  "monitor_id": "uuid",
  "title": "API degradation",
  "status": "investigating"
}
GET/api/incidents/:idGet incident with timeline
POST/api/incidents/:id/updatesAdd status update
{
  "status": "identified",  // investigating | identified | monitoring | resolved
  "message": "Root cause identified — deploying fix"
}
DELETE/api/incidents/:idDelete incident

Status Pages

GET/api/status-pagesList status pages
POST/api/status-pagesCreate status page
{
  "name": "Acme Status",
  "slug": "acme",
  "custom_domain": "status.acme.com"  // optional, Business+ plans
}
POST/api/status-pages/:id/monitorsLink monitors
POST/api/status-pages/:id/domain/verifyVerify custom domain

Notification Channels

GET/api/notificationsList channels
POST/api/notificationsCreate channel
// Slack
{ "name": "Ops Slack", "type": "slack", "config": { "webhook_url": "https://hooks.slack.com/..." } }

// Discord
{ "name": "Alerts", "type": "discord", "config": { "webhook_url": "https://discord.com/api/webhooks/..." } }

// Webhook
{ "name": "Custom", "type": "webhook", "config": { "url": "https://example.com/hook", "secret": "hmac_secret" } }
POST/api/notifications/:id/testSend test notification
PUT/api/monitors/:id/notificationsLink channels to monitor

Heartbeat Pings

Heartbeat monitors work like a dead man's switch. Create a heartbeat monitor to get a unique ping URL. Your cron job or service should hit this URL on a schedule. If we don't receive a ping within the expected interval + grace period, we alert.

POST/api/heartbeat/:tokenSend heartbeat ping (no auth required)
# Add to your crontab:
*/5 * * * * curl -fsS -o /dev/null https://myupmonitor.com/api/heartbeat/your_token_here

# Or from a script:
curl -X POST https://myupmonitor.com/api/heartbeat/your_token_here

Also accepts GET for simplicity. Returns { "ok": true } on success.

POST/api/monitorsCreate heartbeat monitor
{
  "url": "Nightly Backup Job",
  "check_type": "heartbeat",
  "interval_seconds": 86400,
  "heartbeat_grace_minutes": 30
}

// Response includes heartbeat_token:
{
  "monitor": {
    "id": "uuid",
    "heartbeat_token": "a1b2c3..."  // Use this in your ping URL
  }
}

Webhook Verification

When using webhook notification channels with a secret, we sign the payload with HMAC-SHA256. Verify like this:

HMACSignature Verification
const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return `sha256=${expected}` === signature;
}

// In your handler:
const sig = req.headers['x-signature-256'];
if (!verifyWebhook(rawBody, sig, 'your_secret')) {
  return res.status(401).send('Invalid signature');
}

Webhook Payload

{
  "event": "monitor.down",
  "monitor": {
    "id": "uuid",
    "website": "https://example.com",
    "check_type": "http"
  },
  "status": {
    "http_status": 503,
    "response_ms": 5000,
    "error": "timeout",
    "region": "us-east"
  },
  "timestamp": "2026-03-25T10:00:00Z"
}

Events: monitor.down, monitor.up, ssl.expiring