Skip to main content

Stats API

Stats provide aggregated uptime and performance data for your monitors. Sentro rolls up individual check results into daily statistics, giving you a clear picture of reliability over time without needing to process thousands of raw checks.

The current day is always included. Because the nightly rollup only covers completed days, today's figures are computed from raw checks on request — so an outage happening right now is reflected immediately rather than appearing tomorrow.

Daily Stat Object​

{
"date": "2025-01-15",
"totalChecks": 1440,
"successfulChecks": 1436,
"uptimePercentage": 99.72,
"avgLatencyMs": 187,
"minLatencyMs": 94,
"maxLatencyMs": 1203
}
FieldTypeDescription
datestringDate in YYYY-MM-DD format (UTC)
totalChecksnumberTotal number of checks performed on this day
successfulChecksnumberNumber of checks that succeeded
uptimePercentagenumberPercentage of successful checks for the day (0-100)
avgLatencyMsnumberAverage response time in milliseconds for the day
minLatencyMsnumberFastest response of the day, in milliseconds
maxLatencyMsnumberSlowest response of the day, in milliseconds

List Monitor Stats​

GET /v1/monitors/:monitorId/stats

Returns daily statistics for a specific monitor, ordered by most recent date first, together with a summary across the whole period. Each record represents one day of check data.

Path Parameters​

ParameterTypeDescription
monitorIdstringThe monitor ID

Query Parameters​

ParameterTypeDefaultDescription
fromstring30 days agoStart date filter (ISO 8601, e.g. 2025-01-01)
tostringnowEnd date filter (ISO 8601, e.g. 2025-01-31)
limitnumber90Number of days to return (max 365)

Example Request​

curl "https://api.sentro.dev/v1/monitors/cly1abc2d0001abcdef012345/stats?from=2025-01-01&to=2025-01-31&limit=31" \
-H "Authorization: Bearer sentro_sk_live_your_key_here"

Response 200 OK​

{
"data": {
"monitorId": "cly1abc2d0001abcdef012345",
"summary": {
"uptimePercentage": 99.07,
"avgLatencyMs": 220,
"totalChecks": 4320,
"successfulChecks": 4280,
"daysWithData": 3
},
"daily": [
{
"date": "2025-01-15",
"totalChecks": 1440,
"successfulChecks": 1436,
"uptimePercentage": 99.72,
"avgLatencyMs": 187,
"minLatencyMs": 94,
"maxLatencyMs": 1203
},
{
"date": "2025-01-14",
"totalChecks": 1440,
"successfulChecks": 1440,
"uptimePercentage": 100.0,
"avgLatencyMs": 162,
"minLatencyMs": 88,
"maxLatencyMs": 402
},
{
"date": "2025-01-13",
"totalChecks": 1440,
"successfulChecks": 1404,
"uptimePercentage": 97.5,
"avgLatencyMs": 312,
"minLatencyMs": 91,
"maxLatencyMs": 4008
}
]
}
}

Summary Object​

The summary field provides aggregate metrics across the whole requested period.

FieldTypeDescription
uptimePercentagenumber | nullShare of all checks in the period that succeeded
avgLatencyMsnumber | nullAverage response time in milliseconds across the days with data
totalChecksnumberTotal check count across the period
successfulChecksnumberSuccessful check count across the period
daysWithDatanumberNumber of days that recorded at least one check
No data is not 100%

When a monitor recorded no checks in the requested period, uptimePercentage and avgLatencyMs are null and daily is empty. A monitor that was never checked is never reported as 100% up — treat null as "not measured" rather than substituting a value.

Errors​

Monitor not found:

{
"error": {
"code": "NOT_FOUND",
"message": "Monitor with id 'mon_invalid' not found"
}
}

Invalid date range:

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Parameter 'from' must be a valid ISO 8601 date"
}
}
Try it

Fetch daily uptime and performance stats for a specific monitor.

GET/v1/monitors/:monitorId/stats?limit=90
Path Parameters
Query Parameters
Click ⚙ to configure your API key, then hit Send.

Get Organization Overview​

GET /v1/stats/overview

Returns a high-level summary of your organization's current resource counts. Useful for building dashboards, health widgets, and at-a-glance status indicators.

Example Request​

curl "https://api.sentro.dev/v1/stats/overview" \
-H "Authorization: Bearer sentro_sk_live_your_key_here"

Response 200 OK​

{
"data": {
"monitors": {
"total": 24,
"active": 21,
"paused": 3
},
"incidents": {
"total": 147,
"open": 2,
"resolved": 145
},
"alertChannels": 5,
"heartbeats": 8,
"statusPages": 2
}
}

Overview Fields​

FieldTypeDescription
monitors.totalnumberTotal number of monitors in the organization
monitors.activenumberNumber of monitors currently active and checking
monitors.pausednumberNumber of monitors that are paused
incidents.totalnumberTotal number of incidents ever recorded
incidents.opennumberNumber of currently unresolved incidents
incidents.resolvednumberNumber of resolved incidents
alertChannelsnumberTotal configured alert channels
heartbeatsnumberTotal heartbeat monitors
statusPagesnumberTotal public status pages
Try it

Get organization-level overview counts for monitors, incidents, and more.

GET/v1/stats/overview
Click ⚙ to configure your API key, then hit Send.

Limiting the Period​

Use from, to, and limit to control the window. There is no offset — a single request covers the whole period you ask for, up to 365 days.

# Last 7 days
GET /v1/monitors/:id/stats?limit=7

