openapi: 3.0.3 info: title: 'Miterl API Documentation' description: 'REST API for the Miterl uptime monitoring platform.' version: 1.0.0 servers: - url: 'https://miterl.com' tags: - name: Monitors description: "\nCreate and manage uptime monitors. All endpoints are scoped to the\nauthenticated company." - name: Workspaces description: "\nWorkspaces group monitors into management units. Scoped to the\nauthenticated company." - name: Incidents description: "\nRead-only incident history, scoped to the authenticated company's monitors.\nInternal drills are never exposed." - name: Alerts description: "\nRead-only history of alert deliveries (email, Slack, webhook, ...) for the\nauthenticated company." - name: 'Pre-launch Audits' description: "\nBatch pre-deployment checks (HTTP status, response time, SSL, optional keyword)\nfor CI/CD gating. Scoped to the authenticated company." - name: 'Status Pages' description: "\nPublic, read-only access to status pages. No authentication required." - name: Webhooks description: "\nCI/CD webhooks authenticated by a per-monitor path token (no API key)." - name: 'Alert Contacts' description: "\nRead-only listing of the company's alert contacts (Slack, email, etc.).\nUse an id with a monitor's `alert_contact_ids` to wire who gets notified\non down/recovery. Contacts themselves are created in the dashboard." - name: 'WordPress Connect' description: "\nEndpoints called by the Miterl Connect WordPress plugin, authenticated by a\nper-monitor connect key in the path (no API key)." components: securitySchemes: default: type: http scheme: bearer description: 'Generate an API key from your dashboard under Settings → API Keys (owner only). Send it as a Bearer token (Authorization: Bearer <key>) or via the X-API-Key header.' security: - default: [] paths: /api/v1/monitors: get: summary: 'List monitors' operationId: listMonitors description: "Returns a paginated list of the company's monitors, newest first." parameters: - in: query name: status description: 'Filter by status: up, down, paused, pending.' example: up required: false schema: type: string description: 'Filter by status: up, down, paused, pending.' example: up - in: query name: type description: 'Filter by monitor type (e.g. http, keyword, ssl).' example: http required: false schema: type: string description: 'Filter by monitor type (e.g. http, keyword, ssl).' example: http - in: query name: location description: 'Filter by probe location key.' example: default required: false schema: type: string description: 'Filter by probe location key.' example: default - in: query name: workspace_id description: 'Filter by workspace.' example: 3 required: false schema: type: integer description: 'Filter by workspace.' example: 3 - in: query name: search description: 'Partial match against name or URL.' example: example.com required: false schema: type: string description: 'Partial match against name or URL.' example: example.com - in: query name: per_page description: 'Results per page (1-100). Defaults to 25.' example: 25 required: false schema: type: integer description: 'Results per page (1-100). Defaults to 25.' example: 25 - in: query name: page description: 'Page number.' example: 1 required: false schema: type: integer description: 'Page number.' example: 1 responses: 200: description: Success content: application/json: schema: type: object example: data: - id: 1 name: 'Example Site' type: http url: 'https://example.com' status: up interval_seconds: 300 timeout_seconds: 30 failure_threshold: 2 consecutive_failures: 0 is_active: true last_checked_at: '2026-05-21T12:00:00+00:00' location: default workspace_id: null created_at: '2026-05-01T09:00:00+00:00' uptime_30d: 99.95 links: first: 'https://miterl.com/api/v1/monitors?page=1' last: 'https://miterl.com/api/v1/monitors?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 path: 'https://miterl.com/api/v1/monitors' per_page: 25 to: 1 total: 1 properties: data: type: array example: - id: 1 name: 'Example Site' type: http url: 'https://example.com' status: up interval_seconds: 300 timeout_seconds: 30 failure_threshold: 2 consecutive_failures: 0 is_active: true last_checked_at: '2026-05-21T12:00:00+00:00' location: default workspace_id: null created_at: '2026-05-01T09:00:00+00:00' uptime_30d: 99.95 items: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' type: type: string example: http url: type: string example: 'https://example.com' status: type: string example: up interval_seconds: type: integer example: 300 timeout_seconds: type: integer example: 30 failure_threshold: type: integer example: 2 consecutive_failures: type: integer example: 0 is_active: type: boolean example: true last_checked_at: type: string example: '2026-05-21T12:00:00+00:00' location: type: string example: default workspace_id: type: string example: null nullable: true created_at: type: string example: '2026-05-01T09:00:00+00:00' uptime_30d: type: number example: 99.95 links: type: object properties: first: type: string example: 'https://miterl.com/api/v1/monitors?page=1' last: type: string example: 'https://miterl.com/api/v1/monitors?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 path: type: string example: 'https://miterl.com/api/v1/monitors' per_page: type: integer example: 25 to: type: integer example: 1 total: type: integer example: 1 tags: - Monitors post: summary: 'Create a monitor' operationId: createAMonitor description: '' parameters: [] responses: 201: description: Created content: application/json: schema: type: object example: data: id: 1 name: 'Example Site' type: http url: 'https://example.com' status: pending interval_seconds: 300 timeout_seconds: 30 failure_threshold: 2 consecutive_failures: 0 is_active: true last_checked_at: null location: default workspace_id: null created_at: '2026-05-21T12:00:00+00:00' uptime_30d: 100 properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' type: type: string example: http url: type: string example: 'https://example.com' status: type: string example: pending interval_seconds: type: integer example: 300 timeout_seconds: type: integer example: 30 failure_threshold: type: integer example: 2 consecutive_failures: type: integer example: 0 is_active: type: boolean example: true last_checked_at: type: string example: null nullable: true location: type: string example: default workspace_id: type: string example: null nullable: true created_at: type: string example: '2026-05-21T12:00:00+00:00' uptime_30d: type: integer example: 100 422: description: 'Validation error' content: application/json: schema: type: object example: message: 'The name field is required.' code: validation_failed errors: name: - 'The name field is required.' properties: message: type: string example: 'The name field is required.' code: type: string example: validation_failed errors: type: object properties: name: type: array example: - 'The name field is required.' items: type: string tags: - Monitors requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Display name.' example: 'Example Site' type: type: string description: 'Monitor type: http, keyword, ping, ssl, tcp, heartbeat, whois, dom_integrity, robots_txt.' example: http url: type: string description: 'URL or host to monitor.' example: 'https://example.com' interval_seconds: type: integer description: 'Check interval in seconds (plan-dependent minimum). Defaults to 300.' example: 300 timeout_seconds: type: integer description: 'Request timeout in seconds. Defaults to 30.' example: 30 failure_threshold: type: integer description: 'Consecutive failures before alerting. Defaults to 2.' example: 2 keyword: type: string description: 'Keyword to search for (keyword monitors).' example: Welcome keyword_exists: type: boolean description: 'Whether the keyword should be present (true) or absent (false). Defaults to true.' example: true ssl_expiry_alert_days: type: integer description: 'Days before SSL expiry to alert. Defaults to 14.' example: 14 whois_expiry_alert_days: type: integer description: 'Days before domain expiry to alert. Defaults to 30.' example: 30 location: type: string description: 'Probe location key. Defaults to "default".' example: default workspace_id: type: integer description: 'Workspace to assign the monitor to.' example: 3 alert_contact_ids: type: array description: "Alert contact ids to notify on down/recovery. Omit to fall back to the workspace's contacts." example: - 1 - 2 items: type: integer required: - name - type - url '/api/v1/monitors/{id}': get: summary: 'Get a monitor' operationId: getAMonitor description: '' parameters: [] responses: 200: description: Success content: application/json: schema: type: object example: data: id: 1 name: 'Example Site' type: http url: 'https://example.com' status: up interval_seconds: 300 timeout_seconds: 30 failure_threshold: 2 consecutive_failures: 0 is_active: true last_checked_at: '2026-05-21T12:00:00+00:00' location: default workspace_id: null created_at: '2026-05-01T09:00:00+00:00' uptime_30d: 99.95 properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' type: type: string example: http url: type: string example: 'https://example.com' status: type: string example: up interval_seconds: type: integer example: 300 timeout_seconds: type: integer example: 30 failure_threshold: type: integer example: 2 consecutive_failures: type: integer example: 0 is_active: type: boolean example: true last_checked_at: type: string example: '2026-05-21T12:00:00+00:00' location: type: string example: default workspace_id: type: string example: null nullable: true created_at: type: string example: '2026-05-01T09:00:00+00:00' uptime_30d: type: number example: 99.95 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - Monitors put: summary: 'Update a monitor' operationId: updateAMonitor description: 'Accepts the same fields as creation (all optional); the monitor `type` cannot be changed.' parameters: [] responses: 200: description: Updated content: application/json: schema: type: object example: data: id: 1 name: 'Example Site' type: http url: 'https://example.com' status: up interval_seconds: 300 timeout_seconds: 30 failure_threshold: 2 consecutive_failures: 0 is_active: true last_checked_at: '2026-05-21T12:00:00+00:00' location: default workspace_id: null created_at: '2026-05-01T09:00:00+00:00' uptime_30d: 99.95 properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' type: type: string example: http url: type: string example: 'https://example.com' status: type: string example: up interval_seconds: type: integer example: 300 timeout_seconds: type: integer example: 30 failure_threshold: type: integer example: 2 consecutive_failures: type: integer example: 0 is_active: type: boolean example: true last_checked_at: type: string example: '2026-05-21T12:00:00+00:00' location: type: string example: default workspace_id: type: string example: null nullable: true created_at: type: string example: '2026-05-01T09:00:00+00:00' uptime_30d: type: number example: 99.95 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - Monitors requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Display name.' example: 'Example Site' url: type: string description: 'URL or host to monitor.' example: 'https://example.com' interval_seconds: type: integer description: 'Check interval in seconds.' example: 300 timeout_seconds: type: integer description: 'Request timeout in seconds.' example: 30 failure_threshold: type: integer description: 'Consecutive failures before alerting.' example: 2 keyword: type: string description: 'Keyword to search for.' example: Welcome keyword_exists: type: boolean description: 'Whether the keyword should be present.' example: true ssl_expiry_alert_days: type: integer description: 'Days before SSL expiry to alert.' example: 14 whois_expiry_alert_days: type: integer description: 'Days before domain expiry to alert.' example: 30 location: type: string description: 'Probe location key.' example: default workspace_id: type: integer description: 'Workspace to assign the monitor to.' example: 3 alert_contact_ids: type: array description: 'Alert contact ids to notify (replaces the existing set).' example: - 1 - 2 items: type: integer delete: summary: 'Delete a monitor' operationId: deleteAMonitor description: '' parameters: [] responses: 204: description: Deleted content: text/plain: schema: type: string example: '' 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - Monitors parameters: - in: path name: id description: 'The monitor ID.' example: 1 required: true schema: type: integer '/api/v1/monitors/{id}/alert-status': get: summary: "Preview a monitor's alert routing" operationId: previewAMonitorsAlertRouting description: "Answers \"if this monitor went down right now, would anyone be paged —\nand if not, why?\" without waiting for a real outage. Returns the\nresolved recipients (the monitor's own active contacts merged with its\nworkspace's) and the two silent-suppression gates the down-listener\napplies: an active maintenance window and the company's quiet hours.\n`would_notify_now` is true only when there is at least one recipient and\nneither gate is active. A monitor that is down while this is false is\nthe classic \"silent\" case (no contacts wired, or suppressed)." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: 'Would notify' type: object example: data: monitor_id: 1 would_notify_now: true under_maintenance: false quiet_hours: false contacts: - id: 1 type: slack name: 'Ops Slack' is_active: true properties: data: type: object properties: monitor_id: type: integer example: 1 would_notify_now: type: boolean example: true under_maintenance: type: boolean example: false quiet_hours: type: boolean example: false contacts: type: array example: - id: 1 type: slack name: 'Ops Slack' is_active: true items: type: object properties: id: type: integer example: 1 type: type: string example: slack name: type: string example: 'Ops Slack' is_active: type: boolean example: true - description: 'Suppressed by quiet hours' type: object example: data: monitor_id: 1 would_notify_now: false under_maintenance: false quiet_hours: true contacts: - id: 1 type: slack name: 'Ops Slack' is_active: true properties: data: type: object properties: monitor_id: type: integer example: 1 would_notify_now: type: boolean example: false under_maintenance: type: boolean example: false quiet_hours: type: boolean example: true contacts: type: array example: - id: 1 type: slack name: 'Ops Slack' is_active: true items: type: object properties: id: type: integer example: 1 type: type: string example: slack name: type: string example: 'Ops Slack' is_active: type: boolean example: true 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - Monitors parameters: - in: path name: id description: 'The monitor ID.' example: 1 required: true schema: type: integer '/api/v1/monitors/{id}/pause': post: summary: 'Pause a monitor' operationId: pauseAMonitor description: 'Stops checks until the monitor is resumed.' parameters: [] responses: 200: description: Paused content: application/json: schema: type: object example: data: id: 1 name: 'Example Site' type: http url: 'https://example.com' status: paused interval_seconds: 300 timeout_seconds: 30 failure_threshold: 2 consecutive_failures: 0 is_active: true last_checked_at: '2026-05-21T12:00:00+00:00' location: default workspace_id: null created_at: '2026-05-01T09:00:00+00:00' uptime_30d: 99.95 properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' type: type: string example: http url: type: string example: 'https://example.com' status: type: string example: paused interval_seconds: type: integer example: 300 timeout_seconds: type: integer example: 30 failure_threshold: type: integer example: 2 consecutive_failures: type: integer example: 0 is_active: type: boolean example: true last_checked_at: type: string example: '2026-05-21T12:00:00+00:00' location: type: string example: default workspace_id: type: string example: null nullable: true created_at: type: string example: '2026-05-01T09:00:00+00:00' uptime_30d: type: number example: 99.95 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - Monitors parameters: - in: path name: id description: 'The monitor ID.' example: 1 required: true schema: type: integer '/api/v1/monitors/{id}/resume': post: summary: 'Resume a monitor' operationId: resumeAMonitor description: 'Re-activates a paused monitor and schedules an immediate check.' parameters: [] responses: 200: description: Resumed content: application/json: schema: type: object example: data: id: 1 name: 'Example Site' type: http url: 'https://example.com' status: up interval_seconds: 300 timeout_seconds: 30 failure_threshold: 2 consecutive_failures: 0 is_active: true last_checked_at: '2026-05-21T12:00:00+00:00' location: default workspace_id: null created_at: '2026-05-01T09:00:00+00:00' uptime_30d: 99.95 properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' type: type: string example: http url: type: string example: 'https://example.com' status: type: string example: up interval_seconds: type: integer example: 300 timeout_seconds: type: integer example: 30 failure_threshold: type: integer example: 2 consecutive_failures: type: integer example: 0 is_active: type: boolean example: true last_checked_at: type: string example: '2026-05-21T12:00:00+00:00' location: type: string example: default workspace_id: type: string example: null nullable: true created_at: type: string example: '2026-05-01T09:00:00+00:00' uptime_30d: type: number example: 99.95 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - Monitors parameters: - in: path name: id description: 'The monitor ID.' example: 1 required: true schema: type: integer /api/v1/workspaces: get: summary: 'List workspaces' operationId: listWorkspaces description: "Returns a paginated list of the company's workspaces, ordered by name." parameters: - in: query name: per_page description: 'Results per page (1-100). Defaults to 25.' example: 25 required: false schema: type: integer description: 'Results per page (1-100). Defaults to 25.' example: 25 - in: query name: page description: 'Page number.' example: 1 required: false schema: type: integer description: 'Page number.' example: 1 responses: 200: description: Success content: application/json: schema: type: object example: data: - id: 1 name: Production description: 'Live customer sites' created_at: '2026-05-01T09:00:00+00:00' links: first: 'https://miterl.com/api/v1/workspaces?page=1' last: 'https://miterl.com/api/v1/workspaces?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 path: 'https://miterl.com/api/v1/workspaces' per_page: 25 to: 1 total: 1 properties: data: type: array example: - id: 1 name: Production description: 'Live customer sites' created_at: '2026-05-01T09:00:00+00:00' items: type: object properties: id: type: integer example: 1 name: type: string example: Production description: type: string example: 'Live customer sites' created_at: type: string example: '2026-05-01T09:00:00+00:00' links: type: object properties: first: type: string example: 'https://miterl.com/api/v1/workspaces?page=1' last: type: string example: 'https://miterl.com/api/v1/workspaces?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 path: type: string example: 'https://miterl.com/api/v1/workspaces' per_page: type: integer example: 25 to: type: integer example: 1 total: type: integer example: 1 tags: - Workspaces post: summary: 'Create a workspace' operationId: createAWorkspace description: '' parameters: [] responses: 201: description: Created content: application/json: schema: type: object example: data: id: 1 name: Production description: 'Live customer sites' created_at: '2026-05-21T12:00:00+00:00' properties: data: type: object properties: id: type: integer example: 1 name: type: string example: Production description: type: string example: 'Live customer sites' created_at: type: string example: '2026-05-21T12:00:00+00:00' 422: description: '' content: application/json: schema: oneOf: - description: 'Limit reached' type: object example: message: 'Workspace limit reached (5). Upgrade the plan to add more.' code: workspace_limit_reached properties: message: type: string example: 'Workspace limit reached (5). Upgrade the plan to add more.' code: type: string example: workspace_limit_reached - description: 'Validation error' type: object example: message: 'The name field is required.' code: validation_failed errors: name: - 'The name field is required.' properties: message: type: string example: 'The name field is required.' code: type: string example: validation_failed errors: type: object properties: name: type: array example: - 'The name field is required.' items: type: string tags: - Workspaces requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Workspace name (unique within the company).' example: Production description: type: string description: 'Optional description.' example: 'Live customer sites' required: - name /api/v1/incidents: get: summary: 'List incidents' operationId: listIncidents description: "Returns a paginated incident history across the company's monitors, newest first." parameters: - in: query name: monitor_id description: 'Filter by monitor.' example: 1 required: false schema: type: integer description: 'Filter by monitor.' example: 1 - in: query name: severity description: 'Filter by severity.' example: critical required: false schema: type: string description: 'Filter by severity.' example: critical - in: query name: status description: 'Filter by lifecycle: `resolved` or `ongoing`.' example: resolved required: false schema: type: string description: 'Filter by lifecycle: `resolved` or `ongoing`.' example: resolved - in: query name: per_page description: 'Results per page (1-100). Defaults to 25.' example: 25 required: false schema: type: integer description: 'Results per page (1-100). Defaults to 25.' example: 25 - in: query name: page description: 'Page number.' example: 1 required: false schema: type: integer description: 'Page number.' example: 1 responses: 200: description: Success content: application/json: schema: type: object example: data: - id: 1 monitor_id: 1 severity: critical cause: 'Connection timeout' started_at: '2026-05-20T03:00:00+00:00' resolved_at: '2026-05-20T03:15:00+00:00' acknowledged_at: '2026-05-20T03:05:00+00:00' duration_seconds: 900 is_resolved: true is_acknowledged: true has_postmortem: false created_at: '2026-05-20T03:00:00+00:00' monitor: id: 1 name: 'Example Site' url: 'https://example.com' links: first: 'https://miterl.com/api/v1/incidents?page=1' last: 'https://miterl.com/api/v1/incidents?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 path: 'https://miterl.com/api/v1/incidents' per_page: 25 to: 1 total: 1 properties: data: type: array example: - id: 1 monitor_id: 1 severity: critical cause: 'Connection timeout' started_at: '2026-05-20T03:00:00+00:00' resolved_at: '2026-05-20T03:15:00+00:00' acknowledged_at: '2026-05-20T03:05:00+00:00' duration_seconds: 900 is_resolved: true is_acknowledged: true has_postmortem: false created_at: '2026-05-20T03:00:00+00:00' monitor: id: 1 name: 'Example Site' url: 'https://example.com' items: type: object properties: id: type: integer example: 1 monitor_id: type: integer example: 1 severity: type: string example: critical cause: type: string example: 'Connection timeout' started_at: type: string example: '2026-05-20T03:00:00+00:00' resolved_at: type: string example: '2026-05-20T03:15:00+00:00' acknowledged_at: type: string example: '2026-05-20T03:05:00+00:00' duration_seconds: type: integer example: 900 is_resolved: type: boolean example: true is_acknowledged: type: boolean example: true has_postmortem: type: boolean example: false created_at: type: string example: '2026-05-20T03:00:00+00:00' monitor: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' url: type: string example: 'https://example.com' links: type: object properties: first: type: string example: 'https://miterl.com/api/v1/incidents?page=1' last: type: string example: 'https://miterl.com/api/v1/incidents?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 path: type: string example: 'https://miterl.com/api/v1/incidents' per_page: type: integer example: 25 to: type: integer example: 1 total: type: integer example: 1 tags: - Incidents '/api/v1/incidents/{id}': get: summary: 'Get an incident' operationId: getAnIncident description: "Includes the related monitor and the incident's public updates." parameters: [] responses: 200: description: Success content: application/json: schema: type: object example: data: id: 1 monitor_id: 1 severity: critical cause: 'Connection timeout' started_at: '2026-05-20T03:00:00+00:00' resolved_at: '2026-05-20T03:15:00+00:00' acknowledged_at: '2026-05-20T03:05:00+00:00' duration_seconds: 900 is_resolved: true is_acknowledged: true has_postmortem: false created_at: '2026-05-20T03:00:00+00:00' monitor: id: 1 name: 'Example Site' url: 'https://example.com' updates: [] properties: data: type: object properties: id: type: integer example: 1 monitor_id: type: integer example: 1 severity: type: string example: critical cause: type: string example: 'Connection timeout' started_at: type: string example: '2026-05-20T03:00:00+00:00' resolved_at: type: string example: '2026-05-20T03:15:00+00:00' acknowledged_at: type: string example: '2026-05-20T03:05:00+00:00' duration_seconds: type: integer example: 900 is_resolved: type: boolean example: true is_acknowledged: type: boolean example: true has_postmortem: type: boolean example: false created_at: type: string example: '2026-05-20T03:00:00+00:00' monitor: type: object properties: id: type: integer example: 1 name: type: string example: 'Example Site' url: type: string example: 'https://example.com' updates: type: array example: [] 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - Incidents parameters: - in: path name: id description: 'The incident ID.' example: 1 required: true schema: type: integer /api/v1/alerts: get: summary: 'List alert deliveries' operationId: listAlertDeliveries description: 'Returns a paginated history of alert deliveries, newest first.' parameters: - in: query name: status description: 'Filter by delivery status (e.g. sent, failed).' example: sent required: false schema: type: string description: 'Filter by delivery status (e.g. sent, failed).' example: sent - in: query name: channel description: 'Filter by channel (e.g. email, slack, webhook).' example: email required: false schema: type: string description: 'Filter by channel (e.g. email, slack, webhook).' example: email - in: query name: event description: 'Filter by event (e.g. monitor.down, monitor.up).' example: monitor.down required: false schema: type: string description: 'Filter by event (e.g. monitor.down, monitor.up).' example: monitor.down - in: query name: monitor_id description: 'Filter by monitor.' example: 1 required: false schema: type: integer description: 'Filter by monitor.' example: 1 - in: query name: per_page description: 'Results per page (1-100). Defaults to 25.' example: 25 required: false schema: type: integer description: 'Results per page (1-100). Defaults to 25.' example: 25 - in: query name: page description: 'Page number.' example: 1 required: false schema: type: integer description: 'Page number.' example: 1 responses: 200: description: Success content: application/json: schema: type: object example: data: - id: 1 monitor_id: 1 incident_id: 1 channel: email event: monitor.down status: sent recipient: ops@example.com error_message: null sent_at: '2026-05-20T03:01:00+00:00' created_at: '2026-05-20T03:01:00+00:00' links: first: 'https://miterl.com/api/v1/alerts?page=1' last: 'https://miterl.com/api/v1/alerts?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 path: 'https://miterl.com/api/v1/alerts' per_page: 25 to: 1 total: 1 properties: data: type: array example: - id: 1 monitor_id: 1 incident_id: 1 channel: email event: monitor.down status: sent recipient: ops@example.com error_message: null sent_at: '2026-05-20T03:01:00+00:00' created_at: '2026-05-20T03:01:00+00:00' items: type: object properties: id: type: integer example: 1 monitor_id: type: integer example: 1 incident_id: type: integer example: 1 channel: type: string example: email event: type: string example: monitor.down status: type: string example: sent recipient: type: string example: ops@example.com error_message: type: string example: null nullable: true sent_at: type: string example: '2026-05-20T03:01:00+00:00' created_at: type: string example: '2026-05-20T03:01:00+00:00' links: type: object properties: first: type: string example: 'https://miterl.com/api/v1/alerts?page=1' last: type: string example: 'https://miterl.com/api/v1/alerts?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 path: type: string example: 'https://miterl.com/api/v1/alerts' per_page: type: integer example: 25 to: type: integer example: 1 total: type: integer example: 1 tags: - Alerts /api/v1/pre-launch: post: summary: 'Start a pre-launch audit' operationId: startAPreLaunchAudit description: "Queues a batch check of one or more URLs. Returns immediately with status\n`pending`; poll the show endpoint for results." parameters: [] responses: 202: description: Accepted content: application/json: schema: type: object example: data: id: 1 name: 'Release v2.0 smoke test' status: pending started_at: null completed_at: null passed_count: 0 failed_count: 0 results: [] properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Release v2.0 smoke test' status: type: string example: pending started_at: type: string example: null nullable: true completed_at: type: string example: null nullable: true passed_count: type: integer example: 0 failed_count: type: integer example: 0 results: type: array example: [] 422: description: 'Validation error' content: application/json: schema: type: object example: message: 'The urls field is required.' code: validation_failed errors: urls: - 'The urls field is required.' properties: message: type: string example: 'The urls field is required.' code: type: string example: validation_failed errors: type: object properties: urls: type: array example: - 'The urls field is required.' items: type: string tags: - 'Pre-launch Audits' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'A label for this audit run.' example: 'Release v2.0 smoke test' urls: type: array description: 'URLs to check (1-20 items).' example: - 'https://example.com' items: type: string required_keyword: type: string description: 'Optional keyword that must be present in each page body.' example: Welcome required: - name - urls '/api/v1/pre-launch/{id}': get: summary: 'Get a pre-launch audit' operationId: getAPreLaunchAudit description: "The HTTP status mirrors the audit outcome so CI/CD can branch on it:\n`200` all passed, `422` some failed, `202` still running, `500` audit errored." parameters: [] responses: 200: description: 'All passed' content: application/json: schema: type: object example: data: id: 1 name: 'Release v2.0 smoke test' status: completed started_at: '2026-05-21T12:00:00+00:00' completed_at: '2026-05-21T12:00:05+00:00' passed_count: 1 failed_count: 0 results: - url: 'https://example.com' passed: true status_code: 200 response_time_ms: 124 ssl_valid: true ssl_days_until_expiry: 78 ssl_expires_at: '2026-08-07T12:00:00+00:00' ssl_issuer: R3 keyword_present: true errors: [] properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Release v2.0 smoke test' status: type: string example: completed started_at: type: string example: '2026-05-21T12:00:00+00:00' completed_at: type: string example: '2026-05-21T12:00:05+00:00' passed_count: type: integer example: 1 failed_count: type: integer example: 0 results: type: array example: - url: 'https://example.com' passed: true status_code: 200 response_time_ms: 124 ssl_valid: true ssl_days_until_expiry: 78 ssl_expires_at: '2026-08-07T12:00:00+00:00' ssl_issuer: R3 keyword_present: true errors: [] items: type: object properties: url: type: string example: 'https://example.com' passed: type: boolean example: true status_code: type: integer example: 200 response_time_ms: type: integer example: 124 ssl_valid: type: boolean example: true ssl_days_until_expiry: type: integer example: 78 ssl_expires_at: type: string example: '2026-08-07T12:00:00+00:00' ssl_issuer: type: string example: R3 keyword_present: type: boolean example: true errors: type: array example: [] 202: description: 'Still running' content: application/json: schema: type: object example: data: id: 1 name: 'Release v2.0 smoke test' status: running started_at: '2026-05-21T12:00:00+00:00' completed_at: null passed_count: 0 failed_count: 0 results: [] properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Release v2.0 smoke test' status: type: string example: running started_at: type: string example: '2026-05-21T12:00:00+00:00' completed_at: type: string example: null nullable: true passed_count: type: integer example: 0 failed_count: type: integer example: 0 results: type: array example: [] 404: description: 'Not found' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found 422: description: 'Some failed' content: application/json: schema: type: object example: data: id: 1 name: 'Release v2.0 smoke test' status: completed started_at: '2026-05-21T12:00:00+00:00' completed_at: '2026-05-21T12:00:05+00:00' passed_count: 0 failed_count: 1 results: - url: 'https://example.com' passed: false status_code: 500 response_time_ms: 210 ssl_valid: true ssl_days_until_expiry: 78 ssl_expires_at: '2026-08-07T12:00:00+00:00' ssl_issuer: R3 keyword_present: null errors: - http_status_not_2xx properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Release v2.0 smoke test' status: type: string example: completed started_at: type: string example: '2026-05-21T12:00:00+00:00' completed_at: type: string example: '2026-05-21T12:00:05+00:00' passed_count: type: integer example: 0 failed_count: type: integer example: 1 results: type: array example: - url: 'https://example.com' passed: false status_code: 500 response_time_ms: 210 ssl_valid: true ssl_days_until_expiry: 78 ssl_expires_at: '2026-08-07T12:00:00+00:00' ssl_issuer: R3 keyword_present: null errors: - http_status_not_2xx items: type: object properties: url: type: string example: 'https://example.com' passed: type: boolean example: false status_code: type: integer example: 500 response_time_ms: type: integer example: 210 ssl_valid: type: boolean example: true ssl_days_until_expiry: type: integer example: 78 ssl_expires_at: type: string example: '2026-08-07T12:00:00+00:00' ssl_issuer: type: string example: R3 keyword_present: type: string example: null nullable: true errors: type: array example: - http_status_not_2xx items: type: string tags: - 'Pre-launch Audits' parameters: - in: path name: id description: 'The audit ID.' example: 1 required: true schema: type: integer '/api/v1/status-pages/{slug}': get: summary: 'Get a public status page' operationId: getAPublicStatusPage description: "Public, unauthenticated JSON view of a status page. Only fully public\npages are exposed — password-protected (\"restricted\") and disabled\npages return 404 so their existence stays hidden." parameters: [] responses: 200: description: Success content: application/json: schema: type: object example: data: name: 'Acme Status' slug: acme overall_status: operational monitors: - id: 1 name: Website status: up uptime_90d: 99.9 last_checked_at: '2026-05-21T12:00:00+00:00' uptime_daily: - date: '2026-05-21' uptime: 100 group_name: null last_dom_issue: null incidents: [] upcoming_maintenance: [] properties: data: type: object properties: name: type: string example: 'Acme Status' slug: type: string example: acme overall_status: type: string example: operational monitors: type: array example: - id: 1 name: Website status: up uptime_90d: 99.9 last_checked_at: '2026-05-21T12:00:00+00:00' uptime_daily: - date: '2026-05-21' uptime: 100 group_name: null last_dom_issue: null items: type: object properties: id: type: integer example: 1 name: type: string example: Website status: type: string example: up uptime_90d: type: number example: 99.9 last_checked_at: type: string example: '2026-05-21T12:00:00+00:00' uptime_daily: type: array example: - date: '2026-05-21' uptime: 100 items: type: object properties: date: type: string example: '2026-05-21' uptime: type: integer example: 100 group_name: type: string example: null nullable: true last_dom_issue: type: string example: null nullable: true incidents: type: array example: [] upcoming_maintenance: type: array example: [] 404: description: 'Not found or not public' content: application/json: schema: type: object example: message: 'Resource not found.' code: not_found properties: message: type: string example: 'Resource not found.' code: type: string example: not_found tags: - 'Status Pages' security: [] parameters: - in: path name: slug description: 'The status page slug.' example: acme required: true schema: type: string '/api/v1/webhooks/release-mode/{token}': post: summary: 'Trigger release mode' operationId: triggerReleaseMode description: "Starts intensive release monitoring for the monitor identified by the path\ntoken. Authenticated by the webhook token only." parameters: [] responses: 200: description: Started content: application/json: schema: type: object example: status: started monitor_id: 1 monitor_name: 'Example Site' release_mode_run_id: 10 duration_hours: 24 interval_seconds: 15 started_at: '2026-05-21T12:00:00+00:00' until: '2026-05-22T12:00:00+00:00' properties: status: type: string example: started monitor_id: type: integer example: 1 monitor_name: type: string example: 'Example Site' release_mode_run_id: type: integer example: 10 duration_hours: type: integer example: 24 interval_seconds: type: integer example: 15 started_at: type: string example: '2026-05-21T12:00:00+00:00' until: type: string example: '2026-05-22T12:00:00+00:00' 403: description: 'Not on plan' content: application/json: schema: type: object example: error: 'Release mode is not available on this plan' monitor_id: 1 properties: error: type: string example: 'Release mode is not available on this plan' monitor_id: type: integer example: 1 404: description: 'Invalid token' content: application/json: schema: type: object example: error: 'Invalid webhook token' properties: error: type: string example: 'Invalid webhook token' 409: description: 'Under maintenance' content: application/json: schema: type: object example: error: 'Monitor is under an active maintenance window' monitor_id: 1 properties: error: type: string example: 'Monitor is under an active maintenance window' monitor_id: type: integer example: 1 422: description: 'Already active' content: application/json: schema: type: object example: error: 'Release mode is already active for this monitor' monitor_id: 1 until: '2026-05-22T12:00:00+00:00' properties: error: type: string example: 'Release mode is already active for this monitor' monitor_id: type: integer example: 1 until: type: string example: '2026-05-22T12:00:00+00:00' tags: - Webhooks requestBody: required: false content: application/json: schema: type: object properties: duration_hours: type: integer description: 'How long to keep release mode active (1-72). Defaults to 24.' example: 24 interval_seconds: type: integer description: 'Check interval during release mode (15-300). Defaults to 15.' example: 15 security: [] parameters: - in: path name: token description: "The monitor's release-mode webhook token." example: a1b2c3d4e5f6 required: true schema: type: string '/api/v1/webhooks/maintenance/{token}/start': post: summary: 'Start a maintenance window' operationId: startAMaintenanceWindow description: "Opens a maintenance window for the monitor identified by the path token,\nsuppressing alerts during a deployment. Authenticated by the webhook token only." parameters: [] responses: 200: description: Started content: application/json: schema: type: object example: status: started monitor_id: 1 monitor_name: 'Example Site' window_id: 5 started_at: '2026-05-21T12:00:00+00:00' until: '2026-05-21T16:00:00+00:00' properties: status: type: string example: started monitor_id: type: integer example: 1 monitor_name: type: string example: 'Example Site' window_id: type: integer example: 5 started_at: type: string example: '2026-05-21T12:00:00+00:00' until: type: string example: '2026-05-21T16:00:00+00:00' 404: description: 'Invalid token' content: application/json: schema: type: object example: error: 'Invalid webhook token' properties: error: type: string example: 'Invalid webhook token' 422: description: 'Already active' content: application/json: schema: type: object example: error: 'A webhook-initiated maintenance window is already active for this monitor' monitor_id: 1 properties: error: type: string example: 'A webhook-initiated maintenance window is already active for this monitor' monitor_id: type: integer example: 1 tags: - Webhooks requestBody: required: false content: application/json: schema: type: object properties: duration_hours: type: integer description: 'Window length in hours (1-24). Defaults to 4.' example: 4 name: type: string description: 'Optional label for the window.' example: 'Deployment maintenance' security: [] parameters: - in: path name: token description: "The monitor's maintenance webhook token." example: a1b2c3d4e5f6 required: true schema: type: string '/api/v1/webhooks/maintenance/{token}/end': post: summary: 'End a maintenance window' operationId: endAMaintenanceWindow description: 'Closes the active webhook-initiated maintenance window for the monitor.' parameters: [] responses: 200: description: Ended content: application/json: schema: type: object example: status: ended monitor_id: 1 window_id: 5 properties: status: type: string example: ended monitor_id: type: integer example: 1 window_id: type: integer example: 5 404: description: 'No active window' content: application/json: schema: type: object example: error: 'No active webhook-initiated maintenance window found' monitor_id: 1 properties: error: type: string example: 'No active webhook-initiated maintenance window found' monitor_id: type: integer example: 1 tags: - Webhooks security: [] parameters: - in: path name: token description: "The monitor's maintenance webhook token." example: a1b2c3d4e5f6 required: true schema: type: string /api/v1/alert-contacts: get: summary: 'List alert contacts' operationId: listAlertContacts description: "Returns the company's alert contacts, ordered by name." parameters: - in: query name: per_page description: 'Results per page (1-100). Defaults to 25.' example: 25 required: false schema: type: integer description: 'Results per page (1-100). Defaults to 25.' example: 25 - in: query name: page description: 'Page number.' example: 1 required: false schema: type: integer description: 'Page number.' example: 1 responses: 200: description: Success content: application/json: schema: type: object example: data: - id: 1 type: slack name: 'Ops Slack' is_active: true links: first: null last: null prev: null next: null meta: current_page: 1 from: 1 last_page: 1 path: 'https://miterl.com/api/v1/alert-contacts' per_page: 25 to: 1 total: 1 properties: data: type: array example: - id: 1 type: slack name: 'Ops Slack' is_active: true items: type: object properties: id: type: integer example: 1 type: type: string example: slack name: type: string example: 'Ops Slack' is_active: type: boolean example: true links: type: object properties: first: type: string example: null nullable: true last: type: string example: null nullable: true prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 path: type: string example: 'https://miterl.com/api/v1/alert-contacts' per_page: type: integer example: 25 to: type: integer example: 1 total: type: integer example: 1 tags: - 'Alert Contacts' '/api/v1/wp/{key}/ping': get: summary: 'Ping (connection test)' operationId: pingconnectionTest description: "Returns the identity of the monitor linked to the connect key. Used by the\nplugin's \"Test connection\" button." parameters: [] responses: 200: description: Connected content: application/json: schema: type: object example: ok: true monitor_id: 1 monitor_name: client-a.example.com site_url: 'https://client-a.example.com/' properties: ok: type: boolean example: true monitor_id: type: integer example: 1 monitor_name: type: string example: client-a.example.com site_url: type: string example: 'https://client-a.example.com/' 404: description: 'Invalid key' content: application/json: schema: type: object example: error: 'Invalid connect key' properties: error: type: string example: 'Invalid connect key' tags: - 'WordPress Connect' security: [] parameters: - in: path name: key description: 'The connect key issued on the monitor page.' example: mc_abcdefghijklmnopqrstuvwxyz0123456789ABCD required: true schema: type: string '/api/v1/wp/{key}/heartbeat': post: summary: 'wp-cron heartbeat' operationId: wpCronHeartbeat description: "Records a heartbeat on the wp-cron Heartbeat monitor linked to the connection\n(same effect as `GET /heartbeat/{token}`). When the connection has no\nHeartbeat monitor, or that monitor is paused, nothing is recorded and\n`heartbeat` is false." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: Recorded type: object example: ok: true heartbeat: true properties: ok: type: boolean example: true heartbeat: type: boolean example: true - description: 'No heartbeat monitor' type: object example: ok: true heartbeat: false properties: ok: type: boolean example: true heartbeat: type: boolean example: false 404: description: 'Invalid key' content: application/json: schema: type: object example: error: 'Invalid connect key' properties: error: type: string example: 'Invalid connect key' tags: - 'WordPress Connect' security: [] parameters: - in: path name: key description: 'The connect key issued on the monitor page.' example: mc_abcdefghijklmnopqrstuvwxyz0123456789ABCD required: true schema: type: string '/api/v1/wp/{key}/maintenance/start': post: summary: 'Start a maintenance window (before a WordPress update)' operationId: startAMaintenanceWindowbeforeAWordPressUpdate description: "Opens a webhook-initiated maintenance window on the monitor linked to the connect\nkey (same effect and response as `POST /api/v1/webhooks/maintenance/{token}/start`),\nso the temporary 5xx during a core/plugin/theme update is not alerted." parameters: [] responses: 200: description: Started content: application/json: schema: type: object example: status: started monitor_id: 1 monitor_name: client-a.example.com window_id: 5 started_at: '2026-09-13T12:00:00+00:00' until: '2026-09-13T13:00:00+00:00' properties: status: type: string example: started monitor_id: type: integer example: 1 monitor_name: type: string example: client-a.example.com window_id: type: integer example: 5 started_at: type: string example: '2026-09-13T12:00:00+00:00' until: type: string example: '2026-09-13T13:00:00+00:00' 404: description: 'Invalid key' content: application/json: schema: type: object example: error: 'Invalid connect key' properties: error: type: string example: 'Invalid connect key' 422: description: 'Already active' content: application/json: schema: type: object example: error: 'A webhook-initiated maintenance window is already active for this monitor' monitor_id: 1 properties: error: type: string example: 'A webhook-initiated maintenance window is already active for this monitor' monitor_id: type: integer example: 1 tags: - 'WordPress Connect' requestBody: required: false content: application/json: schema: type: object properties: duration_hours: type: integer description: 'Window length in hours (1-24). Defaults to 4.' example: 1 name: type: string description: 'Optional label for the window.' example: 'Plugin update' security: [] parameters: - in: path name: key description: 'The connect key issued on the monitor page.' example: mc_abcdefghijklmnopqrstuvwxyz0123456789ABCD required: true schema: type: string '/api/v1/wp/{key}/maintenance/end': post: summary: 'End a maintenance window (after a WordPress update)' operationId: endAMaintenanceWindowafterAWordPressUpdate description: "Closes the active webhook-initiated maintenance window on the linked monitor\n(same effect and response as `POST /api/v1/webhooks/maintenance/{token}/end`)." parameters: [] responses: 200: description: Ended content: application/json: schema: type: object example: status: ended monitor_id: 1 window_id: 5 properties: status: type: string example: ended monitor_id: type: integer example: 1 window_id: type: integer example: 5 404: description: '' content: application/json: schema: oneOf: - description: 'Invalid key' type: object example: error: 'Invalid connect key' properties: error: type: string example: 'Invalid connect key' - description: 'No active window' type: object example: error: 'No active webhook-initiated maintenance window found' monitor_id: 1 properties: error: type: string example: 'No active webhook-initiated maintenance window found' monitor_id: type: integer example: 1 tags: - 'WordPress Connect' security: [] parameters: - in: path name: key description: 'The connect key issued on the monitor page.' example: mc_abcdefghijklmnopqrstuvwxyz0123456789ABCD required: true schema: type: string '/api/v1/wp/{key}/inventory': post: summary: 'Send the site inventory (daily)' operationId: sendTheSiteInventorydaily description: "Stores the WordPress core / plugin / theme versions and available updates on the\nconnection, replacing the previous inventory (no history is kept). Miterl shows the\npending updates on the monitor page and, on Standard and above, alerts when they\nare left unapplied." parameters: [] responses: 200: description: Stored content: application/json: schema: type: object example: ok: true pending_updates: 2 properties: ok: type: boolean example: true pending_updates: type: integer example: 2 404: description: 'Invalid key' content: application/json: schema: type: object example: error: 'Invalid connect key' properties: error: type: string example: 'Invalid connect key' 422: description: Malformed content: application/json: schema: type: object example: message: 'The php version field is required. (and 1 more error)' errors: php_version: - 'The php version field is required.' plugins: - 'The plugins field must be an array.' properties: message: type: string example: 'The php version field is required. (and 1 more error)' errors: type: object properties: php_version: type: array example: - 'The php version field is required.' items: type: string plugins: type: array example: - 'The plugins field must be an array.' items: type: string tags: - 'WordPress Connect' requestBody: required: true content: application/json: schema: type: object properties: wp_version: type: string description: 'WordPress version.' example: 6.8.1 php_version: type: string description: 'PHP version.' example: 8.3.12 core: type: object description: 'Core version and available update.' example: [] properties: version: type: string description: '' example: 6.8.1 new_version: type: string description: 'Available core version, or null.' example: 6.8.2 nullable: true required: - version plugins: type: array description: 'Installed plugins (max 300). Send `[]` when none.' example: - [] items: type: object properties: slug: type: string description: '' example: akismet name: type: string description: '' example: Akismet version: type: string description: 'Installed version, or null when the plugin has no `Version:` header.' example: '5.3' nullable: true new_version: type: string description: 'Available version, or null.' example: '5.4' nullable: true active: type: boolean description: '' example: true required: - slug - name - version - active themes: type: array description: 'Installed themes (max 50). Same shape as `plugins`.' example: - [] items: type: object properties: slug: type: string description: valueは255文字以下で入力してください。. example: 'y' name: type: string description: valueは255文字以下で入力してください。. example: v version: type: string description: valueは64文字以下で入力してください。. example: d nullable: true new_version: type: string description: valueは64文字以下で入力してください。. example: l nullable: true active: type: boolean description: '' example: true required: - slug - name - active required: - wp_version - php_version - core - plugins - themes security: [] parameters: - in: path name: key description: 'The connect key issued on the monitor page.' example: mc_abcdefghijklmnopqrstuvwxyz0123456789ABCD required: true schema: type: string