The WebSocket API gives your app a live channel from Orenda: instead of polling REST endpoints, you hold one connection open and events are pushed as they happen. Today it carries 3DS challenges — a card payment needing approval reaches the customer’s device instantly. See 3DS events.

Connecting

Pass the user’s id_token (from sign-in — the same token you send as the Authorization bearer on REST calls) as the token query parameter. It’s checked once, during the handshake:
  • Valid token → connection opens (onopen).
  • Invalid or expired token → handshake rejected (onclose / onerror).
The connection is scoped to the authenticated user — you only receive their events.
The id_token is short-lived (about 5 minutes), so by the time you reconnect it has almost certainly expired. The open connection isn’t affected (auth happens only at the handshake), but refresh before every reconnect — the refresh response includes a fresh id_token. Never reuse a cached one. And once the refresh token itself expires (about an hour), the user signs in again before the WebSocket can reconnect.

Keeping the connection alive

Two server-side limits shape your client:
A client that never pings will be disconnected after 10 idle minutes and silently miss events until it reconnects. Build the ping loop and the reconnect handler first — they’re not optional hardening.

Missed events

If a 3DS challenge is pushed while the customer is offline, it’s re-delivered automatically on reconnect — any still-pending challenge from the last 10 minutes that wasn’t delivered is pushed again as soon as the connection opens. Anything older has expired anyway (3DS challenges are short-lived). Other event types are not replayed; treat the connection as a live feed, with REST as the source of truth.

Receiving events

Every message is JSON with a code discriminator:
Route on code (a small pub/sub registry per event type works well) and ignore codes you don’t recognise — new event types may be added without notice.