Chat SDK reference

The API surface for @getuserfeedback/chat and @getuserfeedback/chat-react.

Last reviewed

Chat SDK reference

The Chat SDK is a headless client for user-facing conversation UIs. Use it when your app should show conversation history and let a signed-in user reply from your own UI.

If you're setting up for the first time, start with the React Chat SDK guide or JavaScript Chat SDK guide.

Packages

PackageUse it when
@getuserfeedback/chatYou want a TypeScript client for the Chat API. Works in browsers, React Native, and server-side proxy code with fetch.
@getuserfeedback/chat-reactYou want React or React Native hooks.

Authentication

Every request needs a JWT bearer token created by your app. Configure your backend or auth provider to issue a token for the signed-in user with this audience:

aud: https://getuserfeedback.com/v1/apps/{appId}sub: the stable identity for this user in your app

The default setup uses sub as the user's stable app identity. If your getuserfeedback.com app uses a custom JWT claim mapping, configure one primary signed claim for chat, such as the per-user id from your app.

Pass that token to the SDK. The SDK sends it as a bearer token:

Authorization: Bearer <token>

getuserfeedback.com verifies the token and uses the signed app identity to decide which conversations the user can read or reply to.

createChatClient(options)

import { createChatClient } from "@getuserfeedback/chat";const chat = createChatClient({auth: {jwt: {token,},},});

Options

OptionTypeDefaultDescription
auth.jwt.tokenstringrequiredJWT bearer token for the current user session.
baseUrlstringhttps://api.getuserfeedback.com/v1Absolute API base URL. Custom values are used exactly.
fetchtypeof fetchglobalThis.fetchCustom fetch implementation. Required only in runtimes without global fetch.

baseUrl must be absolute. If you proxy through your backend, include the full path your proxy expects:

createChatClient({baseUrl: "https://app.example.com/api/chat/v1",auth: { jwt: { token: appSessionToken } },});

In proxy mode, auth.jwt.token is the bearer token your backend expects. Your backend should authenticate that token, then call getuserfeedback.com with a JWT minted for your getuserfeedback.com app and that user.

chat.configure(updates)

Update auth after the client has been created.

await chat.configure({auth: {jwt: {token: refreshedToken,},},});

Clear auth on logout:

await chat.configure({auth: {jwt: null,},});

After auth is cleared, SDK requests fail with missing_auth_jwt until a new token is configured.

chat.conversations.list(input?)

Lists conversations visible to the signed app identity.

const page = await chat.conversations.list({limit: 25,});

Input

FieldTypeDescription
limitnumberPage size. Defaults to the API default.
cursorstringCursor returned by a previous page.
signalAbortSignalOptional cancellation signal.

Response

type ChatConversationListResponse = {conversations: ChatConversation[];limit: number;nextCursor: string | null;};

chat.conversations.markRead(input)

Marks a conversation as read through a specific message. Call this after your UI has shown that message to the user.

const { readState, unreadCount } = await chat.conversations.markRead({conversationId: "conv_123",messageId: "msg_123",});

Input

FieldTypeDescription
conversationIdstringConversation containing the visible message.
messageIdstringLatest message the user has seen.
signalAbortSignalOptional cancellation signal.

Response

type ChatConversationMarkReadResponse = {readState: {lastReadMessageId: string;lastReadMessageTimestamp: string;readAt: string;};unreadCount: number;};

Read state only moves forward. Marking an older message does not make newer messages unread again. The response includes the conversation's authoritative remaining unread count after the update.

Use compareChatConversationReadPositions(left, right) when reconciling read state from concurrent requests. It returns -1, 0, or 1 and follows the same message ordering as the API.

chat.messages.list(input)

Lists messages in one conversation.

const page = await chat.messages.list({conversationId: "conv_123",limit: 50,});

Input

FieldTypeDescription
conversationIdstringConversation to read.
limitnumberPage size. Defaults to the API default.
cursorstringCursor returned by a previous page.
signalAbortSignalOptional cancellation signal.

Response

type ChatMessageListResponse = {conversationId: string;limit: number;messages: ChatMessage[];nextCursor: string | null;};

chat.messages.send(input)

Sends a message from the signed app identity into an existing conversation.

const { message } = await chat.messages.send({conversationId: "conv_123",text: "Thanks — that helps.",});

Input

