{"components":{"responses":{},"schemas":{"DashboardResponse":{"description":"Dashboard overview response","properties":{"overall_uptime":{"description":"Overall uptime percentage","format":"float","type":"number"},"period_days":{"description":"Period in days","type":"integer"},"stats":{"$ref":"#/components/schemas/DashboardStats"},"uptime_trend":{"description":"Daily uptime trend","items":{"$ref":"#/components/schemas/UptimeTrendPoint"},"type":"array"}},"required":["stats","overall_uptime","period_days"],"title":"DashboardResponse","type":"object"},"DashboardStats":{"description":"Dashboard statistics summary","example":{"active_monitors":10,"ongoing_incidents":1,"recent_incidents":3,"total_monitors":12},"properties":{"active_monitors":{"description":"Number of active monitors","type":"integer"},"ongoing_incidents":{"description":"Current ongoing incidents","type":"integer"},"recent_incidents":{"description":"Incidents in the last 7 days","type":"integer"},"total_monitors":{"description":"Total number of monitors","type":"integer"}},"title":"DashboardStats","type":"object"},"DnsRecord":{"description":"DNS record for domain verification","example":{"name":"_uptrack-verification.status.example.com","type":"TXT","value":"abc123xyz"},"properties":{"name":{"description":"Record name (hostname)","type":"string"},"type":{"description":"Record type","enum":["TXT","CNAME","A"],"type":"string"},"value":{"description":"Record value","type":"string"}},"title":"DnsRecord","type":"object"},"DnsRecords":{"description":"Required DNS records for domain verification","properties":{"cname_record":{"$ref":"#/components/schemas/DnsRecord"},"txt_record":{"$ref":"#/components/schemas/DnsRecord"}},"title":"DnsRecords","type":"object"},"DomainConfigResponse":{"description":"Domain configuration and status","example":{"custom_domain":"status.example.com","dns_records":{"cname_record":{"name":"status.example.com","type":"CNAME","value":"status.uptrack.app"},"txt_record":{"name":"_uptrack-verification.status.example.com","type":"TXT","value":"abc123xyz"}},"domain_verification_token":"abc123xyz","domain_verified":false,"ssl_status":"pending"},"properties":{"custom_domain":{"description":"Custom domain name","nullable":true,"type":"string"},"dns_records":{"description":"Required DNS records (null if no domain set)","oneOf":[{"$ref":"#/components/schemas/DnsRecords"},{"type":"null"}]},"domain_verification_token":{"description":"Token for DNS TXT record verification","type":"string"},"domain_verified":{"description":"Whether domain is verified","type":"boolean"},"domain_verified_at":{"description":"When domain was verified","format":"date-time","nullable":true,"type":"string"},"ssl_expires_at":{"description":"SSL certificate expiration","format":"date-time","nullable":true,"type":"string"},"ssl_status":{"description":"SSL certificate status","enum":["pending","provisioning","active","expired","failed"],"type":"string"}},"title":"DomainConfigResponse","type":"object"},"DomainErrorResponse":{"example":{"error":"Status page not found"},"properties":{"details":{"description":"Validation error details","type":"object"},"error":{"description":"Error message","type":"string"}},"title":"DomainErrorResponse","type":"object"},"DomainSuccessResponse":{"example":{"message":"Custom domain removed","success":true},"properties":{"message":{"type":"string"},"success":{"type":"boolean"}},"title":"DomainSuccessResponse","type":"object"},"DomainUpdateRequest":{"description":"Request to set custom domain","example":{"custom_domain":"status.example.com"},"properties":{"custom_domain":{"description":"Domain name (e.g., status.example.com)","pattern":"^([a-z0-9]([a-z0-9-]*[a-z0-9])?\\.)+[a-z]{2,}$","type":"string"}},"required":["custom_domain"],"title":"DomainUpdateRequest","type":"object"},"DomainVerifyResponse":{"description":"Domain verification result","example":{"domain":"status.example.com","message":"Domain verified successfully","verified":true,"verified_at":"2024-01-01T00:00:00Z"},"properties":{"dns_records":{"description":"Required DNS records (shown on failure)","oneOf":[{"$ref":"#/components/schemas/DnsRecords"},{"type":"null"}]},"domain":{"description":"The domain that was verified","type":"string"},"error":{"description":"Error details if failed","nullable":true,"type":"string"},"message":{"description":"Success or error message","type":"string"},"verified":{"description":"Whether verification succeeded","type":"boolean"},"verified_at":{"description":"Verification timestamp","format":"date-time","type":"string"}},"title":"DomainVerifyResponse","type":"object"},"HealthResponse":{"description":"Liveness probe response","properties":{"node_region":{"description":"Node region","example":"eu-central","type":"string"},"status":{"description":"Health status","example":"alive","type":"string"},"timestamp":{"description":"Check timestamp","format":"date-time","type":"string"},"version":{"description":"Application version","example":"0.1.0","type":"string"}},"required":["status","timestamp"],"title":"HealthResponse","type":"object"},"HeartbeatErrorResponse":{"description":"Error response from heartbeat endpoint","properties":{"error":{"example":"Invalid or inactive heartbeat token","type":"string"},"ok":{"example":false,"type":"boolean"}},"required":["ok","error"],"title":"HeartbeatErrorResponse","type":"object"},"HeartbeatPingRequest":{"description":"Optional payload for heartbeat ping","properties":{"execution_time":{"description":"Execution time in milliseconds","example":1234,"type":"integer"},"message":{"description":"Optional message or details","example":"Job completed successfully","type":"string"},"status":{"description":"Custom status message","example":"success","type":"string"}},"title":"HeartbeatPingRequest","type":"object"},"HeartbeatPingResponse":{"description":"Response from heartbeat ping","properties":{"monitor":{"properties":{"id":{"format":"uuid","type":"string"},"name":{"example":"Daily backup job","type":"string"},"status":{"enum":["active","paused"],"type":"string"}},"type":"object"},"ok":{"example":true,"type":"boolean"}},"required":["ok"],"title":"HeartbeatPingResponse","type":"object"},"IncidentFrequencyPoint":{"description":"Daily incident count","properties":{"count":{"description":"Number of incidents","type":"integer"},"date":{"format":"date","type":"string"}},"title":"IncidentFrequencyPoint","type":"object"},"IncidentStats":{"description":"Incident statistics","example":{"mttr_minutes":12.5,"ongoing_incidents":0,"resolved_incidents":5,"total_incidents":5},"properties":{"mttr_minutes":{"description":"Mean Time To Recovery in minutes","type":"number"},"ongoing_incidents":{"description":"Currently ongoing","type":"integer"},"resolved_incidents":{"description":"Resolved incidents","type":"integer"},"total_incidents":{"description":"Total incidents","type":"integer"}},"title":"IncidentStats","type":"object"},"MonitorAnalyticsResponse":{"description":"Detailed analytics for a single monitor","properties":{"incident_stats":{"$ref":"#/components/schemas/IncidentStats"},"monitor_id":{"description":"Monitor ID","type":"integer"},"period_days":{"description":"Analysis period in days","type":"integer"},"response_times":{"description":"Daily response time trends","items":{"$ref":"#/components/schemas/ResponseTimePoint"},"type":"array"},"uptime_chart":{"description":"Daily uptime data for charts","items":{"$ref":"#/components/schemas/UptimeTrendPoint"},"type":"array"}},"required":["monitor_id","period_days"],"title":"MonitorAnalyticsResponse","type":"object"},"OrganizationTrendsResponse":{"description":"Organization-wide analytics trends","properties":{"incident_frequency":{"description":"Daily incident counts","items":{"$ref":"#/components/schemas/IncidentFrequencyPoint"},"type":"array"},"overall_uptime":{"description":"Overall uptime percentage","type":"number"},"period_days":{"description":"Analysis period in days","type":"integer"},"top_offenders":{"description":"Monitors with most incidents","items":{"$ref":"#/components/schemas/TopOffender"},"type":"array"},"uptime_trends":{"description":"Daily uptime trends","items":{"$ref":"#/components/schemas/UptimeTrendPoint"},"type":"array"}},"required":["period_days","overall_uptime"],"title":"OrganizationTrendsResponse","type":"object"},"ReadinessResponse":{"description":"Readiness probe response with dependency checks","properties":{"checks":{"description":"Individual dependency check results","properties":{"database":{"description":"Database status","type":"string"},"idle_prevention":{"description":"Idle prevention stats","type":"object"},"oban":{"description":"Oban job queue status","type":"string"}},"type":"object"},"node_name":{"description":"Node hostname","type":"string"},"node_region":{"description":"Node region","type":"string"},"status":{"description":"Readiness status","enum":["ready","not_ready"],"type":"string"},"timestamp":{"description":"Check timestamp","format":"date-time","type":"string"},"version":{"description":"Application version","example":"0.1.0","type":"string"}},"required":["status","checks","timestamp"],"title":"ReadinessResponse","type":"object"},"ResponseTimePoint":{"description":"Response time data point","properties":{"avg":{"description":"Average response time (ms)","type":"number"},"date":{"format":"date","type":"string"},"max":{"description":"Maximum response time (ms)","type":"integer"},"min":{"description":"Minimum response time (ms)","type":"integer"},"total_checks":{"description":"Number of checks","type":"integer"}},"title":"ResponseTimePoint","type":"object"},"SubscribeRequest":{"description":"Request to subscribe to status page updates","properties":{"email":{"example":"user@example.com","format":"email","type":"string"}},"required":["email"],"title":"SubscribeRequest","type":"object"},"SubscribeResponse":{"description":"Response after subscription request","properties":{"message":{"example":"Please check your email to verify your subscription","type":"string"},"ok":{"example":true,"type":"boolean"}},"required":["ok","message"],"title":"SubscribeResponse","type":"object"},"SubscriberErrorResponse":{"description":"Error response from subscriber endpoints","properties":{"error":{"example":"Invalid email address","type":"string"},"ok":{"example":false,"type":"boolean"}},"required":["ok","error"],"title":"SubscriberErrorResponse","type":"object"},"TopOffender":{"description":"Monitor with most incidents","properties":{"incident_count":{"description":"Number of incidents","type":"integer"},"monitor_id":{"type":"integer"},"monitor_name":{"type":"string"},"total_downtime_seconds":{"description":"Total downtime in seconds","type":"integer"}},"title":"TopOffender","type":"object"},"UnsubscribeResponse":{"description":"Response after unsubscribing","properties":{"message":{"example":"You have been unsubscribed","type":"string"},"ok":{"example":true,"type":"boolean"}},"required":["ok","message"],"title":"UnsubscribeResponse","type":"object"},"UptimeTrendPoint":{"description":"Single data point in uptime trend","properties":{"date":{"description":"Date","format":"date","type":"string"},"total_checks":{"description":"Total checks on this day","type":"integer"},"uptime":{"description":"Uptime percentage","format":"float","type":"number"}},"title":"UptimeTrendPoint","type":"object"},"VerifyResponse":{"description":"Response after verifying subscription","properties":{"message":{"example":"Your subscription has been verified","type":"string"},"ok":{"example":true,"type":"boolean"}},"required":["ok","message"],"title":"VerifyResponse","type":"object"}},"securitySchemes":{"bearerAuth":{"description":"API key from your Uptrack dashboard (Settings → API Keys)","scheme":"bearer","type":"http"},"session":{"description":"Session-based authentication cookie","in":"cookie","name":"_uptrack_key","type":"apiKey"}}},"info":{"description":"Uptrack is an uptime monitoring service. This API provides:\n\n- **Monitor Management** - Create, update, and manage monitors\n- **Heartbeat Endpoints** - Receive heartbeat pings from cron jobs and services\n- **Status Badges** - SVG badges for README files\n- **Status Widgets** - Embeddable status widgets\n- **Subscriptions** - Email notifications for status changes\n- **Team Management** - Manage organization members and invitations\n","title":"Uptrack API","version":"1.0.0"},"openapi":"3.0.0","paths":{"/api/analytics/dashboard":{"get":{"callbacks":{},"description":"Returns dashboard statistics and overview data for the current organization.\nIncludes monitor counts, incident counts, and overall uptime.\n","operationId":"UptrackWeb.Api.AnalyticsController.dashboard","parameters":[{"description":"Number of days to include in calculations","in":"query","name":"days","required":false,"schema":{"default":30,"maximum":365,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardResponse"}}},"description":"Dashboard overview"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatErrorResponse"}}},"description":"Unauthorized"}},"security":[{"session":[]}],"summary":"Get dashboard overview","tags":["Analytics"]}},"/api/analytics/monitors/{monitor_id}":{"get":{"callbacks":{},"description":"Returns detailed analytics for a specific monitor including:\n- Uptime chart data (daily breakdown)\n- Response time trends\n- Incident statistics\n","operationId":"UptrackWeb.Api.AnalyticsController.monitor_stats","parameters":[{"description":"Monitor ID","in":"path","name":"monitor_id","required":true,"schema":{"type":"integer"}},{"description":"Number of days to include","in":"query","name":"days","required":false,"schema":{"default":30,"maximum":365,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorAnalyticsResponse"}}},"description":"Monitor analytics"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatErrorResponse"}}},"description":"Monitor not found"}},"security":[{"session":[]}],"summary":"Get monitor analytics","tags":["Analytics"]}},"/api/analytics/organization/trends":{"get":{"callbacks":{},"description":"Returns aggregated analytics across all monitors for the organization.\nIncludes overall uptime trends and incident frequency.\n","operationId":"UptrackWeb.Api.AnalyticsController.organization_trends","parameters":[{"description":"Number of days to include","in":"query","name":"days","required":false,"schema":{"default":30,"maximum":365,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationTrendsResponse"}}},"description":"Organization trends"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatErrorResponse"}}},"description":"Unauthorized"}},"security":[{"session":[]}],"summary":"Get organization-wide trends","tags":["Analytics"]}},"/api/health":{"get":{"callbacks":{},"description":"Full health check for readiness probes. Verifies all dependencies:\n- Database connectivity (AppRepo)\n- Background job system (Oban/ObanRepo)\n- Idle prevention service\n\nUse this for Kubernetes readiness probes or load balancer health checks.\n","operationId":"UptrackWeb.HealthController.ready","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadinessResponse"}}},"description":"Ready"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadinessResponse"}}},"description":"Not Ready"}},"summary":"Readiness probe","tags":["Health"]}},"/api/health/monitoring":{"get":"ok"},"/api/heartbeat/{token}":{"head":{"callbacks":{},"description":"HEAD request for heartbeat - useful for curl-based monitoring scripts.","operationId":"UptrackWeb.Api.HeartbeatController.head_ping","parameters":[{"description":"Unique heartbeat token for the monitor","in":"path","name":"token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Heartbeat recorded"},"404":{"description":"Invalid token"}},"summary":"Lightweight heartbeat ping","tags":["Heartbeat"]},"post":{"callbacks":{},"description":"Receives a heartbeat ping from a monitored service. Used for cron job and scheduled task monitoring.","operationId":"UptrackWeb.Api.HeartbeatController.ping","parameters":[{"description":"Unique heartbeat token for the monitor","in":"path","name":"token","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatPingRequest"}}},"description":"Heartbeat payload","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatPingResponse"}}},"description":"Heartbeat recorded"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatErrorResponse"}}},"description":"Invalid token"}},"summary":"Record heartbeat","tags":["Heartbeat"]}},"/api/status-pages/{status_page_id}/domain":{"delete":{"callbacks":{},"description":"Removes the custom domain from a status page.","operationId":"UptrackWeb.Api.DomainController.delete","parameters":[{"description":"Status page ID","in":"path","name":"status_page_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainSuccessResponse"}}},"description":"Domain removed"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Status page not found"}},"security":[{"session":[]}],"summary":"Remove custom domain","tags":["Domains"]},"get":{"callbacks":{},"description":"Returns the custom domain configuration and DNS records needed for verification.","operationId":"UptrackWeb.Api.DomainController.show","parameters":[{"description":"Status page ID","in":"path","name":"status_page_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainConfigResponse"}}},"description":"Domain configuration"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Status page not found"}},"security":[{"session":[]}],"summary":"Get domain configuration","tags":["Domains"]},"put":{"callbacks":{},"description":"Sets or updates the custom domain for a status page. Resets verification status.","operationId":"UptrackWeb.Api.DomainController.update","parameters":[{"description":"Status page ID","in":"path","name":"status_page_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainUpdateRequest"}}},"description":"Domain settings","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainConfigResponse"}}},"description":"Domain updated"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Unauthorized"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Validation error"}},"security":[{"session":[]}],"summary":"Set custom domain","tags":["Domains"]}},"/api/status-pages/{status_page_id}/domain/verify":{"post":{"callbacks":{},"description":"Checks DNS records to verify domain ownership. Must have TXT and CNAME records configured.","operationId":"UptrackWeb.Api.DomainController.verify","parameters":[{"description":"Status page ID","in":"path","name":"status_page_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainVerifyResponse"}}},"description":"Domain verified"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Unauthorized"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainErrorResponse"}}},"description":"Verification failed"}},"security":[{"session":[]}],"summary":"Verify domain ownership","tags":["Domains"]}},"/api/status/{slug}/subscribe":{"post":{"callbacks":{},"description":"Subscribe an email address to receive notifications about status page incidents.","operationId":"UptrackWeb.Api.SubscriberController.subscribe","parameters":[{"description":"Status page slug","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"}}},"description":"Subscription request","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeResponse"}}},"description":"Already subscribed"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeResponse"}}},"description":"Subscription created"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriberErrorResponse"}}},"description":"Subscriptions disabled"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriberErrorResponse"}}},"description":"Status page not found"}},"summary":"Subscribe to status page","tags":["Subscriptions"]}},"/api/subscribe/unsubscribe/{token}":{"get":{"callbacks":{},"description":"Unsubscribe an email from status page notifications.","operationId":"UptrackWeb.Api.SubscriberController.unsubscribe","parameters":[{"description":"Unsubscribe token from email footer","in":"path","name":"token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubscribeResponse"}}},"description":"Unsubscribed"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriberErrorResponse"}}},"description":"Invalid token"}},"summary":"Unsubscribe from notifications","tags":["Subscriptions"]}},"/api/subscribe/verify/{token}":{"get":{"callbacks":{},"description":"Verify an email subscription using the token sent via email.","operationId":"UptrackWeb.Api.SubscriberController.verify","parameters":[{"description":"Verification token from email","in":"path","name":"token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResponse"}}},"description":"Email verified"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriberErrorResponse"}}},"description":"Invalid token"}},"summary":"Verify email subscription","tags":["Subscriptions"]}},"/healthz":{"get":{"callbacks":{},"description":"Lightweight health check for liveness probes. Returns 200 if the application\nprocess is running. Does not check external dependencies.\n\nUse this for Kubernetes liveness probes or basic uptime monitoring.\n","operationId":"UptrackWeb.HealthController.show","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}},"description":"Healthy"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}},"description":"Unhealthy"}},"summary":"Liveness probe","tags":["Health"]}},"/ready":{"get":{"callbacks":{},"description":"Full health check for readiness probes. Verifies all dependencies:\n- Database connectivity (AppRepo)\n- Background job system (Oban/ObanRepo)\n- Idle prevention service\n\nUse this for Kubernetes readiness probes or load balancer health checks.\n","operationId":"UptrackWeb.HealthController.ready (2)","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadinessResponse"}}},"description":"Ready"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadinessResponse"}}},"description":"Not Ready"}},"summary":"Readiness probe","tags":["Health"]}}},"security":[],"servers":[{"description":"Production","url":"https://api.uptrack.app","variables":{}},{"description":"Development","url":"https://uptrack.app","variables":{}}],"tags":[]}