Widget Customer Conversation List
For server-selected customer/staff/admin identities with one frontend embed, see Unified Widget Session.
Optional Sidebar and Launcher Badge (Released)
Deployed to the production Widget and Gateway on 2026-09-16. Merchants using the local SDK must update its types and components; self-hosted Widget installations must update their static assets. With a customer-directory session, containers wider than 620px show the conversation list beside the existing chat component. Narrow containers switch between list and chat. showConversationList defaults to true. Since 2.3.7, disabling it hides both sidebar and back button; conversationId selects a target, or the most recent chat opens when no target is provided. Re-enable the option to restore list navigation. This never changes token permissions.
Open4XWidget.init(customerSessionToken, {
gatewayUrl: 'https://api.open4x.com',
showConversationList: true,
showUnreadBadge: true
});
Open4XWidget.configure({ showConversationList: false });
const unread = Open4XWidget.getUnreadCount();Loader attributes: data-show-conversation-list and data-show-unread-badge. React uses the same camelCase properties. Custom elements accept show-conversation-list and show-unread-badge. Both default to true.
The launcher polls all accessible conversations every 30 seconds while the host page is visible and online, including before the chat window is opened. It pauses while hidden/offline, backs off on errors, and stops on 401/403 or expiry. Disable the badge to stop its polling. Logout/account changes abort old requests and clear counts. Counts over 99 display as 99+. Opening a window alone does not mark messages read.
GET /v1/apps/bot/widget/conversations/unread
Authorization: Bearer <customer-directory-session>Response: {"data":{"unread_count":12}}, with Cache-Control: no-store. This unpaginated count excludes own messages, internal notes, other recipients' messages and revoked conversations. No message body is returned and no read receipt is written. Existing Widget rate limits apply. This is periodic synchronization, not guaranteed instant push. Single-chat tokens do not enable cross-conversation unread polling.
Release status · 2026-09-14
Customer conversation lists, message excerpts and unread counts are deployed to api.open4x.com and widget.open4x.com; production migrations are applied through 0054. Merchants still need their own authenticated Session endpoint and business acceptance. This feature release does not constitute SLA, DPA or commercial production acceptance. Obtain the confirmed SDK delivery package; a public npm release is not implied.
Since 2.3.7, the Widget also lists never-opened support conversations with an active matching customer participant. Opening one creates a Widget binding only with exactly one active support recipient; ambiguous setups require explicit merchant configuration. Revoked bindings are never restored. Existing single-conversation tokens remain supported. See Unified Widget Session for current version and scope requirements.
See Chat Images and Files for the separately enabled attachment extension. Directory tokens cannot upload files directly.
Merchant Backend
Implement your own protected POST /api/open4x/customer-session. Authenticate the visitor, enforce CSRF/origin and rate limits, derive the stable external user ID from server-side login, then call:
POST /v1/conversations/customer-session
Authorization: Bearer <server Bridge Key>
Content-Type: application/json
{"external_user_id":"site-a:user-123","ttl_seconds":1800}Requires conversation:read and conversation:write. TTL is 900–3600 seconds. Return only data.session_token and data.expires_in to the visitor with Cache-Control: no-store. Never log secrets. Namespace identities per website and use exactly the same external user ID used when opening the original Widget sessions.
SDK methods: createCustomerSession, listCustomerConversations, and createOpen4XCustomerSessionHandler. The handler's resolve(request) must verify login, CSRF and business authorization before returning identity or null; do not trust request-body identities.
Widget Integration
With the confirmed local SDK delivery, point the existing component to the new merchant endpoint:
<Open4XSupportWidget
sessionUrl="/api/open4x/customer-session"
widgetUrl="https://widget.open4x.com"
gatewayUrl="https://api.open4x.com"
autoOpen
/>These are the deployed production domains. Use the matching staging package for staging tests without mixing production data; do not assume a public npm release. The Widget detects directory versus chat token type. It handles empty/loading/error states, pagination, selecting a chat, returning to the list and expiry. Logout/account switching must call destroy() and obtain fresh authorization. Directory tokens stay in memory; Loader passes tokens via fragment rather than query parameters. Do not share token-bearing browser URLs.
API
| Method and path | Credential | Purpose |
|---|---|---|
GET /v1/conversations/customer-conversations?external_user_id=... | Server Key, conversation:read | Merchant-owned UI; backend must fix identity from authenticated login |
POST /v1/conversations/customer-session | Server Key, read and write scopes | Issue directory token |
GET /v1/apps/bot/widget/conversations | Directory Bearer token | List only the token's user |
POST /v1/apps/bot/widget/conversations/{id}/session | Directory Bearer token | Resume original chat; no request body |
Both list endpoints accept limit (1–100, default 20) and cursor. Entries contain id, conversation_type, status, created_at, last_message and unread_count, plus pagination.has_more and pagination.next_cursor. Copy the opaque next_cursor into the next request.
The group queue extension, deployed to production on 2026-09-16, adds context_type/context_id and changes ordering to the latest customer-visible public message time (creation time for empty conversations), with ID-ascending ties. The earlier deployment used ID-ascending order. Confirm other environments before relying on the new fields. Refresh the first page for new activity; pagination is not a frozen snapshot.
Resume returns data.conversation_id, data.session_token and data.expires_in. The new single-chat token cannot outlive its parent and preserves existing Chat ID and explicit recipients. It does not create a conversation, restore revoked permissions or reopen business status.
Errors: 400 invalid input; 401 expired/revoked credentials; 403 wrong token type or scope; 404 missing/inaccessible conversation; 409 recipients need merchant reconfiguration; 429 rate/quota limit. Use platform request_id diagnostics, not privilege escalation.
Security and Limitations
Excerpts and Read Receipts
last_message is null or {id, text, created_at, sender_role} for the latest visible message by sequence. Text is truncated to 200 Unicode characters and must be rendered as text, not HTML. This is an excerpt, not an AI summary, and incurs no model call.
unread_count counts visible messages from other participants without a read receipt for the current participant's external identity. Own messages, internal notes and private messages addressed only to others are excluded. Receipts persist across devices. With multiple identities, statistics use the active Widget participant selected when resuming the conversation.
Opening a chat or fetching history does not mark anything read. The Widget submits messages after they enter the visible viewport. Custom clients call POST /v1/apps/bot/widget/read using the single-chat Bearer token, not a directory token or API Key, with {"message_ids":["msg_example"]} (1–50 IDs).
The response is {"data":{"acknowledged":true}}. Invisible, missing and foreign IDs are ignored without disclosing counts. Retries are safe. Only submitted visible messages are marked; unloaded older messages and concurrent arrivals remain unread. Access revocation denies the request. Existing receipt storage is reused, with no new migration.
Returning to or refreshing the list fetches the server count. It is not optimistically reset in the browser. Read failures may temporarily preserve unread counts; honor Retry-After on 429.
- Lists only existing Widget chats with an active channel matching the external identity and an active customer/creator participant. Participant-only conversations and legacy unbound Bot chats are excluded.
- Tenant, channel, chat, participant and deletion state are rechecked. Revoked/expired issuing keys or scope removal invalidate directory and derived chat access.
- No per-directory-JWT revocation endpoint is added. Clear the client on logout; tokens expire naturally. Emergency key revocation affects every user sharing that key. Chat or participant revocation removes the corresponding access.
- The list includes authorized excerpts and unread counts, but excludes metadata, customer names, internal notes, others' private messages and attachment contents.
- Merchants must synchronize lost business permissions into participant/chat revocation. Open4X cannot infer changed order authorization.
- Existing Widget rate limits and actual Key quotas apply. AI is optional and remains off.
- New consultations still use the original creation flow; this list resumes existing consultations only.
Test list/pagination, switching/history recovery, two-user isolation, no internal data exposure, participant/channel/key revocation, empty/expired states and existing direct-chat compatibility. Distinguish local mocks from staging and production acceptance. See merchant quick start and OpenAPI.