TypeScript Tips
Not yet available on FTStatus
The FTStatus SDKs aren't available yet. Talk to support if you need programmatic access for your account.
Working with bigint Fields
Protocol Buffers int64 fields map to bigint in TypeScript. This affects:
- Monitor configuration:
timeout,retry,degradedAt - Assertions:
StatusCodeAssertion.target - Monitor summary:
totalSuccessful,totalDegraded,totalFailed,p50,p75,p90,p95,p99
Use BigInt() to create values:
const { monitor } = await client.monitor.v1.MonitorService.createHTTPMonitor({
monitor: {
name: "My API",
url: "https://example.com",
periodicity: Periodicity.PERIODICITY_1M,
active: true,
timeout: BigInt(30000), // 30 seconds
retry: BigInt(5), // 5 retries
degradedAt: BigInt(3000), // degraded after 3s
statusCodeAssertions: [
{ comparator: NumberComparator.EQUAL, target: BigInt(200) },
],
},
});
Reading bigint values:
const summary = await client.monitor.v1.MonitorService.getMonitorSummary({
id: "mon_123",
timeRange: TimeRange.TIME_RANGE_7D,
regions: [],
});
// bigint values — use Number() for display if values are safe
console.log(`P95 latency: ${summary.p95}ms`);
console.log(`Total checks: ${summary.totalSuccessful + summary.totalDegraded + summary.totalFailed}`);
Handling oneof Types
Several responses use protobuf oneof fields, which map to discriminated unions in TypeScript.
MonitorConfig (getMonitor)
const { monitor } = await client.monitor.v1.MonitorService.getMonitor({
id: "mon_123",
});
switch (monitor?.config.case) {
case "http":
// monitor.config.value is HTTPMonitor
console.log(`URL: ${monitor.config.value.url}`);
break;
case "tcp":
// monitor.config.value is TCPMonitor
console.log(`URI: ${monitor.config.value.uri}`);
break;
case "dns":
// monitor.config.value is DNSMonitor
console.log(`Domain: ${monitor.config.value.uri}`);
break;
}
NotificationData (createNotification)
The data.data field selects the provider-specific configuration:
// The case string matches the provider in camelCase
data: {
data: { case: "slack", value: { webhookUrl: "..." } }
}
data: {
data: { case: "googleChat", value: { webhookUrl: "..." } }
}
data: {
data: { case: "grafanaOncall", value: { webhookUrl: "..." } }
}
Status Page Identifiers
getStatusPageContent and getOverallStatus accept a page identifier by ID or slug:
// By ID
{ identifier: { case: "id", value: "page_123" } }
// By slug
{ identifier: { case: "slug", value: "my-service" } }
Unsubscribe Identifier
unsubscribeFromPage accepts an email or subscriber ID:
// By email
{ identifier: { case: "email", value: "user@example.com" } }
// By subscriber ID
{ identifier: { case: "id", value: "sub_456" } }
Migrating from Default Client to createFTStatusClient
Before — manual headers on every call:
import { openstatus } from "@openstatus/sdk-node";
const headers = { "x-openstatus-key": process.env.OPENSTATUS_API_KEY };
const { httpMonitors } = await openstatus.monitor.v1.MonitorService
.listMonitors({}, { headers });
const { monitor } = await openstatus.monitor.v1.MonitorService
.createHTTPMonitor({
monitor: { name: "API", url: "https://example.com", periodicity: 2, active: true },
}, { headers });
After — configure once, use everywhere:
import { createFTStatusClient, Periodicity } from "@openstatus/sdk-node";
const client = createFTStatusClient({
apiKey: process.env.OPENSTATUS_API_KEY,
});
const { httpMonitors } = await client.monitor.v1.MonitorService
.listMonitors({});
const { monitor } = await client.monitor.v1.MonitorService
.createHTTPMonitor({
monitor: {
name: "API",
url: "https://example.com",
periodicity: Periodicity.PERIODICITY_1M,
active: true,
},
});
