Getting started
Getting started
This page takes you from pnpm add to a live listener in under a minute. If you do not have an API key yet, the Developer quickstart walks through creating an organization and copying one.
Install
pnpm add @e-bon/realtime
npm install @e-bon/realtime and yarn add @e-bon/realtime work too. The package has a single runtime dependency on @e-bon/types and ships with TypeScript declarations.
RealtimeClient uses the runtime's native WebSocket. On Node it requires Node 22 or newer. No polyfill is bundled — install one globally before importing @e-bon/realtime if your runtime does not expose WebSocket.Instantiate the client
RealtimeClient takes a baseUrl and a RealtimeClientOptions object with one of two auth modes — never both at once. The constructor connects immediately; there is no connect() method.
With an API key (POS partners, server integrations)
import { RealtimeClient } from '@e-bon/realtime';
const realtime = new RealtimeClient('https://api.e-bon.ro', {
apiKey: process.env.EBON_API_KEY!,
});
The client rewrites https:// → wss://, appends /ws and sends the API key as the apiKey query parameter.
With a JWT (portal sessions, the mobile app)
import { RealtimeClient } from '@e-bon/realtime';
const realtime = new RealtimeClient('https://api.e-bon.ro', {
token: 'eyJ...',
});
The token is sent as the token query parameter and takes precedence over apiKey when both are set.
Options
| Option | Type | Default | Meaning |
|---|---|---|---|
apiKey | string | — | API key for POS partner authentication. Mutually exclusive with token. |
token | string | — | JWT access token for portal authentication. Mutually exclusive with apiKey. |
cursorStore | CursorStore | — | Optional persistence hook for the last-seen event cursor. See Reconnect and lifecycle. |
If you pass neither apiKey nor token, the gateway will reject the WebSocket handshake with a 401.
Register your first listener
on / off / once are typed by the EventName union derived from EventMap, so the listener payload is inferred for you:
import { RealtimeClient, type ReceiptCreatedEvent } from '@e-bon/realtime';
const realtime = new RealtimeClient('https://api.e-bon.ro', {
apiKey: process.env.EBON_API_KEY!,
});
realtime.on('connected', () => console.log('realtime: live'));
realtime.on('disconnected', () => console.warn('realtime: reconnecting…'));
realtime.on('receipt.created', (event: ReceiptCreatedEvent) => {
console.log(`receipt ${event.receiptId} on device ${event.deviceId} = ${event.total}`);
});
realtime.on('command.failed', (event) => {
// event.fiscalError is a real FiscalError instance — you can throw it directly.
console.error(event.fiscalError);
});
// Later, on shutdown:
process.on('SIGTERM', () => realtime.close());
Listener errors are swallowed — a throw inside one listener will not prevent other listeners from running and will not crash the WebSocket loop.
Where to next
- Events — the full catalogue of subscribable events.
- Reconnect and lifecycle — backoff schedule,
suspend/resume, and theCursorStorehook. - Schemas — wire-protocol frames if you build a custom client.