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

# PHP SDK - API Reference

> Every public method on NexusClient with signatures, parameters, return values, and thrown exceptions.

Every public symbol in `westyx/nexus`. All read methods (`getConfig`, `getSecret`, `getFlag`, etc.) are non-blocking - they hit the in-memory cache. Only `NexusClient::create`, `sync`, and `evaluateAb` make network calls.

## Construction

### `NexusClient::create(NexusConfig $config, ?GuzzleClient $http = null): static`

Creates a client and runs a **blocking** initial sync. Returns the populated client. Throws on failure.

```php theme={null}
use WestyxNexus\NexusClient;
use WestyxNexus\NexusConfig;

$client = NexusClient::create(new NexusConfig(
    baseUrl: $_ENV['NEXUS_URL'],
    apiKey:  $_ENV['NEXUS_API_KEY'],
));
```

| Parameter | Type            | Description                                                                      |
| --------- | --------------- | -------------------------------------------------------------------------------- |
| `$config` | `NexusConfig`   | Required. See [Configuration](configuration).                                    |
| `$http`   | `?GuzzleClient` | Optional. Custom Guzzle client. SDK builds a default (10 s timeout) when `null`. |

Throws:

* `NexusUnauthorizedException` - initial sync returned 401
* `NexusBillingException` - initial sync returned 402
* `NexusNotFoundException` - initial sync returned 404

## Configs

### `getConfig(string $key, mixed $default = null): mixed`

Returns the resolved config value, or `$default` when the key is absent.

```php theme={null}
$dbUrl = $client->getConfig('database.url');          // null if not found
$port  = $client->getConfig('server.port', 8080);    // 8080 if not found
```

The value mirrors the wire-level JSON type: `string`, `int`, `float`, `bool`, `array`, or `null`. Cast or validate as needed.

### `getAllConfigs(): array`

Returns a snapshot copy of every config key-value pair currently in the cache. The returned array is independent of the SDK's internal storage - mutating it has no effect.

```php theme={null}
foreach ($client->getAllConfigs() as $key => $value) {
    echo "{$key}: " . json_encode($value) . PHP_EOL;
}
```

## Feature flags

### `getFlag(string $key, bool $default = false): bool`

Returns the `is_active` state of a flag, or `$default` when the key is absent.

```php theme={null}
$isOn = $client->getFlag('checkout.v2', false);
```

The server computes `is_active` (combining `is_enabled`, `starts_at`, `ends_at`); the SDK never makes that call itself.

### `getAllFlags(): array`

Returns a snapshot copy of every flag key-is\_active pair in the cache. Keys are strings, values are booleans.

```php theme={null}
$flags = $client->getAllFlags();
// ['checkout.v2' => true, 'dark-mode' => false, ...]
```

## Secrets (secret key only)

<Warning>
  All secret methods throw `NexusPublicKeyException` synchronously when the client uses a public key - before any network call.
</Warning>

### `getSecret(string $key): ?string`

Returns the plaintext value of a **text-type** secret, or `null` when the key is absent or the secret is file-type.

```php theme={null}
$password = $client->getSecret('DB_PASSWORD');
if ($password === null) {
    throw new \RuntimeException('nexus: missing DB_PASSWORD secret');
}
```

Returns `null` (does not throw) when:

* The key does not exist in the cache
* The secret has `type = 'file'` - use `getSecretFilePath` instead

Throws:

* `NexusPublicKeyException` - client uses a public key

### `getSecretFilePath(string $key): ?string`

Returns the temp-file path holding the value of a **file-type** secret, or `null` when the key is absent or the secret is text-type.

```php theme={null}
$certPath = $client->getSecretFilePath('TLS_CERT');
if ($certPath === null) {
    throw new \RuntimeException('nexus: TLS_CERT is missing or not a file-type secret');
}
// Pass $certPath to openssl, curl CURLOPT_SSLCERT, etc.
```

The SDK materialises every `file`-type secret to a temp file on every sync. The file path includes a hash of the value - when the secret changes on the server the path changes and the old file is removed. Files are written mode `0600`. Temp files are deleted in `__destruct`.

Returns `null` when:

* The key does not exist in the cache
* The secret has `type = 'text'` - use `getSecret` instead

Throws:

* `NexusPublicKeyException` - client uses a public key

## Write API (secret key only)

<Warning>
  Write methods require a secret key. A public key throws `NexusPublicKeyException` before making any network call. All write methods call the API directly and do not update the local cache - call `sync()` afterward if you need the new value immediately.
