Monitors

A monitor checks one server's VPN/proxy tunnels — one or more protocols on the same server — from ExitProbe's probe network (or your own custom probes), verifying it connects, the exit IP matches what's expected, and reporting latency and uptime history.

For the exact configuration fields each protocol needs (WireGuard config, VLESS/Hysteria2/Trojan/Shadowsocks/VMess URIs, IKEv2 credentials, OpenVPN config), see the Protocol Reference — Create Monitor below only lists the field names, not their formats.
GET/monitors
List Monitors

List your monitors with filtering, optional pagination, and fleet status counts. `data.summary` always counts the WHOLE filtered fleet (up / down / degraded / flapping / ip_mismatch / inactive), never just the page you asked for. Send `per_page` (and optionally `page`) to paginate; omit both and every monitor is returned.

Query Parameters
project_idintegerFilter by project ID
protocolstringFilter by protocol: wireguard, openvpn, ikev2, vless, hysteria, trojan, shadowsocks, vmess
statusstringFilter by fleet health: up, down, degraded, flapping, ip_mismatch, unknown
tagstringOnly monitors carrying this tag
per_pageintegerPage size, 1–100. Sending this (or page) turns pagination on and fills data.pagination.
pageintegerPage number, starting at 1
defer_uptimebooleanSkip the per-monitor uptime bars and the fleet chart — much faster for large fleets
leanbooleanDrop stored configs and credentials from each row
searchstringSearch by name, IP, or hostname
rangestringUptime history range: 1h, 6h, 12h, 24h, 7d, 30d, 90d
Example Request
curl -X GET '/api/v1/monitors?status=up&range=24h' \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "total": 2,
    "summary": {
      "total": 2,
      "up": 2,
      "down": 0,
      "degraded": 0,
      "flapping": 0,
      "ip_mismatch": 0,
      "unknown": 0,
      "inactive": 0
    },
    "pagination": { "page": 1, "per_page": 25, "total": 2, "last_page": 1, "has_more": false },
    "fleet_counts": {
      "total": 2,
      "up": 2,
      "down": 0,
      "ip_mismatch": 0
    },
    "fleet_uptime": {
      "uptime_percentage": 99.8,
      "avg_latency_ms": 45,
      "total_checks": 288,
      "incidents_count": 1,
      "range": "24h",
      "bars": [
        {
          "status": "up",
          "percentage": 100,
          "uptime_pct": 100.0,
          "latency_ms": 42,
          "avg_latency_ms": 42,
          "checks_count": 144,
          "label": "0%",
          "timestamp_label": "00:00",
          "tooltip": "Up - 100%",
          "color": "green",
          "color_class": "bg-green-500"
        }
      ]
    },
    "monitors": [
      {
        "id": 1,
        "project_id": 1,
        "project_name": "Default",
        "name": "VPN Exit Node 1",
        "expected_exit_ip": "203.0.113.45",
        "is_active": true,
        "is_ip_verified": true,
        "is_test": false,
        "check_interval_seconds": 300,
        "status": "up",
        "fleet_health": {
          "status": "up",
          "label": "All Systems Operational",
          "reason": "All enabled protocols are working correctly"
        },
        "protocols_summary": {
          "wireguard": {
            "enabled": true,
            "status": "working",
            "latency_ms": 42,
            "last_check_at": "2026-08-22T10:30:00Z",
            "last_exit_ip": "203.0.113.45"
          },
          "openvpn": {
            "enabled": false,
            "status": "not_configured",
            "latency_ms": null
          }
        },
        "uptime_history": {
          "uptime_percentage": 99.8,
          "avg_latency_ms": 42,
          "total_checks": 144,
          "incidents_count": 1,
          "range": "24h",
          "bars": []
        },
        "last_check_at": "2026-08-22T10:30:00Z",
        "last_latency_ms": 42,
        "last_exit_ip": "203.0.113.45",
        "last_exit_location": "New York, US",
        "exit_country_code": "US",
        "flag_url": "https://flags.example.com/us.svg",
        "wireguard_enabled": true,
        "openvpn_enabled": false,
        "ikev2_enabled": false,
        "vless_enabled": false,
        "hysteria_enabled": false,
        "probe_mode": "all",
        "probe_id": null,
        "probe_ids": [],
        "probes": [],
        "single_probe": null
      }
    ]
  }
}
POST/monitors
Create Monitor