FieldTypeDescription
conversationIdstringConversation to send into.
textstringMessage text, from 1 to 10,000 characters.
clientMessageIdstringOptional idempotency key for this message. Set this only when you manage send retries yourself, such as in a proxy or non-React client. Reuse the same value when retrying the same send after a timeout or lost response.
signalAbortSignalOptional cancellation signal.

Response

type ChatMessageSendResponse = {message: ChatMessage;};

Message shape

type ChatMessage = {author: "system" | "team" | "unknown" | "user";content:| { type: "text"; text: string }| { type: "flow_response"; responseId: string }| { type: "unsupported" };conversationId: string;id: string;receivedAt: string;sentAt: string;timestamp: string;};

Render unsupported with a quiet fallback. It means the conversation contains a message type this SDK version doesn't know how to display yet.

React provider

import { GetUserFeedbackChatProvider } from "@getuserfeedback/chat-react";<GetUserFeedbackChatProviderclientOptions={{auth: {jwt: {token,},},}}><App /></GetUserFeedbackChatProvider>

The provider creates the chat client and owns an in-memory store for the hooks below it. When clientOptions.auth.jwt.token changes, the provider updates auth and resets the store so the next user doesn't see the previous user's cached conversations.

Props

PropTypeDescription
clientOptionsChatClientOptionsRecommended. Provider-owned client options.
clientChatClientAdvanced. Pass an explicitly created client instead of clientOptions.

Use clientOptions.baseUrl when proxying through your backend:

<GetUserFeedbackChatProviderclientOptions={{baseUrl: "https://app.example.com/api/chat/v1",auth: { jwt: { token: appSessionToken } },}}><App /></GetUserFeedbackChatProvider>

useConversations(options?)

Loads conversations on mount by default.

const {conversations,error,hasMore,loadMore,refresh,status,} = useConversations({ limit: 25 });

Options

FieldTypeDefaultDescription
enabledbooleantrueSet to false to disable the first load.
limitnumber25Page size for the initial load and pagination.

Return value

FieldDescription
conversationsLoaded conversations.
statusLoad state for the list.
errorLast load error, if any.
hasMoretrue when another page is available.
loadMore()Loads the next page.
refresh()Reloads the first page.

useCreateConversation()

Stores a draft for a new conversation and creates the conversation with the first message.

const {create,error,reset,setText,status,text,} = useCreateConversation();

Return value

FieldDescription
textCurrent draft text.
setText(text)Updates the draft text.
reset()Clears the draft and resets create state.
create({ text? })Creates a conversation with the draft or provided text and returns the created conversation and message.
statusCreate state: idle, pending, success, or error.
errorLast create error, if any.

useConversation(options)

Loads one conversation's messages on mount by default.

const {error,hasMore,loadMore,markRead,messages,refresh,send,sendState,status,} = useConversation({ conversationId: "conv_123" });

Options

FieldTypeDefaultDescription
conversationIdstringrequiredConversation to read and send into.
enabledbooleantrueSet to false to disable the first load.
limitnumber50Page size for the initial load and pagination.

Return value

FieldDescription
messagesLoaded messages.
statusLoad state for messages.
errorLast message load error, if any.
hasMoretrue when older messages are available.
loadMore()Loads older messages.
markRead({ messageId })Marks the conversation read through a message your UI has confirmed is visible and returns the updated read state.
refresh()Reloads the first page.
send({ text })Sends a message and returns the saved message.
sendState.statusCurrent send state.
sendState.errorLast send error, if any.

Errors

Failed API responses throw ChatApiError.

import { ChatApiError } from "@getuserfeedback/chat";try {await chat.conversations.list();} catch (error) {if (error instanceof ChatApiError) {console.log(error.status, error.code, error.message);}}

Common codes:

CodeMeaning
missing_auth_jwtThe client has no configured JWT.
identity_missingThe verified JWT did not include a signed app identity.
identity_ambiguousThe verified JWT mapped to more than one equally preferred signed app identity.
invalid_cursorThe pagination cursor is malformed or belongs to a different request.
not_foundThe conversation or referenced message does not exist, is inaccessible, or the message does not belong to that conversation.

Current limits

  • You can start and list conversations, list and send messages, and advance the signed user's read cursor.
  • Realtime updates, typing indicators, automatic visibility tracking, and peer-visible read receipts are not exposed in the SDK yet.