Getting Started

Install the alrt SDK and start sending notifications in under 5 minutes. One API key, 6+ channels, zero external account setup.

Installation

$npm install @alrt/node

Initialize the Client

Create an alrt client instance with your server API key. Get your key from the Settings page in the dashboard.

Constructor Options

apiKeystringrequiredYour alrt server API key (alrt_sk_...)
baseUrlstring= "https://api.alrt.dev"Override the API base URL
maxRetriesnumber= 3Max retry attempts for failed requests
timeoutnumber= 30000Request timeout in ms (Node) / seconds (Python)
TypeScript
1import { Alrt } from "@alrt/node";
2
3const client = new Alrt({
4 apiKey: process.env.ALRT_API_KEY,
5});
6
7// Send your first notification
8const result = await client.events.trigger({
9 workflow: "welcome",
10 subscriberId: "user-123",
11 payload: { name: "Alice" },
12});
13
14console.log(result.eventId);
Async Usage
1// Node.js is async by default — no additional setup needed.
2// All methods return Promises.
3const result = await client.events.trigger({ ... });

Authentication

The SDK authenticates via your API key passed to the constructor. alrt supports two key types:

alrt_sk_...
Server Key
Full read/write access. Use server-side only.
alrt_ck_...
Client Key
Read-only. Safe for browser/mobile use.

Keys are SHA-256 hashed before storage. The raw key is only shown once at creation time. Manage keys in the dashboard under Settings → API Keys.

TypeScript
1// Server-side (Next.js API route, Express, etc.)
2import { Alrt } from "@alrt/node";
3
4const client = new Alrt({
5 apiKey: process.env.ALRT_API_KEY,
6 // key is sent as: Authorization: Bearer alrt_sk_...
7});
8
9// The SDK automatically includes the key
10// in every request header. No manual setup needed.

Events

Events are the primary way to trigger notification workflows. Each event maps to a workflow you've built in the visual editor.

client.events.trigger(params)

Trigger a notification workflow for a single subscriber. The workflow determines which channels to send on, applies templates, and executes any delay/condition nodes.

ReturnsPromise<TriggerEventResponse>

Parameters

workflowstringrequiredThe workflow name (must match a workflow in the dashboard)
subscriberIdstringoptionalID of an existing subscriber
subscriberSubscriberInlineoptionalInline subscriber object — auto-creates if not found
payloadRecord<string, unknown>optionalDynamic data merged into notification templates
channelsChannel[]optionalRestrict delivery to specific channels
overridesChannelOverridesoptionalPer-channel overrides (email.to, slack.channelId, etc.)
deliverAtstringoptionalISO 8601 timestamp for scheduled delivery
metadataRecord<string, unknown>optionalArbitrary metadata stored with the event
idempotencyKeystringoptionalPrevents duplicate processing of the same event

Errors

400Missing required field: workflow
401Invalid or missing API key
404Subscriber not found (when using subscriberId)
422No workflow found matching the event name
429Rate limit exceeded
TypeScript
1const result = await client.events.trigger({
2 workflow: "order.shipped",
3 subscriberId: "user-456",
4 payload: {
5 orderId: "ORD-789",
6 trackingUrl: "https://track.example.com/789",
7 },
8 channels: ["email", "in_app"],
9 idempotencyKey: "order-shipped-789",
10});
11
12console.log(result.eventId);
13// => "evt_abc123def456"
Response
1{
2 "event_id": "evt_abc123def456",
3 "status": "accepted",
4 "channels_requested": ["email", "in_app"],
5 "channels_matched": ["email", "in_app"],
6 "warnings": [],
7 "scheduled_at": null
8}
client.events.triggerBulk(params)

Trigger a workflow for up to 1,000 subscribers in a single request. Each subscriber is processed independently — partial failures don't block the batch.

ReturnsPromise<TriggerBulkResponse>

Parameters

workflowstringrequiredThe workflow name
subscribersSubscriberInline[]requiredArray of inline subscriber objects (max 1,000)
payloadRecord<string, unknown>optionalShared payload for all subscribers
channelsChannel[]optionalRestrict channels for all subscribers
idempotencyKeystringoptionalDeduplication key for the entire batch
TypeScript
1const result = await client.events.triggerBulk({
2 workflow: "weekly-digest",
3 subscribers: [
4 { id: "user-1", email: "alice@co.com" },
5 { id: "user-2", email: "bob@co.com" },
6 { id: "user-3", email: "carol@co.com" },
7 ],
8 payload: { weekOf: "2026-03-15" },
9});
10
11console.log(result.accepted); // => 3
12console.log(result.errors); // => 0
Response
1{
2 "batch_id": "batch_xyz789",
3 "status": "accepted",
4 "total": 3,
5 "accepted": 3,
6 "duplicates": 0,
7 "errors": 0,
8 "results": [
9 { "subscriber_id": "user-1", "event_id": "evt_1", "status": "accepted" },
10 { "subscriber_id": "user-2", "event_id": "evt_2", "status": "accepted" },
11 { "subscriber_id": "user-3", "event_id": "evt_3", "status": "accepted" }
12 ]
13}