</Warning>

### `setSecret(string $key, string $value, string $type = 'text'): void`

Creates or updates a secret. `$type` must be `'text'` or `'file'`.

```php theme={null}
$client->setSecret('STRIPE_KEY', 'sk_live_abc123');
$client->setSecret('TLS_CERT', $certPem, 'file');
```

Throws:

* `NexusPublicKeyException` - client uses a public key
* `NexusUnauthorizedException` - 401
* `NexusBillingException` - 402
* `NexusNotFoundException` - 404 (unknown service)
* `NexusRateLimitedException` - 429

### `deleteSecret(string $key): void`

Deletes all versions of a secret.

```php theme={null}
$client->deleteSecret('OLD_API_KEY');
```

Throws:

* `NexusPublicKeyException` - client uses a public key
* `NexusUnauthorizedException` - 401
* `NexusBillingException` - 402
* `NexusNotFoundException` - 404 (secret or service not found)
* `NexusRateLimitedException` - 429

### `deleteSecretVersion(string $key, int $version): void`

Deletes a specific version of a secret. Version numbers are 1-based integers matching the server's version sequence.

```php theme={null}
$client->deleteSecretVersion('DB_PASSWORD', 3);
```

Throws:

* `NexusPublicKeyException` - client uses a public key
* `NexusUnauthorizedException` - 401
* `NexusBillingException` - 402
* `NexusNotFoundException` - 404 (secret, version, or service not found)
* `NexusRateLimitedException` - 429

## A/B Testing

### `evaluateAb(array $keys, string $userId, array $attributes = []): array`

Batch-evaluates feature flags through the **AB Testing** add-on against the supplied user context. Issues a single `POST /v1/flags/evaluate-ab` and returns the results map - flag key to evaluated boolean. Unlike `getFlag`, this method **always** performs a network call and does **not** consult the local cache.

```php theme={null}
$results = $client->evaluateAb(
    keys:       ['checkout.v2', 'homepage.banner'],
    userId:     'user-42',
    attributes: ['country' => 'HU', 'plan' => 'pro'],
);

if ($results['checkout.v2'] ?? false) {
    // bucketed into the new checkout
}
```

| Parameter     | Type     | Description                                                  |
| ------------- | -------- | ------------------------------------------------------------ |
| `$keys`       | `array`  | Flag keys to evaluate.                                       |
| `$userId`     | `string` | Stable user/session identifier for bucketing.                |
| `$attributes` | `array`  | Key-value context for targeting rules (plan, country, etc.). |

Returns `array<string, bool>`. Missing keys in the response default to `false`.

Throws:

* `NexusUnauthorizedException` - 401
* `NexusBillingException` - 402
* `NexusNotFoundException` - 404
* `NexusRateLimitedException` - 429 (no AB Testing add-on returns 403 which is surfaced as `NexusNotFoundException`)

## SSE

### `connectStream(int $maxErrors = 3): void`

Opens the SSE live-update connection. **This method blocks indefinitely.** It must only be called from CLI daemons and queue workers - never from FPM request handlers.

```php theme={null}
// CLI daemon
$client->connectStream();
```

The method returns when:

* `$maxErrors` consecutive transport errors have occurred (TTL polling continues)

After returning, the SDK falls back to TTL polling automatically. See [SSE live updates](sse-live-updates) for the full backoff table and event reference.

<Warning>
  Do NOT call `connectStream()` inside a PHP-FPM request handler. It blocks the worker indefinitely, preventing it from serving further HTTP requests. Use it only in long-running CLI scripts started with `php artisan queue:work`, Swoole workers, or equivalent.
</Warning>

## Sync

### `sync(): void`

Forces an immediate sync, bypassing the TTL. ETag / `If-None-Match` is used automatically - a `304` resets the TTL without downloading data.

```php theme={null}
$client->sync(); // force refresh
$value = $client->getConfig('feature.threshold');
```

Throws:

* `NexusUnauthorizedException` - 401
* `NexusBillingException` - 402
* `NexusNotFoundException` - 404
* `NexusRateLimitedException` - 429
* `NexusQuarantinedException` - 429 quarantine body

## Metadata

### `getKeyType(): string`

Returns `'sk'` or `'pk'` based on the configured `apiKey` prefix. Returns `''` when authentication is exclusively via WIF and no static `apiKey` is set.

```php theme={null}
if ($client->getKeyType() === 'pk') {
    // public-key client - secrets not available
}
```
