> ## 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 Event Tracking SDK

> Track events from your backend with the Notifizz SDK — Node, Java, or PHP. Emit one event, the orchestrator builds recipients and dispatches notifications server-side.

# Notifizz Event Tracking SDK

Event tracking is how your backend tells Notifizz that something happened. You emit one event with a flat `track(eventName, properties)` call, and the Notifizz orchestrator resolves campaigns, builds recipients, and dispatches notifications across every channel — no client-side workflow or recipient targeting.

## TL;DR

* **One call, server-side routing.** `client.track(eventName, properties)` is the only method you need to send. Campaign matching, enrichment, and channel dispatch happen in Notifizz.
* **Three SDKs, same wire format.** Node, Java, and PHP all post to `POST /v1/events/track` with the same payload shape.
* **Idempotency built in.** Every `track()` call carries an idempotency key (auto-generated UUID by default, caller-supplied when retrying jobs).
* **Retries built in.** Each SDK retries transient failures twice (`1s`, then `2s`) before bubbling the error.
* **Enrichers are Node-only today.** Java and PHP can still receive enriched data — they just can't *expose* enrichers. Parity is on the roadmap.

## Available SDKs

<CardGroup cols={3}>
  <Card title="Node.js" icon="node-js" href="/docs/sdks/event-tracking/node-js">
    `@notifizz/nodejs` — full surface including the enricher subsystem and the body-only `dispatch()` webhook entry point.
  </Card>

  <Card title="Java / Kotlin" icon="java" href="/docs/sdks/event-tracking/java">
    `com.notifizz:notifizz-java` — Maven Central package for JVM applications.
  </Card>

  <Card title="PHP" icon="php" href="/docs/sdks/event-tracking/php">
    `notifizz/php` — Composer package for PHP applications.
  </Card>
</CardGroup>

## Cross-language feature matrix

| Capability                                                 | Node     | Java                               | PHP                           |
| ---------------------------------------------------------- | -------- | ---------------------------------- | ----------------------------- |
| `track(eventName, properties, options?)`                   | ✅        | ✅ (overload with `idempotencyKey`) | ✅ (`?string $idempotencyKey`) |
| Auto-generated idempotency key                             | ✅ (UUID) | ✅ (UUID)                           | ✅ (random hex)                |
| Caller-supplied idempotency key                            | ✅        | ✅                                  | ✅                             |
| Retry on transient failure (1s, 2s)                        | ✅        | ✅                                  | ✅                             |
| `generateHashedToken(userId)`                              | ✅        | ✅                                  | ✅                             |
| `config({ baseUrl })`                                      | ✅        | ✅                                  | ✅                             |
| Expose enrichers (`enricher()` + `dispatch(body)`)         | ✅        | —                                  | —                             |
| Declare events with schema (`declareEvent(name, options)`) | ✅        | —                                  | —                             |
| Schema validation modes (`schemaMode: 'soft' \| 'strict'`) | ✅        | —                                  | —                             |
| Bundled Zod re-export                                      | ✅        | n/a                                | n/a                           |

<Note>
  The enricher subsystem (registering server-side resolvers that the Notifizz orchestrator calls back via HMAC-signed webhooks) ships only with the Node SDK today. A campaign that runs on Java or PHP backends can still consume enriched data — the enrichers themselves just need to be hosted from a Node service. Java/PHP parity is on the roadmap; track the docs gap audit for status.
</Note>

## Wire format

All three SDKs hit the same backend endpoint:

```http theme={null}
POST /v1/events/track
Authorization: Bearer <sdkSecretKey>
X-Idempotency-Key: <idempotencyKey>
Content-Type: application/json

{
  "eventName": "order.shipped",
  "properties": { "orderId": "ORD-4521", "userId": "u_42" },
  "sdkSecretKey": "<sdkSecretKey>",
  "idempotencyKey": "<idempotencyKey>"
}
```

The full DTO and idempotency contract are in the [Event Tracking reference](/docs/sdks/event-tracking/overview).

## FAQ

<AccordionGroup>
  <Accordion title="Which SDK should I pick?">
    Use the SDK that matches your backend runtime. There is no functional gap between them for `track()`. The only feature delta is the **enricher subsystem**, which is Node-only today — if your campaigns need server-side enrichment, host the enrichers from a Node service (the rest of your stack stays in Java or PHP).
  </Accordion>

  <Accordion title="Why is there no `send()` method anymore?">
    `client.send(...)` and the `POST /v1/notification/.../track` route were removed. The whole platform is now event-driven: emit an event, let a campaign decide the channel and the recipients. Migrating is a one-line change to `client.track(eventName, properties)`.
  </Accordion>

  <Accordion title="What if I need to send to a specific list of recipients?">
    Put the recipient identifiers in the event properties (`{ userId, email, ... }`) and let the campaign's orchestrator resolve them — directly, via an enricher, or via a [dynamic recipient source](/docs/concepts/recipients). The shape "one event per audience" is intentional: it keeps the recipient resolution server-side and traceable.
  </Accordion>

  <Accordion title="Can I batch several events in one call?">
    Not today. Each `track()` call is one event. If you need to emit many events at once, fire them in parallel from your code — the SDK retries each one independently and idempotency keys prevent duplicates.
  </Accordion>

  <Accordion title="What does `{ duplicate: true }` mean in the response?">
    The backend has already accepted an event with the same idempotency key. This is the success path for a retried emit — your code does not need to do anything. See the [Event Tracking reference](/docs/sdks/event-tracking/overview) for the full response shape.
  </Accordion>

  <Accordion title="My language isn't listed — can I still call the API?">
    Yes. The wire format is plain HTTP+JSON — see the [Event Tracking reference](/docs/sdks/event-tracking/overview). Any language that can make an authenticated POST works. The SDKs only add idempotency-key generation, retries, and HMAC token helpers on top.
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="Backend quickstart" icon="rocket" href="/docs/quickstart/backend">
    Send your first event in under five minutes.
  </Card>

  <Card title="Event Tracking reference" icon="code" href="/docs/sdks/event-tracking/overview">
    Full HTTP wire format, idempotency contract, error shapes.
  </Card>

  <Card title="Notification Center widget" icon="bell" href="/docs/sdks/notification-center/overview">
    Display the notifications your events drive.
  </Card>

  <Card title="Authentication overview" icon="key" href="/docs/sdks/authentication/overview">
    Pick the right widget auth mode for your stack.
  </Card>
</CardGroup>