Subscribers

Subscribers represent the people who receive your notifications. Each subscriber has channel-specific contact info and delivery preferences.

client.subscribers.create(params)

Create a new subscriber with channel-specific contact information.

ReturnsPromise<SubscriberResponse>

Parameters

externalIdstringrequiredYour system's unique user ID
emailstringoptionalEmail address for email channel
namestringoptionalDisplay name for templates
phoneNumberstringoptionalPhone number for SMS/WhatsApp
slackUserIdstringoptionalSlack user ID for DM delivery
discordWebhookUrlstringoptionalDiscord webhook URL
telegramChatIdstringoptionalTelegram chat ID
customPropertiesRecord<string, unknown>optionalArbitrary metadata for template personalization
channelPreferencesRecord<string, unknown>optionalPer-channel opt-in/out preferences

Errors

400Invalid subscriber data
409Subscriber with this externalId already exists
TypeScript
1const sub = await client.subscribers.create({
2 externalId: "user-456",
3 email: "alice@example.com",
4 name: "Alice Chen",
5 customProperties: {
6 plan: "pro",
7 company: "Acme Corp",
8 },
9});
10
11console.log(sub.id); // internal UUID
client.subscribers.get(subscriberId)

Retrieve a subscriber by their external ID.

ReturnsPromise<SubscriberResponse>

Parameters

subscriberIdstringrequiredThe subscriber's external ID

Errors

404Subscriber not found
TypeScript
1const sub = await client.subscribers.get("user-456");
2
3console.log(sub.email); // "alice@example.com"
4console.log(sub.customProperties); // { plan: "pro" }
client.subscribers.list(params?)

List subscribers with optional pagination.

ReturnsPromise<SubscriberResponse[]>

Parameters

limitnumber= 20Max results per page
offsetnumber= 0Number of results to skip
TypeScript
1const subs = await client.subscribers.list({
2 limit: 50,
3 offset: 0,
4});
5
6for (const sub of subs) {
7 console.log(sub.externalId, sub.email);
8}
client.subscribers.update(subscriberId, params)

Update a subscriber's contact info or custom properties. Only provided fields are changed.

ReturnsPromise<SubscriberResponse>

Parameters

subscriberIdstringrequiredThe subscriber's external ID
emailstringoptionalUpdated email address
namestringoptionalUpdated display name
customPropertiesRecord<string, unknown>optionalUpdated custom properties (merges with existing)

Errors

404Subscriber not found
TypeScript
1const updated = await client.subscribers.update(
2 "user-456",
3 {
4 name: "Alice Chen-Williams",
5 customProperties: { plan: "enterprise" },
6 },
7);
client.subscribers.delete(subscriberId)

Permanently delete a subscriber and all their notification history.

ReturnsPromise<void>

Parameters

subscriberIdstringrequiredThe subscriber's external ID

Errors

404Subscriber not found
TypeScript
1await client.subscribers.delete("user-456");

Preferences

Manage subscriber notification preferences — global channel opt-in/out, per-category settings, do-not-disturb windows, and frequency caps.

client.subscribers.getPreferences(subscriberId)

Get the notification preferences for a subscriber.

ReturnsPromise<PreferencesResponse>

Parameters

subscriberIdstringrequiredThe subscriber's external ID
TypeScript
1const prefs = await client.subscribers
2 .getPreferences("user-456");
3
4console.log(prefs.global);
5// => { email: true, slack: true, in_app: true }
6
7console.log(prefs.dnd);
8// => { timezone: "US/Pacific", start: "22:00", end: "08:00" }
client.subscribers.updatePreferences(subscriberId, prefs)

Update notification preferences. Supports granular per-category and per-channel settings.

ReturnsPromise<PreferencesResponse>

Parameters

