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

# WebSockets (merchant)

> Realtime invoice and payment events with recovery and filters.

## Overview

Use merchant WebSockets for realtime invoice and payment updates across your account. These streams emit canonical `PepayEvent` frames for `invoice.*` and `invoice_payment.*`.

If you are building commerce order UIs, use the commerce stream to receive `commerce.order.*` updates. See [WebSockets (commerce)](/sdk/commerce/websockets).
For webhook signature validation, see [Webhooks (merchant)](/sdk/merchants/webhooks).

## Authentication in the SDK

The SDK connects via query params, so use a short-lived `ws_token` minted server-side. WebSocket headers (for direct `x-api-key` auth) are supported by the raw endpoint but are not wired into the SDK today.

## Request

### Mint a `ws_token`

```ts theme={null}
const token = await pepay.ws.token.mint({ scope: 'merchant', ttlSeconds: 60 });
```

### Connect to merchant events

```ts theme={null}
const stream = pepay.ws.connectMerchantEvents({
  token: String(token?.data?.token),
  format: 'event_v1',
  types: 'invoice.*,invoice_payment.*'
});

stream.on('event', (event) => {
  console.log('event', event.id, event.type);
});
```

### Filters you can pass

* `types`: Comma-separated event types (supports wildcards, e.g. `invoice.*`).
* `invoice_type`: Optional invoice type filter.
* `invoice_id`: Scope to a single invoice.
* `customer_id`: Scope to a merchant customer.
* `environment`: `devnet` or `mainnet`.
* `format`: `event_v1` (recommended).

### Common use cases

* **Merchant dashboards**: `types=invoice.*,invoice_payment.*` with optional `environment` filter.
* **Single-invoice UI**: pass `invoice_id` to reduce noise.
* **Commerce order tracking**: use the commerce stream with `types=commerce.order.*` and optional `order_id`.

### Commerce stream (order lifecycle)

Use the commerce stream for `commerce.order.*` updates and linked invoice/payment context. See [WebSockets (commerce)](/sdk/commerce/websockets) for the full guide.

```ts theme={null}
const token = await pepay.ws.token.mint({ scope: 'commerce', ttlSeconds: 60 });
const stream = pepay.ws.connectCommerceEvents({
  token: String(token?.data?.token),
  format: 'event_v1',
  types: 'commerce.order.*'
});
```

## Response

Example event frame:

```json theme={null}
{
  "id": "evt_1734780000000-123",
  "object": "event",
  "created": 1734780000,
  "type": "invoice.updated",
  "data": {
    "object": {
      "object": "invoice",
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "paid"
    }
  }
}
```

## Errors

* `401`/`403` when token or API-key auth is invalid.
* `400` when query filters are malformed.
* Network disconnects are expected; reconnect and resume with `since=<last_event_id>`.

## Event frames and delivery

* `object=event`: business events (`PepayEvent`).
* `object=ws_control`: replay/resync hints (listen via `stream.on('control')`).
* `object=ws_error`: terminal error (connection closes).
* Delivery is at-least-once; dedupe by `event.id`.

## Relationship to webhooks

* Merchant WebSockets deliver the same event types as merchant webhooks.
* The WebSocket stream includes replay + REST backfill, making it more redundant and reliable than webhooks for realtime consumption.
* Webhooks remain best for server-to-server side effects and audit trails.

## Recovery and backfill

`connectMerchantEvents` and `connectCommerceEvents` return a `PepayEventStream` that:

1. Replays from `since=<last_event_id>` on reconnect.
2. Backfills missed events over REST (`/api/v1/events`).
3. Buffers WS frames during backfill and emits in order.

Notes:

* Recovery is disabled if no API key is available. To force it, pass `recovery.request.auth` with the appropriate key.
* Use `connectMerchantEventsRaw` or `connectCommerceEventsRaw` if you want raw websockets without REST backfill.

## SDK configuration

* `webSocketFactory` is required outside the browser (use `ws` in Node).
* `websocketBaseUrl` overrides the default ws URL.
* `wsHeartbeatMs`, `wsIdleTimeoutMs`, and `wsPingMessage` control liveness behavior.
* `retry` controls reconnect backoff.

## Examples

* Persist the last seen `event.id` in durable storage so you can resume after deploys/restarts.

Next: [WebSockets (commerce)](/sdk/commerce/websockets)