Register a new VPN monitor. At least one protocol (WireGuard, OpenVPN, IKEv2, VLESS, Hysteria, Trojan, Shadowsocks, or VMess) must be enabled and configured, or the request fails with 422.

Request Body
name*stringMonitor name (max 255 chars)
expected_exit_ipstringExpected exit IP for verification (enables IP mismatch alerts). Max 64 chars.
protocolstringLegacy single-protocol mode: one of wireguard, openvpn, ikev2, vless, hysteria, trojan, shadowsocks, vmess. When set, use the legacy config_content/uri/target_host/auth_* fields below instead of the per-protocol ones.
check_interval_secondsintegerCheck frequency in seconds. Minimum is plan-dependent, maximum is 3600. Defaults to your plan's minimum interval.
probe_idintegerSingle probe ID for dedicated monitoring (must exist in probes table; requires plan permission — see notes)
probe_idsarray<integer>Array of probe IDs for custom subset monitoring (each must exist in probes table; requires plan permission — see notes)
wireguard_enabledbooleanEnable WireGuard monitoring
wireguard_configstringWireGuard client configuration file content (required if wireguard_enabled and protocol is not legacy-set)
openvpn_enabledbooleanEnable OpenVPN monitoring
openvpn_configstringOpenVPN client configuration file content
openvpn_auth_usernamestringOpenVPN auth username, if the config requires separate credentials (max 255 chars)
openvpn_auth_passwordstringOpenVPN auth password, if the config requires separate credentials
ikev2_enabledbooleanEnable IKEv2 monitoring
ikev2_target_hoststringIKEv2 server address (required if ikev2_enabled). Max 255 chars.
ikev2_remote_idstringIKEv2 remote ID / remote address, if different from target_host. Max 255 chars.
ikev2_auth_usernamestringIKEv2 EAP identity (required if ikev2_enabled). Max 255 chars.
ikev2_auth_passwordstringIKEv2 EAP secret (required if ikev2_enabled)
vless_enabledbooleanEnable VLESS monitoring
vless_uristringFull vless:// connection URI (required if vless_enabled). Any URI is accepted — Reality, plain TLS, or unencrypted; raw TCP, WebSocket, gRPC, HTTPUpgrade, or XHTTP — not just Reality.
hysteria_enabledbooleanEnable Hysteria 2 monitoring
hysteria_uristringFull hysteria2:// connection URI (required if hysteria_enabled)
trojan_enabledbooleanEnable Trojan monitoring
trojan_uristringFull trojan:// connection URI (required if trojan_enabled)
shadowsocks_enabledbooleanEnable Shadowsocks monitoring
shadowsocks_uristringFull ss:// connection URI (required if shadowsocks_enabled). SIP002 (plaintext or base64 userinfo) and legacy fully-base64-encoded forms are both accepted.
vmess_enabledbooleanEnable VMess monitoring
vmess_uristringFull vmess:// connection URI (required if vmess_enabled) — the standard base64(JSON) share-link format
config_contentstring[Legacy] Config file content — only used when protocol is set directly (wireguard or openvpn)
uristring[Legacy] Connection URI — only used when protocol is set directly (vless or hysteria)
target_hoststring[Legacy] Server address — only used when protocol is set to ikev2. Max 255 chars.
target_portinteger[Legacy] Server port (1–65535)
remote_idstring[Legacy] Remote ID — only used when protocol is set to ikev2. Max 255 chars.
auth_usernamestring[Legacy] Auth username — only used when protocol is set to ikev2 or openvpn. Max 255 chars.
auth_passwordstring[Legacy] Auth password — only used when protocol is set to ikev2 or openvpn
Notes
  • •At least one of the *_enabled flags (or the matching config/URI field) must be set, or the request fails with a 422 "At least one VPN protocol must be configured."
  • •Fails with 422 if your monitor count is already at or over your plan's monitor_limit.
  • •check_interval_seconds has no fixed minimum — the floor is plan-dependent (getMinCheckIntervalSeconds()); the max is always 3600. Sending below your plan's floor returns a 422 naming the exact minimum.
  • •probe_id / probe_ids are only honored if your plan allows manual probe selection (canSelectProbes()) — otherwise they're silently ignored and the monitor runs against the global probe pool.
  • •The legacy config_content / uri / target_host / target_port / remote_id / auth_username / auth_password fields exist for single-protocol payloads (protocol set directly) — for multi-protocol monitors, prefer the per-protocol fields below (wireguard_config, ikev2_target_host, vless_uri, etc).
