Skip to content

Live Chat & Widgets

How chat renders depends on the operator's provider (see Support Overview): an injected vendor widget, or your own UI on the platform's REST chat.

Provider widgets (Zendesk / Intercom)

If the operator configured a provider, the SDK injects the vendor's <script> tag once and passes the player's display context (name, email, VIP tier) to the widget; support agents know who they are talking to the moment a chat starts.

javascript
const config = await sdk.support.getConfig();

if (config.liveChatEnabled && config.provider !== 'CUSTOM' && config.provider !== 'NONE') {
  await sdk.support.injectWidget(config, {
    userId: user.id,
    username: user.username,
    email: user.email,
    vipTier: 'Gold' // optional; surfaces VIP status for priority support
  });
}

Rules:

text
GIVEN a provider widget is configured
WHEN injectWidget(config, userContext) is called
THEN the vendor script is injected exactly once (repeated calls are no-ops),
     and the widget receives only the display context; never tokens or JWTs.

GIVEN a provider is configured WITHOUT a providerKeyId
WHEN injectWidget is called
THEN nothing is injected and the call reports the misconfiguration;
     check the operator's widget key.

Security: the injected script runs on the operator's origin. Content-Security-Policy is the operator's responsibility; the SDK never passes tokens or JWTs to any widget.

Custom chat (REST)

With provider: 'CUSTOM', you build the UI on the platform's chat. The player's context is derived server-side from the authenticated session; user id, username, email, and VIP tier are never client-supplied, so identity and priority cannot be spoofed.

javascript
const sessionId = await sdk.support.initializeChat();
await sdk.support.sendMessage("My deposit hasn't reflected yet.");

Agent replies: real-time, with polling fallback

Agent replies arrive on the platform's shared real-time channel:

typescript
interface ChatMessageReceivedPayload {
  eventId: string;        // dedupe key; see Real-Time Channel
  sessionId: string;
  message: ChatMessage;   // the full typed message (id, sender, body, timestamp)
}
text
GIVEN an active chat session
WHEN the agent sends a message
THEN a CHAT_MESSAGE_RECEIVED event fires on the real-time channel,
     carrying the full message.

GIVEN a client that was disconnected when the agent replied
WHEN it reconnects within the 24-hour replay window
THEN the missed reply is redelivered (dedupe by eventId);
     otherwise, and always as a fallback, getHistory(sessionId) returns
     the full transcript.
javascript
sdk.support.onChatMessage((event) => {
  appendToTranscript(event.message);
});

Session lifecycle

StateEntry triggerAllowed transitionsSide effects
ACTIVEinitializeChat() succeedsENDED (player or agent ends the chat, or inactivity timeout)Messages exchangeable; events fire
ENDEDEnd/timeoutterminalTranscript retained; see Chat History

endChat() ends the current session locally and server-side. Sessions never vanish: ended transcripts remain reviewable via getSessions() / getHistory().

Error contract

CodeError classHTTP statusTrigger conditionRetryable
SUPPORT_SESSION_NOT_FOUNDChatSessionNotFoundError404Unknown sessionId (history/send)No
SUPPORT_NO_ACTIVE_SESSIONNoActiveChatSessionError409History/send with no active session and no sessionIdNo (initializeChat first)
SUPPORT_WIDGET_MISCONFIGUREDWidgetMisconfiguredError400injectWidget with a provider configured but no providerKeyIdNo (check the operator's widget key)

Common errors are defined once in the Error Reference.

Sandbox

The sandbox provider is CUSTOM with live chat enabled; the REST chat flow with seeded greeting messages.

Divergence flag: sandbox agent auto-replies are fixed English text delivered ~1.5 seconds after each player message; good enough for UI testing, not for content testing.