Search by

inverge / nexus

Official PHP SDK for the Inverge Nexus platform — realtime, events, errors, logs, feature flags, links, sessions. Framework-agnostic with first-class Laravel and Symfony integrations.

Maintainers

Package info

github.com/Inverge-team/nexus-php

Homepage

pkg:composer/inverge/nexus

Transparency log

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.1 2026-09-04 20:18 UTC

This package is auto-updated.

Last update: 2026-09-04 20:25:38 UTC


README

inverge/nexus is the server‑side client for the Inverge Nexus platform: realtime messaging, product analytics, structured logging, error monitoring, sessions, feature flags, remote config, deep‑link attribution, and surveys — from plain PHP, Laravel, or Symfony.

  • Package: inverge/nexus
  • PHP: >= 8.1

Table of contents

  1. Installation
  2. Plain PHP setup
  3. Laravel setup
  4. Symfony setup
  5. Dispatchers (sync vs queued)
  6. Sessions
  7. Events
  8. Logs
  9. Errors
  10. Feature flags
  11. Remote Config
  12. Deep links & attribution
  13. Realtime
  14. Surveys
  15. Monolog handler
  16. Low‑level request

1. Installation

composer require inverge/nexus

2. Plain PHP setup

use Inverge\Nexus\NexusClient;
use Inverge\Nexus\Config;

$nexus = new NexusClient(new Config(
    apiKey: 'nxs_live_xxx',
    baseUrl: 'https://services.inverge.net',  // optional
    timeout: 10.0,                          // optional (seconds)
    defaultHeaders: [],                     // optional
));

$nexus->events()->capture('order_placed', ['total' => 42.0], ['distinctId' => 'user_1']);

Config fields: apiKey (required), baseUrl, timeout, defaultHeaders. Config::fromArray('nxs_…', [...]) is also available.

Resources: realtime(), events(), errors(), logs(), sessions(), flags(), links(), surveys(), remoteConfig(). Plus config() and request().

3. Laravel setup

The service provider auto‑registers. Publish config if you want to tweak it:

php artisan vendor:publish --tag=nexus-config

.env:

NEXUS_API_KEY=nxs_live_xxx
NEXUS_BASE_URL=https://services.inverge.net
NEXUS_TIMEOUT=10
NEXUS_QUEUE=false            # true → dispatch telemetry on the queue
NEXUS_QUEUE_CONNECTION=
NEXUS_QUEUE_NAME=
NEXUS_LOGGING=false          # true → forward Laravel logs to Nexus
NEXUS_LOG_LEVEL=debug
NEXUS_CAPTURE_ERRORS=true    # report unhandled exceptions automatically

Use the facade anywhere:

use Inverge\Nexus\Laravel\Nexus;

Nexus::realtime()->emit('orders:42', 'status', ['state' => 'shipped']);
Nexus::events()->capture('order_placed', ['total' => 42], ['distinctId' => auth()->id()]);
Nexus::remoteConfig()->all(['userProperties' => ['governorate' => 'Erbil']]);

Queued variant (offloads the HTTP call to a job):

app('nexus.queue')->events()->capture('order_placed', ['total' => 42], ['distinctId' => $userId]);

Unhandled exceptions are reported automatically when NEXUS_CAPTURE_ERRORS=true.

4. Symfony setup

Register the bundle and configure it:

# config/packages/nexus.yaml
nexus:
    api_key: '%env(NEXUS_API_KEY)%'
    base_url: 'https://services.inverge.net'

Inject NexusClient via autowiring; an exception subscriber reports uncaught exceptions, and a Messenger handler is available for async dispatch.

5. Dispatchers (sync vs queued)

The client sends requests through a dispatcher. Default is synchronous cURL. Swap it for a queued one (Laravel QueueDispatcher, Symfony MessengerDispatcher) so telemetry never blocks the request:

$queued = $nexus->withDispatcher($myDispatcher); // returns a new client

You can also inject a custom PSR‑18 transport: new NexusClient($config, $psr18Transport).

6. Sessions

// Identify an end‑user:
$nexus->sessions()->identify('user_123', [
    'email'  => 'a@b.com',
    'name'   => 'Ada',
    'traits' => ['plan' => 'pro'],
]);

// Start/refresh a session:
$nexus->sessions()->track([
    'distinctId' => 'user_123',
    'deviceKey'  => 'dev_abc',
    'sessionKey' => 'sess_abc',
    'country'    => 'IQ',
]);

Returns the server payload (incl. sessionId).

7. Events

// One event → returns the number written (0/1):
$nexus->events()->capture('order_placed', ['total' => 42.0, 'currency' => 'USD'], [
    'distinctId' => 'user_1',
    'sessionKey' => 'sess_1',
]);

// A batch of events sharing one identity/context:
$nexus->events()->batch([
    ['name' => 'view',  'properties' => ['sku' => 'A1']],
    ['name' => 'click', 'properties' => ['sku' => 'A1']],
], ['distinctId' => 'user_1']);

capture(string $name, array $properties = [], array $context = []): int. Context keys: distinctId, sessionKey, deviceKey, release, osType, osVersion, browser, appVersion, timestamp.

8. Logs

$nexus->logs()->info('payment started', ['source' => 'checkout']);
$nexus->logs()->error('charge failed', ['context' => ['code' => 'declined']]);

// Generic + all levels: trace, debug, info, warn, error, fatal
$nexus->logs()->log('warn', 'retrying', ['context' => ['attempt' => 2]]);

// Batch:
$nexus->logs()->batch([
    ['level' => 'info',  'message' => 'a'],
    ['level' => 'error', 'message' => 'b'],
], ['distinctId' => 'user_1']);

Each level method: info(string $message, array $options = []): int. Options include source, context, and the usual identity keys.