Example Request
curl -X POST /api/v1/monitors \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VPN Exit Node 1",
    "expected_exit_ip": "203.0.113.45",
    "check_interval_seconds": 300,
    "wireguard_enabled": true,
    "wireguard_config": "[Interface]\nPrivateKey=...",
    "probe_mode": "all"
  }'
Example Response
{
  "success": true,
  "message": "Server Monitor registered successfully. Probing will initiate shortly.",
  "data": {
    "monitor": {
      "id": 1,
      "user_id": 1,
      "project_id": 1,
      "name": "VPN Exit Node 1",
      "protocol": "wireguard",
      "expected_exit_ip": "203.0.113.45",
      "check_interval_seconds": 300,
      "status": "pending",
      "is_active": true,
      "wireguard_enabled": true,
      "wireguard_config": "[Interface]\nPrivateKey=...",
      "openvpn_enabled": false,
      "ikev2_enabled": false,
      "vless_enabled": false,
      "hysteria_enabled": false,
      "probe_id": null,
      "probe_ids": [],
      "created_at": "2026-08-22T10:30:00Z",
      "updated_at": "2026-08-22T10:30:00Z"
    },
    "protocols": ["wireguard"]
  }
}
GET/monitors/{id}
Get Monitor

Retrieve detailed information about a specific monitor, including recent checks.

Query Parameters
rangestringUptime history range: 1h, 6h, 12h, 24h, 7d, 30d, 90d
Example Request
curl -X GET /api/v1/monitors/1 \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "monitor": {
      "id": 1,
      "user_id": 1,
      "project_id": 1,
      "name": "VPN Exit Node 1",
      "protocol": "wireguard",
      "expected_exit_ip": "203.0.113.45",
      "is_active": true,
      "is_ip_verified": true,
      "check_interval_seconds": 300,
      "status": "up",
      "last_check_at": "2026-08-22T10:30:00Z",
      "last_latency_ms": 42,
      "last_exit_ip": "203.0.113.45",
      "exit_country_code": "US",
      "exit_location_display": "New York, US",
      "wireguard_enabled": true,
      "wireguard_config": "[Interface]\nPrivateKey=...",
      "openvpn_enabled": false,
      "ikev2_enabled": false,
      "vless_enabled": false,
      "hysteria_enabled": false
    },
    "is_active": true,
    "is_ip_verified": true,
    "ip_mismatch_details": null,
    "fleet_health": {
      "status": "up",
      "label": "All Systems Operational",
      "reason": "All enabled protocols are working correctly"
    },
    "protocols_summary": {
      "wireguard": {
        "enabled": true,
        "status": "working",
        "latency_ms": 42,
        "last_check_at": "2026-08-22T10:30:00Z",
        "last_exit_ip": "203.0.113.45"
      }
    },
    "uptime_history": {
      "uptime_percentage": 99.8,
      "avg_latency_ms": 42,
      "total_checks": 144,
      "incidents_count": 1,
      "range": "24h",
      "bars": []
    },
    "flag_url": "https://flags.example.com/us.svg",
    "checks": []
  }
}
PUT/monitors/{id}
Update Monitor

Modify monitor configuration, protocols, check interval, probe assignment, or active/paused state. Accepts every body field Create Monitor does (all optional here) plus is_active.

