# UptimeSignal - Full API Reference > This is the detailed API reference for AI agents that need to call the UptimeSignal API directly. For a summary, see /llms.txt. Base URL: `https://api.uptimesignal.io` Authentication: `Authorization: Bearer ` header on all authenticated endpoints. --- ## Authentication ### Request Magic Link ``` POST /auth/magic-link Content-Type: application/json { "email": "user@example.com" } Response 200: { "success": true } ``` Sends a magic link email. Creates user account if new. ### Verify Magic Link ``` POST /auth/verify Content-Type: application/json { "token": "" } Response 200: { "token": "eyJ...", "user": { "id": "uuid", "email": "user@example.com", "plan": "free" } } ``` Use the returned `token` as Bearer token for all subsequent requests. Tokens expire in 7 days. ### Get Current User ``` GET /auth/me Authorization: Bearer Response 200: { "user": { "id": "uuid", "email": "user@example.com", "plan": "free", "stripe_customer_id": null } } ``` ### Logout ``` POST /auth/logout Authorization: Bearer Response 200: { "success": true } ``` --- ## Monitors ### List Monitors ``` GET /monitors GET /monitors?tags=production,api Authorization: Bearer Response 200: { "monitors": [ { "id": "uuid", "name": "My API", "url": "https://api.example.com/health", "method": "GET", "interval_seconds": 300, "expected_status_code": 200, "status": "active", "current_status": "up", "consecutive_failures": 0, "last_check_at": 1709900000000, "last_response_time_ms": 145, "created_at": 1709800000000, "keyword": null, "keyword_invert": 0, "ssl_issuer": "R3", "ssl_expires_at": 1717200000000, "ssl_checked_at": 1709900000000, "ssl_alert_days": 14, "paused_at": null, "tags": "[\"production\",\"api\"]", "badge_enabled": 1 } ] } ``` ### Create Monitor ``` POST /monitors Authorization: Bearer Content-Type: application/json { "name": "My API Health", "url": "https://api.example.com/health", "method": "GET", "headers": { "Authorization": "Bearer api-key-123" }, "body": null, "content_type": "application/json", "interval_seconds": 60, "expected_status_code": 200, "keyword": "healthy", "keyword_invert": false, "ssl_alert_days": 14, "tags": ["production", "api"], "response_time_threshold": 2000, "response_time_alert_enabled": true } Response 201: { "id": "uuid" } ``` Parameters: - `name` (required, string, max 100 chars) - `url` (required, string, must start with http:// or https://, max 2000 chars) - `method` (optional, default "GET") - GET, POST, PUT, PATCH, DELETE - `headers` (optional, object) - Custom request headers - `body` (optional, string) - Request body for POST/PUT/PATCH - `content_type` (optional, default "application/json") - Content-Type for request body - `interval_seconds` (optional, default 300) - Check interval. Free: min 300 (5min). Pro: min 60 (1min). - `expected_status_code` (optional, default 200) - Expected HTTP status (100-599) - `keyword` (optional, string) - Keyword to check for in response body - `keyword_invert` (optional, boolean) - If true, alert when keyword IS found - `ssl_alert_days` (optional, default 14) - Days before SSL expiry to alert - `tags` (optional, string[]) - Max 5 tags, lowercase alphanumeric + hyphens, max 20 chars each - `response_time_threshold` (optional, number 1-60000) - Response time threshold in ms - `response_time_alert_enabled` (optional, boolean) - Enable response time SLA alerts ### Get Monitor ``` GET /monitors/:id Authorization: Bearer Response 200: { "monitor": { ...full monitor object... } } ``` ### Update Monitor ``` PUT /monitors/:id Authorization: Bearer Content-Type: application/json { "name": "Updated Name", "url": "https://api.example.com/v2/health", "interval_seconds": 60, "keyword": "ok", "tags": ["production"], "badge_enabled": true, "response_time_threshold": 1500, "response_time_alert_enabled": true } Response 200: { "success": true } ``` All fields are optional. Only provided fields are updated. ### Delete Monitor ``` DELETE /monitors/:id Authorization: Bearer Response 200: { "success": true } ``` ### Pause Monitor ``` POST /monitors/:id/pause Authorization: Bearer Response 200: { "success": true } ``` ### Resume Monitor ``` POST /monitors/:id/resume Authorization: Bearer Response 200: { "success": true } ``` ### Quick Suppress Alerts ``` POST /monitors/:id/suppress Authorization: Bearer Content-Type: application/json { "minutes": 30 } Response 200: { "success": true, "id": "uuid", "message": "Alerts suppressed for 30 minutes", "end_time": 1709901800000 } ``` Creates a one-time maintenance window. Minutes: 1-1440. ### Get Check History ``` GET /monitors/:id/checks?limit=100 Authorization: Bearer Response 200: { "checks": [ { "id": "uuid", "status": "up", "response_time_ms": 145, "status_code": 200, "checked_at": 1709900000000, "error": null } ] } ``` ### Get Single Check (with response body) ``` GET /monitors/:id/checks/:checkId Authorization: Bearer Response 200: { "check": { "id": "uuid", "status": "down", "response_time_ms": 2300, "status_code": 500, "checked_at": 1709900000000, "error": "Expected 200, got 500", "response_body": "{\"error\":\"internal server error\"}", "response_headers": { "content-type": "application/json" } } } ``` ### Get Monitor Stats ``` GET /monitors/:id/stats?period=24h Authorization: Bearer Response 200: { "uptime_percent": 99.85, "avg_response_time": 145, "min_response_time": 98, "max_response_time": 2340, "total_checks": 288, "successful_checks": 287, "incident_count": 1 } ``` Periods: `24h`, `7d`, `30d` ### Get Uptime Bars ``` GET /monitors/:id/uptime-bars?hours=24 Authorization: Bearer Response 200: { "bars": [ { "hour": "2024-03-08T00:00:00.000Z", "status": "up", "avg_response": 142 }, { "hour": "2024-03-08T01:00:00.000Z", "status": "partial", "avg_response": 1200 } ] } ``` Status values: `up`, `down`, `partial`, `empty`. Max hours: 168 (7 days). ### Get Alert History ``` GET /monitors/:id/alerts?limit=50 Authorization: Bearer Response 200: { "alerts": [ { "id": "uuid", "type": "down", "message": "Expected 200, got 500", "sent_at": 1709900000000 } ] } ``` Alert types: `down`, `up`, `ssl_expiring`, `slow`, `slow_recovery` --- ## Dashboard Stats ``` GET /stats Authorization: Bearer Response 200: { "total": 12, "up": 10, "down": 1, "paused": 1, "pending": 0 } ``` ## Tags ``` GET /tags Authorization: Bearer Response 200: { "tags": [ { "name": "production", "count": 5 }, { "name": "api", "count": 3 } ] } ``` --- ## Status Pages ### Create Status Page ``` POST /status-pages Authorization: Bearer Content-Type: application/json { "slug": "my-company", "name": "My Company Status", "logo_url": "https://example.com/logo.png", "monitors": ["monitor-uuid-1", "monitor-uuid-2"] } Response 201: { "id": "uuid", "slug": "my-company" } ``` Free plan: 1 status page. Pro: unlimited. ### Update Status Page ``` PUT /status-pages/:id Authorization: Bearer Content-Type: application/json { "name": "Updated Name", "monitors": ["uuid1", "uuid2"], "accent_color": "#10b981", "header_text": "All systems operational", "show_powered_by": false } Response 200: { "success": true } ``` ### Set Custom Domain (Pro) ``` POST /status-pages/:id/custom-domain Authorization: Bearer Content-Type: application/json { "domain": "status.example.com" } Response 200: { "success": true, "domain": "status.example.com", "cname_target": "status-pages.uptimesignal.io", "validation_records": [ { "txt_name": "_cf-custom-hostname.status.example.com", "txt_value": "..." } ], "ssl_status": "pending_validation", "instructions": "Add a CNAME record pointing status.example.com to status-pages.uptimesignal.io, and add the TXT record for SSL verification." } ``` ### Verify Custom Domain ``` POST /status-pages/:id/custom-domain/verify Authorization: Bearer Response 200 (pending): { "verified": false, "hostname_status": "pending", "ssl_status": "pending_validation", "validation_records": [...], "status_message": "Waiting for your CNAME record.", "status_step": 1, "expected_cname": "status-pages.uptimesignal.io" } Response 200 (verified): { "verified": true, "domain": "status.example.com" } ``` --- ## Incidents ### Create Incident ``` POST /status-pages/:id/incidents Authorization: Bearer Content-Type: application/json { "title": "API Degraded Performance", "status": "investigating", "impact": "minor", "message": "We are investigating reports of slow API responses.", "affected_monitors": ["monitor-uuid-1"] } Response 201: { "id": "uuid" } ``` Statuses: `investigating`, `identified`, `monitoring`, `resolved` Impacts: `none`, `minor`, `major`, `critical` ### Add Incident Update ``` POST /status-pages/:id/incidents/:incidentId/updates Authorization: Bearer Content-Type: application/json { "status": "identified", "message": "Root cause identified. A database connection pool was exhausted." } Response 201: { "id": "uuid" } ``` --- ## Components & Groups ### Create Component Group ``` POST /status-pages/:id/component-groups Authorization: Bearer Content-Type: application/json { "name": "Core Services", "description": "Primary APIs", "collapsed": false } Response 201: { "id": "uuid" } ``` ### Create Component ``` POST /status-pages/:id/components Authorization: Bearer Content-Type: application/json { "name": "User API", "description": "Authentication and user management", "group_id": "group-uuid", "status": "operational" } Response 201: { "id": "uuid" } ``` Statuses: `operational`, `degraded`, `partial_outage`, `major_outage`, `maintenance` ### Update Component Status ``` PUT /status-pages/:id/components/:componentId Authorization: Bearer Content-Type: application/json { "status": "degraded" } Response 200: { "success": true } ``` --- ## Inbound Webhooks (Status Page Automation) ### Create Webhook ``` POST /status-pages/:id/webhooks Authorization: Bearer Content-Type: application/json { "name": "GitHub Actions" } Response 201: { "id": "uuid", "secret": "a1b2c3d4e5...", "webhook_url": "https://api.uptimesignal.io/webhook/a1b2c3d4e5..." } ``` ### Use Inbound Webhook (Public, no auth) ``` POST /webhook/:secret Content-Type: application/json ``` #### Update Component Status ```json { "action": "update_component", "component_name": "User API", "component_status": "degraded" } ``` #### Create Incident ```json { "action": "create_incident", "incident_title": "Deploy in progress", "incident_message": "Deploying v2.3.0 to production.", "incident_impact": "minor" } ``` #### Update Incident ```json { "action": "update_incident", "incident_id": "uuid", "incident_message": "Deploy completed. Verifying stability." } ``` #### Resolve Incident ```json { "action": "resolve_incident", "incident_id": "uuid", "incident_message": "Deploy successful. All systems normal." } ``` --- ## Integrations (Pro only) ### Create Integration ``` POST /integrations Authorization: Bearer Content-Type: application/json ``` #### Slack ```json { "type": "slack", "name": "Slack #alerts", "config": { "webhook_url": "https://hooks.slack.com/services/T00/B00/xxx" } } ``` #### Discord ```json { "type": "discord", "name": "Discord alerts", "config": { "webhook_url": "https://discord.com/api/webhooks/123/abc" } } ``` #### Telegram ```json { "type": "telegram", "name": "Telegram", "config": { "chat_id": "123456789" } } ``` Use the Telegram verification flow instead of providing chat_id directly: 1. `POST /integrations/telegram/init` - Returns `{ "code": "USG-ABC123", "deepLink": "https://t.me/UptimeSignal_Bot?start=USG-ABC123" }` 2. User clicks deep link and sends /start to bot 3. `GET /integrations/telegram/status` - Returns `{ "connected": true }` when verified #### Custom Webhook ```json { "type": "webhook", "name": "PagerDuty", "config": { "webhook_url": "https://my-server.com/webhook", "headers": { "X-Custom-Header": "value" } } } ``` Webhook payload format (sent by UptimeSignal to your URL): ```json { "event": "monitor.down", "monitor": { "id": "uuid", "name": "My API", "url": "https://api.example.com/health" }, "check": { "status_code": 500, "response_time_ms": 2340, "error": "Expected 200, got 500", "timestamp": "2024-03-08T12:00:00.000Z" }, "alert": { "type": "down", "sent_at": "2024-03-08T12:00:05.000Z" }, "downtime_seconds": null } ``` ### Test Integration ``` POST /integrations/:id/test Authorization: Bearer Response 200: { "success": true } ``` --- ## Maintenance Windows ### Create Maintenance Window ``` POST /maintenance Authorization: Bearer Content-Type: application/json ``` #### One-time window ```json { "name": "Server migration", "monitor_id": "uuid-or-null-for-all", "start_time": 1709900000000, "end_time": 1709910000000 } ``` #### Recurring daily ```json { "name": "Nightly backups", "monitor_id": null, "start_time": 1709900000000, "end_time": 1709910000000, "recurring": "daily", "recurring_start_minutes": 120, "recurring_duration_minutes": 60, "timezone": "UTC" } ``` `recurring_start_minutes`: minutes from midnight UTC (e.g., 120 = 02:00 UTC) #### Recurring weekly ```json { "name": "Sunday maintenance", "monitor_id": null, "start_time": 1709900000000, "end_time": 1709910000000, "recurring": "weekly", "recurring_day": 0, "recurring_start_minutes": 60, "recurring_duration_minutes": 120, "timezone": "UTC" } ``` `recurring_day`: 0=Sunday, 1=Monday, ..., 6=Saturday #### Recurring monthly ```json { "name": "Monthly patching", "monitor_id": null, "start_time": 1709900000000, "end_time": 1709910000000, "recurring": "monthly", "recurring_day": 1, "recurring_start_minutes": 0, "recurring_duration_minutes": 240, "timezone": "UTC" } ``` `recurring_day`: 1-31 (day of month) --- ## Badges (Public, no auth required) ### Uptime Badge (SVG) ``` GET /badge/:monitor_id/uptime.svg Returns SVG image showing 30-day uptime percentage. Colors: green (>=99%), yellow (95-99%), red (<95%), gray (N/A) Cache: 5 minutes ``` ### Status Badge (SVG) ``` GET /badge/:monitor_id/status.svg Returns SVG showing current status: operational/down/pending Colors: green (up), red (down), yellow (pending), gray (unknown) ``` ### Response Time Badge (SVG) ``` GET /badge/:monitor_id/response.svg Returns SVG showing average 24h response time in ms. Colors: green (<500ms), yellow (500-1000ms), red (>1000ms) ``` ### Badge Data (JSON) ``` GET /badge/:monitor_id/data.json Response 200: { "monitor_id": "uuid", "name": "My API", "status": "up", "uptime_percent_30d": 99.95, "avg_response_ms_24h": 145, "generated_at": "2024-03-08T12:00:00.000Z" } ``` Embed in README: ```markdown ![Uptime](https://api.uptimesignal.io/badge/MONITOR_ID/uptime.svg) ![Status](https://api.uptimesignal.io/badge/MONITOR_ID/status.svg) ``` --- ## Billing ### Create Checkout (Upgrade to Pro) ``` POST /stripe/checkout Authorization: Bearer Response 200: { "url": "https://checkout.stripe.com/..." } ``` Redirect user to the returned URL for Stripe Checkout. ### Create Billing Portal ``` POST /stripe/portal Authorization: Bearer Response 200: { "url": "https://billing.stripe.com/..." } ``` --- ## Tools (Public, rate-limited: 10 req/min per IP) ### Check URL ``` POST /tools/check-url Content-Type: application/json { "url": "https://example.com" } Response 200: { "url": "https://example.com", "status": 200, "statusText": "OK", "responseTime": 245, "isUp": true, "timestamp": "2024-03-08T12:00:00.000Z" } ``` ### SSL Check ``` POST /tools/ssl-check Content-Type: application/json { "domain": "example.com" } Response 200: { "domain": "example.com", "valid": true, "protocol": "TLS", "message": "SSL certificate is valid and the site is accessible over HTTPS.", "checkedAt": "2024-03-08T12:00:00.000Z" } ``` --- ## Public Status Page Data (no auth) ``` GET /public/status/:slug Response 200: { "name": "My Company Status", "logo_url": "https://example.com/logo.png", "accent_color": "#10b981", "header_text": "All systems operational", "show_powered_by": 1, "overall_status": "operational", "monitors": [ { "id": "uuid", "name": "API", "status": "up", "uptime_30d": 99.95, "uptime_bars": [100, 100, 99.5, ...], "last_checked": "2024-03-08T12:00:00.000Z", "affected_by_incident": false } ], "component_groups": [...], "components": [...], "active_incidents": [...], "past_incidents": [...], "updated_at": "2024-03-08T12:00:00.000Z" } ``` Overall status: `operational`, `partial`, `major` --- ## Test Endpoints (Public) All return JSON: `{ "status": , "message": "...", "timestamp": "...", "powered_by": "UptimeSignal" }` | Endpoint | Status Code | Notes | |---|---|---| | GET /test/healthy | 200 | | | GET /test/unhealthy | 500 | | | GET /test/200 | 200 | | | GET /test/201 | 201 | | | GET /test/400 | 400 | | | GET /test/401 | 401 | | | GET /test/403 | 403 | | | GET /test/404 | 404 | | | GET /test/500 | 500 | | | GET /test/502 | 502 | | | GET /test/503 | 503 | | | GET /test/504 | 504 | | | GET /test/timeout | 200 | 60s delay | | GET /test/slow | 200 | 5s delay | | GET /test/random | 200/500/503 | Random | --- ## Error Responses All errors follow this format: ```json { "error": "Human-readable error message", "code": "OPTIONAL_ERROR_CODE" } ``` Common error codes: - `INTERVAL_RESTRICTED` - Check interval below plan minimum - `PRO_REQUIRED` - Feature requires Pro plan Common HTTP status codes: - 400 - Bad request / validation error - 401 - Unauthorized / invalid token - 403 - Forbidden / plan limit reached - 404 - Resource not found - 429 - Rate limit exceeded - 500 - Internal server error --- ## Monitoring Behavior - Checks run every minute via Cloudflare Workers cron - A monitor is marked "down" after 2 consecutive failures - Recovery alert sent when next check succeeds - SSL certificates checked once per day for HTTPS monitors - Alerts suppressed during active maintenance windows (one-time and recurring) - Response time SLA: alert when response exceeds threshold, recovery when back below - Keyword validation runs after status code check - Response body and headers captured on failed checks (truncated at 10KB) - User-Agent: `UptimeSignal/1.0 (https://uptimesignal.io)`