9. Errors

// From a caught throwable (recommended):
try {
    doWork();
} catch (\Throwable $e) {
    $nexus->errors()->captureException($e, [
        'handled' => true,
        'level'   => 'error',
        'context' => ['feature' => 'checkout'],
        'distinctId' => 'user_1',
    ]);
}

// Or a manual error:
$nexus->errors()->capture('Payment gateway timeout', [
    'type' => 'GatewayTimeout',
    'level' => 'error',
    'fingerprint' => 'gateway-timeout',
]);

Options: type, level, handled, fingerprint, stack, context, release, url, distinctId, sessionKey, deviceKey, osType, osVersion, browser, appVersion.

10. Feature flags

$nexus->flags()->isEnabled('new_checkout', 'user_1', ['plan' => 'pro']); // bool
$nexus->flags()->variant('paywall', 'user_1');                           // ?string
$nexus->flags()->payload('paywall', 'user_1');                           // mixed
$all = $nexus->flags()->evaluate('user_1', ['plan' => 'pro']);           // full result

evaluate(string $distinctId, array $properties = []): array returns every flag; the others are convenience wrappers.

11. Remote Config

Fetch the active, published template resolved for a context (conditions — platform, version, country, percentile, custom attributes — evaluated server‑side).

// Flat key => value map:
$config = $nexus->remoteConfig()->all([
    'appVersion'     => '2.1.0',
    'country'        => 'IQ',
    'userProperties' => ['governorate' => 'Duhok'],
]);
$phone = $config['phone_number'];

// A single value with a default:
$phone = $nexus->remoteConfig()->get('phone_number', '+9640000000000', [
    'userProperties' => ['governorate' => 'Erbil'],
]);

// Full result (version, etag, per‑parameter value + which condition supplied it):
$result = $nexus->remoteConfig()->fetch(
    ['userProperties' => ['governorate' => 'Duhok']],
    $previousEtag, // optional If-None-Match; result['notModified'] === true when unchanged
);
// $result['parameters']['phone_number'] === ['value' => ..., 'valueType' => 'STRING', 'source' => 'Duhok']

Context keys: appInstanceId, appVersion, appBuild, platform, osVersion, country, language, firstOpenTime, userProperties. userProperties values must be primitives (strings/numbers/bools) and match condition values exactly.

  • fetch(array $context = [], ?string $etag = null): array
  • all(array $context = []): array
  • get(string $key, mixed $default = null, array $context = []): mixed

12. Deep links & attribution

$data = $nexus->links()->attribute('install', [
    'clickId'    => 'abc',
    'name'       => 'summer_sale',
    'platform'   => 'ios',
    'distinctId' => 'user_1',
    'properties' => ['campaign' => 'promo'],
]);

attribute(string $type, array $options = []): array. Types: install, open, reengagement, … Options include name, clickId, distinctId, deviceId, sessionKey, platform, osType, country, revenue, properties.

13. Realtime

Server‑to‑client fan‑out and room management over the data plane.

use Inverge\Nexus\RoomMessage;

// Emit one or more events to a room:
$nexus->realtime()->emit('orders:42', 'status', ['state' => 'shipped']);
$nexus->realtime()->emit('orders:42', ['status', 'updated'], ['state' => 'shipped']);

// Emit with a RoomMessage value object:
$nexus->realtime()->emit(new RoomMessage('orders:42', ['status'], ['state' => 'shipped']));

// Batch many messages:
$nexus->realtime()->broadcast([
    new RoomMessage('room:a', ['ping'], ['n' => 1]),
    new RoomMessage('room:b', ['ping'], ['n' => 2]),
]);

// Same payload to several rooms:
$nexus->realtime()->emitToRooms(['a', 'b'], 'ping', ['n' => 1]);

// Room management:
$nexus->realtime()->registerRoom('orders', 'standard');
$rooms = $nexus->realtime()->rooms();
$nexus->realtime()->deleteRoom($roomId);
$nexus->realtime()->related('orders');

// Link / unlink related rooms:
$nexus->realtime()->link($roomId, $relatedId);
$nexus->realtime()->unlink($roomId, $relatedId);

// Payload schema (validation):
$nexus->realtime()->setSchema($roomId, ['type' => 'object', 'required' => ['state']]);
$nexus->realtime()->enableSchema($roomId, true);
$nexus->realtime()->schema($roomId);
$nexus->realtime()->clearSchema($roomId);

14. Surveys

// Surveys a user is eligible for (targeting/sampling/capping applied):
$surveys = $nexus->surveys()->active([
    'distinctId' => 'user_1',
    'properties' => ['plan' => 'pro'],
    'osType'     => 'ios',
]);

// Submit a response (answers keyed by question id):
$nexus->surveys()->respond('survey_1', ['q1' => 9, 'q2' => 'Great'], [
    'completed'  => false,
    'distinctId' => 'user_1',
]);

// Convenience wrappers:
$nexus->surveys()->complete('survey_1', ['q1' => 9], ['distinctId' => 'user_1']);
$nexus->surveys()->dismiss('survey_1', ['distinctId' => 'user_1']);

15. Monolog handler

Forward your app's Monolog records to Nexus logs:

use Inverge\Nexus\Monolog\NexusLogHandler;

$logger->pushHandler(new NexusLogHandler($nexus /*, level, bubble, flushAt */));

In Laravel, set NEXUS_LOGGING=true (and NEXUS_LOG_LEVEL) to wire this automatically.

16. Low‑level request

For endpoints without a dedicated resource method:

$response = $nexus->request('POST', '/partner/events', ['events' => [...]], [
    'If-None-Match' => $etag, // extra headers
]);

request(string $method, string $path, ?array $json = null, array $headers = []): ?array — returns the decoded body, or null on failure.