Quickstart

Register, create a project, add the bell to your app and send your first notification.

This guide takes you from a new account to a notification showing up in your app. You need a backend that can make HTTPS requests and a web or React Native app with signed-in users.

1

Register and start your trial

Register at notificationstream.com. Right after, the dashboard asks you to pick a plan (preselected if you chose one on the pricing page) and complete the Stripe checkout. Every plan starts with a 3-day free trial. Until your organization has an active or trialing subscription, the dashboard stays on that step and the REST API rejects writes (such as sending a notification) with 402 payment_required. See Billing and limits.

2

Create a project

In the dashboard, create a project for each app and environment, for example "Acme (production)" and "Acme (staging)". Projects never share project users or notifications. Starter includes one project, Growth five and Scale unlimited. Set the default locale to the language most of your users read.

3

Save your keys

Creating a project also creates its first keys:

KeyLooks likeWhere it goes
Publishable keypk_…Your frontend. Safe to ship in browsers and apps.
Signing keyA private key PEMYour backend only. Signs user tokens.
Secret keysk_…Your backend only. Sends notifications through the REST API.

The dashboard shows the backend keys once, as a .env block to copy or download: NOTIFICATIONSTREAM_SECRET_KEY and NOTIFICATIONSTREAM_SIGNING_KEY (the PEM). The private signing key is generated in your browser and never sent to NotificationStream. If you lose a key, create a new one on the project's API keys page. The project page then walks you through the remaining steps with your publishable key already filled in.

4

Sign a user token on your backend

The SDK must prove which user it is acting for with a user token: a short-lived ES256 JWT whose sub is the user id, signed with your signing key. Add an endpoint that returns one for the signed-in user:

app/api/notifications/token/route.ts
import { createUserToken } from "@notificationstream/node";
import { getSession } from "@/lib/auth";

export async function GET() {
  const session = await getSession();
  if (!session) return new Response("Unauthorized", { status: 401 });
  const token = await createUserToken(process.env.NOTIFICATIONSTREAM_SIGNING_KEY!, session.user.id);
  return new Response(token, { headers: { "Cache-Control": "no-store" } });
}

Tokens last an hour by default. Other languages are in Identity verification.

5

Install an SDK and render the bell

Pass the publishable key, the signed-in user (with the same id you signed) and the user token from the previous step. A function lets the SDK fetch a new token when the old one expires.

pnpm add @notificationstream/js
import { createNotificationClient } from "@notificationstream/js";

const client = createNotificationClient({
  publishableKey: "pk_…",
  user: { id: user.id, name: user.name },
  token: () => fetch("/api/notifications/token").then((r) => r.text()),
});

// Render your own bell and inbox from the state.
client.subscribe((state) => {
  renderBadge(state.unseenCount);
  renderList(state.items);
});

The JavaScript SDK has no bundled UI; its headless UI core gives your components the same behaviour as the React ones.

The SDK loads the feed and applies your dashboard theme. It refetches when users come back to your app. To update an open screen, call useRealtime() in a component under the provider (or client.realtime(); Growth plan and up), and usePolling(60_000) (or client.poll(60_000)) to also check on a timer while realtime isn't connected. See Polling, realtime and performance and the SDK pages for every option.

6

Send your first notification

From your backend, with the secret key:

curl https://api.notificationstream.com/v1/notifications \
  -H "Authorization: Bearer $NOTIFICATIONSTREAM_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: welcome-user_123" \
  -d '{
    "audience": { "type": "users", "userIds": ["user_123"] },
    "contents": {
      "en": {
        "title": "Welcome aboard!",
        "body": "Your organization is ready. Invite your team to get started.",
        "actionLabel": "Invite people"
      }
    },
    "category": "onboarding",
    "actionUrl": "/settings/team"
  }'

The response is 201 Created with the stored notification ("status": "published"). On the Growth plan and up you can greet users by name with a template such as {{user.name | there}}. With the Node SDK the same call is await ns.notifications.create({ audience, contents, category, actionUrl }).

7

Watch it arrive

The bell picks it up on its next fetch: right away with realtime, otherwise when you reload the page, switch back to its tab, or after one poll interval if you poll. Without realtime, notifications sent to all, tags or segments can take up to about 30 seconds longer, because the broadcast list is cached per project. To check from the server side, read the user's feed:

curl "https://api.notificationstream.com/v1/project-users/user_123/feed" \
  -H "Authorization: Bearer $NOTIFICATIONSTREAM_SECRET_KEY"

User ids

The user id is your own stable id for the user (a database id, not an email that can change). You can target users by id before they ever open your app: they are created as placeholder project users and see the notification on their first visit.

Next steps