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

> PHP reference for notifizz/php — track events from PHP and Laravel, generate widget auth tokens, configure base URL.

# Notifizz PHP SDK reference

`notifizz/php` is the PHP SDK for tracking events. It exposes a single `track()` method, a hashed-token helper for widget auth, and ships on [Packagist](https://packagist.org/packages/notifizz/php).

## TL;DR

* `new NotifizzClient($authSecretKey, $sdkSecretKey)` — two-argument constructor (no `webhookSigningSecret`, since the PHP SDK doesn't expose enrichers).
* `$client->track($eventName, $properties = [], $idempotencyKey = null)` — emits one event; rethrows the underlying Guzzle exception after retries.
* Each `track()` retries twice (1s, then 2s) before bubbling the last exception.
* The enricher subsystem is **Node-only today** — PHP backends consume enriched data normally, but cannot host enrichers.

## Installation

```bash theme={null}
composer require notifizz/php
```

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

## Constructor

```php theme={null}
<?php

require_once __DIR__ . '/vendor/autoload.php';

use Notifizz\NotifizzClient;

$client = new NotifizzClient(
    getenv('NOTIFIZZ_AUTH_SECRET_KEY'),
    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 = [], $idempotencyKey = null)`

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.

```php theme={null}
$client->track('order.shipped', [
    'orderId' => 'ORD-4521',
    'userId'  => 'u_42',
    'carrier' => 'FedEx',
]);

// With a caller-supplied idempotency key (recommended for retried jobs):
$client->track(
    'order.shipped',
    ['orderId' => 'ORD-4521', 'userId' => 'u_42'],
    'order-shipped:ORD-4521'
);
```

### Parameters

| Parameter         | Type      | Default             | Description                                                                     |
| ----------------- | --------- | ------------------- | ------------------------------------------------------------------------------- |
| `$eventName`      | `string`  | —                   | Canonical event name. Must match the event you registered in the dashboard.     |
| `$properties`     | `array`   | `[]`                | Associative array of event data.                                                |
| `$idempotencyKey` | `?string` | `null` (random hex) | Caller-supplied dedupe key. Set this when the same logical emit may be retried. |

### 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.
* Rethrows the last `GuzzleHttp\Exception\GuzzleException` if all attempts fail.

## `$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.

```php theme={null}
$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.

```php theme={null}
$client->config(['baseUrl' => 'https://eu.api.notifizz.com/v1']);
```

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

## Laravel example

In a Laravel application, register the client as a singleton:

```php theme={null}
// app/Providers/AppServiceProvider.php
use Notifizz\NotifizzClient;

public function register(): void
{
    $this->app->singleton(NotifizzClient::class, function () {
        return new NotifizzClient(
            config('services.notifizz.auth_secret'),
            config('services.notifizz.sdk_secret'),
        );
    });
}
```

Then inject it where you need it:

```php theme={null}
use Notifizz\NotifizzClient;

class OrderController extends Controller
{
    public function ship(Order $order, NotifizzClient $notifizz)
    {
        // ... ship the order ...

        $notifizz->track('order.shipped', [
            'orderId' => $order->id,
            'userId'  => (string) $order->user_id,
            'carrier' => $order->carrier,
        ], "order-shipped:{$order->id}");
    }
}
```

## 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 PHP 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 PHP application. PHP 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 PHP.

## Error handling

`track()` rethrows the last Guzzle exception after exhausting retries. Wrap it where you need a custom log line:

```php theme={null}
try {
    $client->track('order.shipped', ['orderId' => $orderId]);
} catch (\GuzzleHttp\Exception\GuzzleException $e) {
    Log::error('notifizz track failed', [
        'orderId' => $orderId,
        'message' => $e->getMessage(),
    ]);
    throw $e;
}
```

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

## FAQ

<AccordionGroup>
  <Accordion title="Why does `track()` rethrow Guzzle exceptions?">
    Tracking is a network call to `POST /v1/events/track`. After the SDK exhausts its 3 retry attempts, the last `GuzzleHttp\Exception\GuzzleException` is rethrown. Catch it explicitly — 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, retry middleware). Use a deterministic key derived from your domain — `"order-shipped:{$orderId}"` is better than `bin2hex(random_bytes(16))` 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 PHP 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 PHP 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 request for up to \~3s. In Laravel, dispatch tracking from a queued job when latency matters.
  </Accordion>

  <Accordion title="How do I configure a custom base URL for staging?">
    Call `$client->config(['baseUrl' => '...'])` after construction. The SDK reads the option on every `track()` call. Use it 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. Use Laravel's queue or a Symfony Messenger transport to fire many events in parallel; 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>