Request Body (all optional)
namestringMonitor name (max 255 chars)
expected_exit_ipstringExpected exit IP (max 64 chars)
check_interval_secondsintegerCheck interval in seconds (plan-dependent minimum, max 3600)
is_activebooleanPause (false) or resume (true) this monitor. Omitting it defaults to true — see notes.
statusstringOne of up, down, pending, paused. Rarely set directly — status is normally driven by check results.
wireguard_enabledbooleanEnable/disable WireGuard monitoring
wireguard_configstringUpdated WireGuard configuration
openvpn_enabledbooleanEnable/disable OpenVPN monitoring
ikev2_enabledbooleanEnable/disable IKEv2 monitoring
vless_enabledbooleanEnable/disable VLESS monitoring
hysteria_enabledbooleanEnable/disable Hysteria 2 monitoring
probe_idintegerReassign to a single probe (requires plan permission — see notes)
probe_idsarray<integer>Reassign to a custom subset of probes (requires plan permission — see notes)
Notes
  • •Every field is optional — send only what you're changing. Fields you omit keep their current value, with one exception: is_active resets to true on every update unless you explicitly send is_active in the same request (this is how the "Reactivate" action works after an IP-mismatch deactivation).
  • •Send is_active: false to pause a monitor (fires the monitor.paused webhook event); is_active: true resumes it (monitor.resumed). Changing any other field without touching is_active fires monitor.updated instead.
  • •Updating always clears any existing IP-mismatch deactivation reason on the monitor.
  • •probe_id / probe_ids are only honored if your plan allows manual probe selection (canSelectProbes()) or you're an admin.
  • •See Create Monitor for the full set of per-protocol config/URI fields (openvpn_config, ikev2_target_host, vless_uri, hysteria_uri, etc.) — all of them are accepted here too.
Example Request
curl -X PUT /api/v1/monitors/1 \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "Content-Type: application/json" \
  -d '{
    "check_interval_seconds": 600
  }'
Example Response
{
  "success": true,
  "message": "Server Monitor updated successfully.",
  "data": {
    "monitor": {
      "id": 1,
      "user_id": 1,
      "project_id": 1,
      "name": "VPN Exit Node 1",
      "protocol": "wireguard",
      "check_interval_seconds": 600,
      "status": "up",
      "updated_at": "2026-08-22T10:45:00Z"
    },
    "protocols_summary": {
      "wireguard": {
        "enabled": true,
        "status": "working",
        "latency_ms": 42
      }
    }
  }
}
DELETE/monitors/{id}
Delete Monitor

Permanently delete a monitor and stop all checks.

Example Request
curl -X DELETE /api/v1/monitors/1 \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "message": "Server Monitor deleted successfully."
}
POST/monitors/{id}/check-now
Trigger Check Now

Immediately dispatch diagnostic checks for all enabled protocols across assigned probes.

Example Request
curl -X POST /api/v1/monitors/1/check-now \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "message": "Diagnostic checks dispatched to edge probes for all enabled protocols.",
  "data": {
    "dispatched_checks_count": 3,
    "check_ids": [101, 102, 103]
  }
}
GET/monitors/{id}/check-status
Get Check Status

Poll the lifecycle status of checks dispatched by check-now requests.

Example Request
curl -X GET /api/v1/monitors/1/check-status \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "checks": [
      {
        "id": 101,
        "protocol": "wireguard",
        "probe_id": 1,
        "probe_name": "New York",
        "probe_country_code": "US",
        "status": "up",
        "latency_ms": 42,
        "packet_loss": "0%",
        "exit_ip": "203.0.113.45",
        "is_ip_mismatch": false,
        "error_message": null,
        "created_at": "2026-08-22T10:30:00Z",
        "completed_at": "2026-08-22T10:30:05Z"
      }
    ],
    "pending_count": 0,
    "completed_count": 1,
    "total": 1,
    "all_complete": true
  }
}
GET/monitors/{id}/checks
Get Checks History

Retrieve paginated history of all checks performed on a monitor.

