npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@openstatus/sdk-node

v0.2.0

Published

SDK for openstatus.

Readme

OpenStatus Node.js SDK

JSR npm License: MIT

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-node

JSR

npx jsr add @openstatus/sdk-node

Deno

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 with createPrivateLocation / 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

License

MIT