# A specific calendar month
GET /v1/monitors/:id/stats?from=2025-01-01&to=2025-01-31

Days on which the monitor recorded no checks are omitted from daily, so daily.length may be smaller than limit. Use summary.daysWithData to see how many days actually held data.


Common Patterns​

Calculate Monthly Uptime​

Retrieve stats for a full calendar month and use the summary:

curl "https://api.sentro.dev/v1/monitors/mon_123/stats?from=2025-01-01&to=2025-01-31&limit=31" \
-H "Authorization: Bearer sentro_sk_live_your_key_here"
const response = await fetch(
'https://api.sentro.dev/v1/monitors/mon_123/stats?from=2025-01-01&to=2025-01-31&limit=31',
{ headers: { Authorization: `Bearer ${API_KEY}` } },
);

const { data } = await response.json();

if (data.summary.uptimePercentage === null) {
console.log('January: no checks recorded');
} else {
console.log(`January uptime: ${data.summary.uptimePercentage.toFixed(2)}%`);
console.log(`Average latency: ${data.summary.avgLatencyMs}ms`);
console.log(`Total checks: ${data.summary.totalChecks}`);
}

Compare Performance Over Time​

Fetch stats for two different periods and compare:

async function fetchStats(monitorId, from, to) {
const res = await fetch(
`https://api.sentro.dev/v1/monitors/${monitorId}/stats?from=${from}&to=${to}&limit=365`,
{ headers: { Authorization: `Bearer ${API_KEY}` } },
);
const { data } = await res.json();
return data;
}

const thisMonth = await fetchStats('mon_123', '2025-01-01', '2025-01-31');
const lastMonth = await fetchStats('mon_123', '2024-12-01', '2024-12-31');

// Only compare periods that both have data
if (thisMonth.summary.uptimePercentage !== null && lastMonth.summary.uptimePercentage !== null) {
const latencyDelta = thisMonth.summary.avgLatencyMs - lastMonth.summary.avgLatencyMs;
const uptimeDelta = thisMonth.summary.uptimePercentage - lastMonth.summary.uptimePercentage;

console.log(`Latency change: ${latencyDelta > 0 ? '+' : ''}${latencyDelta}ms`);
console.log(`Uptime change: ${uptimeDelta > 0 ? '+' : ''}${uptimeDelta.toFixed(2)}%`);
}

Build a Dashboard Summary​

Combine the overview endpoint with per-monitor stats:

// Fetch organization overview
const overviewRes = await fetch('https://api.sentro.dev/v1/stats/overview', {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const { data: overview } = await overviewRes.json();

console.log(`Monitors: ${overview.monitors.active} active / ${overview.monitors.total} total`);
console.log(`Open incidents: ${overview.incidents.open}`);
console.log(`Alert channels: ${overview.alertChannels}`);
console.log(`Status pages: ${overview.statusPages}`);

// Fetch last 7 days of stats for a specific monitor
const statsRes = await fetch('https://api.sentro.dev/v1/monitors/mon_123/stats?limit=7', {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const { data } = await statsRes.json();

console.log(`\n7-day uptime: ${data.summary.uptimePercentage ?? 'not measured'}`);
console.log(`7-day avg latency: ${data.summary.avgLatencyMs ?? 'not measured'}`);

Detect Performance Degradation​

Find days where response time or uptime crossed a threshold:

const { data } = await fetch(
'https://api.sentro.dev/v1/monitors/mon_123/stats?from=2025-01-01&to=2025-01-31&limit=31',
{ headers: { Authorization: `Bearer ${API_KEY}` } },
).then((r) => r.json());

const LATENCY_THRESHOLD_MS = 500;
const UPTIME_THRESHOLD = 99.5;

const slowDays = data.daily.filter((day) => day.avgLatencyMs > LATENCY_THRESHOLD_MS);
const degradedDays = data.daily.filter((day) => day.uptimePercentage < UPTIME_THRESHOLD);

if (slowDays.length > 0) {
console.log(`${slowDays.length} day(s) with avg latency above ${LATENCY_THRESHOLD_MS}ms:`);
slowDays.forEach((day) => console.log(` ${day.date}: ${day.avgLatencyMs}ms`));
}

if (degradedDays.length > 0) {
console.log(`${degradedDays.length} day(s) below ${UPTIME_THRESHOLD}% uptime:`);
degradedDays.forEach((day) => console.log(` ${day.date}: ${day.uptimePercentage}%`));
}

Generate an SLA Report​

Calculate SLA compliance for a given period. A period with no checks is not compliance — it is an absence of evidence, so handle it separately rather than treating it as a pass:

const SLA_TARGET = 99.9;

const { data } = await fetch(
'https://api.sentro.dev/v1/monitors/mon_123/stats?from=2025-01-01&to=2025-01-31&limit=31',
{ headers: { Authorization: `Bearer ${API_KEY}` } },
).then((r) => r.json());

if (data.summary.uptimePercentage === null) {
console.log('No checks recorded for this period — SLA cannot be assessed.');
} else {
const slaBreaches = data.daily.filter((day) => day.uptimePercentage < SLA_TARGET);
const compliant = data.summary.uptimePercentage >= SLA_TARGET;

console.log(`SLA target: ${SLA_TARGET}%`);
console.log(`Actual uptime: ${data.summary.uptimePercentage.toFixed(3)}%`);
console.log(`Status: ${compliant ? 'COMPLIANT' : 'BREACHED'}`);
console.log(`Days in violation: ${slaBreaches.length} / ${data.summary.daysWithData}`);
}