Public Status Page API
Programmatic, read-only REST access to your public status page. Fetch overall status, component health, active incidents, and uptime metrics to power dashboards, integrations, and internal tooling.
The Public Status Page API gives you programmatic, read-only access to the same data shown on your hosted status page. Use it to embed live status indicators in your own app, build custom dashboards, sync incidents into internal tooling, or run automated health checks against your public status.
Overview
| Property | Value |
|---|---|
| Base URL | https://api.pingara.io/api/v1/status/{slug} |
| Method | GET |
| Authentication | None — endpoints are public for public status pages |
| Format | JSON |
| CORS | Enabled (Access-Control-Allow-Origin: *) |
| Rate Limit | 120 requests per minute per IP |
| Cache | Cache-Control: public, max-age=30 |
The {slug} is the same identifier used in your public status page URL (e.g., acme-corp in https://status.pingara.io/acme-corp).
Tip: Only public status pages are exposed via the API. If your status page is private, the API returns
404 Not Found.
Endpoints
| Endpoint | Description |
|---|---|
GET /api/v1/status/{slug} | Overall status summary (alias for /summary) |
GET /api/v1/status/{slug}/summary | Overall status summary |
GET /api/v1/status/{slug}/components | List of components (monitors) and their status |
GET /api/v1/status/{slug}/incidents | Recent incidents (filterable by status) |
GET /api/v1/status/{slug}/uptime | Uptime percentages per component |
Summary
Returns the overall status of the status page.
curl https://api.pingara.io/api/v1/status/acme-corp/summary
Response:
{
"name": "Acme Corp Status",
"slug": "acme-corp",
"overallStatus": "operational",
"updatedAt": "2026-05-14T15:32:11.000Z"
}
| Field | Type | Description |
|---|---|---|
name | string | Display name of the status page |
slug | string | URL slug |
overallStatus | enum | operational, degraded_performance, partial_outage, or major_outage |
updatedAt | ISO 8601 | Last time the page data was updated |
Components
Returns each monitor (component) shown on the status page with its current status.
curl https://api.pingara.io/api/v1/status/acme-corp/components
Response:
{
"components": [
{
"id": "j97abc...",
"name": "API",
"status": "operational",
"displayOrder": 1
},
{
"id": "j97def...",
"name": "Website",
"status": "degraded_performance",
"displayOrder": 2
}
]
}
| Field | Type | Description |
|---|---|---|
id | string | Component identifier (monitor ID) |
name | string | Display name shown on the status page |
status | enum | operational, degraded_performance, partial_outage, or major_outage |
displayOrder | number | Position on the status page (1-indexed) |
Incidents
Returns recent incidents for the status page. Filter by status using the status query parameter.
curl "https://api.pingara.io/api/v1/status/acme-corp/incidents?status=active"
| Query Param | Values | Default | Description |
|---|---|---|---|
status | active, resolved, all | all | Filter incidents by lifecycle state |
Response:
{
"incidents": [
{
"id": "j97xyz...",
"name": "API",
"status": "investigating",
"impact": "major_outage",
"startedAt": "2026-05-14T14:22:00.000Z",
"resolvedAt": null,
"affectedComponents": ["j97abc..."]
}
]
}
| Field | Type | Description |
|---|---|---|
id | string | Incident identifier |
name | string | Affected monitor name |
status | enum | investigating, identified, monitoring, or resolved |
impact | enum | degraded_performance, partial_outage, or major_outage |
startedAt | ISO 8601 | When the incident began |
resolvedAt | ISO 8601 or null | When the incident was resolved |
affectedComponents | string[] | IDs of affected components |
Uptime
Returns uptime percentages per component over a given period.
curl "https://api.pingara.io/api/v1/status/acme-corp/uptime?period=30d"
| Query Param | Values | Default | Description |
|---|---|---|---|
period | 7d, 30d, 90d | 30d | Reporting window |
Response:
{
"period": "30d",
"components": [
{
"id": "j97abc...",
"name": "API",
"uptimePercent": 99.987
},
{
"id": "j97def...",
"name": "Website",
"uptimePercent": 99.92
}
]
}
Status Values
The API normalizes monitor states into standard status-page nomenclature so it's easy to map into existing tooling.
| API Status | Meaning |
|---|---|
operational | All checks passing, performance within thresholds |
degraded_performance | Service is up but latency exceeds the Apdex threshold |
partial_outage | Some regions or checks are failing |
major_outage | All monitors on the page are down |
Incident statuses map directly to internal incident lifecycle:
| API Status | Pingara Internal Status |
|---|---|
investigating | investigating |
identified | identified |
monitoring | monitoring |
resolved | resolved |
Rate Limiting
The API allows 120 requests per minute per client IP. If you exceed the limit:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{ "error": "Rate limit exceeded" }
Tip: The API sets
Cache-Control: public, max-age=30. Cache responses for 30 seconds in your application to stay well under the rate limit and reduce load.
Error Responses
| Status | Body | Cause |
|---|---|---|
400 | { "error": "Invalid status. Expected active, resolved, or all." } | Invalid query parameter |
400 | { "error": "Invalid period. Expected 7d, 30d, or 90d." } | Invalid period parameter |
404 | { "error": "Not found" } | Slug doesn't exist, page is private, or endpoint is invalid |
429 | { "error": "Rate limit exceeded" } | Over the 120 req/min limit |
All error responses use Content-Type: application/json.
CORS
All endpoints respond with permissive CORS headers, making them safe to call directly from browser-based applications:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Preflight OPTIONS requests return 204 No Content.
Example: Embed Status in Your App
async function fetchStatus(slug: string) {
const res = await fetch(
`https://api.pingara.io/api/v1/status/${slug}/summary`
);
if (!res.ok) throw new Error('Status page unavailable');
return res.json() as Promise<{
name: string;
slug: string;
overallStatus:
| 'operational'
| 'degraded_performance'
| 'partial_outage'
| 'major_outage';
updatedAt: string;
}>;
}
const status = await fetchStatus('acme-corp');
if (status.overallStatus !== 'operational') {
showBanner(`Service status: ${status.overallStatus.replace('_', ' ')}`);
}
Example: Polling for Active Incidents
#!/bin/bash
# Check every minute for active incidents
while true; do
curl -s "https://api.pingara.io/api/v1/status/acme-corp/incidents?status=active" \
| jq '.incidents[] | "\(.name): \(.status) (\(.impact))"'
sleep 60
done
Best Practices
Cache Aggressively
Status data only changes when a check result flips a monitor's state. A 30-second client-side cache is usually more than enough for live displays.
Use the Correct Endpoint
- For a status pill or badge: use
/summary - For a list of services: use
/components - For an incident feed: use
/incidents?status=active - For uptime widgets: use
/uptime?period=30d
Handle 404s Gracefully
A 404 may mean the page was made private or the slug changed. Surface a friendly fallback rather than failing your UI.
Don't Hammer the API
If you need real-time updates in a customer-facing widget, prefer the hosted status page (which uses WebSockets) or poll the API every 30–60 seconds.
Next Steps
- Creating Status Pages — Set up the public status page that backs the API
- Subscriber Notifications — Push updates to your users via email
- Understanding Incidents — How incidents flow through to the API