@openstatus/sdk-node
v0.2.0
Published
SDK for openstatus.
Readme
OpenStatus Node.js SDK
Official Node.js SDK for OpenStatus - The open-source status page with uptime monitoring.
Table of Contents
For comprehensive documentation, see docs/index.md.
Features
Monitoring
- HTTP Monitoring - Monitor websites and APIs with customizable assertions
- TCP Monitoring - Check database connections and other TCP services
- DNS Monitoring - Verify DNS records and resolution
- Global Regions - Monitor from 28 locations worldwide
- Private Locations - Run checks from your own network with self-hosted agents
Status Page
- Status Pages - Create and manage public status pages with custom domains, themes, and custom CSS variable overrides
- Page Components - Add monitor-based or static components with grouping
- Subscribers - Manage email subscriptions for status updates
- Status Reports - Manage incident reports with update timelines
- Maintenance Windows - Schedule and manage planned maintenance periods
Notifications
- 13 Providers - Slack, Discord, Email, PagerDuty, Opsgenie, Microsoft Teams, and more
- Webhook Support - Custom webhooks with headers for any integration
- Monitor Alerts - Get notified when monitors go down or recover
Developer Experience
- Type-safe - Full TypeScript support with generated types from protobuf
- Multiple Runtimes - Works with Node.js, Deno, and Bun
Installation
npm
npm install @openstatus/sdk-nodeJSR
npx jsr add @openstatus/sdk-nodeDeno
import { createOpenStatusClient } from "jsr:@openstatus/sdk-node";Quick Start
import {
createOpenStatusClient,
HTTPMethod,
NumberComparator,
Periodicity,
Region,
} from "@openstatus/sdk-node";
// Create a client with your API key
const client = createOpenStatusClient({
apiKey: process.env.OPENSTATUS_API_KEY,
});
// Create a monitor
const { monitor } = await client.monitor.v1.MonitorService.createHTTPMonitor({
monitor: {
name: "My API",
url: "https://api.example.com/health",
periodicity: Periodicity.PERIODICITY_1M,
method: HTTPMethod.HTTP_METHOD_GET,
regions: [Region.FLY_AMS, Region.FLY_IAD, Region.FLY_SYD],
active: true,
statusCodeAssertions: [
{ comparator: NumberComparator.EQUAL, target: BigInt(200) },
],
},
});
console.log(`Monitor created: ${monitor?.id}`);
// List all monitors
const { httpMonitors, tcpMonitors, dnsMonitors, totalSize } = await client
.monitor.v1.MonitorService.listMonitors({});
console.log(`Found ${totalSize} monitors`);Authentication
All API requests require an API key. Get yours from the OpenStatus dashboard.
Recommended: Configure client once
import { createOpenStatusClient } from "@openstatus/sdk-node";
const client = createOpenStatusClient({
apiKey: process.env.OPENSTATUS_API_KEY,
});
// No need to pass headers on each call
await client.monitor.v1.MonitorService.listMonitors({});Alternative: Manual headers
import { openstatus } from "@openstatus/sdk-node";
const headers = {
"x-openstatus-key": process.env.OPENSTATUS_API_KEY,
};
// Pass headers to each service method
await openstatus.monitor.v1.MonitorService.listMonitors({}, { headers });Environment Variables
| Variable | Description | Default |
| -------------------- | ----------------------- | -------------------------------- |
| OPENSTATUS_API_KEY | Your OpenStatus API key | Required |
| OPENSTATUS_API_URL | Custom API endpoint | https://api.openstatus.dev/rpc |
SDK Reference
Note: All examples below assume you've created a client:
const client = createOpenStatusClient({ apiKey: process.env.OPENSTATUS_API_KEY, });
Monitor Service
Manage HTTP, TCP, and DNS monitors.
createHTTPMonitor(request)
Create an HTTP/HTTPS monitor.
import {
createOpenStatusClient,
HTTPMethod,
Periodicity,
Region,
} from "@openstatus/sdk-node";
const { monitor } = await client.monitor.v1.MonitorService.createHTTPMonitor({
monitor: {
name: "My Website",
url: "https://example.com",
periodicity: Periodicity.PERIODICITY_1M,
method: HTTPMethod.HTTP_METHOD_GET,
regions: [Region.FLY_AMS, Region.FLY_IAD, Region.FLY_SYD],
active: true,
},
});updateHTTPMonitor(request)
Update an existing HTTP monitor.
const { monitor } = await client.monitor.v1.MonitorService.updateHTTPMonitor({
id: "mon_123",
monitor: {
name: "Updated Name",
active: false,
},
});createTCPMonitor(request)
Create a TCP connection monitor.
const { monitor } = await client.monitor.v1.MonitorService.createTCPMonitor({
monitor: {
name: "Database",
uri: "db.example.com:5432",
periodicity: Periodicity.PERIODICITY_5M,
regions: [Region.FLY_AMS, Region.FLY_IAD],
active: true,
},
});updateTCPMonitor(request)
Update an existing TCP monitor.
const { monitor } = await client.monitor.v1.MonitorService.updateTCPMonitor({
id: "mon_123",
monitor: {
name: "Updated Database Monitor",
},
});createDNSMonitor(request)
Create a DNS resolution monitor.
import { Periodicity, RecordComparator, Region } from "@openstatus/sdk-node";
const { monitor } = await client.monitor.v1.MonitorService.createDNSMonitor({
monitor: {
name: "DNS Check",
uri: "example.com",
periodicity: Periodicity.PERIODICITY_10M,
regions: [Region.FLY_AMS],
active: true,
recordAssertions: [
{
record: "A",
comparator: RecordComparator.EQUAL,
target: "93.184.216.34",
},
],
},
});updateDNSMonitor(request)
Update an existing DNS monitor.
const { monitor } = await client.monitor.v1.MonitorService.updateDNSMonitor({
id: "mon_123",
monitor: {
name: "Updated DNS Check",
},
});listMonitors(request)
List all monitors with pagination. Returns monitors grouped by type.
const { httpMonitors, tcpMonitors, dnsMonitors, totalSize } = await client
.monitor.v1.MonitorService.listMonitors({
limit: 10,
offset: 0,
});getMonitor(request)
Get a single monitor by ID. Returns the monitor configuration (HTTP, TCP, or DNS).
const { monitor } = await client.monitor.v1.MonitorService.getMonitor({
id: "mon_123",
});
// Handle the monitor type
if (monitor?.config.case === "http") {
console.log(`HTTP Monitor: ${monitor.config.value.name}`);
} else if (monitor?.config.case === "tcp") {
console.log(`TCP Monitor: ${monitor.config.value.name}`);
} else if (monitor?.config.case === "dns") {
console.log(`DNS Monitor: ${monitor.config.value.name}`);
}triggerMonitor(request)
Trigger an immediate check.
const { success } = await client.monitor.v1.MonitorService.triggerMonitor({
id: "mon_123",
});deleteMonitor(request)
Delete a monitor.
const { success } = await client.monitor.v1.MonitorService.deleteMonitor({
id: "mon_123",
});getMonitorStatus(request)
Get the current status of a monitor across all configured regions.
import { MonitorStatus, Region } from "@openstatus/sdk-node";
const { id, regions } = await client.monitor.v1.MonitorService.getMonitorStatus(
{ id: "mon_123" },
);
for (const { region, status } of regions) {
console.log(`${Region[region]}: ${MonitorStatus[status]}`);
}getMonitorSummary(request)
Get aggregated metrics and latency percentiles for a monitor.
import { TimeRange } from "@openstatus/sdk-node";
const summary = await client.monitor.v1.MonitorService.getMonitorSummary({
id: "mon_123",
timeRange: TimeRange.TIME_RANGE_7D,
regions: [], // optional: filter by specific regions
});
console.log(`Last ping: ${summary.lastPingAt}`);
console.log(`Success: ${summary.totalSuccessful}`);
console.log(`Failed: ${summary.totalFailed}`);
console.log(`P50 latency: ${summary.p50}ms`);
console.log(`P95 latency: ${summary.p95}ms`);
console.log(`P99 latency: ${summary.p99}ms`);listMonitorHTTPResponseLogs(request)
List HTTP response logs for a monitor within the 14-day retention window. Supports time range filtering and offset pagination.
const { logs, pagination } = await client.monitor.v1.MonitorService
.listMonitorHTTPResponseLogs({
id: "mon_123",
fromTimestamp: BigInt(Date.now() - 24 * 60 * 60 * 1000), // last 24h
toTimestamp: BigInt(Date.now()),
limit: 25,
offset: 0,
});
for (const log of logs) {
console.log(`${log.timestamp}: ${log.statusCode} (${log.latency}ms)`);
}
if (pagination?.hasMore) {
console.log(`Next offset: ${pagination.nextOffset}`);
}getMonitorHTTPResponseLog(request)
Get a single HTTP response log with full debugging details (URL, headers, assertions, error message).
const { log } = await client.monitor.v1.MonitorService
.getMonitorHTTPResponseLog({
id: "mon_123",
logId: "log_456",
});
console.log(`URL: ${log?.url}`);
console.log(`Errored: ${log?.error}`);
console.log(`Message: ${log?.message ?? "n/a"}`);
console.log(`Status code: ${log?.log?.statusCode}`);
for (const [key, value] of Object.entries(log?.headers ?? {})) {
console.log(` ${key}: ${value}`);
}Health Service
Check API health status (no authentication required).
import { openstatus, ServingStatus } from "@openstatus/sdk-node";
const { status } = await openstatus.health.v1.HealthService.check({});
console.log(ServingStatus[status]); // "SERVING"Status Report Service
Manage incident reports with update timelines.
createStatusReport(request)
Create a new status report.
import { PageComponentImpact, StatusReportStatus } from "@openstatus/sdk-node";
const { statusReport } = await client.statusReport.v1.StatusReportService
.createStatusReport({
title: "API Degradation",
status: StatusReportStatus.INVESTIGATING,
message: "We are investigating reports of increased latency.",
date: "2024-01-15T10:30:00Z",
pageId: "page_123",
pageComponentIds: ["comp_456"],
notify: true,
// Optionally set per-component impacts
componentImpacts: [
{
pageComponentId: "comp_456",
impact: PageComponentImpact.DEGRADED_PERFORMANCE,
},
],
});
console.log(`Status report created: ${statusReport?.id}`);getStatusReport(request)
Get a status report by ID (includes full update timeline).
import { StatusReportStatus } from "@openstatus/sdk-node";
const { statusReport } = await client.statusReport.v1.StatusReportService
.getStatusReport({
id: "sr_123",
});
console.log(`Title: ${statusReport?.title}`);
console.log(`Status: ${StatusReportStatus[statusReport?.status ?? 0]}`);
for (const update of statusReport?.updates ?? []) {
console.log(`${update.date}: ${update.message}`);
}listStatusReports(request)
List all status reports with pagination and optional filtering.
import { StatusReportStatus } from "@openstatus/sdk-node";
const { statusReports, totalSize } = await client.statusReport.v1
.StatusReportService.listStatusReports({
limit: 10,
offset: 0,
statuses: [StatusReportStatus.INVESTIGATING, StatusReportStatus.IDENTIFIED],
});
console.log(`Found ${totalSize} status reports`);updateStatusReport(request)
Update status report metadata.
const { statusReport } = await client.statusReport.v1.StatusReportService
.updateStatusReport({
id: "sr_123",
title: "Updated Title",
pageComponentIds: ["comp_456", "comp_789"],
});deleteStatusReport(request)
Delete a status report and all its updates.
const { success } = await client.statusReport.v1.StatusReportService
.deleteStatusReport({
id: "sr_123",
});addStatusReportUpdate(request)
Add a new update to an existing status report timeline. Components named in
componentImpacts are added to the report's affected set; omitted components
keep their prior impact.
import { PageComponentImpact, StatusReportStatus } from "@openstatus/sdk-node";
const { statusReport } = await client.statusReport.v1.StatusReportService
.addStatusReportUpdate({
statusReportId: "sr_123",
status: StatusReportStatus.IDENTIFIED,
message: "The issue has been identified as a database connection problem.",
date: "2024-01-15T11:00:00Z", // optional, defaults to current time
notify: true,
componentImpacts: [
{
pageComponentId: "comp_456",
impact: PageComponentImpact.PARTIAL_OUTAGE,
},
],
});Status Page Service
Manage status pages, components, and subscribers.
createStatusPage(request)
Create a new status page.
const { statusPage } = await client.statusPage.v1.StatusPageService
.createStatusPage({
title: "My Service Status",
slug: "my-service",
description: "Status page for My Service",
homepageUrl: "https://example.com",
contactUrl: "https://example.com/contact",
// Optional: per-mode CSS variable overrides merged over the page theme
customTheme: {
light: { "--primary": "hsl(24 94% 50%)" },
dark: { "--primary": "hsl(24 94% 60%)" },
},
});
console.log(`Status page created: ${statusPage?.id}`);getStatusPage(request)
Get a status page by ID.
const { statusPage } = await client.statusPage.v1.StatusPageService
.getStatusPage({
id: "page_123",
});listStatusPages(request)
List all status pages with pagination.
const { statusPages, totalSize } = await client.statusPage.v1.StatusPageService
.listStatusPages({ limit: 10, offset: 0 });
console.log(`Found ${totalSize} status pages`);updateStatusPage(request)
Update a status page.
const { statusPage } = await client.statusPage.v1.StatusPageService
.updateStatusPage({
id: "page_123",
title: "Updated Title",
description: "Updated description",
});deleteStatusPage(request)
Delete a status page.
const { success } = await client.statusPage.v1.StatusPageService
.deleteStatusPage({
id: "page_123",
});addMonitorComponent(request)
Add a monitor-based component to a status page.
const { component } = await client.statusPage.v1.StatusPageService
.addMonitorComponent({
pageId: "page_123",
monitorId: "mon_456",
name: "API Server",
description: "Main API endpoint",
order: 1,
});addStaticComponent(request)
Add a static component (not linked to a monitor).
const { component } = await client.statusPage.v1.StatusPageService
.addStaticComponent({
pageId: "page_123",
name: "Third-party Service",
description: "External dependency",
order: 2,
});updateComponent(request)
Update a component.
const { component } = await client.statusPage.v1.StatusPageService
.updateComponent({
id: "comp_123",
name: "Updated Component Name",
order: 3,
});removeComponent(request)
Remove a component from a status page.
const { success } = await client.statusPage.v1.StatusPageService
.removeComponent({
id: "comp_123",
});getPageComponent(request)
Get a single component by ID, scoped to your workspace. Use it to resolve a
component ID to its name instead of fetching the whole page with
getStatusPageContent and filtering .components.
const { component } = await client.statusPage.v1.StatusPageService
.getPageComponent({
id: "comp_123",
});
console.log(`Component: ${component?.name}`);createComponentGroup(request)
Create a component group.
const { group } = await client.statusPage.v1.StatusPageService
.createComponentGroup({
pageId: "page_123",
name: "Core Services",
});updateComponentGroup(request)
Update a component group.
const { group } = await client.statusPage.v1.StatusPageService
.updateComponentGroup({
id: "group_123",
name: "Updated Group Name",
});deleteComponentGroup(request)
Delete a component group.
const { success } = await client.statusPage.v1.StatusPageService
.deleteComponentGroup({
id: "group_123",
});subscribeToPage(request)
Subscribe an email to status page updates. Self-signup flow: a verification email is sent and the subscription activates only once the recipient confirms (double opt-in).
const { subscriber } = await client.statusPage.v1.StatusPageService
.subscribeToPage({
pageId: "page_123",
email: "[email protected]",
});createPageSubscription(request)
Add a vendor-managed subscriber (email or webhook) with no verification flow.
Use this when an operator adds a subscriber on behalf of a partner and consent
is already established out-of-band. Set exactly one channel via the channel
oneof.
// Email channel
const { subscriber } = await client.statusPage.v1.StatusPageService
.createPageSubscription({
pageId: "page_123",
name: "Partner #incidents", // optional label
componentIds: ["comp_456"], // optional scope, empty = entire page
channel: {
case: "emailChannel",
value: { email: "[email protected]" },
},
});
// Webhook channel (Slack / Discord / generic auto-detected from the URL)
const { subscriber: webhookSub } = await client.statusPage.v1.StatusPageService
.createPageSubscription({
pageId: "page_123",
channel: {
case: "webhookChannel",
value: {
webhookUrl: "https://hooks.slack.com/services/...",
headers: [{ key: "Authorization", value: "Bearer token" }], // optional
},
},
});unsubscribeFromPage(request)
Unsubscribe from a status page.
// By email
const { success } = await client.statusPage.v1.StatusPageService
.unsubscribeFromPage({
pageId: "page_123",
identifier: { case: "email", value: "[email protected]" },
});
// Or by subscriber ID
const { success: success2 } = await client.statusPage.v1.StatusPageService
.unsubscribeFromPage({
pageId: "page_123",
identifier: { case: "id", value: "sub_456" },
});listSubscribers(request)
List all subscribers for a status page.
const { subscribers, totalSize } = await client.statusPage.v1.StatusPageService
.listSubscribers({
pageId: "page_123",
limit: 50,
offset: 0,
includeUnsubscribed: false,
});getStatusPageContent(request)
Get full status page content including components, groups, and active reports.
const content = await client.statusPage.v1.StatusPageService
.getStatusPageContent({
identifier: { case: "slug", value: "my-service" },
});
console.log(`Page: ${content.statusPage?.title}`);
console.log(`Components: ${content.components.length}`);
console.log(`Active reports: ${content.statusReports.length}`);getOverallStatus(request)
Get the aggregated status of a status page.
import { OverallStatus } from "@openstatus/sdk-node";
const { overallStatus, componentStatuses } = await client.statusPage.v1
.StatusPageService.getOverallStatus({
identifier: { case: "id", value: "page_123" },
});
console.log(`Overall: ${OverallStatus[overallStatus]}`);
for (const { componentId, status } of componentStatuses) {
console.log(` ${componentId}: ${OverallStatus[status]}`);
}getStatusPageOverview(request)
Get everything about a single status page in one authenticated call: the page,
its rendering configuration, components, groups, active/recent status reports,
maintenances, and the computed overall + per-component statuses.
Workspace-scoped by ID — there is no public slug access path. Uptime time series
are not included; use getPageComponentDailySummary for that.
import { OverallStatus, PageMetricType } from "@openstatus/sdk-node";
const overview = await client.statusPage.v1.StatusPageService
.getStatusPageOverview({ id: "page_123" });
console.log(`Page: ${overview.statusPage?.title}`);
console.log(`Overall: ${OverallStatus[overview.overallStatus]}`);
console.log(`Components: ${overview.components.length}`);
console.log(
`Metric: ${PageMetricType[overview.configuration?.metricType ?? 0]}`,
);getPageComponentDailySummary(request)
Get per-component daily status buckets (ok/degraded/error/count plus a
resolved status) merged with the incident, maintenance, and status-report
timeline over the last N days (max 45). Use it to render status bars and uptime
calendars. Identify the page by ID (authenticated) or slug (public).
import { ComponentDayStatus } from "@openstatus/sdk-node";
const { components } = await client.statusPage.v1.StatusPageService
.getPageComponentDailySummary({
identifier: { case: "id", value: "page_123" },
componentIds: [], // optional, empty = all components
days: 45, // optional, 1–45, defaults to 45
});
for (const component of components) {
console.log(`${component.name} (${component.componentId})`);
for (const bucket of component.buckets) {
console.log(
` ${bucket.day}: ${bucket.ok}/${bucket.count} ok ` +
`[${ComponentDayStatus[bucket.status]}]`,
);
}
}Maintenance Service
Manage scheduled maintenance windows.
createMaintenance(request)
Create a new maintenance window.
const { maintenance } = await client.maintenance.v1.MaintenanceService
.createMaintenance({
title: "Database Upgrade",
message: "We will be upgrading our database infrastructure.",
from: "2024-01-20T02:00:00Z",
to: "2024-01-20T04:00:00Z",
pageId: "page_123",
pageComponentIds: ["comp_456"],
notify: true,
});
console.log(`Maintenance created: ${maintenance?.id}`);getMaintenance(request)
Get a maintenance window by ID.
const { maintenance } = await client.maintenance.v1.MaintenanceService
.getMaintenance({
id: "maint_123",
});
console.log(`Title: ${maintenance?.title}`);
console.log(`From: ${maintenance?.from}`);
console.log(`To: ${maintenance?.to}`);listMaintenances(request)
List all maintenance windows with pagination and optional filtering.
const { maintenances, totalSize } = await client.maintenance.v1
.MaintenanceService.listMaintenances({
limit: 10,
offset: 0,
pageId: "page_123", // optional filter
});
console.log(`Found ${totalSize} maintenance windows`);updateMaintenance(request)
Update a maintenance window.
const { maintenance } = await client.maintenance.v1.MaintenanceService
.updateMaintenance({
id: "maint_123",
title: "Extended Database Upgrade",
to: "2024-01-20T06:00:00Z",
});deleteMaintenance(request)
Delete a maintenance window.
const { success } = await client.maintenance.v1.MaintenanceService
.deleteMaintenance({
id: "maint_123",
});Notification Service
Manage notification channels for monitor alerts. Supports 13 providers including Slack, Discord, Email, PagerDuty, Microsoft Teams, and custom webhooks.
createNotification(request)
Create a new notification channel.
import { NotificationProvider } from "@openstatus/sdk-node";
const { notification } = await client.notification.v1.NotificationService
.createNotification({
name: "Slack Alerts",
provider: NotificationProvider.SLACK,
data: {
data: {
case: "slack",
value: { webhookUrl: "https://hooks.slack.com/services/..." },
},
},
monitorIds: ["mon_123", "mon_456"],
});
console.log(`Notification created: ${notification?.id}`);getNotification(request)
Get a notification channel by ID.
import { NotificationProvider } from "@openstatus/sdk-node";
const { notification } = await client.notification.v1.NotificationService
.getNotification({
id: "notif_123",
});
console.log(`Name: ${notification?.name}`);
console.log(`Provider: ${NotificationProvider[notification?.provider ?? 0]}`);listNotifications(request)
List all notification channels with pagination.
const { notifications, totalSize } = await client.notification.v1
.NotificationService.listNotifications({ limit: 10, offset: 0 });
console.log(`Found ${totalSize} notification channels`);updateNotification(request)
Update a notification channel.
const { notification } = await client.notification.v1.NotificationService
.updateNotification({
id: "notif_123",
name: "Updated Slack Alerts",
monitorIds: ["mon_123", "mon_456", "mon_789"],
});deleteNotification(request)
Delete a notification channel.
const { success } = await client.notification.v1.NotificationService
.deleteNotification({
id: "notif_123",
});sendTestNotification(request)
Send a test notification to verify configuration.
import { NotificationProvider } from "@openstatus/sdk-node";
const { success, errorMessage } = await client.notification.v1
.NotificationService.sendTestNotification({
provider: NotificationProvider.SLACK,
data: {
data: {
case: "slack",
value: { webhookUrl: "https://hooks.slack.com/services/..." },
},
},
});
if (success) {
console.log("Test notification sent successfully");
} else {
console.log(`Test failed: ${errorMessage}`);
}checkNotificationLimit(request)
Check if the workspace has reached its notification limit.
const { limitReached, currentCount, maxCount } = await client.notification.v1
.NotificationService.checkNotificationLimit({});
console.log(`${currentCount}/${maxCount} notification channels used`);Provider Configuration Examples
{
provider: NotificationProvider.SLACK,
data: {
data: {
case: "slack",
value: { webhookUrl: "https://hooks.slack.com/services/..." }
}
}
}{
provider: NotificationProvider.DISCORD,
data: {
data: {
case: "discord",
value: { webhookUrl: "https://discord.com/api/webhooks/..." }
}
}
}{
provider: NotificationProvider.EMAIL,
data: {
data: {
case: "email",
value: { email: "[email protected]" }
}
}
}{
provider: NotificationProvider.PAGERDUTY,
data: {
data: {
case: "pagerduty",
value: { integrationKey: "your-integration-key" }
}
}
}import { OpsgenieRegion } from "@openstatus/sdk-node";
{
provider: NotificationProvider.OPSGENIE,
data: {
data: {
case: "opsgenie",
value: { apiKey: "your-api-key", region: OpsgenieRegion.US }
}
}
}{
provider: NotificationProvider.TELEGRAM,
data: {
data: {
case: "telegram",
value: { chatId: "123456789" }
}
}
}{
provider: NotificationProvider.GOOGLE_CHAT,
data: {
data: {
case: "googleChat",
value: { webhookUrl: "https://chat.googleapis.com/v1/spaces/..." }
}
}
}{
provider: NotificationProvider.GRAFANA_ONCALL,
data: {
data: {
case: "grafanaOncall",
value: { webhookUrl: "https://oncall.example.com/..." }
}
}
}{
provider: NotificationProvider.NTFY,
data: {
data: {
case: "ntfy",
value: {
topic: "my-alerts",
serverUrl: "https://ntfy.sh", // optional, defaults to ntfy.sh
token: "tk_..." // optional auth token
}
}
}
}{
provider: NotificationProvider.SMS,
data: {
data: {
case: "sms",
value: { phoneNumber: "+1234567890" }
}
}
}{
provider: NotificationProvider.WHATSAPP,
data: {
data: {
case: "whatsapp",
value: { phoneNumber: "+1234567890" }
}
}
}{
provider: NotificationProvider.MS_TEAMS,
data: {
data: {
case: "msTeams",
value: { webhookUrl: "https://prod-00.westeurope.logic.azure.com:443/workflows/..." }
}
}
}{
provider: NotificationProvider.WEBHOOK,
data: {
data: {
case: "webhook",
value: {
endpoint: "https://api.example.com/webhook",
headers: [
{ key: "Authorization", value: "Bearer token" },
{ key: "X-Custom-Header", value: "value" }
]
}
}
}
}Private Location Service
Manage private locations — self-hosted checker agents that run your monitors from inside your own network. Each private location owns an agent token used by the agent to authenticate; treat it as a secret.
createPrivateLocation(request)
Create a private location. The server generates the agent token and returns it.
const { privateLocation } = await client.privateLocation.v1
.PrivateLocationService.createPrivateLocation({
name: "eu-datacenter",
monitorIds: ["123456"], // optional, monitors this location runs
metadata: { env: "production" }, // optional key/value labels
});
console.log(`Token: ${privateLocation?.token}`);getPrivateLocation(request)
Get a private location by ID, including its agent token.
import { PrivateLocationStatus } from "@openstatus/sdk-node";
const { privateLocation } = await client.privateLocation.v1
.PrivateLocationService.getPrivateLocation({ id: "pl_123" });
console.log(`Status: ${PrivateLocationStatus[privateLocation!.status]}`);
console.log(`Last seen: ${privateLocation?.lastSeenAt || "never"}`);listPrivateLocations(request)
List private location summaries with pagination. Agent tokens are not
included — use getPrivateLocation to fetch one.
const { privateLocations, totalSize } = await client.privateLocation.v1
.PrivateLocationService.listPrivateLocations({ limit: 10, offset: 0 });
console.log(`Found ${totalSize} private locations`);
for (const location of privateLocations) {
console.log(` ${location.name}: ${location.monitorCount} monitors`);
}updatePrivateLocation(request)
Update a private location.
const { privateLocation } = await client.privateLocation.v1
.PrivateLocationService.updatePrivateLocation({
id: "pl_123",
name: "eu-datacenter-2",
monitorIds: ["123456", "123457"],
});deletePrivateLocation(request)
Delete a private location.
const { success } = await client.privateLocation.v1.PrivateLocationService
.deletePrivateLocation({ id: "pl_123" });Reference
Monitor Options
HTTP Monitor
| Option | Type | Required | Description |
| ---------------------- | ------------------- | -------- | ------------------------------------------- |
| name | string | Yes | Monitor name (max 256 chars) |
| url | string | Yes | URL to monitor (max 2048 chars) |
| periodicity | Periodicity | Yes | Check interval |
| method | HTTPMethod | No | HTTP method (default: GET) |
| body | string | No | Request body |
| headers | Headers[] | No | Custom headers { key, value }[] |
| timeout | bigint | No | Timeout in ms (default: 45000, max: 120000) |
| retry | bigint | No | Retry attempts (default: 3, max: 10) |
| followRedirects | boolean | No | Follow redirects (default: true) |
| regions | Region[] | No | Regions for checks |
| active | boolean | No | Enable monitoring (default: false) |
| public | boolean | No | Public visibility (default: false) |
| degradedAt | bigint | No | Latency threshold (ms) for degraded status |
| description | string | No | Monitor description (max 1024 chars) |
| statusCodeAssertions | array | No | Status code assertions |
| bodyAssertions | array | No | Body assertions |
| headerAssertions | array | No | Header assertions |
| openTelemetry | OpenTelemetryConfig | No | OpenTelemetry export configuration |
TCP Monitor
| Option | Type | Required | Description |
| --------------- | ------------------- | -------- | ------------------------------------------- |
| name | string | Yes | Monitor name (max 256 chars) |
| uri | string | Yes | host:port to monitor (max 2048 chars) |
| periodicity | Periodicity | Yes | Check interval |
| timeout | bigint | No | Timeout in ms (default: 45000, max: 120000) |
| retry | bigint | No | Retry attempts (default: 3, max: 10) |
| regions | Region[] | No | Regions for checks |
| active | boolean | No | Enable monitoring (default: false) |
| public | boolean | No | Public visibility (default: false) |
| degradedAt | bigint | No | Latency threshold (ms) for degraded status |
| description | string | No | Monitor description (max 1024 chars) |
| openTelemetry | OpenTelemetryConfig | No | OpenTelemetry export configuration |
DNS Monitor
| Option | Type | Required | Description |
| ------------------ | ------------------- | -------- | ------------------------------------------- |
| name | string | Yes | Monitor name (max 256 chars) |
| uri | string | Yes | Domain to resolve (max 2048 chars) |
| periodicity | Periodicity | Yes | Check interval |
| timeout | bigint | No | Timeout in ms (default: 45000, max: 120000) |
| retry | bigint | No | Retry attempts (default: 3, max: 10) |
| regions | Region[] | No | Regions for checks |
| active | boolean | No | Enable monitoring (default: false) |
| public | boolean | No | Public visibility (default: false) |
| degradedAt | bigint | No | Latency threshold (ms) for degraded status |
| description | string | No | Monitor description (max 1024 chars) |
| recordAssertions | array | No | DNS record assertions |
| openTelemetry | OpenTelemetryConfig | No | OpenTelemetry export configuration |
Note: HTTP, TCP, and DNS monitors returned by the API also carry a read-only
privateLocationIds: string[]listing the private locations that run them. Assign monitors to a private location withcreatePrivateLocation/updatePrivateLocation.
Assertions
Status Code Assertions
Validate HTTP response status codes using NumberComparator.
import { NumberComparator } from "@openstatus/sdk-node";
{
statusCodeAssertions: [
{ comparator: NumberComparator.EQUAL, target: BigInt(200) },
{ comparator: NumberComparator.LESS_THAN, target: BigInt(400) },
];
}Body Assertions
Validate response body content using StringComparator.
import { StringComparator } from "@openstatus/sdk-node";
{
bodyAssertions: [
{ comparator: StringComparator.CONTAINS, target: '"status":"ok"' },
{ comparator: StringComparator.NOT_EMPTY, target: "" },
];
}Header Assertions
Validate response headers using StringComparator.
import { StringComparator } from "@openstatus/sdk-node";
{
headerAssertions: [
{
key: "content-type",
comparator: StringComparator.CONTAINS,
target: "application/json",
},
];
}DNS Record Assertions
Validate DNS records using RecordComparator.
import { RecordComparator } from "@openstatus/sdk-node";
{
recordAssertions: [
{
record: "A",
comparator: RecordComparator.EQUAL,
target: "93.184.216.34",
},
{ record: "CNAME", comparator: RecordComparator.CONTAINS, target: "cdn" },
];
}Supported record types: A, AAAA, CNAME, MX, TXT
Regions
Monitor from 28 global locations across multiple providers.
import { Region } from "@openstatus/sdk-node";
regions: [Region.FLY_AMS, Region.FLY_IAD, Region.KOYEB_FRA];Fly.io Regions (18)
| Enum Value | Location |
| ---------- | --------------- |
| FLY_AMS | Amsterdam |
| FLY_ARN | Stockholm |
| FLY_BOM | Mumbai |
| FLY_CDG | Paris |
| FLY_DFW | Dallas |
| FLY_EWR | Newark |
| FLY_FRA | Frankfurt |
| FLY_GRU | São Paulo |
| FLY_IAD | Washington D.C. |
| FLY_JNB | Johannesburg |
| FLY_LAX | Los Angeles |
| FLY_LHR | London |
| FLY_NRT | Tokyo |
| FLY_ORD | Chicago |
| FLY_SJC | San Jose |
| FLY_SIN | Singapore |
| FLY_SYD | Sydney |
| FLY_YYZ | Toronto |
Koyeb Regions (6)
| Enum Value | Location |
| ----------- | ------------- |
| KOYEB_FRA | Frankfurt |
| KOYEB_PAR | Paris |
| KOYEB_SFO | San Francisco |
| KOYEB_SIN | Singapore |
| KOYEB_TYO | Tokyo |
| KOYEB_WAS | Washington |
Railway Regions (4)
| Enum Value | Location |
| ------------------------- | -------------- |
| RAILWAY_US_WEST2 | US West |
| RAILWAY_US_EAST4 | US East |
| RAILWAY_EUROPE_WEST4 | Europe West |
| RAILWAY_ASIA_SOUTHEAST1 | Asia Southeast |
Enums
Periodicity
| Value | Description |
| ----------------- | ----------- |
| PERIODICITY_30S | Every 30s |
| PERIODICITY_1M | Every 1m |
| PERIODICITY_5M | Every 5m |
| PERIODICITY_10M | Every 10m |
| PERIODICITY_30M | Every 30m |
| PERIODICITY_1H | Every 1h |
HTTPMethod
| Value | Description |
| --------------------- | ----------- |
| HTTP_METHOD_GET | GET |
| HTTP_METHOD_POST | POST |
| HTTP_METHOD_HEAD | HEAD |
| HTTP_METHOD_PUT | PUT |
| HTTP_METHOD_PATCH | PATCH |
| HTTP_METHOD_DELETE | DELETE |
| HTTP_METHOD_TRACE | TRACE |
| HTTP_METHOD_CONNECT | CONNECT |
| HTTP_METHOD_OPTIONS | OPTIONS |
MonitorStatus
| Value | Description |
| ---------- | -------------------------- |
| ACTIVE | Monitor is healthy |
| DEGRADED | Latency threshold exceeded |
| ERROR | Monitor is failing |
TimeRange
| Value | Description |
| ---------------- | ------------ |
| TIME_RANGE_1D | Last 1 day |
| TIME_RANGE_7D | Last 7 days |
| TIME_RANGE_14D | Last 14 days |
HTTPResponseLogRequestStatus
| Value | Description |
| ------------------------------------------- | ---------------------------------- |
| HTTP_RESPONSE_LOG_REQUEST_STATUS_SUCCESS | Response satisfied assertions |
| HTTP_RESPONSE_LOG_REQUEST_STATUS_ERROR | Response failed its assertions |
| HTTP_RESPONSE_LOG_REQUEST_STATUS_DEGRADED | Response slower than the threshold |
HTTPResponseLogTrigger
| Value | Description |
| -------------------------------- | ------------------------- |
| HTTP_RESPONSE_LOG_TRIGGER_CRON | Scheduled monitor run |
| HTTP_RESPONSE_LOG_TRIGGER_API | API-triggered monitor run |
StatusReportStatus
| Value | Description |
| --------------- | -------------------------------- |
| INVESTIGATING | Actively investigating the issue |
| IDENTIFIED | Root cause has been identified |
| MONITORING | Fix deployed, monitoring |
| RESOLVED | Issue fully resolved |
PageComponentImpact
| Value | Description |
| ---------------------- | --------------------------------- |
| UNSPECIFIED | No impact set (legacy reports) |
| OPERATIONAL | Component is operational |
| DEGRADED_PERFORMANCE | Component performance is degraded |
| PARTIAL_OUTAGE | Component is partially down |
| MAJOR_OUTAGE | Component is down |
OverallStatus
| Value | Description |
| ---------------- | --------------------------- |
| OPERATIONAL | All systems operational |
| DEGRADED | Performance is degraded |
| PARTIAL_OUTAGE | Some systems are down |
| MAJOR_OUTAGE | Major systems are down |
| MAINTENANCE | Scheduled maintenance |
| UNKNOWN | Status cannot be determined |
NotificationProvider
| Value | Description |
| ---------------- | ------------------- |
| DISCORD | Discord webhook |
| EMAIL | Email notification |
| GOOGLE_CHAT | Google Chat webhook |
| GRAFANA_ONCALL | Grafana OnCall |
| MS_TEAMS | Microsoft Teams |
| NTFY | Ntfy push service |
| PAGERDUTY | PagerDuty |
| OPSGENIE | Opsgenie |
| SLACK | Slack webhook |
| SMS | SMS notification |
| TELEGRAM | Telegram bot |
| WEBHOOK | Custom webhook |
| WHATSAPP | WhatsApp |
OpsgenieRegion
| Value | Description |
| ----- | ----------- |
| US | US region |
| EU | EU region |
PageAccessType
| Value | Description |
| -------------------- | ----------------------- |
| PUBLIC | Publicly accessible |
| PASSWORD_PROTECTED | Requires password |
| AUTHENTICATED | Requires authentication |
PageTheme
| Value | Description |
| -------- | ------------------- |
| SYSTEM | Follow system theme |
| LIGHT | Light theme |
| DARK | Dark theme |
PageComponentType
| Value | Description |
| --------- | ------------------------- |
| MONITOR | Linked to a monitor |
| STATIC | Static component (manual) |
Locale
| Value | Description |
| ------------- | ------------- |
| UNSPECIFIED | No locale set |
| EN | English |
| FR | French |
| DE | German |
| TR | Turkish |
| HI | Hindi |
| KO | Korean |
PageMetricType
Which metric the status bars represent (PageConfiguration.metricType).
| Value | Description |
| ------------- | -------------------------- |
| UNSPECIFIED | Not set |
| DURATION | Response time |
| REQUESTS | Request counts |
| MANUAL | Manually managed component |
PageBarType
How the status bar is computed (PageConfiguration.barType).
| Value | Description |
| ------------- | ------------------------- |
| UNSPECIFIED | Not set |
| ABSOLUTE | Absolute values |
| MANUAL | Manually managed statuses |
PrivateLocationStatus
Computed health of a private location agent (read-only).
| Value | Description |
| ------------- | --------------------------- |
| UNSPECIFIED | Unknown status |
| ACTIVE | Agent is reporting normally |
| ERROR | Agent has stopped reporting |
SubscriberSource
| Value | Description |
| ------------- | ------------------------------------------------ |
| UNSPECIFIED | Source not set |
| SELF_SIGNUP | Created by the user via the subscribe form |
| VENDOR | Added by an operator, skipping verification |
| IMPORT | Imported from a third-party status-page provider |
ComponentDayStatus
Resolved status of a component on a given day (from
getPageComponentDailySummary).
| Value | Description |
| ------------- | -------------------- |
| UNSPECIFIED | No status |
| OPERATIONAL | Operational |
| DEGRADED | Degraded performance |
| DOWN | Down |
| MAINTENANCE | Under maintenance |
| EMPTY | No data for the day |
ComponentEventType
| Value | Description |
| ------------- | ------------------ |
| UNSPECIFIED | No type |
| MAINTENANCE | Maintenance window |
| INCIDENT | Incident |
| REPORT | Status report |
ComponentEventStatus
| Value | Description |
| ------------- | -------------------- |
| UNSPECIFIED | No status |
| OPERATIONAL | Operational |
| DEGRADED | Degraded performance |
| DOWN | Down |
| MAINTENANCE | Under maintenance |
NumberComparator
| Value | Description |
| ----------------------- | --------------------- |
| EQUAL | Equal to target |
| NOT_EQUAL | Not equal to target |
| GREATER_THAN | Greater than target |
| GREATER_THAN_OR_EQUAL | Greater than or equal |
| LESS_THAN | Less than target |
| LESS_THAN_OR_EQUAL | Less than or equal |
StringComparator
| Value | Description |
| ----------------------- | --------------------------- |
| CONTAINS | Contains target string |
| NOT_CONTAINS | Does not contain target |
| EQUAL | Equal to target |
| NOT_EQUAL | Not equal to target |
| EMPTY | Value is empty |
| NOT_EMPTY | Value is not empty |
| GREATER_THAN | Lexicographically greater |
| GREATER_THAN_OR_EQUAL | Lexicographically >= target |
| LESS_THAN | Lexicographically less |
| LESS_THAN_OR_EQUAL | Lexicographically <= target |
RecordComparator
| Value | Description |
| -------------- | ----------------------- |
| EQUAL | Equal to target |
| NOT_EQUAL | Not equal to target |
| CONTAINS | Contains target string |
| NOT_CONTAINS | Does not contain target |
Error Handling
The SDK uses Connect RPC. Errors include a code and message:
import { ConnectError } from "@connectrpc/connect";
try {
await client.monitor.v1.MonitorService.deleteMonitor({ id: "invalid" });
} catch (error) {
if (error instanceof ConnectError) {
console.error(`Error ${error.code}: ${error.message}`);
}
}Related
- OpenStatus - Open-source monitoring platform
- Documentation - Full API documentation
- Status Page - OpenStatus service status
License
MIT
