Enori API Documentation

The Enori API lets you manage monitors, incidents, alerts, status pages, and more programmatically. All endpoints use REST conventions with JSON request and response bodies.

Base URL: https://api.enori.io

Quick Start

Get monitoring set up in three steps.

1. Get Your API Key

Navigate to Settings → API Keys in your dashboard and create a new key. Choose scopes based on what you need:

ScopeAccess
monitors:readList and view monitors
monitors:writeCreate, update, delete, pause/resume monitors
incidents:readList and view incidents
status-pages:readList and view status pages
status-pages:writeCreate, update, delete status pages
teams:readList teams and members
teams:writeManage teams
*Full access (all scopes)

2. Make Your First Request

bash
curl -H "X-API-Key: YOUR_API_KEY" https://api.enori.io/api/monitors

3. Set Up Alerts

Create a webhook alert channel to receive real-time notifications when monitors go down or recover:

bash
curl -X POST https://api.enori.io/api/alert-channels \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Webhook",
    "type": "Webhook",
    "webhookUrl": "https://your-server.com/webhook"
  }'

Authentication

All API requests require an API key passed in the X-API-Key header:

bash
curl -H "X-API-Key: YOUR_API_KEY" https://api.enori.io/api/monitors

API keys are scoped — choose the minimum permissions needed. Keys can be created and managed at Settings → API Keys or via the /api/keys endpoint.

Never share your API key. Treat it like a password. If compromised, revoke it immediately from the dashboard and create a new one.

Managing API Keys

POST/api/keys

Create a new API key. The full key is returned only once in the response — store it securely.

json
{
  "name": "CI/CD Pipeline",
  "scopes": ["monitors:read", "monitors:write"]
}
GET/api/keys

List all API keys (key values are masked).

DELETE/api/keys/{id}

Revoke and delete an API key.

Rate Limits

Rate limits protect the API from abuse. Limits are applied per API key.

EndpointLimit
General API calls100 / minute
Read operations200 / minute
Create monitor10 / hour
Check now5 / minute
Test alert5 / minute

When rate limited, the API returns HTTP 429 Too Many Requests with these headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed
X-RateLimit-RemainingRequests remaining in window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait before retrying

Monitors

List Monitors

GET/api/monitors

Query parameters:

ParameterTypeDescription
tagstringFilter by tag (repeat for AND logic: ?tag=prod&tag=api)
typestringFilter by type: Website, Ping, Port, Dns, Domain, Job
bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://api.enori.io/api/monitors?type=Website"

Response:

json
{
  "items": [
    {
      "id": "mon_abc123",
      "name": "Production API",
      "type": "Website",
      "url": "https://api.example.com",
      "status": "Up",
      "uptimePercentage": 99.95,
      "lastCheckedAt": "2026-03-24T10:30:00Z",
      "intervalSeconds": 60
    }
  ],
  "totalCount": 1
}

Get Monitor

GET/api/monitors/{id}

Returns full monitor details including configuration and current state.

Create Monitor

POST/api/monitors
json
{
  "name": "Production API",
  "type": "Website",
  "url": "https://api.example.com",
  "intervalSeconds": 60,
  "timeoutSeconds": 30,
  "httpMethod": "GET",
  "expectedStatusCode": 200,
  "failureThreshold": 2,
  "alertOnDown": true,
  "alertOnRecovered": true,
  "alertChannelIds": ["ch_abc123"],
  "regions": ["UsEast", "EuWest"],
  "tags": ["production", "api"]
}

Monitor types:

TypeValueUse For
Website10HTTP/HTTPS endpoints, APIs, websites
Ping3ICMP ping checks
Port2TCP port availability
Dns4DNS record monitoring
Domain6Domain expiry tracking
Job8Cron job / heartbeat monitoring

Update Monitor

PUT/api/monitors/{id}

Send the full monitor configuration. Fields not included will be reset to defaults.

Upsert by Name

PUT/api/monitors/by-name/{name}

Idempotent — creates if not exists, updates if exists. Always returns 200. Ideal for infrastructure-as-code and Terraform workflows. The URL name takes precedence over the body name.

Delete Monitor

DELETE/api/monitors/{id}

