Connecting
id_token (from sign-in — the same token set as
your 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
id_token is short-lived (about 5 minutes, like the access token), 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:| Limit | What to do |
|---|---|
| 10 minutes idle — the connection drops if nothing is sent | Send a ping at least every ~9 minutes: {"action": "ping"}. No reply is sent; it just keeps the connection (and your server-side registration) alive. |
| 2 hours maximum — every connection is closed after 2 hours, active or not | Treat onclose as routine: reconnect with exponential backoff (2s, 4s, 8s, … capped at 30s) and a fresh token. |
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 acode discriminator:
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.