> ## 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 Java SDK Reference

> Java and Kotlin reference for notifizz-java — track events from the JVM, generate widget auth tokens, configure base URL.

# Notifizz Java SDK reference

`com.notifizz:notifizz-java` is the JVM SDK for tracking events. It exposes `track()` overloads, a hashed-token helper for widget auth, and works the same from Java or Kotlin. The package is published to [Maven Central](https://central.sonatype.com/artifact/com.notifizz/notifizz-java).

## TL;DR

* `new NotifizzClient(authSecretKey, sdkSecretKey)` — two-argument constructor (no `webhookSigningSecret`, since the JVM SDK doesn't expose enrichers).
* `client.track(eventName, properties)` — emits one event; throws `IOException` on transient failures after retries.
* `client.track(eventName, properties, idempotencyKey)` — overload for retried jobs.
* Each `track()` retries twice (1s, then 2s) before bubbling `IOException`.
* The enricher subsystem is **Node-only today** — Java backends consume enriched data normally, but cannot host enrichers.

## Installation

<Tabs>
  <Tab title="Maven">
    ```xml theme={null}
    <dependency>
        <groupId>com.notifizz</groupId>
        <artifactId>notifizz-java</artifactId>
        <version>1.0.0</version>
    </dependency>
    ```
  </Tab>

  <Tab title="Gradle (Kotlin DSL)">
    ```kotlin theme={null}
    dependencies {
        implementation("com.notifizz:notifizz-java:1.0.0")
    }
    ```
  </Tab>

  <Tab title="Gradle (Groovy)">
    ```groovy theme={null}
    dependencies {
        implementation "com.notifizz:notifizz-java:1.0.0"
    }
    ```
  </Tab>
</Tabs>

No custom repository or credentials are required — Maven Central is used by default.

## Constructor

```java theme={null}
import com.notifizz.NotifizzClient;

NotifizzClient client = new NotifizzClient(
    System.getenv("NOTIFIZZ_AUTH_SECRET_KEY"),
    System.getenv("NOTIFIZZ_SDK_SECRET_KEY")
);
```

| Parameter       | Type     | Description                                                          |
| --------------- | -------- | -------------------------------------------------------------------- |
| `authSecretKey` | `String` | Used by `generateHashedToken()` for widget backend-token auth.       |
| `sdkSecretKey`  | `String` | Used as the Bearer token on the tracking API and posted in the body. |

## `client.track(eventName, properties)`

Emits a single event. Notifizz resolves campaigns by `eventName` and runs each campaign's orchestrator server-side to build the recipient list — there is no client-side workflow or recipient targeting.

```java theme={null}
import java.util.Map;

client.track("order.shipped", Map.of(
    "orderId", "ORD-4521",
    "userId", "u_42",
    "carrier", "FedEx"
));
```

### `client.track(eventName, properties, idempotencyKey)`

Overload with an explicit idempotency key. Use this when the same logical emit may run twice (retry, dedupe).

```java theme={null}
client.track(
    "order.shipped",
    Map.of("orderId", "ORD-4521", "userId", "u_42"),
    "order-shipped:ORD-4521"
);
```

### Parameters

| Parameter        | Type                  | Description                                                                      |
| ---------------- | --------------------- | -------------------------------------------------------------------------------- |
| `eventName`      | `String`              | Canonical event name. Must match the event you registered in the dashboard.      |
| `properties`     | `Map<String, Object>` | Arbitrary key-value data passed to campaigns. `null` is treated as an empty map. |
| `idempotencyKey` | `String`              | Caller-supplied dedupe key. `null` generates a UUID. Only on the 3-arg overload. |

### Behaviour

* Posts `{ eventName, properties, sdkSecretKey, idempotencyKey }` to `POST /v1/events/track`.
* Sends `Authorization: Bearer <sdkSecretKey>` and `X-Idempotency-Key: <idempotencyKey>`.
* Retries transient failures twice (1s, then 2s) — three total attempts.
* Throws `java.io.IOException` if all attempts fail or the response status is `>= 400`.

### Kotlin

The SDK works naturally with Kotlin — the same `Map.of` / `mapOf` interop applies:

```kotlin theme={null}
val client = NotifizzClient(
    System.getenv("NOTIFIZZ_AUTH_SECRET_KEY"),
    System.getenv("NOTIFIZZ_SDK_SECRET_KEY"),
)

client.track("order.shipped", mapOf(
    "orderId" to "ORD-4521",
    "userId" to "u_42",
))

// With idempotency key:
client.track(
    "order.shipped",
    mapOf("orderId" to "ORD-4521"),
    "order-shipped:ORD-4521",
)
```

## `client.generateHashedToken(userId)`

Generates the SHA-256 of `userId + authSecretKey`. Pass it to your frontend so the Notification Center widget can authenticate in `backendToken` mode.

```java theme={null}
String token = client.generateHashedToken("u_42");
```

| Parameter | Type     | Description                                                                    |
| --------- | -------- | ------------------------------------------------------------------------------ |
| `userId`  | `String` | The user's unique identifier — must match the `userId` you pass to the widget. |

**Returns** — `String`, hex-encoded SHA-256.

See [backend tokens](/docs/sdks/authentication/backend-tokens) for the widget side.

## `client.config(opts)`

Overrides default options. Currently only `baseUrl` is configurable.

```java theme={null}
client.config(Map.of("baseUrl", "https://eu.api.notifizz.com/v1"));
```

| Option    | Default                          | Description                     |
| --------- | -------------------------------- | ------------------------------- |
| `baseUrl` | `https://eu.api.notifizz.com/v1` | Base URL for all SDK API calls. |

## Enrichers — Node-only today

The enricher subsystem (registering server-side resolvers that the orchestrator calls back via HMAC-signed webhooks) ships only with the Node SDK today. A Java backend can still consume enriched data normally — campaigns receive enriched inputs the same way regardless of where the enricher is hosted. If your campaigns need server-side enrichment, host the enrichers from a Node service alongside your Java application. Java parity is on the roadmap.

See the [enrichers protocol reference](/docs/sdks/event-tracking/enrichers-protocol) for the wire format if you decide to implement an enricher endpoint manually in Java.

## Error handling

`track()` declares `throws IOException`. Wrap it where you need a custom log line:

```java theme={null}
try {
    client.track("order.shipped", Map.of("orderId", orderId));
} catch (IOException e) {
    logger.error("notifizz track failed for order " + orderId, e);
    throw new RuntimeException(e);
}
```

After three failed attempts, the last `IOException` is rethrown — the SDK does not silently swallow failures.

The full error catalogue (including HTTP status mappings) is in [error catalogue](/docs/sdks/error-catalogue).

## FAQ

<AccordionGroup>
  <Accordion title="Why does `track()` throw `IOException`?">
    Tracking is a network call to `POST /v1/events/track`. After the SDK exhausts its 3 retry attempts, the underlying `IOException` (or a wrapped one for `>= 400` HTTP statuses) is rethrown. Always handle it — silent network failures are a foot-gun.
  </Accordion>

  <Accordion title="Should I generate the idempotency key myself?">
    Yes when the same logical emit may be retried (queued jobs, scheduler, retry middleware). Use a deterministic key derived from your domain — `order-shipped:{orderId}` is better than `UUID.randomUUID()` from outside the SDK, which generates a new key per attempt and defeats the dedupe.
  </Accordion>

  <Accordion title="Can I host an enricher from my Java service?">
    Not via the SDK today. The enricher subsystem ships only with `@notifizz/nodejs`. If you need an enricher right now, host a small Node service alongside your Java app (the [enrichers tutorial](/docs/sdks/how-to/enrichers-tutorial) walks through it). If you're comfortable implementing the wire protocol manually, see the [enrichers protocol reference](/docs/sdks/event-tracking/enrichers-protocol) — it's a plain HTTP+HMAC contract.
  </Accordion>

  <Accordion title="Is `track()` blocking?">
    Yes — `track()` is synchronous and the SDK retries failures with 1s + 2s delays, so a degraded backend can stall the calling thread for up to \~3s. Run it on an `ExecutorService` or virtual thread when latency matters.
  </Accordion>

  <Accordion title="How do I configure a custom base URL for staging?">
    Call `client.config(Map.of("baseUrl", "..."))` after construction. The SDK reads the option on every `track()` call. Use this for local mocks, regional endpoints, or staging environments — production is `https://eu.api.notifizz.com/v1`.
  </Accordion>

  <Accordion title="Can I batch several events in one call?">
    Not today. Each `track()` call is one event. Fire them in parallel with an executor when batching matters; idempotency keys ensure retries dedupe at the backend.
  </Accordion>
</AccordionGroup>

## See also

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

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

  <Card title="Event Tracking overview" icon="satellite-dish" href="/docs/sdks/event-tracking/overview">
    Cross-language feature matrix.
  </Card>

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