Permanently deletes the monitor and all associated data (check results, incidents, alerts).

Pause and Resume

POST/api/monitors/{id}/pause
POST/api/monitors/{id}/resume

Pausing stops checks and alerts. Resuming triggers an immediate check.

Trigger Immediate Check

POST/api/monitors/{id}/check

Triggers an on-demand check outside the regular interval. Rate limited to 5 per minute.

Check Results

GET/api/monitors/{id}/checks?limit=50

Returns recent check results with response time, status code, and error details.

Statistics

GET/api/monitors/{id}/stats?days=30
GET/api/monitors/{id}/response-time-stats?days=7
GET/api/monitors/{id}/stats/hourly
GET/api/monitors/{id}/stats/daily

Incidents

List Incidents

GET/api/incidents

Returns { items: [...], totalCount: N }.

ParameterTypeDescription
monitorIdstringFilter by monitor
statusstringFilter by status
fromdatetimeStart date (ISO 8601)
todatetimeEnd date (ISO 8601)
limitintMax results (default 50)
offsetintPagination offset

Recent and Active Incidents

GET/api/incidents/recent
GET/api/incidents/active

Get Incident

GET/api/incidents/{id}

Create Manual Incident

POST/api/incidents

Acknowledge

POST/api/incidents/{id}/acknowledge

Stops escalation timers for this incident.

Resolve

POST/api/incidents/{id}/resolve

Add Update

POST/api/incidents/{id}/updates

Post a status update to the incident timeline.

Incident Statistics

GET/api/incidents/stats

Incidents by Monitor

GET/api/incidents/by-monitor/{monitorId}

Alerts

List Alert Records

GET/api/alerts
ParameterTypeDescription
monitorIdstringFilter by monitor
statusstringFilter by delivery status
typestringAlert type (Down, Recovered, P95, etc.)
fromdatetimeStart date
todatetimeEnd date
limitintMax results
offsetintPagination offset

Alert Channels

Manage where alerts are delivered.

GET/api/alert-channels
POST/api/alert-channels
PUT/api/alert-channels/{id}
DELETE/api/alert-channels/{id}
POST/api/alert-channels/{id}/test

Supported channel types: Email, Slack, Discord, Teams, Webhook

Alert Rules

Configure which monitors trigger which channels.

GET/api/alerts/rules
POST/api/alerts/rules
PUT/api/alerts/rules/{id}
DELETE/api/alerts/rules/{id}
POST/api/alerts/rules/{id}/enable
POST/api/alerts/rules/{id}/disable
POST/api/alerts/rules/{id}/test

Job Monitoring

Enori's Job monitor type tracks cron jobs and scheduled tasks using heartbeat pings.

How It Works

  1. Create a Job monitor with a cron expression defining your expected schedule
  2. Get the unique ping token from the monitor details
  3. Add ping calls to your job script — Enori alerts you if pings stop arriving

Ping Endpoints

These endpoints require no authentication — just the unique token.

GET/ping/{token}

Report job success (heartbeat).

GET/ping/{token}/fail

Report job failure.

GET/ping/{token}/start

Report job start (enables runtime tracking).

All three endpoints accept GET, HEAD, and POST methods.

Example: Shell Cron Job

bash
#!/bin/bash
# Notify Enori the job has started
curl -fsS -m 10 https://api.enori.io/ping/YOUR_TOKEN/start

# Run the actual job
/usr/bin/backup-database.sh

# Report success or failure based on exit code
if [ $? -eq 0 ]; then
  curl -fsS -m 10 https://api.enori.io/ping/YOUR_TOKEN
else
  curl -fsS -m 10 https://api.enori.io/ping/YOUR_TOKEN/fail
fi

Example: GitHub Actions

yaml
name: Nightly Build
on:
  schedule:
    - cron: '0 2 * * *'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: curl -fsS https://api.enori.io/ping/${{ secrets.ENORI_TOKEN }}/start
      - run: npm ci && npm run build
      - run: curl -fsS https://api.enori.io/ping/${{ secrets.ENORI_TOKEN }}
        if: success()
      - run: curl -fsS https://api.enori.io/ping/${{ secrets.ENORI_TOKEN }}/fail
        if: failure()