Query Parameters
per_pageintegerResults per page (max 100, default 20)
pageintegerPage number (default 1)
Example Request
curl -X GET '/api/v1/monitors/1/checks?per_page=20' \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "data": [
      {
        "id": 100,
        "monitor_id": 1,
        "probe_id": 1,
        "probe_name": "New York",
        "probe_city": "New York",
        "probe_country": "United States",
        "probe_country_code": "US",
        "protocol": "wireguard",
        "status": "up",
        "latency_ms": 42,
        "packet_loss": "0%",
        "exit_ip": "203.0.113.45",
        "exit_location": "New York, US",
        "is_ip_mismatch": false,
        "error_message": null,
        "completed_at": "2026-08-22T10:30:00Z",
        "created_at": "2026-08-22T10:30:00Z"
      }
    ],
    "links": {
      "first": "/api/v1/monitors/1/checks?page=1",
      "last": "/api/v1/monitors/1/checks?page=5",
      "next": "/api/v1/monitors/1/checks?page=2"
    },
    "meta": {
      "current_page": 1,
      "from": 1,
      "last_page": 5,
      "per_page": 20,
      "to": 20,
      "total": 100
    }
  }
}
DELETE/monitors/{id}/checks
Clear Check History

Wipe a single monitor's check history — the monitor itself is kept, only its historical MonitorCheck rows are deleted. Irreversible.

Notes
  • •This does not delete the monitor — use Delete Monitor for that.
  • •Resets uptime percentage and every chart on the monitor detail page back to "no data" until new checks come in.
Example Request
curl -X DELETE /api/v1/monitors/1/checks \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "message": "Cleared 1042 check record(s) for this monitor."
}
GET/monitors/{id}/uptime
Get Uptime History

Retrieve segmented uptime timeline showing status bars across a time range.

Query Parameters
rangestringTime range: 1h, 6h, 12h, 24h, 7d, 30d, 90d (default 24h)
barsintegerNumber of bars to return (max 100, default 30)
Example Request
curl -X GET '/api/v1/monitors/1/uptime?range=24h&bars=48' \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "monitor_id": 1,
    "name": "VPN Exit Node 1",
    "expected_exit_ip": "203.0.113.45",
    "range": "24h",
    "uptime_percentage": 99.8,
    "avg_latency_ms": 45,
    "total_checks": 288,
    "incidents_count": 1,
    "bars": [
      {
        "status": "up",
        "percentage": 100,
        "uptime_pct": 100.0,
        "latency_ms": 42,
        "avg_latency_ms": 42,
        "checks_count": 144,
        "label": "0%",
        "timestamp_label": "00:00",
        "tooltip": "Up - 100%",
        "color": "green",
        "color_class": "bg-green-500"
      }
    ]
  }
}
GET/monitors/{id}/uptime/regions
Get Regional Breakdown for One Uptime Bar

Per-probe breakdown of checks within a single uptime bar's time window — powers "click for regional detail" under the uptime timeline. Pass the bar's own timestamp and the response's top-level bucket_seconds straight from a Get Uptime History call.

Query Parameters
start*string (ISO 8601 datetime)Window start — use one bar's timestamp field from Get Uptime History verbatim
bucket_seconds*integerWindow length in seconds — use the uptime response's top-level bucket_seconds (1–604800)
Example Request
curl -X GET '/api/v1/monitors/1/uptime/regions?start=2026-08-23T17:00:00Z&bucket_seconds=3600' \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "monitor_id": 1,
    "window_start": "2026-08-23T17:00:00+00:00",
    "window_end": "2026-08-23T18:00:00+00:00",
    "total_checks": 12,
    "up_checks": 12,
    "avg_latency_ms": 47,
    "regions": [
      {
        "probe_id": 3,
        "probe_name": "London UK",
        "location_city": "London",
        "location_country": "United Kingdom",
        "up": 12,
        "total": 12,
        "avg_latency_ms": 47,
        "status": "up"
      }
    ]
  }
}
GET/monitors/{id}/analytics
Get Analytics

Retrieve comprehensive analytics including latency trends, protocol stats, incidents, and exit IP history for charting.

