> ## Documentation Index
> Fetch the complete documentation index at: https://notifizz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Notifizz Backend Quickstart

> Install the Notifizz Node SDK and send your first notification in under five minutes — track an event, watch the campaign fire, see the message land.

# Notifizz backend quickstart

Send your first event from a backend in under five minutes. The SDK call is one line; Notifizz resolves the campaign, builds the recipients, and dispatches the notification — all server-side.

## TL;DR

* Install `@notifizz/nodejs` (or the Java / PHP SDK).
* Construct the client with your **auth secret** + **SDK secret**.
* Call `await client.track(eventName, properties, { idempotencyKey })`.
* The backend acks within milliseconds; the campaign runs asynchronously.

<Info>
  Get your **Auth Secret Key** and **SDK Secret Key** from the [Notifizz dashboard](https://notifizz.com) under your environment settings. Keys are scoped per environment (dev / prod) — see [keys and environments](/docs/environments/api-keys).
</Info>

## 1. Install the SDK

<CodeGroup>
  ```bash npm theme={null}
  npm install @notifizz/nodejs
  ```

  ```bash yarn theme={null}
  yarn add @notifizz/nodejs
  ```

  ```bash pnpm theme={null}
  pnpm add @notifizz/nodejs
  ```
</CodeGroup>

Java and PHP have the same shape — see [Java](/docs/sdks/event-tracking/java) or [PHP](/docs/sdks/event-tracking/php) for their install snippets. The rest of this quickstart uses Node.

## 2. Initialise the client

```javascript theme={null}
import { NotifizzClient } from "@notifizz/nodejs";

const client = new NotifizzClient(
  process.env.NOTIFIZZ_AUTH_SECRET_KEY,
  process.env.NOTIFIZZ_SDK_SECRET_KEY,
);
```

The third constructor argument (`webhookSigningSecret`) is required only if you mount enrichers. Skip it for the quickstart.

## 3. Track your first event

Match the `eventName` to an event you registered in the dashboard (or one tied to an active campaign):

```javascript theme={null}
await client.track("user.signed_up", {
  userId: "u_42",
  email: "alice@example.com",
  plan: "pro",
});
```

That's it. `client.track()` posts to `POST /v1/events/track`, and Notifizz takes over: the event is queued, one workflow instance is created per matching campaign, the AI orchestrator builds the recipient list (calling enrichers to fetch any live data the event didn't carry), and the notification ships through every channel the campaign configures.

<Tip>
  Notice what's *not* in the call: no campaign ID, no recipient list, no template. Routing is server-side — that's the whole point. New campaigns ship without redeploying your code.
</Tip>

## 4. Use idempotency for retried jobs

If the same logical emit may run twice (queue retries, scheduler, retry middleware), set an explicit idempotency key derived from your domain:

```javascript theme={null}
await client.track(
  "order.shipped",
  { orderId: "ORD-4521", userId: "u_42" },
  { idempotencyKey: `order-shipped:ORD-4521` },
);
```

A retried emit with the same key produces the same outcome — the backend responds `{ duplicate: true, idempotencyKey }` and does **not** re-enqueue the campaign.

## 5. Watch retries

The SDK retries transient failures twice (1s, then 2s) before bubbling the error:

```javascript theme={null}
try {
  await client.track("order.shipped", { orderId, userId });
} catch (e) {
  // After 3 total attempts, the original axios error rethrows here.
  logger.error({ err: e, orderId }, "notifizz track failed");
  throw e;
}
```

Don't fire-and-forget without logging — silent network failures hide real outages.

## 6. (Optional) Generate a widget auth token

If your frontend uses [backend-token authentication](/docs/sdks/authentication/backend-tokens), generate a per-user token from the same client:

```javascript theme={null}
const token = client.generateHashedToken("u_42");
// Return this token to your frontend through your own API.
```

Pass it as `token` (along with `userId` + `userEmail`) when initialising the widget — see [frontend quickstart](/docs/quickstart/frontend).

## What just happened

<Steps>
  <Step title="Event accepted">
    `POST /v1/events/track` returned 200 and the SDK resolved its promise.
  </Step>

  <Step title="Campaigns matched">
    Notifizz looked up campaigns wired to `user.signed_up` (or `order.shipped`) in your environment.
  </Step>

  <Step title="Workflow instance created">
    One instance per matching campaign. Each instance has its own recipient list, computed by the orchestrator from your event properties (and any enricher the campaign declares).
  </Step>

  <Step title="Channels dispatched">
    The notification queue (the dispatcher) calls each channel — Notification Center widget, email — with the resolved content.
  </Step>
</Steps>

<Check>
  Open the Notification Center widget for `u_42` (frontend quickstart) and the message appears in real time. No refresh needed.
</Check>

<Tip>
  **Want a measurable programme — fast?** [Notifizz Certified Partners](/docs/partners/certified-partners) are vetted experts who lead complete notification engagements end to end: tagging plan, enrichers wired, AI/MCP configured, first campaigns live, and your team trained to own it. The shortest path from your first event to a programme that pays back. **[Find a partner →](/docs/partners/certified-partners)**
</Tip>

## Troubleshooting

<AccordionGroup>
  <Accordion title="`401 Unauthorized` on `track()`.">
    The `sdkSecretKey` is wrong or scoped to a different environment. Each environment (dev, prod, …) has its own pair — copy the right one from the dashboard. Don't share keys across environments.
  </Accordion>

  <Accordion title="Track returned 200 but no notification arrived.">
    Three checks: (1) is there a campaign in the dashboard listening on this exact `eventName` and is its status `Live` (or `Dev` for dev environments)?; (2) does the campaign's recipient logic resolve from the properties you sent (e.g. `userId` present)?; (3) is the user's widget authenticated with the same `userId`?
  </Accordion>

  <Accordion title="Got `{ duplicate: true }` after a retry — is that an error?">
    No — that's the success path for an idempotent retry. The backend has already processed an event with the same `idempotencyKey`. Your code does not need to do anything.
  </Accordion>

  <Accordion title="Latency on my request handler went up after adding `track()`.">
    `track()` is async and the SDK retries failures with 1s + 2s delays — a degraded backend can stall your handler for up to \~3s. Either fire-and-log (`track().catch(...)` without `await`) or push the emit onto a queue you control.
  </Accordion>

  <Accordion title="Should I generate the idempotency key myself?">
    Yes when the same logical emit may run twice. Use a deterministic key (`order-shipped:${orderId}`), not `crypto.randomUUID()` — random keys defeat the dedupe by producing a new key per attempt.
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="Work with a Certified Partner" icon="handshake" href="/docs/partners/certified-partners">
    Skip the discovery-as-you-go path. Vetted experts run the project end to end.
  </Card>

  <Card title="Frontend quickstart" icon="browser" href="/docs/quickstart/frontend">
    Set up the widget so users see the notifications.
  </Card>

  <Card title="Node.js SDK reference" icon="node-js" href="/docs/sdks/event-tracking/node-js">
    Full API: enrichers, error classes, retry behaviour.
  </Card>

  <Card title="How Notifizz works" icon="diagram-project" href="/docs/concepts/how-it-works">
    The event-driven pipeline, end to end.
  </Card>
</CardGroup>