Example: Python Script

python
import requests
import sys

TOKEN = "YOUR_TOKEN"
BASE = "https://api.enori.io/ping"

# Signal start
requests.get(f"{BASE}/{TOKEN}/start", timeout=10)

try:
    # Your job logic here
    run_etl_pipeline()
    requests.get(f"{BASE}/{TOKEN}", timeout=10)
except Exception:
    requests.get(f"{BASE}/{TOKEN}/fail", timeout=10)
    sys.exit(1)

Ping History

GET/api/monitors/{id}/pings

Returns the heartbeat history for a Job monitor including execution times, status, and messages.

Status Pages

Authenticated Endpoints

GET/api/status-pages
POST/api/status-pages
PUT/api/status-pages/{id}
DELETE/api/status-pages/{id}
POST/api/status-pages/{id}/custom-domain
POST/api/status-pages/{id}/verify-domain
GET/api/status-pages/check-slug/{slug}

Public Endpoints (No Auth)

GET/api/status-pages/public/{slug}

View a public status page — returns component statuses, uptime data, and incident history.

POST/api/status-pages/public/{slug}/subscribe

Subscribe to status page updates via email.

Webhooks

When you create a Webhook alert channel, Enori will POST JSON payloads to your URL whenever monitor events occur.

Payload Format

json
{
  "event": "monitor.down",
  "monitor": {
    "id": "mon_abc123",
    "name": "Production API",
    "url": "https://api.example.com",
    "type": "Website"
  },
  "alert": {
    "type": "Down",
    "message": "HTTP 503 Service Unavailable",
    "timestamp": "2026-03-24T14:30:00Z",
    "responseTimeMs": 5230
  }
}

Event Types

EventDescription
monitor.downMonitor detected as down
monitor.upMonitor recovered
monitor.degradedPerformance degradation (P95 threshold exceeded)
monitor.ssl_expiringSSL certificate expiring soon
incident.createdNew incident created
incident.resolvedIncident resolved

Security

Verify webhook authenticity by checking:

  • The User-Agent header contains Enori-Webhook/1.0
  • The request arrives within seconds of the event timestamp
  • Your endpoint URL uses HTTPS

Retry Policy

Failed webhook deliveries (non-2xx response or timeout) are retried:

  • Up to 3 retries with exponential backoff: 30s, 5m, 30m
  • After all retries fail, the delivery is marked as failed
  • Failed deliveries are visible in your alert history

Uptime Badges

Embed uptime and status badges in your README, documentation, or status page.

Uptime Badge

GET/api/badges/{monitorId}/uptime.svg

Status Badge

GET/api/badges/{monitorId}/status.svg

Parameters

ParameterDefaultOptionsDescription
period30d24h, 7d, 30d, 90dTime range (uptime badge only)
labeluptime / statusAny string (max 30 chars)Left side label text
styleflatflat, flat-squareBadge style

Embed in Markdown

