Skip to content

TypeScript SDK

With @todoke/sdk, you can implement everything from subscription registration to sending notifications in just a few lines.

Terminal window
npm install @todoke/sdk
import { PushCF } from "@todoke/sdk";
const client = new PushCF({
apiKey: "pk_your_key",
// baseUrl: "https://api.todoke.dev" // default value
});

A PushCF instance provides the following three methods.

MethodDescriptionRequired scope
notify(payload: NotifyPayload): Promise<void>Sends a notification (POST /api/v1/notify)notify or higher
subscribe({ registration }: SubscribeOptions): Promise<void>Registers the browser’s Push subscriptionsubscribe_only or higher
getStats(): Promise<Stats>Retrieves statistics (GET /api/v1/stats)notify or higher
// Wait for Service Worker to be ready (place /sw.js in advance)
const registration = await navigator.serviceWorker.ready;
// Register subscription (browser notification permission dialog appears)
await client.subscribe({ registration });

subscribe performs the following three stages in order internally.

  1. Calls GET /api/v1/vapid-public-key to retrieve the app’s VAPID public key
  2. Calls registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey }) with the retrieved key as applicationServerKey (this is where the browser notification permission dialog appears)
  3. Registers the created subscription info (endpoint / p256dh / auth) with the server via POST /api/v1/subscriptions
// Send to all subscribers
await client.notify({
title: "Announcement",
body: "You have a new message",
url: "https://yourapp.com/messages",
icon: "https://yourapp.com/icon.png",
});
// Send to a specific subscriber
await client.notify({
title: "For you",
body: "Targeted notification",
endpoint: "https://push.example.com/specific-endpoint",
});
const stats = await client.getStats();
// {
// activeSubscribers: number,
// totalSent: number,
// totalFailed: number,
// monthlySent: number
// }

notify / subscribe / getStats all throw a PushCFError when the API returns an error response. PushCFError has status (the HTTP status code) and code (the API’s error code string; see the error code list) properties.

import { PushCF, PushCFError } from "@todoke/sdk";
try {
await client.notify({ title: "Test", body: "Send" });
} catch (err) {
if (err instanceof PushCFError) {
console.error(`[${err.code}] ${err.message} (status: ${err.status})`);
}
}

Example of branching on a typical error code:

import { PushCF, PushCFError } from "@todoke/sdk";
try {
await client.notify({ title: "hi", body: "yo" });
} catch (err) {
if (err instanceof PushCFError && err.code === "MONTHLY_LIMIT_EXCEEDED") {
// Monthly limit reached. Wait until next month or upgrade your plan
}
}
type PushCFOptions = {
apiKey: string;
baseUrl?: string; // defaults to "https://api.todoke.dev"
};
type NotifyPayload = {
title: string;
body: string;
url?: string; // https:// only
icon?: string; // https:// only
badge?: string; // https:// only
endpoint?: string; // if specified, sends only to this subscriber
};
type SubscribeOptions = {
registration: ServiceWorkerRegistration; // registered Service Worker
};
type Stats = {
activeSubscribers: number;
totalSent: number;
totalFailed: number;
monthlySent: number;
};