Query Parameters
rangestringAnalytics range: 1h, 6h, 12h, 24h, 7d, 30d, 90d (default 24h)
Example Request
curl -X GET '/api/v1/monitors/1/analytics?range=7d' \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "range": "7d",
    "bucket_seconds": 3600,
    "generated_at": "2026-08-22T10:30:00Z",
    "summary": {
      "uptime_pct": 99.8,
      "avg_latency_ms": 45,
      "p95_latency_ms": 85,
      "min_latency_ms": 32,
      "max_latency_ms": 120,
      "total_checks": 2016,
      "failed_checks": 4,
      "incidents_count": 1,
      "mttr_seconds": 300,
      "longest_outage_seconds": 600,
      "avg_packet_loss": 0.2,
      "exit_ip_stability_pct": 100
    },
    "latency_series": [
      {
        "t": "2026-08-15T00:00:00Z",
        "label": "Aug 15, 00:00",
        "avg_ms": 44,
        "min_ms": 32,
        "max_ms": 85,
        "p95_ms": 78,
        "checks": 288
      }
    ],
    "latency_by_protocol": {
      "wireguard": [
        {
          "t": "2026-08-15T00:00:00Z",
          "label": "Aug 15, 00:00",
          "value": 44,
          "checks": 288
        }
      ]
    },
    "uptime_series": [],
    "packet_loss_series": [],
    "checks_volume_series": [],
    "status_distribution": {
      "up": 2012,
      "down": 4,
      "timeout": 0,
      "error": 0,
      "ip_mismatch": 0,
      "pending": 0
    },
    "protocol_stats": [
      {
        "protocol": "wireguard",
        "label": "WireGuard",
        "enabled": true,
        "checks": 2016,
        "up": 2012,
        "down": 4,
        "uptime_pct": 99.8,
        "avg_latency_ms": 45,
        "p95_latency_ms": 85,
        "min_latency_ms": 32,
        "max_latency_ms": 120,
        "incidents": 1,
        "last_check_at": "2026-08-22T10:30:00Z"
      }
    ],
    "probe_stats": [],
    "incidents": [
      {
        "id": "inc_1",
        "started_at": "2026-08-20T14:30:00Z",
        "ended_at": "2026-08-20T14:35:00Z",
        "duration_seconds": 300,
        "is_ongoing": false,
        "protocol": "wireguard",
        "probe_id": 1,
        "probe_name": "New York",
        "reason": "Connection timeout",
        "failed_checks": 2,
        "kind": "timeout"
      }
    ],
    "exit_ip_history": [
      {
        "ip": "203.0.113.45",
        "is_expected": true,
        "count": 2016,
        "first_seen": "2026-08-15T00:00:00Z",
        "last_seen": "2026-08-22T10:30:00Z",
        "location": "New York, US",
        "country_code": "US"
      }
    ],
    "latency_heatmap": [],
    "latency_distribution": [
      {
        "bucket_label": "0-50ms",
        "from_ms": 0,
        "to_ms": 50,
        "count": 1600
      }
    ]
  }
}
GET/monitors/summary
Monitors Summary

How many monitors are up, down, degraded, flapping, IP-mismatched or inactive — without any rows, uptime bars or credentials. Cheap enough to poll from a status board.

Query Parameters
project_idintegerCount only this project
Example Request
curl -X GET /api/v1/monitors/summary \
  -H "Authorization: Bearer 1|K7f9XyZaQ2mN8pL4vR6tW1sJ0hD3cB5gA7eF9uI2oY4"
Example Response
{
  "success": true,
  "data": {
    "total": 93,
    "up": 88,
    "down": 2,
    "degraded": 1,
    "flapping": 1,
    "ip_mismatch": 1,
    "unknown": 0,
    "inactive": 1
  }
}
GET/monitors/{id}/status
Get Monitor Status

Lightweight status endpoint for third-party integrations showing current monitor health.

Example Request
curl -X GET /api/v1/monitors/1/status \
  -H "Authorization: Bearer ep_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Example Response
{
  "success": true,
  "data": {
    "monitor_id": 1,
    "name": "VPN Exit Node 1",
    "status": "up",
    "last_check_at": "2026-08-22T10:30:00Z",
    "last_latency_ms": 42,
    "last_exit_ip": "203.0.113.45",
    "exit_country_code": "US",
    "uptime_percentage": 99.8
  }
}