subscriberIdstringrequiredThe subscriber's external ID
globalRecord<string, boolean>optionalGlobal channel on/off toggles
categoriesRecord<string, Record<string, boolean>>optionalPer-category channel preferences
dnd{ timezone, start, end }optionalDo-not-disturb window
frequency{ maxPerDay?, maxPerHour? }optionalRate limits per subscriber
TypeScript
1await client.subscribers.updatePreferences(
2 "user-456",
3 {
4 global: { email: true, slack: false },
5 categories: {
6 marketing: { email: false, in_app: true },
7 },
8 dnd: {
9 timezone: "US/Pacific",
10 start: "22:00",
11 end: "08:00",
12 },
13 },
14);

Push Tokens

Register and manage device push tokens for mobile and web push notifications via FCM/APNs.

client.subscribers.registerPushToken(subscriberId, params)

Register a push notification token for a subscriber's device.

ReturnsPromise<PushTokenResponse[]>

Parameters

subscriberIdstringrequiredThe subscriber's external ID
tokenstringrequiredThe FCM/APNs push token
platform"android" | "ios" | "web"requiredDevice platform
deviceIdstringoptionalUnique device identifier for token replacement
TypeScript
1const tokens = await client.subscribers
2 .registerPushToken("user-456", {
3 token: "fcm_dK8x...",
4 platform: "android",
5 deviceId: "pixel-7-abc",
6 });
7
8console.log(tokens.length); // => 1
client.subscribers.listPushTokens(subscriberId)

List all registered push tokens for a subscriber.

ReturnsPromise<PushTokenResponse[]>

Parameters

subscriberIdstringrequiredThe subscriber's external ID
TypeScript
1const tokens = await client.subscribers
2 .listPushTokens("user-456");
3
4for (const t of tokens) {
5 console.log(t.platform, t.token);
6}
client.subscribers.removePushToken(subscriberId, token)

Remove a specific push token from a subscriber (e.g., on logout or token rotation).

ReturnsPromise<PushTokenResponse[]>

Parameters

subscriberIdstringrequiredThe subscriber's external ID
tokenstringrequiredThe push token to remove
TypeScript
1const remaining = await client.subscribers
2 .removePushToken("user-456", "fcm_dK8x...");

Error Handling

The SDK throws typed exceptions for all API errors. All errors extend AlrtError and include status, code, and message properties.

Exception Hierarchy

AlrtAuthError401Invalid or missing API key
AlrtValidationError400/422Invalid request data
AlrtNotFoundError404Resource not found
AlrtConflictError409Resource already exists
AlrtRateLimitError429Rate limit exceeded (includes retryAfter)
AlrtApiError5xxServer error
TypeScript
1import {
2 AlrtError,
3 AlrtAuthError,
4 AlrtRateLimitError,
5 AlrtNotFoundError,
6} from "@alrt/node";
7
8try {
9 await client.events.trigger({
10 workflow: "welcome",
11 subscriberId: "user-123",
12 });
13} catch (err) {
14 if (err instanceof AlrtRateLimitError) {
15 console.log("Retry after:", err.retryAfter);
16 } else if (err instanceof AlrtNotFoundError) {
17 console.log("Subscriber missing:", err.message);
18 } else if (err instanceof AlrtAuthError) {
19 console.error("Check your API key");
20 } else if (err instanceof AlrtError) {
21 console.error(err.status, err.code, err.message);
22 }
23}

Automatic Retries

The SDK automatically retries requests that fail with 429 (rate limit) or 5xx (server error) status codes, using exponential backoff with jitter. Non-retryable errors (400, 401, 404, 409) are thrown immediately.

Max retries
3
Base delay
500ms
Strategy
Exponential + jitter
Retry-After
Respected

WebSocket (In-App Notifications)

For real-time in-app notifications, connect to the WebSocket endpoint using a subscriber-scoped JWT. This is a direct WebSocket connection — no SDK wrapper needed.

How it works

  1. Server-side: call POST /subscribers/:id/token to get a short-lived JWT
  2. Client-side: connect to ws://api.alrt.dev/ws?token=JWT
  3. Receive real-time notification payloads as JSON messages
Note: Subscriber JWTs expire after 1 hour. Implement reconnection logic with token refresh.
TypeScript
1// Server: get subscriber token
2const res = await fetch(
3 "https://api.alrt.dev/subscribers/user-456/token",
4 {
5 method: "POST",
6 headers: {
7 Authorization: "Bearer alrt_sk_...",
8 "Content-Type": "application/json",
9 },
10 }
11);
12const { token } = await res.json();
13
14// Client: connect WebSocket
15const ws = new WebSocket(
16 `wss://api.alrt.dev/ws?token=${token}`
17);
18
19ws.onmessage = (event) => {
20 const notification = JSON.parse(event.data);
21 console.log("New:", notification.title);
22};