Service Status
Service Status
Public, unauthenticated endpoint that returns Uptimeify's own platform availability — check and alert delivery percentages, component states, and the hash-chained frozen monthly totals.
GET /api/service-status
No authentication required. Returns no customer data — only the platform's own delivery figures, published component states, and the frozen monthly totals behind them.
Example (cURL)
curl -X GET "https://uptimeify.io/api/service-status" \
-H "Accept: application/json"Response
{
"checkDelivery": {
"pct": 99.97,
"coveragePct": 99.94,
"insufficientData": false,
"windowDays": 90
},
"alertDelivery": {
"pct": 97.31,
"sampleSize": 2454,
"endpointFailures": 140,
"latencyP90Ms": 1727,
"latencySampleSize": 812,
"insufficientData": false,
"latencyInsufficientData": false
},
"components": [
{ "key": "de-fra", "displayName": "Frankfurt (DE)", "state": "operational", "coveragePct": 99.94 },
{ "key": "alerting", "displayName": "Alert Delivery", "state": "operational", "coveragePct": 100 }
],
"frozenMonths": [
{
"month": "2026-06-01",
"sliKind": "check_delivery",
"scopeKey": "mesh",
"numerator": 4318204,
"denominator": 4319850,
"unknownUnits": 612,
"rowHash": "9f2c1a7e4b8d0f3a6c5e2b1d8a7f4e9c0b3d6a1f8e5c2b9d7a4f1e8c5b2d9a6f"
},
{
"month": "2026-06-01",
"sliKind": "measurement_coverage",
"scopeKey": "mesh",
"numerator": 43176,
"denominator": 43200,
"unknownUnits": 24,
"rowHash": "4d1b8e0cc0a2f7593e6b4c1d8a05f2e7b9c3d6a1f8e5c2b9d7a4f1e8c5b2d9a6"
}
]
}Notes:
checkDelivery.pctandalertDelivery.pctare trailingwindowDaysfigures (currently 90 days), truncated to two decimals — never rounded up.unknownUnitsis NOT in the denominator of any percentage on this endpoint. A percentage is measured over what the platform could actually account for;denominatoris the expectation over the recorded units andunknownUnitsis the expectation over the units that were never recorded — a gap in the per-minute recorder, a stalled rollup. The two are separate axes because "we were unavailable" and "we could not measure" are different facts: folding the second into the first would publish an outage that did not happen and make the figure a measure of the recorder's own reliability.coveragePctis the second half of every claim and is never omitted. It is the share of the window the platform can account for,0-100, truncated to two decimals —nullonly when nothing was owed in the window yet.checkDelivery.coveragePctcovers the whole mesh;components[].coveragePctis per component and isnullfor a component that has never been measured at all. For the conservative reading — the share of the window positively confirmed as delivered — multiply the two:pct x coveragePct / 100.- From any
frozenMonthsrow you can recompute coverage yourself asdenominator / (denominator + unknownUnits). Rows with"sliKind": "measurement_coverage"state it directly in minutes instead:numeratoris the minutes recorded,denominatorthe minutes owed. That kind exists because a day on which the recorder never ran leavescheck_deliveryat0/0— there is no observed rate to price a missing check-minute with — so only a minute-based row keeps such a day visible. - Alert delivery is two figures, and neither is a 60-second threshold.
alertDelivery.pctis the share of attempted deliveries that eventually got through, andalertDelivery.latencyP90Msis the p90 time from the incident opening to the first notification that actually left our systems, in milliseconds. The former answers "did it arrive", the latter "how fast" — one number cannot answer both, and the single figure published before this (the share dispatched inside 60 seconds) answered neither: at a median dispatch under one second it could not tell a fast delivery from one that took most of a minute, and it scored a delivery that never arrived exactly like a slow one. alertDelivery.pctcounts each delivery once, not each attempt. The unit is one(incident, notification channel)pair; the pair counts as delivered if any attempt for it succeeded. A notification that failed twice and got through on the third attempt is therefore one success — counting attempts instead would publish a worse figure the harder our retry mechanism works.alertDelivery.sampleSizeis the number of such pairs. Where a delivery carries no channel id (an owner-address email, the incident-management bridge) the transport type stands in as its identity.alertDelivery.pctcounts the failures we are responsible for, andendpointFailurescounts the ones we are not. A delivery that never arrived because the receiving endpoint was gone (404,410), because the credentials you gave us were revoked (401,403), because your service rate-limited us (429), because it returned a5xx, or because its host could not be reached at all (DNS failure, refused connection, TLS failure, timeout) is a failure of that endpoint, not of our alerting. Those deliveries leavepct— they are in neither its numerator nor itssampleSize— and are counted inalertDelivery.endpointFailuresinstead. Failures on our side stay in and count against the figure: a payload one of the chat services rejected as malformed, a channel type our dispatcher had no handler for, our own relay or send-throttle skipping a send, or any failure we cannot confidently attribute to the far end. The tie-break always goes against us — anything unattributable counts as ours, because the opposite rule would let the figure improve every time we failed in a new way.endpointFailuresis never suppressed and never omitted. It is a count, so it is exactly true at any sample size and carries no publication floor: it is present even whenpctisnull. Add it to the failures insidepctand you have every alert that did not arrive in the window, for any reason at all — the exclusion above changes which number a failure is reported in, never whether it is reported.- What the alert figures exclude, and what they do not. Incidents that were never owed a notification are outside both: alerting suppressed by a maintenance window, a monitor with no notification channel configured, an incident held back by flap damping, or one that resolved before a notification became due. A delivery whose every attempt failed on our side is inside
alertDelivery.pctand counts against it — a failed send is a delivery failure, not an exclusion. One that failed at your endpoint is inendpointFailuresinstead, per the rule above. It is absent from the p90, because an alert that never left has no dispatch time; charging it one would hide a delivery failure inside a latency figure.alertDelivery.latencySampleSizeis therefore the number of incidents that were successfully notified, and is always smaller thansampleSize. - No alert figure reaches back past the date measurement began.
alertDelivery.pct,endpointFailuresandlatencyP90Msare all bounded below at the instant our recorder first wrote a sample — the same instant the public status page prints as "Measuring since". Our notification log holds real history from long before that date; it is not counted, because a figure reaching past the start date printed beside it would be a different claim than the one that date supports. The rows stay in the database; they are simply outside the window. - Attempts are counted for 24 hours after the incident's day. A delivery still not through a full day after the incident opened is a failed delivery, whatever happens afterwards. Measured over a real trailing 90 days this bound reclassifies 2 of 2590 delivery pairs, and it reclassifies them against us.
- Latency is a percentile, so it is neither summed nor frozen. The published p90 is computed over the window's own distribution, not derived from the daily figures behind it: the sum of daily percentiles is not a percentile, and neither is their weighted mean. For the same reason no
alert_dispatch_latency_p90row appears infrozenMonths— a monthly figure that cannot be computed by summing days is better absent than invented. The daily rows exist in our own evidence table, each carrying its own sample size. - A percentage is always published together with its sample size, and is withheld when that sample is too small.
alertDelivery.pctandalertDelivery.latencyP90Msarenullwith the matchinginsufficientData/latencyInsufficientDataflag set totruewhile fewer than 20 events stand behind them.checkDelivery.pctisnullwithcheckDelivery.insufficientDatatrue until our measured series covers 24 hours: what a minute owes is a per-minute rate and what it delivers is a whole check, so on a short series the figure reads a fraction under 100% with nothing wrong at all. In every case the sample size andcoveragePctare still published — they are what explains the absence. Anullwith the flagfalsemeans something different: nothing has been measured yet at all. components[].stateis one ofoperational,degraded,down,unknown.unknownmeans no recent sample exists for that component; the endpoint never fills the gap with the last known state. A component that isunknownright now is not a component that is down — check itscoveragePctto see how much of the window that has been true for.frozenMonthslists every append-only monthly total fromplatform_sli_month, identified bymonth+sliKind+scopeKey.sliKindis one ofcheck_delivery,component_availability,alert_delivery,alert_endpoint_failureormeasurement_coverage— the dispatch-latency percentile is deliberately not among them (see above). Each row'srowHashchains to the previous row for the samesliKind/scopeKey, and a database trigger rejects any UPDATE or DELETE against the table. If you saved a copy of this response earlier, arowHashthat no longer matches for a givenmonth/sliKind/scopeKeymeans that month's figures were restated after being frozen.
Common errors
500 Unexpected server erroron an internal failure