Openstatus sdk
www.openstatus.dev
1# OpenStatus Node.js SDK (Beta)
2
3[](https://jsr.io/@openstatus/sdk-node)
4[](https://www.npmjs.com/package/@openstatus/sdk-node)
5[](https://opensource.org/licenses/MIT)
6
7Official Node.js SDK for [OpenStatus](https://openstatus.dev) - The open-source status page with uptime monitoring.
8
9## Features
10
11### Status Page
12- **Status Reports** - Manage incident and maintenance reports with update timelines
13
14### Monitoring
15- **HTTP Monitoring** - Monitor websites and APIs with customizable assertions
16- **TCP Monitoring** - Check database connections and other TCP services
17- **DNS Monitoring** - Verify DNS records and resolution
18
19- **Global Regions** - Monitor from 28 locations worldwide
20- **Type-safe** - Full TypeScript support with generated types from protobuf
21
22## Installation
23
24### JSR
25
26```bash
27npx jsr add @openstatus/sdk-node
28```
29
30### npm
31
32```bash
33npm install @openstatus/sdk-node
34```
35
36### Deno
37
38```typescript
39import { openstatus } from "jsr:@openstatus/sdk-node";
40```
41
42## Quick Start
43
44```typescript
45import {
46 HTTPMethod,
47 NumberComparator,
48 openstatus,
49 Periodicity,
50 Region,
51} from "@openstatus/sdk-node";
52
53const headers = {
54 "x-openstatus-key": `${process.env.OPENSTATUS_API_KEY}`,
55};
56
57// Create a monitor
58const { monitor } = await openstatus.monitor.v1.MonitorService
59 .createHTTPMonitor(
60 {
61 monitor: {
62 name: "My API",
63 url: "https://api.example.com/health",
64 periodicity: Periodicity.PERIODICITY_1M,
65 method: HTTPMethod.HTTP_METHOD_GET,
66 regions: [Region.FLY_AMS, Region.FLY_IAD, Region.FLY_SYD],
67 active: true,
68 statusCodeAssertions: [
69 { comparator: NumberComparator.EQUAL, target: BigInt(200) },
70 ],
71 },
72 },
73 { headers },
74 );
75
76console.log(`Monitor created: ${monitor?.id}`);
77
78// List all monitors
79const { httpMonitors, tcpMonitors, dnsMonitors, totalSize } = await openstatus
80 .monitor.v1.MonitorService.listMonitors({}, { headers });
81
82console.log(`Found ${totalSize} monitors`);
83```
84
85## Authentication
86
87All API requests require an API key. Get yours from the
88[OpenStatus dashboard](https://www.openstatus.dev/app).
89
90```typescript
91const headers = {
92 "x-openstatus-key": `${process.env.OPENSTATUS_API_KEY}`,
93};
94
95// Pass headers to any service method
96await openstatus.monitor.v1.MonitorService.listMonitors({}, { headers });
97```
98
99## Environment Variables
100
101| Variable | Description | Default |
102| -------------------- | ----------------------- | -------------------------------- |
103| `OPENSTATUS_API_KEY` | Your OpenStatus API key | - |
104| `OPENSTATUS_API_URL` | Custom API endpoint | `https://api.openstatus.dev/rpc` |
105
106## API Reference
107
108### Monitor Service
109
110#### `createHTTPMonitor(request, options)`
111
112Create an HTTP/HTTPS monitor.
113
114```typescript
115import { HTTPMethod, Periodicity, Region } from "@openstatus/sdk-node";
116
117const { monitor } = await openstatus.monitor.v1.MonitorService
118 .createHTTPMonitor(
119 {
120 monitor: {
121 name: "My Website",
122 url: "https://example.com",
123 periodicity: Periodicity.PERIODICITY_1M,
124 method: HTTPMethod.HTTP_METHOD_GET,
125 regions: [Region.FLY_AMS, Region.FLY_IAD, Region.FLY_SYD],
126 active: true,
127 },
128 },
129 { headers },
130 );
131```
132
133#### `updateHTTPMonitor(request, options)`
134
135Update an existing HTTP monitor.
136
137```typescript
138const { monitor } = await openstatus.monitor.v1.MonitorService
139 .updateHTTPMonitor(
140 {
141 id: "mon_123",
142 monitor: {
143 name: "Updated Name",
144 active: false,
145 },
146 },
147 { headers },
148 );
149```
150
151#### `createTCPMonitor(request, options)`
152
153Create a TCP connection monitor.
154
155```typescript
156const { monitor } = await openstatus.monitor.v1.MonitorService.createTCPMonitor(
157 {
158 monitor: {
159 name: "Database",
160 uri: "db.example.com:5432",
161 periodicity: Periodicity.PERIODICITY_5M,
162 regions: [Region.FLY_AMS, Region.FLY_IAD],
163 active: true,
164 },
165 },
166 { headers },
167);
168```
169
170#### `updateTCPMonitor(request, options)`
171
172Update an existing TCP monitor.
173
174```typescript
175const { monitor } = await openstatus.monitor.v1.MonitorService.updateTCPMonitor(
176 {
177 id: "mon_123",
178 monitor: {
179 name: "Updated Database Monitor",
180 },
181 },
182 { headers },
183);
184```
185
186#### `createDNSMonitor(request, options)`
187
188Create a DNS resolution monitor.
189
190```typescript
191import { RecordComparator } from "@openstatus/sdk-node";
192
193const { monitor } = await openstatus.monitor.v1.MonitorService.createDNSMonitor(
194 {
195 monitor: {
196 name: "DNS Check",
197 uri: "example.com",
198 periodicity: Periodicity.PERIODICITY_10M,
199 regions: [Region.FLY_AMS],
200 active: true,
201 recordAssertions: [
202 {
203 record: "A",
204 comparator: RecordComparator.EQUAL,
205 target: "93.184.216.34",
206 },
207 ],
208 },
209 },
210 { headers },
211);
212```
213
214#### `updateDNSMonitor(request, options)`
215
216Update an existing DNS monitor.
217
218```typescript
219const { monitor } = await openstatus.monitor.v1.MonitorService.updateDNSMonitor(
220 {
221 id: "mon_123",
222 monitor: {
223 name: "Updated DNS Check",
224 },
225 },
226 { headers },
227);
228```
229
230#### `listMonitors(request, options)`
231
232List all monitors with pagination. Returns monitors grouped by type.
233
234```typescript
235const { httpMonitors, tcpMonitors, dnsMonitors, nextPageToken, totalSize } =
236 await openstatus.monitor.v1.MonitorService.listMonitors(
237 { pageSize: 10, pageToken: "" },
238 { headers },
239 );
240```
241
242#### `triggerMonitor(request, options)`
243
244Trigger an immediate check.
245
246```typescript
247const { success } = await openstatus.monitor.v1.MonitorService.triggerMonitor(
248 { id: "mon_123" },
249 { headers },
250);
251```
252
253#### `deleteMonitor(request, options)`
254
255Delete a monitor.
256
257```typescript
258const { success } = await openstatus.monitor.v1.MonitorService.deleteMonitor(
259 { id: "mon_123" },
260 { headers },
261);
262```
263
264#### `getMonitorStatus(request, options)`
265
266Get the current status of a monitor across all configured regions.
267
268```typescript
269import { MonitorStatus, Region } from "@openstatus/sdk-node";
270
271const { id, regions } = await openstatus.monitor.v1.MonitorService
272 .getMonitorStatus(
273 { id: "mon_123" },
274 { headers },
275 );
276
277// regions is an array of { region, status }
278// region: Region enum value (e.g., Region.FLY_AMS)
279// status: MonitorStatus.ACTIVE, MonitorStatus.DEGRADED, or MonitorStatus.ERROR
280for (const { region, status } of regions) {
281 console.log(`${Region[region]}: ${MonitorStatus[status]}`);
282}
283```
284
285#### `getMonitorSummary(request, options)`
286
287Get aggregated metrics and latency percentiles for a monitor.
288
289```typescript
290import { TimeRange } from "@openstatus/sdk-node";
291
292const summary = await openstatus.monitor.v1.MonitorService.getMonitorSummary(
293 {
294 id: "mon_123",
295 timeRange: TimeRange.TIME_RANGE_7D, // TIME_RANGE_1D, TIME_RANGE_7D, or TIME_RANGE_14D
296 regions: [], // optional: filter by specific regions
297 },
298 { headers },
299);
300
301console.log(`Last ping: ${summary.lastPingAt}`);
302console.log(`Success: ${summary.totalSuccessful}`);
303console.log(`Degraded: ${summary.totalDegraded}`);
304console.log(`Failed: ${summary.totalFailed}`);
305console.log(`P50 latency: ${summary.p50}ms`);
306console.log(`P75 latency: ${summary.p75}ms`);
307console.log(`P90 latency: ${summary.p90}ms`);
308console.log(`P95 latency: ${summary.p95}ms`);
309console.log(`P99 latency: ${summary.p99}ms`);
310```
311
312### Health Service
313
314Check API health status (no authentication required).
315
316```typescript
317import { ServingStatus } from "@openstatus/sdk-node";
318
319const { status } = await openstatus.health.v1.HealthService.check({});
320console.log(ServingStatus[status]); // "SERVING"
321```
322
323### Status Report Service
324
325Manage incident and maintenance reports with update timelines.
326
327#### `createStatusReport(request, options)`
328
329Create a new status report.
330
331```typescript
332import { StatusReportStatus } from "@openstatus/sdk-node";
333
334const { statusReport } = await openstatus.statusReport.v1.StatusReportService
335 .createStatusReport(
336 {
337 title: "API Degradation",
338 status: StatusReportStatus.INVESTIGATING,
339 message: "We are investigating reports of increased latency.",
340 date: "2024-01-15T10:30:00",
341 pageId: "page_123",
342 pageComponentIds: ["comp_456"],
343 notify: true,
344 },
345 { headers },
346 );
347
348console.log(`Status report created: ${statusReport?.id}`);
349```
350
351#### `getStatusReport(request, options)`
352
353Get a status report by ID (includes full update timeline).
354
355```typescript
356const { statusReport } = await openstatus.statusReport.v1.StatusReportService
357 .getStatusReport(
358 { id: "sr_123" },
359 { headers },
360 );
361
362console.log(`Title: ${statusReport?.title}`);
363console.log(`Status: ${StatusReportStatus[statusReport?.status ?? 0]}`);
364
365// Access update timeline
366for (const update of statusReport?.updates ?? []) {
367 console.log(`${update.date}: ${update.message}`);
368}
369```
370
371#### `listStatusReports(request, options)`
372
373List all status reports with pagination and optional filtering.
374
375```typescript
376import { StatusReportStatus } from "@openstatus/sdk-node";
377
378const { statusReports, totalSize } = await openstatus.statusReport.v1
379 .StatusReportService.listStatusReports(
380 {
381 limit: 10,
382 offset: 0,
383 statuses: [StatusReportStatus.INVESTIGATING, StatusReportStatus.IDENTIFIED],
384 },
385 { headers },
386 );
387
388console.log(`Found ${totalSize} status reports`);
389```
390
391#### `updateStatusReport(request, options)`
392
393Update status report metadata (title, page components).
394
395```typescript
396const { statusReport } = await openstatus.statusReport.v1.StatusReportService
397 .updateStatusReport(
398 {
399 id: "sr_123",
400 title: "Updated Title",
401 pageComponentIds: ["comp_456", "comp_789"],
402 },
403 { headers },
404 );
405```
406
407#### `deleteStatusReport(request, options)`
408
409Delete a status report and all its updates.
410
411```typescript
412const { success } = await openstatus.statusReport.v1.StatusReportService
413 .deleteStatusReport(
414 { id: "sr_123" },
415 { headers },
416 );
417```
418
419#### `addStatusReportUpdate(request, options)`
420
421Add a new update to an existing status report timeline.
422
423```typescript
424import { StatusReportStatus } from "@openstatus/sdk-node";
425
426const { statusReport } = await openstatus.statusReport.v1.StatusReportService
427 .addStatusReportUpdate(
428 {
429 statusReportId: "sr_123",
430 status: StatusReportStatus.IDENTIFIED,
431 message: "The issue has been identified as a database connection problem.",
432 date: "2024-01-15T11:00:00", // optional, defaults to current time
433 notify: true,
434 },
435 { headers },
436 );
437```
438
439### Status Report Status
440
441| Enum Value | Description |
442| --------------- | ------------------------------- |
443| `UNSPECIFIED` | Default/unspecified status |
444| `INVESTIGATING` | Actively investigating the issue |
445| `IDENTIFIED` | Root cause has been identified |
446| `MONITORING` | Fix deployed, monitoring |
447| `RESOLVED` | Issue fully resolved |
448
449## Monitor Options
450
451### HTTP Monitor
452
453| Option | Type | Required | Description |
454| ---------------------- | ------------------- | -------- | --------------------------------------------------- |
455| `name` | string | Yes | Monitor name (max 256 chars) |
456| `url` | string | Yes | URL to monitor (max 2048 chars) |
457| `periodicity` | Periodicity | Yes | Check interval (see [Periodicity](#periodicity)) |
458| `method` | HTTPMethod | No | HTTP method (see [HTTP Methods](#http-methods)) |
459| `body` | string | No | Request body |
460| `headers` | Headers[] | No | Custom headers (`{ key: string, value: string }[]`) |
461| `timeout` | bigint | No | Timeout in ms (default: 45000, max: 120000) |
462| `retry` | bigint | No | Retry attempts (default: 3, max: 10) |
463| `followRedirects` | boolean | No | Follow redirects (default: true) |
464| `regions` | Region[] | No | [Regions](#regions) for checks |
465| `active` | boolean | No | Enable monitoring (default: false) |
466| `public` | boolean | No | Public visibility (default: false) |
467| `degradedAt` | bigint | No | Latency threshold (ms) for degraded status |
468| `description` | string | No | Monitor description (max 1024 chars) |
469| `statusCodeAssertions` | array | No | [Status code assertions](#status-code-assertions) |
470| `bodyAssertions` | array | No | [Body assertions](#body-assertions) |
471| `headerAssertions` | array | No | [Header assertions](#header-assertions) |
472| `openTelemetry` | OpenTelemetryConfig | No | OpenTelemetry export configuration |
473
474### TCP Monitor
475
476| Option | Type | Required | Description |
477| --------------- | ------------------- | -------- | ------------------------------------------------ |
478| `name` | string | Yes | Monitor name (max 256 chars) |
479| `uri` | string | Yes | `host:port` to monitor (max 2048 chars) |
480| `periodicity` | Periodicity | Yes | Check interval (see [Periodicity](#periodicity)) |
481| `timeout` | bigint | No | Timeout in ms (default: 45000, max: 120000) |
482| `retry` | bigint | No | Retry attempts (default: 3, max: 10) |
483| `regions` | Region[] | No | [Regions](#regions) for checks |
484| `active` | boolean | No | Enable monitoring (default: false) |
485| `public` | boolean | No | Public visibility (default: false) |
486| `degradedAt` | bigint | No | Latency threshold (ms) for degraded status |
487| `description` | string | No | Monitor description (max 1024 chars) |
488| `openTelemetry` | OpenTelemetryConfig | No | OpenTelemetry export configuration |
489
490### DNS Monitor
491
492| Option | Type | Required | Description |
493| ------------------ | ------------------- | -------- | ------------------------------------------------ |
494| `name` | string | Yes | Monitor name (max 256 chars) |
495| `uri` | string | Yes | Domain to resolve (max 2048 chars) |
496| `periodicity` | Periodicity | Yes | Check interval (see [Periodicity](#periodicity)) |
497| `timeout` | bigint | No | Timeout in ms (default: 45000, max: 120000) |
498| `retry` | bigint | No | Retry attempts (default: 3, max: 10) |
499| `regions` | Region[] | No | [Regions](#regions) for checks |
500| `active` | boolean | No | Enable monitoring (default: false) |
501| `public` | boolean | No | Public visibility (default: false) |
502| `degradedAt` | bigint | No | Latency threshold (ms) for degraded status |
503| `description` | string | No | Monitor description (max 1024 chars) |
504| `recordAssertions` | array | No | [DNS record assertions](#dns-record-assertions) |
505| `openTelemetry` | OpenTelemetryConfig | No | OpenTelemetry export configuration |
506
507### Periodicity
508
509| Enum Value | Description |
510| ----------------- | ----------- |
511| `PERIODICITY_30S` | Every 30s |
512| `PERIODICITY_1M` | Every 1m |
513| `PERIODICITY_5M` | Every 5m |
514| `PERIODICITY_10M` | Every 10m |
515| `PERIODICITY_30M` | Every 30m |
516| `PERIODICITY_1H` | Every 1h |
517
518### HTTP Methods
519
520| Enum Value | Description |
521| --------------------- | ----------- |
522| `HTTP_METHOD_GET` | GET |
523| `HTTP_METHOD_POST` | POST |
524| `HTTP_METHOD_HEAD` | HEAD |
525| `HTTP_METHOD_PUT` | PUT |
526| `HTTP_METHOD_PATCH` | PATCH |
527| `HTTP_METHOD_DELETE` | DELETE |
528| `HTTP_METHOD_TRACE` | TRACE |
529| `HTTP_METHOD_CONNECT` | CONNECT |
530| `HTTP_METHOD_OPTIONS` | OPTIONS |
531
532## Assertions
533
534All assertion comparators are exported as enums from the SDK.
535
536### Status Code Assertions
537
538Validate HTTP response status codes using `NumberComparator`.
539
540```typescript
541import { NumberComparator } from "@openstatus/sdk-node";
542
543{
544 statusCodeAssertions: [
545 { comparator: NumberComparator.EQUAL, target: BigInt(200) },
546 { comparator: NumberComparator.LESS_THAN, target: BigInt(400) },
547 ];
548}
549```
550
551**NumberComparator values:**
552
553| Enum Value | Description |
554| ----------------------- | --------------------- |
555| `EQUAL` | Equal to target |
556| `NOT_EQUAL` | Not equal to target |
557| `GREATER_THAN` | Greater than target |
558| `GREATER_THAN_OR_EQUAL` | Greater than or equal |
559| `LESS_THAN` | Less than target |
560| `LESS_THAN_OR_EQUAL` | Less than or equal |
561
562### Body Assertions
563
564Validate response body content using `StringComparator`.
565
566```typescript
567import { StringComparator } from "@openstatus/sdk-node";
568
569{
570 bodyAssertions: [
571 { comparator: StringComparator.CONTAINS, target: '"status":"ok"' },
572 { comparator: StringComparator.NOT_EMPTY, target: "" },
573 ];
574}
575```
576
577**StringComparator values:**
578
579| Enum Value | Description |
580| ----------------------- | --------------------------- |
581| `CONTAINS` | Contains target string |
582| `NOT_CONTAINS` | Does not contain target |
583| `EQUAL` | Equal to target |
584| `NOT_EQUAL` | Not equal to target |
585| `EMPTY` | Body is empty |
586| `NOT_EMPTY` | Body is not empty |
587| `GREATER_THAN` | Lexicographically greater |
588| `GREATER_THAN_OR_EQUAL` | Lexicographically >= target |
589| `LESS_THAN` | Lexicographically less |
590| `LESS_THAN_OR_EQUAL` | Lexicographically <= target |
591
592### Header Assertions
593
594Validate response headers using `StringComparator`.
595
596```typescript
597import { StringComparator } from "@openstatus/sdk-node";
598
599{
600 headerAssertions: [
601 {
602 key: "content-type",
603 comparator: StringComparator.CONTAINS,
604 target: "application/json",
605 },
606 ];
607}
608```
609
610### DNS Record Assertions
611
612Validate DNS records using `RecordComparator`.
613
614```typescript
615import { RecordComparator } from "@openstatus/sdk-node";
616
617{
618 recordAssertions: [
619 {
620 record: "A",
621 comparator: RecordComparator.EQUAL,
622 target: "93.184.216.34",
623 },
624 { record: "CNAME", comparator: RecordComparator.CONTAINS, target: "cdn" },
625 ];
626}
627```
628
629**RecordComparator values:**
630
631| Enum Value | Description |
632| -------------- | ----------------------- |
633| `EQUAL` | Equal to target |
634| `NOT_EQUAL` | Not equal to target |
635| `CONTAINS` | Contains target string |
636| `NOT_CONTAINS` | Does not contain target |
637
638**Supported record types:** `A`, `AAAA`, `CNAME`, `MX`, `TXT`
639
640## Regions
641
642Monitor from 28 global locations across multiple providers. Use the `Region`
643enum:
644
645```typescript
646import { Region } from "@openstatus/sdk-node";
647
648// Example: Use specific regions
649regions: [Region.FLY_AMS, Region.FLY_IAD, Region.KOYEB_FRA];
650```
651
652### Fly.io Regions
653
654| Enum Value | Location |
655| ---------- | --------------- |
656| `FLY_AMS` | Amsterdam |
657| `FLY_ARN` | Stockholm |
658| `FLY_BOM` | Mumbai |
659| `FLY_CDG` | Paris |
660| `FLY_DFW` | Dallas |
661| `FLY_EWR` | Newark |
662| `FLY_FRA` | Frankfurt |
663| `FLY_GRU` | São Paulo |
664| `FLY_IAD` | Washington D.C. |
665| `FLY_JNB` | Johannesburg |
666| `FLY_LAX` | Los Angeles |
667| `FLY_LHR` | London |
668| `FLY_NRT` | Tokyo |
669| `FLY_ORD` | Chicago |
670| `FLY_SJC` | San Jose |
671| `FLY_SIN` | Singapore |
672| `FLY_SYD` | Sydney |
673| `FLY_YYZ` | Toronto |
674
675### Koyeb Regions
676
677| Enum Value | Location |
678| ----------- | ------------- |
679| `KOYEB_FRA` | Frankfurt |
680| `KOYEB_PAR` | Paris |
681| `KOYEB_SFO` | San Francisco |
682| `KOYEB_SIN` | Singapore |
683| `KOYEB_TYO` | Tokyo |
684| `KOYEB_WAS` | Washington |
685
686### Railway Regions
687
688| Enum Value | Location |
689| ------------------------- | -------------- |
690| `RAILWAY_US_WEST2` | US West |
691| `RAILWAY_US_EAST4` | US East |
692| `RAILWAY_EUROPE_WEST4` | Europe West |
693| `RAILWAY_ASIA_SOUTHEAST1` | Asia Southeast |
694
695## Error Handling
696
697The SDK uses Connect RPC. Errors include a `code` and `message`:
698
699```typescript
700import { ConnectError } from "@connectrpc/connect";
701
702try {
703 await openstatus.monitor.v1.MonitorService.deleteMonitor(
704 { id: "invalid" },
705 { headers },
706 );
707} catch (error) {
708 if (error instanceof ConnectError) {
709 console.error(`Error ${error.code}: ${error.message}`);
710 }
711}
712```
713
714## Related
715
716- [OpenStatus](https://openstatus.dev) - Open-source monitoring platform
717- [Documentation](https://docs.openstatus.dev) - Full API documentation
718- [Status Page](https://status.openstatus.dev) - OpenStatus service status
719
720## License
721
722MIT