Everything you need to build on top of the public status data: current service health, uptime statistics, incidents, maintenance windows, embeddable badges and real-time notifications — with live examples you can run right here.
No API key requiredJSON responses15 public endpointsRate limited: 240 req/min
Introduction
The WorthClient Status API exposes live monitoring data from the public status page in a machine-readable format. You can use it to build status widgets, dashboards, Discord or Telegram bots, CI/CD health gates, or any subsystem that needs to know whether WorthClient services are healthy.
Base URL
All endpoints below are relative to your status page origin. If your status page is hosted at https://status.worthclient.com, the base URL is:
Base URL
https://status.worthclient.com/api
Response format
All responses are application/json; charset=utf-8 unless stated otherwise. Timestamps are ISO 8601 strings in UTC (2026-08-18T12:00:00.000Z). The badge, favicon and event stream endpoints return their own content types.
Caching
Status data is rebuilt in memory every few seconds (60 seconds by default, configurable via the admin panel). JSON endpoints are served with Cache-Control: no-store so clients always receive fresh data. Images (badge.svg, favicon.svg) are cached for 30–60 seconds for safe embed use.
Same-origin policy
The API does not send CORS headers. Browser calls must come from the same origin as the status page. Server-side clients and native tools are unaffected.
Interactive testing
Every endpoint in this documentation has a Try it button and a built-in API Tester panel on the right side of the screen — no setup needed, you can call the live API directly from the browser.
Quick Start
The fastest way to check overall service health is a single request to GET /api/status. The examples below use the same request in the five most common languages:
const res = await fetch('/api/status');
const data = await res.json();
console.log(data.overall); // { code, label, message }
console.log(data.counts); // { total, up, down, degraded, paused, unknown, incidentsOpen }
console.log(data.monitors); // every public monitor with uptime stats
import requests
data = requests.get("https://status.worthclient.com/api/status").json()
print(data["overall"]["code"]) # 'up' | 'down' | 'incident' | ...
print(data["counts"])
for monitor in data["monitors"]:
print(monitor["name"], monitor["status"])
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(
URI.create("https://status.worthclient.com/api/status"))
.GET()
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Status struct {
Overall struct {
Code string `json:"code"`
} `json:"overall"`
Counts map[string]int `json:"counts"`
}
func main() {
resp, err := http.Get("https://status.worthclient.com/api/status")
if err != nil {
panic(err)
}
defer resp.Body.Close()
var status Status
json.NewDecoder(resp.Body).Decode(&status)
fmt.Println(status.Overall.Code, status.Counts)
}
# Overall status, counts and services
curl https://status.worthclient.com/api/status
# Same payload, without the full monitors array
curl "https://status.worthclient.com/api/status?compact=1"
Authentication
All endpoints documented on this page are public. No API key, token, session or header is required for reads.
Two exceptions to keep in mind:
POST /api/status/refresh is a write operation and requires a CSRF token header (see its section below).
The administration API (monitors, incidents, maintenance, categories, settings and authentication routes under /api) is private and requires an authenticated session. It is intentionally not documented here.
Rate Limits
The public API is protected by an IP-based rate limiter:
240 requests per minute per IP address across all /api endpoints. Exceeding it returns 429.
Limiter headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset) are included in every response.
POST /api/status/refresh has an additional global throttle: at most one manual refresh every 30 seconds (configurable via the STATUS_REFRESH_MIN_SECONDS environment variable).
Best practices: poll GET /api/status every 30–60 seconds at most, or subscribe to the real-time event stream instead of polling. Cache the payload on your side — it only changes when a check runs.
Errors
Errors are always returned as JSON with a human-readable message. The HTTP status code tells you what went wrong:
Status
Meaning
400
Invalid request — malformed body or missing required fields.
403
CSRF token missing or invalid (write requests).
404
Resource not found — unknown monitor, incident or maintenance ID, or unknown API route.
429
Too many requests — rate limit reached, or refresh throttle active.
500
Internal server error.
Error body format:
Error response
{
"error": "Monitor not found."
}
Some endpoints include extra context on specific errors — for example, POST /api/status/refresh returns a retryAfter field with the number of seconds to wait before trying again.
Status API
Live health data: overall status, monitors, uptime statistics, incidents and maintenance. All endpoints under /api/status.
GET/api/statusFull status payload
Returns the complete public status payload: overall status, counts, categories, monitors with uptime stats, recent incidents and upcoming maintenance windows.
Query parameters
Parameter
Type
Default
Description
compact
1
—
Omits the top-level monitors array (the same monitors are still nested inside categories).
fresh
1
—
Bypasses the in-memory cache and rebuilds the payload on the spot.
overall.code is one of up, down, incident, degraded, maintenance or unknown — see the Overall Status reference.
Uptime fields are percentages (0–100) or null when there is not enough data yet.
bars90d is always present; bars24h and responseTimes24h are present when the monitor has the response chart enabled.
Incident and maintenance objects inside this payload include their updates arrays; the dedicated list endpoints below do not.
Outage bars may also include incidents / maintenance annotation objects with { count, titles, items } when an incident or maintenance overlaps that day.
Examples
const res = await fetch('/api/status');
const data = await res.json();
console.log(data.overall.code);
console.log(data.counts.up, '/', data.counts.total, 'services up');
curl https://status.worthclient.com/api/status
# Compact: without the top-level monitors array
curl "https://status.worthclient.com/api/status?compact=1"
POST/api/status/refreshTrigger a manual re-check
Runs a check against every monitor right away and rebuilds the public status. Useful for on-demand verification (for example, right after a deployment). Globally throttled to one run every 30 seconds.
CSRF token
This is the only public endpoint that accepts a write method. Like every write request in the app, it must include an x-csrf-token header. The token is the value of the vx_status_csrf cookie, which is set automatically on any page visit (or by calling GET /api/auth/csrf).
# The CSRF token lives in the vx_status_csrf cookie.
# Grab it after visiting any page, then send it as a header:
curl -X POST https://status.worthclient.com/api/status/refresh \
-H "x-csrf-token: $CSRF_TOKEN" \
-b "vx_status_csrf=$CSRF_TOKEN"
GET/api/status/monitorsAll public monitors
Returns only the monitors portion of the status payload — every public monitor with its uptime stats.
Query parameters
Parameter
Type
Default
Description
fresh
1
—
Bypasses the in-memory cache and rebuilds the payload on the spot.
Returns one public monitor with its stats, the 30 most recent checks, the 10 most recent incidents and the 10 most recent maintenance windows that affect it.
Path parameters
Parameter
Type
Description
id
string
The monitor ID (UUID). Only monitors with show_on_public enabled can be fetched.
value is the average response time in milliseconds for the bucket, or null when no check happened in that window. Bucket counts: h24 → 1440, d7 → 2016, d30 → 2880.
Errors
Status
Body
When
404
{"error": "Monitor not found."}
The ID does not exist, or the monitor is not public.
import requests
monitor_id = "01j1f2a3b4c5d6e7f8a9b0c2e"
chart = requests.get(
f"https://status.worthclient.com/api/status/monitors/{monitor_id}/chart",
params={"period": "d7"},
).json()
print(chart["period"], chart["bucketSeconds"])
print(len([b for b in chart["buckets"] if b["value"] is not None]), "samples")
import requests
incidents = requests.get("https://status.worthclient.com/api/status/incidents").json()["incidents"]
active = [i for i in incidents if i["status"] != "resolved"]
print(len(active), "active incident(s)")
print(incidents[0]["title"] if incidents else "none")
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(
URI.create("https://status.worthclient.com/api/status/incidents"))
.GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
import requests
maintenance = requests.get("https://status.worthclient.com/api/status/maintenance").json()["maintenance"]
upcoming = [m for m in maintenance if m["status"] == "scheduled"]
print(len(upcoming), "scheduled window(s)")
print(upcoming[0]["starts_at"] if upcoming else "none")
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(
URI.create("https://status.worthclient.com/api/status/maintenance"))
.GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Returns the app icon as SVG with a status-colored dot in the bottom-right corner — the same favicon used by the public page itself. Cached for 30 seconds.
Query parameters
Parameter
Type
Default
Description
format
string
svg
Image format: svg, png, jpg, jpeg, webp or avif. Also works as a file extension: /api/status/favicon.png, etc.
Response 200 OK
Content type image/svg+xml, 192×192. The dot color follows the same mapping as the badge.
Notifications API
Web Push and Server-Sent Events for real-time status updates. These endpoints are public so that any visitor can subscribe to notifications without an account.
Opens a Server-Sent Events stream that pushes status notifications to connected clients. The connection stays open; the server sends a heartbeat every 25 seconds to keep it alive.
Event types
Event
Data
When
ready
{"ok": true, "at": "…"}
Sent immediately when the connection opens.
heartbeat
{"at": "…"}
Every 25 seconds to keep the connection alive.
notification
Push notification payload, see below
Whenever an incident or maintenance notification is published.
POST/api/notifications/subscribeSubscribe to Web Push
Registers a browser push subscription so the visitor receives notifications about new incidents and maintenance. Requires HTTPS (or localhost) in the browser.
Request body
The full PushSubscription JSON from the browser, or wrapped in a subscription property. Fields:
Field
Type
Required
Description
endpoint
string
yes
Push service endpoint URL (https://).
keys.p256dh
string
yes
Base64url-encoded public P-256 key.
keys.auth
string
yes
Base64url-encoded auth secret.
contentEncoding
string
no
aes128gcm (default) or aesgcm.
Client example
JavaScript
// 1. Get the VAPID public key
const { publicKey } = await fetch('/api/notifications/vapid-public-key').then((r) => r.json());
// 2. Ask the browser for a subscription
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicKey)
});
// 3. Register it with the API
await fetch('/api/notifications/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
DELETE/api/notifications/subscribeUnsubscribe from Web Push
Removes a previously registered push subscription.
Request body
Field
Type
Required
Description
endpoint
string
no
The endpoint to remove. The request succeeds even without it.
Response 200 OK
Response · application/json
{
"ok": true
}
Data Model
Field-by-field reference for every object returned by the public API.
OBJECToverallOverall service status
Present in GET /api/status. The status is computed with a fixed priority order: an in-progress maintenance beats incidents, incidents beat down monitors, and so on.
Field
Type
Description
code
string
Machine-readable status: up, down, incident, degraded, maintenance or unknown.
label
string
Short human-readable label (in the configured language).
message
string
One-sentence explanation.
OBJECTmonitorA monitored service
Field
Type
Description
id
string
Monitor ID (UUID).
name
string
Display name.
url
string
Monitored URL.
status
string
up, down, degraded, paused or unknown.
enabled
boolean
Whether checks are running.
show_on_public
boolean
Always true — private monitors are never exposed.
show_response_chart
boolean
Whether bars24h / responseTimes24h are included in stats.
category_id
string | null
Category ID; null for the fallback "Other services" group.
90 daily bars: { status, uptime, checks, downSeconds, degradedSeconds, date, timezone, from, to }. Bars may include incidents / maintenance annotation objects.
bars24h
array
48 half-hour bars (only when the response chart is enabled): { status, uptime, checks, downSeconds, degradedSeconds, from, to }.
responseTimes24h
array
48 average response times, one per half-hour (only when the response chart is enabled).
OBJECTincidentIncident and its updates
Field
Type
Description
id
string
Incident ID (UUID).
monitor_id
string | null
Primary monitor, when the incident targets one.
title
string
Short title.
message
string
Description (Markdown allowed).
severity
string
incident, degraded or major.
status
string
open, monitoring or resolved.
created_at / updated_at / resolved_at
string | null
ISO 8601 timestamps; resolved_at is null while open.
monitors
array
[{ id, name }] of affected monitors; empty = all services.
monitor
object | null
First affected monitor, for convenience.
updates
array
Timeline entries: { id, incident_id, status, title, message, created_at } with status one of investigating, identified, monitoring, resolved. Only present in GET /api/status/incidents/{id} and inside the /api/status payload.
OBJECTmaintenanceMaintenance window and its updates
Field
Type
Description
id
string
Maintenance ID (UUID).
monitor_id
string | null
Primary monitor, when the window targets one.
title
string
Short title.
message
string
Description (Markdown allowed).
status
string
scheduled, in_progress, completed or cancelled.
starts_at / ends_at
string
ISO 8601 window boundaries.
created_at / updated_at
string
ISO 8601 timestamps.
monitors
array
[{ id, name }] of affected monitors; empty = all services.
monitor
object | null
First affected monitor, for convenience.
updates
array
Timeline entries: { id, maintenance_id, status, title, message, created_at }. Only present in GET /api/status/maintenance/{id} and inside the /api/status payload.