Skip to main content

Send in-app notifications from Node.js

Three endpoints and no queue to run. Send a notification to a user id from your server or an agent, read unread ones from the browser, mark them read.

Keys

Sending uses a secret key on your server. Polling from the browser uses a publishable key. Create both under Dashboard → API keys.

Publishable key pasted into the page that embeds the form
NORDVA_SECRET_KEY=nv_live_…

01Server: Node.js

notify.ts

export async function notifyUser(input: Record<string, unknown>) {
  const res = await fetch("https://api.nordva.dev/v1/notifications", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.NORDVA_SECRET_KEY!}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      user_id: input.user_id,
      title: "Export ready",           // ≤ 120 chars
      body: "Your CSV is ready to download.", // ≤ 500 chars
      action_url: "https://app.example.com/exports",
      icon: "check",                   // check | warning | info | error
    }),
  });
  if (!res.ok) {
    const { error } = await res.json();
    throw new Error(`${error.code}: ${error.message}`);
  }
  const { data } = await res.json();
  // data.id — send an Idempotency-Key header to make retries safe
  return data;
}

The notifications API is available on the Builder plan; other plans receive PLAN_UPGRADE_REQUIRED.

02Verify from a terminal

curl -s "https://api.nordva.dev/v1/notifications/unread?user_id=user_123" \
  -H "Authorization: Bearer nv_live_…" | jq '.data.notifications | length'

Behaviour worth knowing

  • Every response is { data, error, meta }. On failure error.code is a stable string such as VALIDATION_ERROR, PLAN_LIMIT_REACHED or RATE_LIMITED, with a remediation message.
  • POST and PATCH requests accept an Idempotency-Key header; the same key with the same body returns the original response for 24 hours.
  • Rate limits per key: 30 requests a minute on Free, 120 on Indie, 500 on Builder. A 429 carries Retry-After.
  • Browser calls with a publishable key must come from an origin registered on the project, otherwise the API answers ORIGIN_NOT_ALLOWED.