markdown
![Uptime](https://api.enori.io/api/badges/mon_abc123/uptime.svg)
![Status](https://api.enori.io/api/badges/mon_abc123/status.svg?style=flat-square)

Embed in HTML

html
<img src="https://api.enori.io/api/badges/mon_abc123/uptime.svg" alt="Uptime" />

Badges are cached for 5 minutes. Returns a gray "unknown" badge if the monitor is not found or inactive.

Error Responses

The API uses standard HTTP status codes and returns JSON error bodies.

Status Codes

CodeDescription
200Success
201Created
202Accepted (async operation started)
204No Content (successful deletion)
400Bad Request — validation error
401Unauthorized — missing or invalid API key
403Forbidden — insufficient scope or plan limit exceeded
404Not Found
429Too Many Requests — rate limit exceeded
500Internal Server Error

Error Format

json
{
  "error": "Monitor limit exceeded",
  "message": "Your Base plan allows 10 monitors. Upgrade to Pro for up to 50.",
  "code": "PLAN_LIMIT_EXCEEDED"
}

Common Errors

ScenarioCodeWhat to Do
Invalid API key401Check the key is correct and not revoked
Missing required scope403Create a new key with the required scope
Plan limit exceeded403Upgrade your plan or remove unused resources
Rate limited429Wait for Retry-After seconds, then retry
Invalid request body400Check the error message for field-level details

Plan Limits

LimitBase (€5.99/mo)Pro (€11.99/mo)Business (€29.99/mo)
Monitors1050200
Check Interval60s60s60s
Data Retention30 days60 days90 days
API Keys21050
Alert Channels515Unlimited
Teams210Unlimited
Members per Team31025
Status Pages31050
Escalation Policies21020
Maintenance Windows210Unlimited
Reports per Month310Unlimited

Add-ons (available on any plan):

Add-onPriceEffect
Extra Monitor€0.50/month each+1 to your plan's monitor limit
30s Check Interval€3.00/monthUnlock 30-second checks (account-wide)

All plans include a 14-day free trial.

Code Examples

cURL

bash
# List all monitors
curl -H "X-API-Key: YOUR_API_KEY" \
  https://api.enori.io/api/monitors

# Create a website monitor
curl -X POST https://api.enori.io/api/monitors \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production API",
    "type": "Website",
    "url": "https://api.example.com/health",
    "intervalSeconds": 60,
    "expectedStatusCode": 200,
    "alertOnDown": true,
    "alertOnRecovered": true
  }'

# Pause a monitor
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  https://api.enori.io/api/monitors/mon_abc123/pause

# Trigger an immediate check
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  https://api.enori.io/api/monitors/mon_abc123/check

Python

python
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.enori.io"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

# Create a monitor
monitor = requests.post(f"{BASE}/api/monitors", headers=HEADERS, json={
    "name": "Staging API",
    "type": "Website",
    "url": "https://staging.example.com",
    "intervalSeconds": 300,
    "expectedStatusCode": 200,
}).json()
print(f"Created monitor: {monitor['id']}")

# List all monitors
data = requests.get(f"{BASE}/api/monitors", headers=HEADERS).json()
for m in data["items"]:
    print(f"  {m['name']}: {m['status']} ({m['uptimePercentage']:.2f}%)")

# Get recent incidents
incidents = requests.get(
    f"{BASE}/api/incidents/recent", headers=HEADERS
).json()
for inc in incidents:
    print(f"  [{inc['status']}] {inc['title']}")

Node.js

javascript
const API_KEY = "YOUR_API_KEY";
const BASE = "https://api.enori.io";

async function enori(path, options = {}) {
  const res = await fetch(\`\${BASE}\${path}\`, {
    ...options,
    headers: {
      "X-API-Key": API_KEY,
      "Content-Type": "application/json",
      ...options.headers,
    },
  });
  if (!res.ok) throw new Error(\`\${res.status}: \${await res.text()}\`);
  return res.json();
}

// Create a monitor
const monitor = await enori("/api/monitors", {
  method: "POST",
  body: JSON.stringify({
    name: "Checkout Service",
    type: "Website",
    url: "https://checkout.example.com/health",
    intervalSeconds: 60,
  }),
});
console.log(\`Created: \${monitor.id}\`);

// List all monitors
const { items } = await enori("/api/monitors");
items.forEach((m) => console.log(\`\${m.name}: \${m.status}\`));

GitHub Actions

yaml
name: Deploy and Verify Uptime
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build && npm run deploy

      - name: Verify monitors after deploy
        env:
          ENORI_KEY: ${{ secrets.ENORI_API_KEY }}
        run: |
          sleep 30
          RESPONSE=$(curl -s -H "X-API-Key: $ENORI_KEY" \
            "https://api.enori.io/api/monitors?tag=production")
          echo "$RESPONSE" | jq '.items[] | "\(.name): \(.status)"'

          DOWN=$(echo "$RESPONSE" | jq '[.items[] | select(.status == "Down")] | length')
          if [ "$DOWN" -gt 0 ]; then
            echo "::error::$DOWN production monitors are down!"
            exit 1
          fi

Interactive API Explorer

For a complete interactive reference with all endpoints, request/response schemas, and the ability to try requests directly, visit the Scalar API documentation:

Open API Explorer →

The OpenAPI 3.0 specification is also available programmatically:

bash
curl https://api.enori.io/openapi/v1.json