# ChatResponse Source: https://chatbase.co/docs/android-sdk/chat-response Reference for ChatResponse, ResponseMetadata, Part, and related types returned by sendMessage and retry. ## ChatResponse `data class ChatResponse` — **Package:** `com.chatbase.sdk.model` The aggregated result returned by `sendMessage` and `retry`. ```kotlin theme={null} data class ChatResponse( val id: String, val role: String, val parts: List, val metadata: ResponseMetadata ) ``` Server-assigned message ID. Always `"assistant"`. The response content — text, tool calls, and tool results. Same as `ChatResponse.id`. Server-assigned ID for the user's message. The conversation ID. Pass this to continue the conversation. Why the stream ended: `STOP`, `ERROR`, `TOOL_CALLS`, or `UNKNOWN`. Credits consumed by this request. ## Part `sealed interface Part` — **Package:** `com.chatbase.sdk.model` ### Part.Text Text content generated by the agent or sent by the user. ```kotlin theme={null} data class Text(val text: String) : Part ``` The text content. ### Part.ToolCall A tool invocation requested by the agent. ```kotlin theme={null} data class ToolCall( val toolCallId: String, val toolName: String, val input: JsonElement? ) : Part ``` Unique tool call identifier. Name of the tool. The tool's input parameters. ### Part.ToolResult The result of a tool execution. ```kotlin theme={null} data class ToolResult( val toolCallId: String, val toolName: String, val output: JsonElement? ) : Part ``` Matches the originating `ToolCall.toolCallId`. Name of the tool. The tool's output. ## Enums ### Role ```kotlin theme={null} enum class Role { USER, // serialized as "user" ASSISTANT // serialized as "assistant" } ``` ### FinishReason ```kotlin theme={null} enum class FinishReason { STOP, // serialized as "stop" — normal completion ERROR, // serialized as "error" — an error occurred TOOL_CALLS, // serialized as "tool-calls" — waiting for tool results UNKNOWN // serialized as "unknown" — unrecognized finish reason } ``` # Client-Side Tools Source: https://chatbase.co/docs/android-sdk/client-side-tools Register local tool handlers that the agent can invoke during a conversation. ## What Are Client-Side Tools? Client-side tools let your agent invoke functions that run locally on the Android device. Register a handler, and the SDK takes care of the rest — when the agent calls the tool, your handler runs and the result is fed back into the conversation automatically. Client-side tools correspond to **Custom Actions** configured on your agent in the [Chatbase Dashboard](https://www.chatbase.co/dashboard). The `toolName` in the SDK matches the name of the configured action. ## tool `interface ChatbaseClient` — **Package:** `com.chatbase.sdk` ```kotlin theme={null} fun tool(name: String, handler: suspend (input: Map) -> Any) ``` Register a client-side tool handler. The tool name. Must match a Custom Action configured on your agent. A suspend function that receives the parsed input and returns a result. ```kotlin theme={null} client.tool("get_weather") { input -> val city = input["city"] as String // Call a weather API, read a sensor, etc. mapOf( "city" to city, "temperature" to "22°C", "condition" to "Sunny" ) } ``` The agent can now call `get_weather` during a conversation. The SDK executes your handler and feeds the result back automatically. This loop can repeat up to 10 times per `sendMessage` call — if the agent requests more, `sendMessage` throws a `ChatbaseException` ("Tool loop exceeded maximum iterations"). Tool results are limited to **20 KB** when serialized to JSON. Keep tool outputs concise — return only the data the agent needs. ## removeTool ```kotlin theme={null} fun removeTool(name: String) ``` Unregister a previously registered tool handler. The tool name to remove. ## Tracking Execution Use the `onToolCall` and `onToolResult` callbacks to observe tool execution: ```kotlin theme={null} client.sendMessage("What's the weather in Tokyo?") { onToolCall { tool -> println("Agent is calling: ${tool.toolName}") println("Input: ${tool.inputAsMap()}") } onToolResult { result -> println("Tool result: ${result.outputAsString()}") } onTextDelta { delta -> print(delta) // Agent's response after the tool result } } ``` ### ToolCallInfo `data class ToolCallInfo` — **Package:** `com.chatbase.sdk` Passed to the `onToolCall` callback before handler execution. ```kotlin theme={null} data class ToolCallInfo( val toolCallId: String, val toolName: String, val input: JsonElement ) ``` ```kotlin theme={null} fun inputAsMap(): Map ``` Parse the JSON input into a `Map` for easy access. ### ToolResultInfo `data class ToolResultInfo` — **Package:** `com.chatbase.sdk` Passed to the `onToolResult` callback after handler execution. ```kotlin theme={null} data class ToolResultInfo( val toolCallId: String, val toolName: String, val output: Any ) ``` ```kotlin theme={null} fun outputAsString(): String ``` Serialize the output to a JSON string. ## Interactive Tools Since handlers are `suspend` functions, they can block on user interaction. For example, showing a color picker and waiting for the user's choice: ```kotlin theme={null} client.tool("pick_color") { _ -> val deferred = CompletableDeferred() // Show a color picker dialog (UI-framework specific) colorPickerRequest.value = deferred // Observed by the Composable // Suspend until the user picks a color val color = deferred.await() mapOf("color" to color) } ``` ## Related Streaming callbacks and Kotlin Flow Handle errors during tool execution # Conversation & Message Source: https://chatbase.co/docs/android-sdk/conversation-models Reference for Conversation, Message, Page, and related types used in conversation history. ## Conversation `data class Conversation` — **Package:** `com.chatbase.sdk.model` ```kotlin theme={null} data class Conversation( val id: String, val title: String?, val createdAt: Long, val updatedAt: Long, val userId: String?, val status: ConversationStatus ) ``` Unique conversation ID. Auto-generated or server-assigned title. Creation timestamp (Unix epoch seconds). Timestamp of the last message (Unix epoch seconds). The identified user who owns this conversation, or `null` for anonymous (device-scoped) conversations. `ONGOING`, `ENDED`, or `TAKEN_OVER`. ### ConversationStatus ```kotlin theme={null} enum class ConversationStatus { ONGOING, // serialized as "ongoing" — active conversation ENDED, // serialized as "ended" — conversation has ended TAKEN_OVER // serialized as "taken_over" — conversation taken over by a human agent } ``` ## Message `data class Message` — **Package:** `com.chatbase.sdk.model` ```kotlin theme={null} data class Message( val id: String, val role: Role, val parts: List, val createdAt: Long?, val feedback: Feedback?, val metadata: MessageMetadata? ) ``` Unique message ID. `USER` or `ASSISTANT`. Message content parts — `Text`, `ToolCall`, or `ToolResult`. See [ChatResponse](/docs/android-sdk/chat-response) for details. Creation timestamp (Unix epoch seconds). Absent on some older messages. User feedback on this message. Confidence/relevance score. ### Feedback ```kotlin theme={null} enum class Feedback { POSITIVE, // serialized as "positive" NEGATIVE // serialized as "negative" } ``` ## Page\ `data class Page` — **Package:** `com.chatbase.sdk.model` Returned by `listConversations()` and `listMessages()`. ```kotlin theme={null} data class Page( val data: List, val cursor: String?, val hasMore: Boolean, val total: Int ) ``` Items on this page. Cursor for the next page. `null` if no more pages. Whether more pages exist. Total item count across all pages. ```kotlin theme={null} val canLoadMore: Boolean ``` `true` if `hasMore` is true and `cursor` is non-null. ```kotlin theme={null} suspend fun loadMore(): Page? ``` Load the next page. Returns a new `Page` with the older items prepended to the existing `data`, so you always have the full accumulated list. Returns `null` if there are no more pages. # Conversations & History Source: https://chatbase.co/docs/android-sdk/conversations Manage conversations, load message history, and navigate paginated results with the Chatbase Android SDK. ## Starting and Continuing Conversations Send a message to start a new conversation. The SDK creates one automatically if no `conversationId` is provided. ```kotlin theme={null} val response = client.sendMessage("Hello!") ``` The conversation ID is returned in the response metadata: ```kotlin theme={null} val conversationId = response.metadata.conversationId ``` Pass the `conversationId` to subsequent calls: ```kotlin theme={null} val followUp = client.sendMessage( message = "Tell me more", conversationId = conversationId ) ``` The SDK automatically tracks the current conversation ID. After your first `sendMessage`, subsequent calls without an explicit `conversationId` reuse the same conversation: ```kotlin theme={null} client.sendMessage("First message") // starts a new conversation client.sendMessage("Follow-up") // continues the same conversation println(client.currentConversationId) // "conv_abc123" ``` ## newConversation `interface ChatbaseClient` — **Package:** `com.chatbase.sdk` ```kotlin theme={null} fun newConversation() ``` Clear the current conversation ID so the next `sendMessage` starts a new conversation. ```kotlin theme={null} client.newConversation() client.sendMessage("Brand new conversation!") ``` ## listConversations ```kotlin theme={null} suspend fun listConversations( cursor: String? = null, limit: Int? = null ): Page ``` Retrieve a paginated list of conversations. Opaque cursor from a previous response. Omit to start from the beginning. Number of items per page, between 1 and 100. Defaults to 20. ```kotlin theme={null} val page = client.listConversations(limit = 20) page.data.forEach { conversation -> println("${conversation.id} — ${conversation.title}") println(" Status: ${conversation.status}") } println("Total: ${page.total}") println("Has more: ${page.hasMore}") ``` ### Conversation `data class Conversation` — **Package:** `com.chatbase.sdk.model` ```kotlin theme={null} data class Conversation( val id: String, val title: String?, val createdAt: Long, val updatedAt: Long, val userId: String?, val status: ConversationStatus ) ``` Unique conversation ID. Auto-generated or server-assigned title. Creation timestamp (Unix epoch seconds). Timestamp of the last message (Unix epoch seconds). The identified user who owns this conversation, or `null` for anonymous (device-scoped) conversations. `ONGOING`, `ENDED`, or `TAKEN_OVER`. ## listMessages ```kotlin theme={null} suspend fun listMessages( conversationId: String, cursor: String? = null, limit: Int? = null ): Page ``` Retrieve messages in a conversation. The conversation to fetch messages from. Opaque cursor from a previous response. Omit to start from the newest messages. Number of items per page, between 1 and 100. Defaults to 20. Messages are returned in **reverse chronological order** — the first page contains the most recent messages. Within each page, messages are ordered oldest to newest. ```kotlin theme={null} val page = client.listMessages(conversationId, limit = 50) page.data.forEach { message -> val role = if (message.role == Role.USER) "You" else "Agent" val text = message.parts .filterIsInstance() .joinToString("") { it.text } println("$role: $text") } ``` ### Message `data class Message` — **Package:** `com.chatbase.sdk.model` ```kotlin theme={null} data class Message( val id: String, val role: Role, val parts: List, val createdAt: Long?, val feedback: Feedback?, val metadata: MessageMetadata? ) ``` Unique message ID. `USER` or `ASSISTANT`. Message content parts (text, tool calls, tool results). Creation timestamp (Unix epoch seconds). Absent on some older messages. `POSITIVE`, `NEGATIVE`, or `null`. Confidence/relevance score. ## Pagination `data class Page` — **Package:** `com.chatbase.sdk.model` All list methods return a `Page` with built-in pagination support. ```kotlin theme={null} data class Page( val data: List, val cursor: String?, val hasMore: Boolean, val total: Int ) ``` Items on this page. Cursor for the next page. `null` if no more pages. Whether more pages exist. Total item count across all pages. ```kotlin theme={null} val canLoadMore: Boolean ``` `true` if `hasMore` is true and `cursor` is non-null. ```kotlin theme={null} suspend fun loadMore(): Page? ``` Load the next page. Returns a new `Page` with the older items prepended to the existing `data`, so you always have the full accumulated list. Returns `null` if there are no more pages. ### Paginating Through All Results ```kotlin theme={null} var page = client.listConversations(limit = 20) while (true) { page.data.forEach { conversation -> println(conversation.title) } if (!page.canLoadMore) break page = page.loadMore() ?: break } ``` ## Related Send messages and stream responses Scope conversations to users # Error Handling Source: https://chatbase.co/docs/android-sdk/error-handling Exception hierarchy and error handling patterns for the Chatbase Android SDK. ## Exception Hierarchy All SDK errors extend `ChatbaseException`: ``` ChatbaseException ├── ApiException — API errors from the Chatbase server └── NetworkException — Connection failures, DNS errors, timeouts ``` ## ApiException `class ApiException : ChatbaseException` — **Package:** `com.chatbase.sdk.exception` Thrown when the Chatbase API returns an error response. ```kotlin theme={null} class ApiException( val httpStatus: Int, val errorCode: String, val errorMessage: String, val details: Map? = null ) : ChatbaseException ``` The HTTP status code of the error response (e.g. `401`, `403`, `429`). Machine-readable error code. Use this for programmatic handling. Human-readable error description. Optional field-level validation errors. ### Convenience Properties ```kotlin theme={null} val isRateLimited: Boolean // httpStatus == 429 val isNotFound: Boolean // httpStatus == 404 val isCreditsExhausted: Boolean // httpStatus == 402 ``` For statuses without a helper — such as `401` (authentication) or `403` (access denied) — check `httpStatus` or `errorCode` directly. ## Error Codes These are the error codes you may encounter through `ApiException.errorCode`:
Status Code Description
400VALIDATION\_INVALID\_BODYThe request body failed validation. details maps field names to messages. Also returned when a tool result exceeds the 20 KB limit.
400CHAT\_RETRY\_NO\_USER\_MESSAGEThe message passed to retry() has no preceding user message to retry from.
401AUTH\_INVALID\_JWTThe JWT token passed to identify() is invalid, expired, or could not be verified — including when identity verification is not configured for the agent. See User Identity.
402CHAT\_CREDITS\_EXHAUSTEDThe workspace's message credit balance is zero. Upgrade the plan or wait for credits to reset. Caught by isCreditsExhausted.
402CHAT\_AGENT\_CREDITS\_EXHAUSTEDThe specific agent's credit allocation has been used up. Caught by isCreditsExhausted.
403AUTH\_OWNERSHIP\_MISMATCHThe conversation belongs to a different user or device. Also returned by retry() and listMessages() when the conversation does not exist.
403CHAT\_CONVERSATION\_MISMATCHThe conversation could not be resolved for this agent.
403CHAT\_MODEL\_NOT\_ALLOWEDThe agent uses a model not available on the current plan.
403CHAT\_CONVERSATION\_NOT\_ONGOINGThe conversation has ended or was taken over and cannot receive new messages. Start a new conversation.
404AGENT\_NOT\_FOUNDNo agent matches the provided ID, or the Android SDK channel is not enabled for the agent (see Quick Start). Caught by isNotFound.
404RESOURCE\_NOT\_FOUNDThe conversation or message does not exist. Caught by isNotFound.
404CHAT\_RETRY\_MESSAGE\_NOT\_FOUNDThe message ID provided for retry() was not found. Caught by isNotFound.
404RESOURCE\_TOOL\_CALL\_NOT\_FOUNDThe tool call was not found or has expired. Can surface through the automatic tool loop. Caught by isNotFound.
404RESOURCE\_TOOL\_CALL\_MISMATCHThe tool call does not belong to this conversation. Caught by isNotFound.
404RESOURCE\_TOOL\_RESULT\_NOT\_PENDINGNo pending tool result exists for this tool call — usually a duplicate submission. Caught by isNotFound.
429RATE\_LIMIT\_TOO\_MANY\_REQUESTSRate limit exceeded (1,000 requests per 10 seconds per device). Back off and retry. Caught by isRateLimited.
500CHAT\_STREAMING\_ERRORThe response stream failed server-side. Safe to retry.
500INTERNAL\_SERVER\_ERRORAn unexpected server error occurred. Retry, or contact support if it persists.
## NetworkException `class NetworkException : ChatbaseException` — **Package:** `com.chatbase.sdk.exception` ```kotlin theme={null} class NetworkException( message: String, cause: Throwable? = null ) : ChatbaseException ``` Thrown for connection-level failures — DNS errors, socket timeouts, no internet connectivity, and similar issues. ## Handling Errors Use a try-catch block with the SDK's exception hierarchy: ```kotlin theme={null} try { val response = client.sendMessage("Hello") } catch (e: ApiException) { when { e.httpStatus == 401 -> { println("Authentication failed. Check your JWT token.") } e.httpStatus == 403 -> { println("Access denied. Check conversation ownership or plan.") } e.isRateLimited -> { println("Rate limited. Back off and retry.") } e.isCreditsExhausted -> { println("No credits remaining. Upgrade plan.") } e.isNotFound -> { println("Not found. Check your agent ID.") } else -> { println("API error: ${e.errorCode} — ${e.errorMessage}") } } } catch (e: NetworkException) { println("Network error: ${e.message}") } catch (e: ChatbaseException) { println("Unknown SDK error: ${e.message}") } ``` Handle errors via the `onError` callback: ```kotlin theme={null} client.sendMessage("Hello") { onTextDelta { delta -> print(delta) } onError { error -> when (error) { is ApiException -> println("API error: ${error.errorCode}") is NetworkException -> println("Network error: ${error.message}") else -> println("Error: ${error.message}") } } } ``` Check for `ChatStreamEvent.Error` events: ```kotlin theme={null} client.sendMessageStream("Hello").collect { event -> when (event) { is ChatStreamEvent.TextDelta -> print(event.delta) is ChatStreamEvent.Error -> { when (val ex = event.exception) { is ApiException -> println("${ex.errorCode}: ${ex.errorMessage}") is NetworkException -> println("Network: ${ex.message}") else -> println("Error: ${ex.message}") } } else -> {} } } ``` ## Related Streaming callbacks and error events SDK setup and configuration # Android SDK Overview Source: https://chatbase.co/docs/android-sdk/overview Introduction to the Chatbase Android SDK — a Kotlin-first library for building conversational AI experiences on Android. **Alpha Release.** The Chatbase Android SDK is currently in alpha (v0.0.1-alpha03). APIs may change in future releases. Conversation methods apply exclusively to conversations created through the mobile SDKs (Android and iOS). Conversations generated through the widget, the API, or external integrations cannot be accessed using the SDK. A user identified on both platforms sees their Android and iOS SDK conversations together. ## What is the Chatbase Android SDK? The Chatbase Android SDK is a Kotlin-first library that lets you integrate Chatbase agents into your Android app. It provides: * **Real-time streaming** with two levels of abstraction * **Client-side tools** that let the agent invoke local functions on the device * **User identity** with JWT-based authentication and automatic device ID tracking * **Conversation management** with cursor-based pagination * **Structured error handling** with typed exceptions **Requirements:** | Requirement | Minimum | | ----------------- | -------------------------------------------------- | | Android API | 24 (Android 7.0) | | Java | 11+ | | Kotlin Coroutines | Required | | Jetpack Compose | Not required — the SDK works with any UI framework | ## Installation ```kotlin theme={null} // build.gradle.kts (app module) dependencies { implementation("com.chatbase:chatbase-sdk:0.0.1-alpha03") } ``` ```groovy theme={null} // build.gradle (app module) dependencies { implementation 'com.chatbase:chatbase-sdk:0.0.1-alpha03' } ``` The SDK declares the `INTERNET` permission in its own manifest. It is merged automatically — you do not need to add it to your app's manifest. ## Quick Start 1. Go to the [Chatbase Dashboard](https://www.chatbase.co/dashboard) 2. Select your agent 3. Go to **Settings** → **General** 4. Copy the **Agent ID** In the dashboard, go to **Deploy** → **Android SDK** and enable the channel for your agent. If the Android SDK channel is not enabled, every SDK request fails with a `404` `AGENT_NOT_FOUND` error — even when the agent ID is correct. ```kotlin theme={null} import com.chatbase.sdk.Chatbase val client = Chatbase.create(context, "YOUR_AGENT_ID") ``` `context` can be any Android `Context` (Activity, Application, etc.). It is only used during creation to generate the device ID. ```kotlin theme={null} import com.chatbase.sdk.model.Part lifecycleScope.launch { val response = client.sendMessage("Hello! How can you help me?") { onTextDelta { delta -> // Called for each text chunk — safe to update UI print(delta) } } // Access the full response val text = response.parts .filterIsInstance() .joinToString("") { it.text } println(text) println("Conversation: ${response.metadata.conversationId}") } ``` ```kotlin theme={null} // In your ViewModel override fun onCleared() { client.close() } ``` ## Chatbase `object Chatbase` — **Package:** `com.chatbase.sdk` The singleton factory for creating SDK clients. ### create ```kotlin theme={null} fun create(context: Context, agentId: String): ChatbaseClient ``` Create a client with default settings. Any Android `Context`. Used only during creation to generate the device ID. The Chatbase agent ID to connect to. ### create (with configuration) ```kotlin theme={null} fun create(context: Context, block: ChatbaseConfig.Builder.() -> Unit): ChatbaseClient ``` Create a client with custom configuration via a DSL builder. ```kotlin theme={null} val client = Chatbase.create(context) { agentId = "YOUR_AGENT_ID" connectTimeoutMs = 15_000 // 15 seconds readTimeoutMs = 60_000 // 60 seconds } ``` ## ChatbaseConfig `data class ChatbaseConfig` — **Package:** `com.chatbase.sdk` | Property | Type | Default | Description | | ------------------ | -------- | ---------- | ------------------------------------ | | `agentId` | `String` | (required) | The Chatbase agent ID to connect to. | | `connectTimeoutMs` | `Long` | `10_000` | Connection timeout in milliseconds. | | `readTimeoutMs` | `Long` | `30_000` | Read timeout in milliseconds. | For streaming responses, the SDK uses a separate 5-minute read timeout regardless of the `readTimeoutMs` setting. This ensures long-running streams are not interrupted prematurely. ## Rate Limits The Chatbase API enforces a rate limit of **1,000 requests per 10 seconds** per device, applied server-side. When the limit is exceeded, the SDK throws an `ApiException` with `isRateLimited == true`. See [Error Handling](/docs/android-sdk/error-handling) for how to handle this. ## Next Steps Real-time streaming with callbacks and Kotlin Flow Register local tool handlers the agent can invoke Manage conversations, history, and pagination Exception hierarchy and error handling patterns # Streaming Source: https://chatbase.co/docs/android-sdk/streaming How to stream real-time responses from the Chatbase Android SDK using callbacks and Kotlin Flow. ## Two-Tier Streaming API The SDK provides two levels of abstraction for streaming: * **`sendMessage()`** — High-level API with a callback DSL. Handles tool calls automatically (up to 10 iterations). Recommended for most use cases. * **`sendMessageStream()`** — Low-level API returning a `Flow`. Tool calls are not handled automatically, giving you full control over event processing. ## sendMessage `interface ChatbaseClient` — **Package:** `com.chatbase.sdk` ```kotlin theme={null} suspend fun sendMessage( message: String, conversationId: String? = null, callbacks: StreamCallbacks.() -> Unit = {} ): ChatResponse ``` Sends a message, streams the response in real time, and automatically handles tool calls (up to 10 iterations). Returns the aggregated `ChatResponse` when the stream completes. The user message to send to the agent. Continue an existing conversation. Omit to use `currentConversationId` or start a new one. Streaming callback DSL. ```kotlin theme={null} val response = client.sendMessage("Tell me a story") { onStart { println("Stream started...") } onTextDelta { delta -> // Called for each text chunk — append to your UI print(delta) } onToolCall { toolCall -> println("Agent is calling: ${toolCall.toolName}") } onToolResult { result -> println("Tool result: ${result.outputAsString()}") } onFinish { response -> println("\nDone! Message ID: ${response.id}") } onError { error -> println("Error: ${error.message}") } } ``` ### StreamCallbacks `class StreamCallbacks` — **Package:** `com.chatbase.sdk` All callbacks are invoked on `Dispatchers.Main` — it is safe to update UI directly from any callback without explicit dispatching. ```kotlin theme={null} fun onStart(handler: () -> Unit) ``` Called when the connection opens and streaming begins. ```kotlin theme={null} fun onTextDelta(handler: (text: String) -> Unit) ``` Called for each incremental text chunk received. ```kotlin theme={null} fun onToolCall(handler: (toolCall: ToolCallInfo) -> Unit) ``` Called when a tool call's full input is available (before execution). ```kotlin theme={null} fun onToolResult(handler: (result: ToolResultInfo) -> Unit) ``` Called after a tool handler executes and returns a result. ```kotlin theme={null} fun onFinish(handler: (response: ChatResponse) -> Unit) ``` Called when the stream completes successfully. ```kotlin theme={null} fun onError(handler: (error: ChatbaseException) -> Unit) ``` Called when an error occurs during streaming. ### ChatResponse `data class ChatResponse` — **Package:** `com.chatbase.sdk.model` The aggregated result after streaming completes. Server-assigned message ID. Always `"assistant"`. The response content — text, tool calls, and tool results. See [ChatResponse](/docs/android-sdk/chat-response). Same as `ChatResponse.id`. Server-assigned ID for the user's message. The conversation ID. Pass this to continue the conversation. Why the stream ended: `STOP`, `ERROR`, `TOOL_CALLS`, or `UNKNOWN`. Credits consumed by this request. ## sendMessageStream ```kotlin theme={null} fun sendMessageStream( message: String, conversationId: String? = null ): Flow ``` Returns a cold `Flow` of raw streaming events. Tool calls are **not** handled in Flow mode — registered tool handlers are not invoked, and the SDK exposes no API for submitting tool results manually. The user message to send to the agent. Continue an existing conversation. Omit to use `currentConversationId` or start a new one. Tool calls are **not** executed in Flow mode — tool events are informational only, and the stream finishes with `finishReason == "tool-calls"` without a final answer. If your agent uses client-side tools, use `sendMessage` with callbacks instead. See [Client-Side Tools](/docs/android-sdk/client-side-tools) for details. ```kotlin theme={null} client.sendMessageStream("Tell me about Kotlin").collect { event -> when (event) { is ChatStreamEvent.TextDelta -> print(event.delta) is ChatStreamEvent.Finish -> println("\nDone: ${event.finishReason}") is ChatStreamEvent.Error -> println("Error: ${event.exception.message}") else -> { /* handle other events as needed */ } } } ``` You can also filter for specific event types: ```kotlin theme={null} client.sendMessageStream("Hello") .filterIsInstance() .collect { event -> print(event.delta) } ``` ## Stream Events The `Flow` returned by `sendMessageStream` emits `ChatStreamEvent` objects — text deltas, tool input/output, step lifecycle, and errors. See [Streaming Events](/docs/android-sdk/streaming-events) for the full type reference. ## Continuing a Conversation The SDK automatically tracks the current conversation. After sending a message, subsequent calls reuse the same conversation: ```kotlin theme={null} // First message — starts a new conversation client.sendMessage("My name is Alice.") println(client.currentConversationId) // "conv_abc123" // Subsequent messages continue the same conversation client.sendMessage("What is my name?") // Agent remembers: "Alice" ``` To start a fresh conversation: ```kotlin theme={null} client.newConversation() client.sendMessage("Fresh start!") // Creates a new conversation ``` See [Conversations & History](/docs/android-sdk/conversations) for listing conversations and loading message history. ## retry ```kotlin theme={null} suspend fun retry( conversationId: String, messageId: String, callbacks: StreamCallbacks.() -> Unit = {} ): ChatResponse ``` Retry a failed assistant message. Same streaming and tool-loop behavior as `sendMessage`. The conversation containing the failed message. The ID of the assistant message to retry. Streaming callback DSL. A convenience extension extracts the IDs from a `ChatResponse`: ```kotlin theme={null} suspend fun ChatbaseClient.retry( response: ChatResponse, callbacks: StreamCallbacks.() -> Unit = {} ): ChatResponse ``` ```kotlin theme={null} val response = client.sendMessage("Hello") // ... later: val retried = client.retry(response) { onTextDelta { delta -> print(delta) } } ``` ## retryStream ```kotlin theme={null} fun retryStream( conversationId: String, messageId: String ): Flow ``` Raw streaming variant of `retry`. Tool calls are **not** handled automatically. ```kotlin theme={null} client.retryStream(conversationId, messageId).collect { event -> when (event) { is ChatStreamEvent.TextDelta -> print(event.delta) is ChatStreamEvent.Finish -> println("\nDone") is ChatStreamEvent.Error -> println("Error: ${event.exception.message}") else -> {} } } ``` ## Related Register tool handlers the agent can invoke Exception hierarchy and error handling patterns # Streaming Events Source: https://chatbase.co/docs/android-sdk/streaming-events Reference for ChatStreamEvent, StreamMessageMetadata, ToolCallInfo, and related streaming types. ## ChatStreamEvent `sealed interface ChatStreamEvent` — **Package:** `com.chatbase.sdk.streaming` Events emitted by `sendMessageStream()` and `retryStream()`. ### TextStart A new text block is starting. ```kotlin theme={null} data class TextStart(val id: String) : ChatStreamEvent ``` ### TextDelta An incremental text chunk. Append to the current text. ```kotlin theme={null} data class TextDelta(val id: String, val delta: String) : ChatStreamEvent ``` ### TextEnd The current text block is complete. ```kotlin theme={null} data class TextEnd(val id: String) : ChatStreamEvent ``` ### ToolInputStart A tool call is starting — input will stream incrementally. ```kotlin theme={null} data class ToolInputStart( val toolCallId: String, val toolName: String ) : ChatStreamEvent ``` ### ToolInputDelta Incremental tool input text. ```kotlin theme={null} data class ToolInputDelta( val toolCallId: String, val inputTextDelta: String ) : ChatStreamEvent ``` ### ToolInputAvailable The tool call's full input is ready. ```kotlin theme={null} data class ToolInputAvailable( val toolCallId: String, val toolName: String, val input: JsonElement ) : ChatStreamEvent ``` Read the full `input` object directly from this event — no need to concatenate preceding deltas. ### ToolOutputAvailable A tool's execution result is available. ```kotlin theme={null} data class ToolOutputAvailable( val toolCallId: String, val output: JsonElement ) : ChatStreamEvent ``` ### StepStart / StepFinish ```kotlin theme={null} object StepStart : ChatStreamEvent object StepFinish : ChatStreamEvent ``` ### Start The message stream is starting. ```kotlin theme={null} data class Start( val messageId: String?, val messageMetadata: StreamMessageMetadata? ) : ChatStreamEvent ``` ### Finish The stream is complete. ```kotlin theme={null} data class Finish( val finishReason: String, val messageMetadata: StreamMessageMetadata? ) : ChatStreamEvent ``` `finishReason` is usually `"stop"`, `"error"`, or `"tool-calls"`. Other values (`"length"`, `"content-filter"`, `"other"`, `"unknown"`) are possible and map to `FinishReason.UNKNOWN` in the aggregated `ChatResponse`. ### MessageMetadataEvent Updated metadata arrived mid-stream. ```kotlin theme={null} data class MessageMetadataEvent( val messageMetadata: StreamMessageMetadata ) : ChatStreamEvent ``` ### Error An error occurred during streaming. ```kotlin theme={null} data class Error(val exception: ChatbaseException) : ChatStreamEvent ``` The `exception` may be an `ApiException` or `NetworkException`. See [Error Handling](/docs/android-sdk/error-handling). ## StreamMessageMetadata `data class StreamMessageMetadata` — **Package:** `com.chatbase.sdk.streaming` Accompanies `Start`, `Finish`, and `MessageMetadataEvent` events. ```kotlin theme={null} data class StreamMessageMetadata( val messageId: String?, val userMessageId: String?, val conversationId: String?, val usage: StreamUsage? ) ``` ### StreamUsage ```kotlin theme={null} data class StreamUsage(val credits: Double = 0.0) ``` ## ToolCallInfo `data class ToolCallInfo` — **Package:** `com.chatbase.sdk` Passed to the `onToolCall` callback before handler execution. ```kotlin theme={null} data class ToolCallInfo( val toolCallId: String, val toolName: String, val input: JsonElement ) ``` ```kotlin theme={null} fun inputAsMap(): Map ``` Parse the JSON input into a `Map` for easy access. ## ToolResultInfo `data class ToolResultInfo` — **Package:** `com.chatbase.sdk` Passed to the `onToolResult` callback after handler execution. ```kotlin theme={null} data class ToolResultInfo( val toolCallId: String, val toolName: String, val output: Any ) ``` ```kotlin theme={null} fun outputAsString(): String ``` Serialize the output to a JSON string. # User Identity Source: https://chatbase.co/docs/android-sdk/user-identity How to identify users with JWT tokens and manage device-level identity in the Chatbase Android SDK. ## Overview The SDK supports two layers of identity: | Layer | How It Works | Scope | | ----------------- | ----------------------------------------- | ---------------------------------- | | **Device ID** | Automatic — generated on first use | Conversations scoped to the device | | **User Identity** | Opt-in — set a JWT token via `identify()` | Conversations scoped to the user | The SDK works anonymously out of the box. Call `identify()` to associate conversations with a specific user. ## Device ID Every SDK instance has a stable device ID, generated automatically on creation: ```kotlin theme={null} val deviceId: String ``` ```kotlin theme={null} val client = Chatbase.create(context, "YOUR_AGENT_ID") println(client.deviceId) // "a1b2c3d4-e5f6-..." ``` The device ID uses Android's `Settings.Secure.ANDROID_ID` when available. On emulators or when restricted, it falls back to a UUID persisted in SharedPreferences (`chatbase_sdk_prefs`). The ID remains stable across app launches. ## identify `interface ChatbaseClient` — **Package:** `com.chatbase.sdk` ```kotlin theme={null} suspend fun identify(token: String) ``` Verify a JWT token with the Chatbase server and identify the current user. Subsequent requests are associated with this user. `identify()` is equivalent to [`verify()`](#verify) — it verifies the token server-side and triggers the anonymous-conversation merge. A JWT generated by your backend and signed with your agent's identity verification secret. The payload must include a `user_id` (or `sub`) claim. Create a signed JWT token on your server containing the user ID in its payload. ```kotlin theme={null} client.identify(jwtToken) ``` Conversations are now scoped to this user. ```kotlin theme={null} println(client.isIdentified) // true println(client.currentUserId) // "user_123" (confirmed by the server during verification) ``` ## Identity Properties ```kotlin theme={null} val deviceId: String ``` Auto-generated device ID. Always available. ```kotlin theme={null} val isIdentified: Boolean ``` `true` if a JWT token has been set via `identify()`. ```kotlin theme={null} val currentUserId: String? ``` User ID confirmed by the server when the token was verified. `null` if not identified. ## verify ```kotlin theme={null} suspend fun verify(token: String) ``` Verify a JWT token with the Chatbase server. On success, the server also merges any conversations created anonymously (with the device ID) into the verified user's account. `identify()` is an alias for this method. The JWT token to verify. ```kotlin theme={null} try { client.verify(jwtToken) println("Token is valid") } catch (e: ApiException) { println("Token verification failed: ${e.errorMessage}") } ``` When `verify()` succeeds, the server automatically merges previously anonymous (device-scoped) conversations into the verified user's account. Conversations started before identification are preserved and accessible under the user's identity. The merge runs asynchronously on the server — a `listConversations()` call issued immediately after `verify()` returns may not reflect it yet. ## How Identity Affects Conversations When identified, conversations are scoped to the user — `listConversations()` returns only that user's conversations. Without identity, conversations are scoped to the device. ## logout ```kotlin theme={null} fun logout() ``` Clear the JWT token and return to anonymous (device-scoped) mode. Also clears the current conversation ID so the next message starts a fresh anonymous conversation. ```kotlin theme={null} client.logout() println(client.isIdentified) // false println(client.currentUserId) // null println(client.currentConversationId) // null println(client.deviceId) // still available — unchanged ``` `identify()` and `verify()` are equivalent — both verify the token with the server and trigger the merge of prior anonymous (device-scoped) conversations into the user's account. You never need to call both. ## Related List conversations and load message history SDK setup and configuration # Delete chatbot icon Source: https://chatbase.co/docs/api-reference/assets/delete-chatbot-icon /openapi.yaml delete /delete-chatbot-icon Deletes the chatbot's icon image # Delete chatbot profile picture Source: https://chatbase.co/docs/api-reference/assets/delete-chatbot-profile-picture /openapi.yaml delete /delete-chatbot-profile-picture Deletes the chatbot's profile picture # Upload chatbot icon Source: https://chatbase.co/docs/api-reference/assets/upload-chatbot-icon /openapi.yaml post /upload-chatbot-icon Uploads an icon image for the chatbot # Upload chatbot profile picture Source: https://chatbase.co/docs/api-reference/assets/upload-chatbot-profile-picture /openapi.yaml post /upload-chatbot-profile-picture Uploads a profile picture for the chatbot # Chat with a chatbot Source: https://chatbase.co/docs/api-reference/chat/chat-with-a-chatbot /openapi.yaml post /chat Send a message to a chatbot and receive a response. Supports streaming responses. Can continue existing conversations by providing a conversationId. **Looking for API v2?** The new Chatbase API v2 features structured error codes, cursor-based pagination, and SSE streaming. Note that API v2 is available starting from the Standard Plan. [Check out the API v2 Reference →](/docs/api-v2/overview) # Create a new chatbot Source: https://chatbase.co/docs/api-reference/chatbots/create-a-new-chatbot /openapi.yaml post /create-chatbot Creates a new chatbot with training data from text # Delete a chatbot Source: https://chatbase.co/docs/api-reference/chatbots/delete-a-chatbot /openapi.yaml delete /delete-chatbot Permanently deletes a chatbot and all associated data # Get all chatbots Source: https://chatbase.co/docs/api-reference/chatbots/get-all-chatbots /openapi.yaml get /get-chatbots Retrieves all chatbots for the authenticated account # Update a chatbot Source: https://chatbase.co/docs/api-reference/chatbots/update-a-chatbot /openapi.yaml post /update-chatbot-data Updates and retrains a chatbot with new content # Update chatbot settings Source: https://chatbase.co/docs/api-reference/chatbots/update-chatbot-settings /openapi.yaml post /update-chatbot-settings Updates various chatbot configuration settings # Create contacts for a chatbot Source: https://chatbase.co/docs/api-reference/contacts/create-contacts-for-a-chatbot /openapi.yaml post /chatbots/{chatbotId}/contacts Creates one or more contacts for a specific chatbot (max 1000 per request) # Create custom attribute Source: https://chatbase.co/docs/api-reference/contacts/create-custom-attribute /openapi.yaml post /chatbots/{chatbotId}/custom-attributes Creates a new custom attribute for contacts # Delete a contact Source: https://chatbase.co/docs/api-reference/contacts/delete-a-contact /openapi.yaml delete /chatbots/{chatbotId}/contacts/{contactId} Permanently deletes a contact # Get a specific contact Source: https://chatbase.co/docs/api-reference/contacts/get-a-specific-contact /openapi.yaml get /chatbots/{chatbotId}/contacts/{contactId} Retrieves a single contact by ID # Get contacts for a chatbot Source: https://chatbase.co/docs/api-reference/contacts/get-contacts-for-a-chatbot /openapi.yaml get /chatbots/{chatbotId}/contacts Retrieves paginated list of contacts for a specific chatbot # Get custom attributes schema Source: https://chatbase.co/docs/api-reference/contacts/get-custom-attributes-schema /openapi.yaml get /chatbots/{chatbotId}/custom-attributes Retrieves the custom attributes schema for contacts # Update a contact Source: https://chatbase.co/docs/api-reference/contacts/update-a-contact /openapi.yaml patch /chatbots/{chatbotId}/contacts/{contactId} Updates an existing contact's information # Update custom attribute Source: https://chatbase.co/docs/api-reference/contacts/update-custom-attribute /openapi.yaml put /chatbots/{chatbotId}/custom-attributes/{name} Updates an existing custom attribute # Get conversations for a chatbot Source: https://chatbase.co/docs/api-reference/conversations/get-conversations-for-a-chatbot /openapi.yaml get /get-conversations Retrieves conversation history for a specific chatbot **Looking for API v2?** The new Chatbase API v2 features structured error codes, cursor-based pagination, and SSE streaming. [Check out the API v2 Reference →](/docs/api-v2/overview) # Get leads for a chatbot Source: https://chatbase.co/docs/api-reference/leads/get-leads-for-a-chatbot /openapi.yaml get /get-leads Retrieves collected leads/customers for a specific chatbot # Agents Source: https://chatbase.co/docs/api-v2/agents Programmatically create, configure, train, and manage your Chatbase AI agents. The Agents API gives you full programmatic control over your AI agents — create them, configure their behavior and widget styles, manage training, and clone them for reuse. All endpoints are scoped to the account that owns the API key; a request for another account's agent returns 404, not 403, to avoid leaking existence. ## Agent status The `status` field on an agent reflects where it is in its training lifecycle: | Status | Meaning | | ----------- | ---------------------------------------------------------- | | `untrained` | Agent has never been trained | | `training` | A training run is in progress | | `trained` | Training completed; agent is using its latest sources | | `updated` | Sources changed since the last training — retrain to apply | Use `GET /agents/{agentId}` to poll `status` after triggering a train or after creating an agent with a URL. ## Partial updates `PUT /agents/{agentId}` uses **partial update semantics** — only the fields you include are changed. | What you send | Result | | ---------------------------------- | ---------------------------------------------- | | Omit a field | No change — field keeps its current value | | Send a value | Field is updated to that value | | Send `null` (nullable fields only) | Feature is disabled or field resets to default | Example: `{ "voiceSettings": null }` disables voice mode. An empty body `{}` makes no changes. The `ipRateLimits` object also supports partial updates within itself — send only the sub-fields you want to change without affecting the others. ## `pendingSteps` Create and clone both return a 201 even when secondary steps fail. The agent always exists — `id` is always in the response. `pendingSteps` tells you what to retry: | Step | Meaning | Recovery | | ------------- | ---------------------------------------- | ------------------------------------------------------------------------------ | | `ADD_SOURCE` | The `url` could not be added as a source | Add sources manually via the [Sources API](/docs/api-v2/sources/create-source) | | `TRAIN_AGENT` | Training could not be started | Trigger manually via [Train agent](/docs/api-v2/agents/train-agent) | When `pendingSteps` is absent, all steps succeeded. ## Training is asynchronous `POST /agents/{agentId}/train` queues a job and returns immediately. Poll `GET /agents/{agentId}` and watch `status` to track progress. If training is already running you'll get `409 AGENT_ALREADY_TRAINING` — wait for the current run to finish rather than retrying. ## Endpoints Paginated list of all agents for the account Create a new agent, optionally seeded with a URL Retrieve full agent details by ID Partial update of agent configuration Configure chat widget and center stage appearance Trigger a training run on current sources Deep-copy an agent including all its sources Enable or disable 7-day automatic retraining Permanently delete an agent and all its data ## Error codes Agent-specific error codes beyond the standard [authentication and rate-limiting errors](/docs/api-v2/error-handling):
Code HTTP Description
AGENT\_NOT\_FOUND404Agent doesn't exist or doesn't belong to the authenticated account.
AGENT\_ALREADY\_TRAINING409A training run is already in progress. Wait for it to complete before starting another.
AGENT\_NOT\_TRAINED409Auto-retrain requires the agent to have been trained at least once. Train the agent first.
AGENT\_LIMIT\_REACHED403The account has reached its plan's maximum number of agents. Delete an existing agent or upgrade your plan.
PLAN\_FEATURE\_NOT\_AVAILABLE403The requested feature is not available on the current plan. Upgrade to unlock it.
# Chat with an agent Source: https://chatbase.co/docs/api-v2/agents/chat-with-an-agent /api-v2-openapi.json post /agents/{agentId}/chat Send a message to an agent and receive a response. Supports streaming responses when `stream: true` is set in the request body. # Clone agent Source: https://chatbase.co/docs/api-v2/agents/clone-agent /api-v2-openapi.json post /agents/{agentId}/clone Creates a full deep-clone of an agent, including all its sources (excluding Notion). Returns the new agent ID. Same response shape as Create Agent — `pendingSteps` indicates if training could not start automatically. The clone is a new, independent agent; changes to the original do not affect it. Subject to plan agent limits — returns `AGENT_LIMIT_REACHED` (403) when the account has reached its maximum number of agents. # Create agent Source: https://chatbase.co/docs/api-v2/agents/create-agent /api-v2-openapi.json post /agents Creates a new agent. If `url` is provided, a link source is created from that URL and training is queued automatically. The agent is always created even if source setup or training fails — `id` is always returned. Check `pendingSteps` in the response to see which steps need to be retried: - `ADD_SOURCE` — the URL could not be added as a source. Add sources manually via the Sources API. - `TRAIN_AGENT` — training could not be started. Trigger it manually via `POST /agents/{agentId}/train`. When `pendingSteps` is absent, all steps succeeded. Subject to plan agent limits — returns `AGENT_LIMIT_REACHED` (403) when the account has reached its maximum number of agents. # Delete agent Source: https://chatbase.co/docs/api-v2/agents/delete-agent /api-v2-openapi.json delete /agents/{agentId} Permanently deletes an agent and all its sources. Also disconnects any active integrations (Slack, WhatsApp, etc.). This action is irreversible. # Get agent Source: https://chatbase.co/docs/api-v2/agents/get-agent /api-v2-openapi.json get /agents/{agentId} Returns a single agent by ID. # List agents Source: https://chatbase.co/docs/api-v2/agents/list-agents /api-v2-openapi.json get /agents Returns a paginated list of all agents for the authenticated account. # Retry a message Source: https://chatbase.co/docs/api-v2/agents/retry-a-message /api-v2-openapi.json post /agents/{agentId}/conversations/{conversationId}/retry Retry generating an assistant response for a given message. Truncates the conversation at the target message, then re-sends the preceding user message through the chat service. # Start a voice session Source: https://chatbase.co/docs/api-v2/agents/start-a-voice-session /api-v2-openapi.json post /agents/{agentId}/voice/sessions Create a real-time voice session for an agent. Pass the response `data` to the Chatbase Voice SDK (`@chatbase-co/voice-sdk`) in your client: the SDK connects, publishes the microphone, and the agent joins automatically. Requires a plan with voice mode enabled; voice minutes consume message credits. Send `{}` when no options are needed. # Submit a tool result Source: https://chatbase.co/docs/api-v2/agents/submit-a-tool-result /api-v2-openapi.json post /agents/{agentId}/conversations/{conversationId}/tool-result Submit the result of a client-side tool call. Use the toolCallId from the tool-call part in the chat response to identify the tool call. # Toggle auto-retrain Source: https://chatbase.co/docs/api-v2/agents/toggle-auto-retrain /api-v2-openapi.json put /agents/{agentId}/auto-retrain Enables or disables automatic retraining. When enabled, the agent retrains every 7 days to reflect any source changes. Requirements: - The agent must have been trained at least once — returns `AGENT_NOT_TRAINED` (409) otherwise. - Requires the Standard plan or higher — returns `PLAN_FEATURE_NOT_AVAILABLE` (403) on unsupported plans. # Train agent Source: https://chatbase.co/docs/api-v2/agents/train-agent /api-v2-openapi.json post /agents/{agentId}/train Queues a training job for the agent. Training is asynchronous — use GET /agents/{agentId} to poll `status` for completion. # Update agent Source: https://chatbase.co/docs/api-v2/agents/update-agent /api-v2-openapi.json put /agents/{agentId} Partially updates an agent. Only provided fields are changed. # Update agent styles Source: https://chatbase.co/docs/api-v2/agents/update-agent-styles /api-v2-openapi.json put /agents/{agentId}/styles Updates the visual styles for an agent. # Authentication Source: https://chatbase.co/docs/api-v2/authentication How to authenticate with the Chatbase API v2 using Bearer tokens, and understand rate limiting. ## Bearer Token Authentication All API v2 endpoints (except the health check) require a Bearer token in the `Authorization` header: ``` Authorization: Bearer ``` ### Getting an API Key 1. Go to the [Chatbase Dashboard](https://www.chatbase.co/dashboard) 2. Go to **Workspace settings** → **API keys** 3. Click **Create API Key** 4. Copy and securely store the generated key API keys grant full access to your workspace. Never expose them in client-side code, public repositories, or browser network requests. API v2 requires a Chatbase Standard Plan or above. Requests from accounts on unsupported plans will be rejected. ### Example Request ```bash theme={null} curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"message": "Hello!"}' ``` ## Rate Limiting The API enforces a rate limit of **100 requests per 10-second sliding window**, scoped per API key and IP address. ### Rate Limit Headers Every response includes rate limit headers so you can track your usage: | Header | Description | | ----------------------- | ----------------------------------------------------------------- | | `X-RateLimit-Limit` | Maximum number of requests allowed in the window (100). | | `X-RateLimit-Remaining` | Number of requests remaining in the current window. | | `X-RateLimit-Reset` | Unix timestamp in milliseconds when the current window resets. | | `Retry-After` | Seconds to wait before retrying. Only present on `429` responses. | ### Handling Rate Limits When you exceed the rate limit, the API returns a `429` status code: ```json theme={null} { "error": { "code": "RATE_LIMIT_TOO_MANY_REQUESTS", "message": "Too many requests, please try again later" } } ``` Use the `Retry-After` header to determine how long to wait before retrying: ```javascript theme={null} async function fetchWithRetry(url, options) { const response = await fetch(url, options); if (response.status === 429) { const retryAfter = parseInt(response.headers.get("Retry-After"), 10); await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000)); return fetchWithRetry(url, options); } return response; } ``` ## Request ID Every response includes an `x-request-id` header containing a unique identifier for the request. When contacting support about an error, always include this value to help with debugging. ``` x-request-id: req_a1b2c3d4e5f6 ``` # Client Actions Source: https://chatbase.co/docs/api-v2/client-actions Handle client-side actions invoked by your AI agent through the Chatbase API v2. ## What Are Client Actions? Client actions allow your AI agent to request that your application perform an action on the client side. When an agent determines it needs external information or wants to trigger an operation, it responds with a `finishReason` of `"tool-calls"` and includes `tool-call` parts describing what it needs. Your application executes the action, submits the result back to the API, and then continues the conversation. Client actions correspond to the **Custom Actions** configured on your agent in the Chatbase dashboard. The `toolName` in the API response is the name of the configured action. ## Flow ```mermaid theme={null} sequenceDiagram participant App as Your App participant API as Chatbase API participant Agent as AI Agent App->>API: POST /chat (message) API->>Agent: Process message Agent-->>API: Response with tool-call parts API-->>App: finishReason: "tool-calls" App->>App: Execute action client-side App->>API: POST /tool-result (toolCallId, output) API-->>App: { success: true } App->>API: POST /chat (continue conversation) API->>Agent: Process with tool result Agent-->>API: Final response API-->>App: finishReason: "stop" ``` Send a message to the chat endpoint as usual. The response has `finishReason: "tool-calls"` and `tool-call` parts containing `toolCallId`, `toolName`, and `input`. Use `toolName` and `input` to determine what to do and execute the action in your application. Send the result to `POST /agents/{agentId}/conversations/{conversationId}/tool-result` with the `toolCallId` and `output`. Call the chat endpoint again with the `conversationId`. You can omit `message` to let the agent continue based on the tool result alone, or include a new message. ## Message Parts Responses can include three types of parts in the `parts` array: Text content generated by the agent. Fields: `type`, `text` A client action the agent wants your app to execute. Fields: `type`, `toolCallId`, `toolName`, `input` The result of a previously executed client action (visible in conversation history). Fields: `type`, `toolCallId`, `toolName`, `output` ## Detecting a Client Action Check the `finishReason` in the response metadata. When it is `"tool-calls"`, the `parts` array will contain one or more `tool-call` entries: ```json theme={null} { "data": { "id": "msg_abc123", "role": "assistant", "parts": [ { "type": "text", "text": "Let me look up that order for you." }, { "type": "tool-call", "toolCallId": "call_abc123", "toolName": "lookupOrder", "input": { "orderId": "ORD-123" } } ], "metadata": { "userMessageId": "msg_xyz789", "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123", "finishReason": "tool-calls", "usage": { "credits": 2 } } } } ``` ## Submitting the Result After executing the action, submit the result using the tool-result endpoint: ``` POST /api/v2/agents/{agentId}/conversations/{conversationId}/tool-result ``` ### Request Body The `toolCallId` from the `tool-call` part in the chat response. The result of executing the action. ### Response ```json theme={null} { "data": { "success": true } } ``` ## Continuing the Conversation After submitting the tool result, continue the conversation by calling the chat endpoint again. You can either: * **Omit `message`** to let the agent continue based on the tool result alone. * **Include a `message`** to provide additional context or a follow-up question. You must include the `conversationId` to continue the same conversation. ```bash theme={null} curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" }' ``` ## Streaming Client Actions When streaming is enabled, client action input arrives incrementally through these events: Signals the start of a client action. Includes `toolCallId` and `toolName`. Incremental chunks of the action input stream in. The complete input is ready. You can read the full `input` object directly from this event without concatenating the preceding deltas. The stream's `finish` event will have `finishReason: "tool-calls"`. See [Streaming](/docs/api-v2/streaming) for full event type reference. ## Code Examples ```javascript Node.js theme={null} // Step 1: Send a message const chatResponse = await fetch( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ message: "What's the status of order ORD-123?", stream: false, }), } ); const { data } = await chatResponse.json(); const { conversationId, finishReason } = data.metadata; // Step 2: Check if a client action was invoked if (finishReason === "tool-calls") { for (const part of data.parts) { if (part.type === "tool-call") { // Step 3: Execute the action const result = await executeAction(part.toolName, part.input); // Step 4: Submit the result await fetch( `https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/conversations/${conversationId}/tool-result`, { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ toolCallId: part.toolCallId, output: result, }), } ); } } // Step 5: Continue the conversation const continueResponse = await fetch( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ conversationId, stream: false, }), } ); const continued = await continueResponse.json(); console.log(continued.data.parts); } // Your action handler async function executeAction(toolName, input) { switch (toolName) { case "lookupOrder": // Call your order service return { status: "shipped", eta: "2026-04-03" }; default: return { error: "Unknown action" }; } } ``` ```python Python theme={null} import requests API_KEY = "YOUR_API_KEY" AGENT_ID = "YOUR_AGENT_ID" BASE_URL = "https://www.chatbase.co/api/v2" HEADERS = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json", } # Step 1: Send a message chat_response = requests.post( f"{BASE_URL}/agents/{AGENT_ID}/chat", headers=HEADERS, json={ "message": "What's the status of order ORD-123?", "stream": False, }, ).json() data = chat_response["data"] conversation_id = data["metadata"]["conversationId"] finish_reason = data["metadata"]["finishReason"] # Step 2: Check if a client action was invoked if finish_reason == "tool-calls": for part in data["parts"]: if part["type"] == "tool-call": # Step 3: Execute the action result = execute_action(part["toolName"], part["input"]) # Step 4: Submit the result requests.post( f"{BASE_URL}/agents/{AGENT_ID}/conversations/{conversation_id}/tool-result", headers=HEADERS, json={ "toolCallId": part["toolCallId"], "output": result, }, ) # Step 5: Continue the conversation continued = requests.post( f"{BASE_URL}/agents/{AGENT_ID}/chat", headers=HEADERS, json={ "conversationId": conversation_id, "stream": False, }, ).json() for part in continued["data"]["parts"]: if part["type"] == "text": print(part["text"]) def execute_action(tool_name, tool_input): if tool_name == "lookupOrder": return {"status": "shipped", "eta": "2026-04-03"} return {"error": "Unknown action"} ``` ```bash curl theme={null} # Step 1: Send a message curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "message": "What is the status of order ORD-123?", "stream": false }' # Step 2: Submit the tool result (use toolCallId from the response) curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/conversations/CONVERSATION_ID/tool-result' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "toolCallId": "call_abc123", "output": { "status": "shipped", "eta": "2026-04-03" } }' # Step 3: Continue the conversation curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "conversationId": "CONVERSATION_ID" }' ``` ## Error Handling | Code | Status | Description | | ------------------------------ | ------ | --------------------------------------------------------------------------------------------------------- | | `RESOURCE_TOOL_CALL_NOT_FOUND` | 404 | No pending client action matches the provided `toolCallId`. It may have expired or already been resolved. | | `VALIDATION_INVALID_BODY` | 400 | The request body failed schema validation. Check the `details` field for specifics. | # Export conversations Source: https://chatbase.co/docs/api-v2/conversations/export-conversations /api-v2-openapi.json get /agents/{agentId}/conversations/export Export all conversations with full message history for an agent. Includes conversations from all sources. Tool results are sanitized to remove internal data. Supports cursor-based pagination. Pass `conversationId` to fetch a single conversation from any source (widget, API, WhatsApp, etc.). Pass `include=summary` to omit message bodies for a cheaper triage pass, `source` to restrict to one or more conversation sources, and `startDate` / `endDate` to restrict to a createdAt window. # Get a conversation Source: https://chatbase.co/docs/api-v2/conversations/get-a-conversation /api-v2-openapi.json get /agents/{agentId}/conversations/{conversationId} Get conversation metadata and its most recent messages. The pagination cursor can be used with the list messages endpoint to fetch older messages. Only returns conversations created through the API. To fetch a conversation from any source (widget, WhatsApp, etc.), use GET /agents/{agentId}/conversations/export?conversationId={conversationId} instead. # List conversation messages Source: https://chatbase.co/docs/api-v2/conversations/list-conversation-messages /api-v2-openapi.json get /agents/{agentId}/conversations/{conversationId}/messages List all messages in a conversation with cursor-based pagination. Messages are returned in chronological order within each page, paginating backward from newest. The cursor from the get-conversation endpoint works here. # List conversations Source: https://chatbase.co/docs/api-v2/conversations/list-conversations /api-v2-openapi.json get /agents/{agentId}/conversations List conversations for an agent, ordered by createdAt date. Supports cursor-based pagination. Pass `startDate` and/or `endDate` to restrict the results to a createdAt window. # List conversations for a user Source: https://chatbase.co/docs/api-v2/conversations/list-conversations-for-a-user /api-v2-openapi.json get /agents/{agentId}/users/{userId}/conversations List conversations for a specific user under an agent, ordered by last activity. Supports cursor-based pagination. # Update message feedback Source: https://chatbase.co/docs/api-v2/conversations/update-message-feedback /api-v2-openapi.json patch /agents/{agentId}/conversations/{conversationId}/messages/{messageId}/feedback Set or clear feedback on an assistant message. Use "positive" or "negative" to set feedback, or null to remove existing feedback. # Error Handling Source: https://chatbase.co/docs/api-v2/error-handling Structured error codes and troubleshooting guide for the Chatbase API v2. ## Error Response Format All errors follow a consistent envelope format: ```json theme={null} { "error": { "code": "ERROR_CODE", "message": "Human-readable description", "details": {} } } ``` | Field | Type | Description | | --------- | -------- | ------------------------------------------------------------------------------- | | `code` | `string` | Machine-readable error code. Use this for programmatic handling. | | `message` | `string` | Human-readable description of the error. | | `details` | `object` | Optional. Field-level validation errors (present on `VALIDATION_INVALID_BODY`). | ## Error Codes
Code Description
VALIDATION\_INVALID\_BODYThe request body failed schema validation. Check the details field for specific field errors.
VALIDATION\_INVALID\_JSONThe request body is not valid JSON.
CHAT\_RETRY\_NO\_USER\_MESSAGEThe retry target message has no preceding user message to re-send.
AUTH\_MISSING\_API\_KEYNo Authorization header was provided.
AUTH\_INVALID\_API\_KEYThe API key is not valid.
AUTH\_EXPIRED\_API\_KEYThe API key has expired. Generate a new one from the dashboard.
CHAT\_CREDITS\_EXHAUSTEDThe workspace's message credit balance is zero. Upgrade the plan or wait for credits to reset.
CHAT\_AGENT\_CREDITS\_EXHAUSTEDThe specific agent's credit allocation has been used up.
SUBSCRIPTION\_API\_RESTRICTED\_PLANYour current plan does not include API access. A Standard Plan or above is required.
AUTH\_INSUFFICIENT\_PERMISSIONSThe API key does not have the required permissions for this operation.
CHAT\_MODEL\_NOT\_ALLOWEDThe agent is configured to use a model that is not available on the current plan.
CHAT\_CONVERSATION\_MISMATCHThe conversation does not belong to the specified agent.
CHAT\_CONVERSATION\_NOT\_ONGOINGThe conversation has ended or been taken over and cannot receive new messages.
RESOURCE\_NOT\_FOUNDThe requested resource does not exist.
RESOURCE\_TOOL\_CALL\_NOT\_FOUNDNo pending client action matches the provided toolCallId. It may have expired or already been resolved.
RESOURCE\_MESSAGE\_NOT\_FOUNDThe specified message was not found in the conversation.
RESOURCE\_MESSAGE\_NOT\_ASSISTANTOnly assistant messages support feedback and metadata updates.
CHAT\_RETRY\_MESSAGE\_NOT\_FOUNDThe message ID provided for retry was not found in the conversation.
RATE\_LIMIT\_TOO\_MANY\_REQUESTSRate limit exceeded. Check the Retry-After header for how long to wait. See Authentication for details.
INTERNAL\_SERVER\_ERRORAn unexpected error occurred. If this persists, contact support with the x-request-id header value.
CHAT\_STREAMING\_ERRORAn error occurred during stream generation. The stream may have been partially delivered.
SOURCE\_NOT\_FOUNDSource doesn't exist, belongs to a different agent, or has been permanently deleted.
SOURCE\_TYPE\_NOT\_SUPPORTEDAttempting to update a notionPage via PUT. Manage Notion sources through the dashboard integration.
SOURCE\_PENDING\_DELETIONSource has toBeDeleted status. Restore it before making edits.
SOURCE\_NOT\_RESTORABLERestore was called on a source that is not in toBeDeleted state.
SOURCE\_LINK\_LIMIT\_EXCEEDEDThe 15 crawl/sitemap-parent limit per agent has been reached on create or restore.
SOURCE\_SIZE\_LIMIT\_EXCEEDEDCreating or updating this source would exceed the plan's storage limit.
SOURCE\_DUPLICATEA link source with this URL and linkType already exists for this agent.
SOURCE\_URL\_IMMUTABLEA link's URL cannot be changed via PUT. Delete and recreate the source to use a different URL.
AGENT\_NOT\_FOUNDAgent doesn't exist or doesn't belong to the authenticated account.
AGENT\_ALREADY\_TRAININGA training run is already in progress. Wait for it to complete before starting another.
AGENT\_NOT\_TRAINEDAuto-retrain requires the agent to have been trained at least once.
AGENT\_LIMIT\_REACHEDThe account has reached its plan's maximum number of agents. Delete an existing agent or upgrade your plan.
PLAN\_FEATURE\_NOT\_AVAILABLEThe requested feature is not available on the current plan. Upgrade to unlock it.
**Example with field-level details (`VALIDATION_INVALID_BODY`):** ```json theme={null} { "error": { "code": "VALIDATION_INVALID_BODY", "message": "Invalid request", "details": { "message": "Required" } } } ``` ## Handling Errors ```javascript theme={null} const response = await fetch( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ message: "Hello" }), } ); if (!response.ok) { const { error } = await response.json(); const requestId = response.headers.get("x-request-id"); switch (error.code) { case "RATE_LIMIT_TOO_MANY_REQUESTS": const retryAfter = response.headers.get("Retry-After"); // Wait and retry break; case "CHAT_CREDITS_EXHAUSTED": // Notify user about credit limit break; case "VALIDATION_INVALID_BODY": // Fix request based on error.details console.log("Validation errors:", error.details); break; default: console.error(`[${error.code}] ${error.message} (request: ${requestId})`); } } ``` # Health check Source: https://chatbase.co/docs/api-v2/health/health-check /api-v2-openapi.json get /health Returns the API health status. No authentication required. # Helpdesk Source: https://chatbase.co/docs/api-v2/helpdesk Programmatically create, triage, and reply to support tickets for your Chatbase agents. The Helpdesk API is the same ticketing that powers the Helpdesk tab in the dashboard. You can create tickets on behalf of customers, list and search them, and change a ticket's status, assignee, or team. Each ticket carries a message thread you can read and reply to. Tickets are numbered per agent. The `ticketNumber` path parameter is that per-agent number, not a global id. A ticket's `channel` records where it originated, such as email, the chat widget, or WhatsApp. Tickets created through this API always have `channel: "api"`. ## Statuses Each ticket has a status, and each status belongs to one of six fixed categories: `new`, `on_you`, `on_customer`, `on_hold`, `closed`, `cancelled`. The statuses themselves are configured per agent in the dashboard; every category has exactly one default status. Write endpoints accept a status in one of two forms, at most one per request: | Field | Meaning | | ---------------- | ----------------------------------------------------------------------------------------------------- | | `statusId` | A specific configured status. Must belong to the agent and be active; archived statuses are rejected. | | `statusCategory` | Resolves to that category's default status. | [List ticket statuses](/docs/api-v2/helpdesk/list-ticket-statuses) returns the agent's active statuses with their ids, categories, and labels. Each status has two labels: `externalLabel` is what the customer sees, `internalLabel` is what the dashboard shows. ## Assignment and routing When you create a ticket, the assignee fields decide whether auto-assignment runs. `assigneeId` and `assigneeEmail` are a mutually exclusive pair; sending both is a 400. | Assignee | `teamId` | Result | | ------------------ | -------- | ------------------------------------------------------------------------------------------ | | Provided | Any | Written as given. No auto-assignment. | | `assigneeId: null` | Any | Ticket is created unassigned. The team is still written if given. | | Omitted | Provided | An agent is picked within that team by its assignment strategy. Routing rules are skipped. | | Omitted | Omitted | Routing rules pick both the team and the assignee. | [Update a ticket](/docs/api-v2/helpdesk/update-a-ticket) never auto-assigns. Omitted fields keep their current value, `assigneeId: null` unassigns the ticket, and `teamId: null` clears the team. [List teams](/docs/api-v2/helpdesk/list-teams) returns the agent's teams; exactly one is the default. ## Messages A ticket's thread contains three message types: | Type | Meaning | | ------- | ------------------------------------------------------------------------------------------------------------------------------ | | `reply` | Customer-visible. Delivered over the ticket's origin channel. | | `note` | Internal. Never delivered to the customer. | | `event` | System record of a change, such as a status transition or assignment. Excluded from list results unless requested via `types`. | [Add a message to a ticket](/docs/api-v2/helpdesk/add-a-message-to-a-ticket) currently accepts only `type: "reply"`, attributed to a team member via `authorId` or `authorEmail`. The body is GitHub-flavored Markdown; raw HTML is stripped. Delivery to the customer is asynchronous, so a 201 means the reply was recorded, not that it reached the customer. ## Endpoints Filterable, sortable, paginated list Free-text search over ticket messages Open a ticket on behalf of a customer Retrieve a single ticket by number Change status, assignee, or team Read a ticket's thread Post an agent reply The agent's teams and the default Configured statuses with ids and labels ## Error codes Helpdesk-specific error codes beyond the standard [authentication and rate-limiting errors](/docs/api-v2/error-handling):
Code HTTP Description
TICKET\_NOT\_FOUND404No ticket matches this number for the agent.
CONVERSATION\_NOT\_TAKEN\_OVER409The ticket is linked to a live conversation that has not been taken over from the AI agent, so a human reply cannot be posted. Take over the conversation from the dashboard first.
MESSAGE\_CONTENT\_NOT\_RENDERABLE422The message body rendered to empty HTML. This happens when it consists only of raw HTML, which is stripped. Send Markdown or plain text.
TICKET\_INVALID\_STATUS422statusId does not belong to a status for this agent.
TICKET\_ARCHIVED\_STATUS422statusId refers to an archived status, which cannot be applied.
TICKET\_TEAM\_MEMBER\_NOT\_FOUND422Neither assigneeId nor assigneeEmail resolved to a team member on this account.
TICKET\_TEAM\_NOT\_FOUND422teamId does not belong to a team for this agent.
TEAM\_MEMBER\_NOT\_FOUND422On message creation, neither authorId nor authorEmail resolved to a team member on this account.
# Add a message to a ticket Source: https://chatbase.co/docs/api-v2/helpdesk/add-a-message-to-a-ticket /api-v2-openapi.json post /agents/{agentId}/helpdesk/tickets/{ticketNumber}/messages Posts an agent reply to a ticket on behalf of a team member. Delivery to the customer is asynchronous; a 201 confirms the reply was recorded, not delivered. Posting a reply may transition the ticket status, matching dashboard behavior. # Create a ticket Source: https://chatbase.co/docs/api-v2/helpdesk/create-a-ticket /api-v2-openapi.json post /agents/{agentId}/helpdesk/tickets Creates a ticket on behalf of a customer. Unless an assignee is provided, the ticket is auto-assigned via the agent's routing rules. # Get a ticket Source: https://chatbase.co/docs/api-v2/helpdesk/get-a-ticket /api-v2-openapi.json get /agents/{agentId}/helpdesk/tickets/{ticketNumber} Returns a single ticket by its per-agent ticket number. # List teams Source: https://chatbase.co/docs/api-v2/helpdesk/list-teams /api-v2-openapi.json get /agents/{agentId}/helpdesk/teams Returns the teams configured for an agent, ordered by creation date. Exactly one team is marked as the default for the agent. # List ticket messages Source: https://chatbase.co/docs/api-v2/helpdesk/list-ticket-messages /api-v2-openapi.json get /agents/{agentId}/helpdesk/tickets/{ticketNumber}/messages Returns a ticket's message thread in chronological order. Supports cursor-based pagination. # List ticket statuses Source: https://chatbase.co/docs/api-v2/helpdesk/list-ticket-statuses /api-v2-openapi.json get /agents/{agentId}/helpdesk/ticket-statuses Returns the active (non-archived) ticket statuses configured for an agent, ordered by category then position. Each category has exactly one default status. # List tickets Source: https://chatbase.co/docs/api-v2/helpdesk/list-tickets /api-v2-openapi.json get /agents/{agentId}/helpdesk/tickets Returns tickets for an agent, sorted by `updatedAt` descending by default. Supports filtering and cursor-based pagination. Filters combine with AND across parameters. # Search tickets Source: https://chatbase.co/docs/api-v2/helpdesk/search-tickets /api-v2-openapi.json post /agents/{agentId}/helpdesk/tickets/search Searches ticket messages with a free-text query and returns matching tickets ranked by relevance. Results are capped and not paginated. # Update a ticket Source: https://chatbase.co/docs/api-v2/helpdesk/update-a-ticket /api-v2-openapi.json patch /agents/{agentId}/helpdesk/tickets/{ticketNumber} Partially updates a ticket's status, assignee, or team. Only provided fields are changed. Fields are validated together but written independently, so a 500 can leave a partial update. # API v2 Overview Source: https://chatbase.co/docs/api-v2/overview Introduction to the Chatbase API v2 — a structured, modern REST API for chatting with agents and managing conversations. **Standard Plan required.** The Chatbase API v2 is available starting from the Standard Plan. [View pricing →](https://www.chatbase.co/pricing) Prefer the terminal? Use the [Chatbase CLI](/docs/cli/overview) for the same API v2 surface from your shell or CI. Most conversation endpoints apply exclusively to conversations created programmatically via the Chatbase API. Conversations generated through the bubble or external integrations cannot be accessed using these endpoints. The exception is the [Export conversations](/docs/api-v2/conversations/export-conversations) endpoint, which returns conversations from **all sources**, including a single conversation when you pass `conversationId`. ## What is the Chatbase API v2? The Chatbase API v2 is a redesigned REST API that provides a clean, consistent interface for interacting with your AI agents. It features structured error codes, cursor-based pagination, streaming support via Server-Sent Events, and a predictable response format. **Base URL:** ``` https://www.chatbase.co/api/v2 ``` ## Quick Start 1. Go to the [Chatbase Dashboard](https://www.chatbase.co/dashboard) 2. Go to **Workspace settings** → **API keys** 3. Click **Create API Key** and copy the generated key Store your API key securely. Never expose it in client-side code. 1. Select your AI Agent in the dashboard 2. Go to the agent’s **Settings** → **General** 3. Copy the **Agent ID** from the **Agent details** card ```bash theme={null} curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "message": "Hello! How can you help me?" }' ``` **Response:** ```json theme={null} { "data": { "id": "msg_abc123", "role": "assistant", "parts": [ { "type": "text", "text": "Hello! I'm here to help. What can I assist you with today?" } ], "metadata": { "userMessageId": "msg_xyz789", "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": null, "finishReason": "stop", "usage": { "credits": 2 } } } } ``` ## Endpoints **Base URL:** `https://www.chatbase.co/api/v2` | Method | Endpoint | | -------- | --------------------------------------------------------------------------------------- | | `GET` | `/api/v2/health` | | `GET` | `/api/v2/agents` | | `POST` | `/api/v2/agents` | | `GET` | `/api/v2/agents/{agentId}` | | `PUT` | `/api/v2/agents/{agentId}` | | `DELETE` | `/api/v2/agents/{agentId}` | | `PUT` | `/api/v2/agents/{agentId}/styles` | | `PUT` | `/api/v2/agents/{agentId}/auto-retrain` | | `POST` | `/api/v2/agents/{agentId}/clone` | | `POST` | `/api/v2/agents/{agentId}/train` | | `POST` | `/api/v2/agents/{agentId}/chat` | | `POST` | `/api/v2/agents/{agentId}/conversations/{conversationId}/retry` | | `GET` | `/api/v2/agents/{agentId}/conversations` | | `GET` | `/api/v2/agents/{agentId}/conversations/export` | | `GET` | `/api/v2/agents/{agentId}/conversations/{conversationId}` | | `GET` | `/api/v2/agents/{agentId}/conversations/{conversationId}/messages` | | `GET` | `/api/v2/agents/{agentId}/users/{userId}/conversations` | | `POST` | `/api/v2/agents/{agentId}/conversations/{conversationId}/tool-result` | | `PATCH` | `/api/v2/agents/{agentId}/conversations/{conversationId}/messages/{messageId}/feedback` | | `GET` | `/api/v2/agents/{agentId}/sources/summary` | | `GET` | `/api/v2/agents/{agentId}/sources` | | `POST` | `/api/v2/agents/{agentId}/sources` | | `GET` | `/api/v2/agents/{agentId}/sources/{sourceId}` | | `PUT` | `/api/v2/agents/{agentId}/sources/{sourceId}` | | `DELETE` | `/api/v2/agents/{agentId}/sources/{sourceId}` | | `POST` | `/api/v2/agents/{agentId}/sources/{sourceId}/restore` | **File upload base URL:** `https://files.chatbase.co/api/v2` | Method | Endpoint | | ------ | --------------------------------------------- | | `POST` | `/api/v2/agents/{agentId}/sources` | | `PUT` | `/api/v2/agents/{agentId}/sources/{sourceId}` | ## Response Headers Every response includes these headers: | Header | Description | | ----------------------- | ---------------------------------------------------------------- | | `x-request-id` | Unique request identifier. Include this when contacting support. | | `X-RateLimit-Limit` | Maximum requests allowed in the current window. | | `X-RateLimit-Remaining` | Requests remaining in the current window. | | `X-RateLimit-Reset` | Unix timestamp (ms) when the rate limit window resets. | ## Next Steps API keys, Bearer tokens, and rate limiting Real-time SSE streaming responses Structured error codes and troubleshooting Cursor-based pagination for list endpoints # Pagination Source: https://chatbase.co/docs/api-v2/pagination How cursor-based pagination works in the Chatbase API v2. ## How It Works The API v2 uses **cursor-based pagination** for all list endpoints. Cursors are opaque, base64-encoded strings — treat them as opaque tokens and do not attempt to decode or construct them. ### Query Parameters | Parameter | Type | Default | Description | | --------- | --------- | ------- | ------------------------------------------------------------------------- | | `cursor` | `string` | — | Opaque cursor from a previous response. Omit to start from the beginning. | | `limit` | `integer` | `20` | Number of items per page. Range: 1–100. | ### Response Shape All paginated responses follow this structure: ```json theme={null} { "data": [...], "pagination": { "cursor": "eyJ0IjoiMjAyNC0wMS0xNVQxMDozMDowMC4wMDBaIiwiaWQiOiJhYmMxMjMifQ==", "hasMore": true, "total": 142 } } ``` | Field | Type | Description | | -------------------- | ---------------- | ------------------------------------------------------------------------ | | `data` | `array` | The page of results. | | `pagination.cursor` | `string \| null` | Cursor to pass for the next page. `null` when there are no more results. | | `pagination.hasMore` | `boolean` | `true` if more results are available beyond this page. | | `pagination.total` | `integer` | Total number of items matching the query. | ## Paginating Through All Results Pass the `cursor` from each response into the next request to iterate through all pages: ```javascript Node.js theme={null} async function fetchAllConversations(agentId, apiKey) { const conversations = []; let cursor = undefined; do { const params = new URLSearchParams({ limit: "100" }); if (cursor) params.set("cursor", cursor); const response = await fetch( `https://www.chatbase.co/api/v2/agents/${agentId}/conversations?${params}`, { headers: { Authorization: `Bearer ${apiKey}` }, } ); const { data, pagination } = await response.json(); conversations.push(...data); cursor = pagination.cursor; } while (cursor); return conversations; } ``` ```python Python theme={null} import requests def fetch_all_conversations(agent_id: str, api_key: str): conversations = [] cursor = None while True: params = {"limit": 100} if cursor: params["cursor"] = cursor response = requests.get( f"https://www.chatbase.co/api/v2/agents/{agent_id}/conversations", headers={"Authorization": f"Bearer {api_key}"}, params=params, ) body = response.json() conversations.extend(body["data"]) cursor = body["pagination"]["cursor"] if not cursor: break return conversations ``` ## Export Pagination The export endpoint (`GET /api/v2/agents/{agentId}/conversations/export`) paginates through **all conversations** (from every source) with full message history included. Each page returns up to `limit` conversations with their complete messages already embedded — no separate call to a messages endpoint is needed. Because each exported conversation includes all of its messages, pages can be significantly larger than other paginated responses. Use a smaller `limit` if you want to keep response sizes manageable. ## Message Pagination The messages endpoint (`GET /api/v2/agents/{agentId}/conversations/{conversationId}/messages`) paginates **backward from the newest messages**. Within each page, messages are returned in chronological order. This means: * The first page contains the most recent messages * Passing the `cursor` fetches the next older page * Each page's messages are ordered oldest → newest The cursor returned by the [Get a conversation](/docs/api-v2/conversations/get-a-conversation) endpoint is compatible with the messages endpoint, so you can use it to fetch older messages beyond what the conversation response includes. # Sources Source: https://chatbase.co/docs/api-v2/sources Programmatically manage the knowledge sources that power your Chatbase agent — web pages, documents, Q&A pairs, and text. The Sources API lets you manage the content your agent is trained on. You can list, inspect, create, update, delete, and restore sources without touching the dashboard. ## Hostname routing **File upload operations use a different base URL from all other endpoints.** | Operation | Base URL | | ---------------------------------------- | ---------------------------------- | | All read operations and JSON-body writes | `https://www.chatbase.co/api/v2` | | Create or update **file** sources | `https://files.chatbase.co/api/v2` | Using the wrong host for file uploads will return a 404. ## Source types | Type | List | Get | Create | Update | Delete | Restore | | ------------ | ---- | --- | ------ | ------ | ------ | ------- | | `text` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `qna` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `link` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `file` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `notionPage` | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ | Notion pages appear in list and get results, but cannot be created or updated via the API. Manage Notion sources through the Notion integration in the dashboard. ## Source status Every source has a `status` field that reflects its position in the training lifecycle. | Status | Meaning | | ---------------- | --------------------------------------------------------------------------------------------------------- | | `untrained` | Newly created; not yet included in a training run | | `trained` | Part of the agent's active knowledge base | | `updated` | Content changed since last training — retrain needed | | `toBeDeletedted` | Marked for removal; will be removed on the next training run | | `deleted` | Permanently removed. Only returned by the DELETE endpoint response; never appears in list or get results. | When [Get sources summary](/docs/api-v2/sources/get-sources-summary) returns `shouldRetrain: true`, at least one source has `untrained`, `updated`, or `toBeDeletedted` status. Retrain your agent from the dashboard to apply the changes. ## Endpoints Paginated list with optional type and name filters Aggregate counts and sizes per source type Retrieve a single source by ID Create text, Q\&A, and link sources Upload PDF, DOCX, or TXT files Update text, Q\&A, and link sources Replace file content or rename a file source Soft-delete with restore support Undo a pending deletion ## Error codes Sources-specific error codes beyond the standard [authentication and rate-limiting errors](/docs/api-v2/error-handling):
Code HTTP Description
SOURCE\_NOT\_FOUND404Source doesn't exist, belongs to a different agent, or has been permanently deleted.
SOURCE\_TYPE\_NOT\_SUPPORTED400Attempting to update a notionPage via PUT. Manage Notion sources through the dashboard.
SOURCE\_PENDING\_DELETION409Source has toBeDeletedted status. Restore it before making edits.
SOURCE\_NOT\_RESTORABLE409Restore was called on a source that is not in toBeDeletedted state.
SOURCE\_LINK\_LIMIT\_EXCEEDED422The 15 crawl/sitemap-parent limit per agent has been reached. Delete an existing crawl or sitemap source before adding another.
SOURCE\_SIZE\_LIMIT\_EXCEEDED422Creating or updating this source would exceed the plan's storage limit. Remove existing sources or upgrade your plan.
SOURCE\_DUPLICATE409A link source with this URL and linkType already exists for this agent.
SOURCE\_URL\_IMMUTABLE400A link's URL cannot be changed via PUT. Delete and recreate the source to use a different URL.
# Create file source Source: https://chatbase.co/docs/api-v2/sources/create-file-source /api-v2-openapi.json post /api/v2/agents/{agentId}/sources Upload a file as a knowledge source for an agent. Accepts PDF, DOC, DOCX, and TXT files up to 20 MB. **Base URL:** `https://files.chatbase.co/api/v2` — this endpoint uses a different host from all other Sources endpoints. # Create source Source: https://chatbase.co/docs/api-v2/sources/create-source /api-v2-openapi.json post /agents/{agentId}/sources Creates a new source. Accepts text, qna, and link source types. File sources require a dedicated endpoint. Ticket and Notion sources are not accepted. **Q&A request body limit:** The total request body must not exceed 4.5 MB for Q&A sources. # Delete source Source: https://chatbase.co/docs/api-v2/sources/delete-source /api-v2-openapi.json delete /agents/{agentId}/sources/{sourceId} Marks a source for deletion. Returns the source in its final state. # Get source Source: https://chatbase.co/docs/api-v2/sources/get-source /api-v2-openapi.json get /agents/{agentId}/sources/{sourceId} Returns a single source by ID. # Get sources summary Source: https://chatbase.co/docs/api-v2/sources/get-sources-summary /api-v2-openapi.json get /agents/{agentId}/sources/summary Returns aggregated counts and sizes for each source type, plus a flag if the chatbot knowledge base requires a retrain to reflect any changes # List sources Source: https://chatbase.co/docs/api-v2/sources/list-sources /api-v2-openapi.json get /agents/{agentId}/sources Returns a paginated list of sources for an agent. Ticket sources are excluded. For link sources only individual or sitemap/crawl parent links are returned with aggregated children metadata. # Restore source Source: https://chatbase.co/docs/api-v2/sources/restore-source /api-v2-openapi.json post /agents/{agentId}/sources/{sourceId}/restore Restores a source that is pending deletion back to its previous active state. # Update file source Source: https://chatbase.co/docs/api-v2/sources/update-file-source /api-v2-openapi.json put /api/v2/agents/{agentId}/sources/{sourceId} Replace a file source's content, rename it, or both. At least one of `name` or `file` must be provided. **Base URL:** `https://files.chatbase.co/api/v2` — this endpoint uses a different host from all other Sources endpoints. # Update source Source: https://chatbase.co/docs/api-v2/sources/update-source /api-v2-openapi.json put /agents/{agentId}/sources/{sourceId} Updates an existing source. Accepts text, qna, and link sources. File sources require a dedicated endpoint. Link URL is immutable — to change it, delete and recreate the source. Ticket and Notion sources are not accepted. **Q&A request body limit:** The total request body must not exceed 4.5 MB for Q&A sources. # Streaming Source: https://chatbase.co/docs/api-v2/streaming How to use Server-Sent Events (SSE) streaming with the Chatbase API v2 for real-time responses. ## Enabling Streaming To receive a streaming response, set `stream: true` in the request body of the chat or retry endpoints: ```bash theme={null} curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "message": "Explain quantum computing", "stream": true, "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123" }' ``` ## Request Body The user message to send to the agent. Omit to continue the conversation after submitting a client action result. Stream the response as SSE. Defaults to `true`. Continue an existing conversation. Omit to create a new one. Associate a user with a new conversation. Max 128 chars, `[a-zA-Z0-9._-]` only. Ignored when `conversationId` is provided. Once set, a conversation's `userId` is immutable — it cannot be changed or removed. See [User Conversations](/docs/api-v2/user-conversations) for details on managing per-user conversation history. The response uses `Content-Type: text/event-stream` and follows the **AI SDK UIMessage Stream** protocol. Events arrive as Server-Sent Events — each event is a `data:` line whose payload is a JSON object with a `type` field, and the stream terminates with `data: [DONE]`: ``` data: {"type":"start","messageId":"msg_abc123"} data: {"type":"text-delta","id":"text_001","delta":"Hello"} data: [DONE] ``` ## Event Types ### `start` Emitted once at the beginning of a new message. Contains the message ID. ```json theme={null} { "type": "start", "messageId": "msg_abc123" } ``` ### `text-start` Emitted at the beginning of a text block. ```json theme={null} { "type": "text-start", "id": "text_001" } ``` ### `text-delta` Emitted for each chunk of generated text. Concatenate all deltas to build the full response. ```json theme={null} { "type": "text-delta", "id": "text_001", "delta": "Quantum computing is" } ``` ### `text-end` Emitted when a text block is complete. ```json theme={null} { "type": "text-end", "id": "text_001" } ``` These events are emitted when the agent invokes a [client action](/docs/api-v2/client-actions). The `toolName` corresponds to the name of the configured action. ### `tool-input-start` Emitted at the start of a client action input. ```json theme={null} { "type": "tool-input-start", "toolCallId": "call_abc123", "toolName": "lookupOrder" } ``` ### `tool-input-delta` Emitted for each chunk of the action input as it streams. ```json theme={null} { "type": "tool-input-delta", "toolCallId": "call_abc123", "inputTextDelta": "{\"order" } ``` ### `tool-input-available` Emitted when the complete action input is ready. You can read the full `input` object directly from this event without concatenating the preceding deltas. ```json theme={null} { "type": "tool-input-available", "toolCallId": "call_abc123", "toolName": "lookupOrder", "input": { "orderId": "ORD-123" } } ``` ### `tool-output-available` Emitted when a tool execution result is available. The full `output` can be read directly from this event. ```json theme={null} { "type": "tool-output-available", "toolCallId": "call_abc123", "output": { "status": "shipped", "eta": "2026-04-03" } } ``` For the full client action flow — including how to submit results and continue the conversation — see [Client Actions](/docs/api-v2/client-actions). ### `start-step` Emitted at the start of a processing step. ```json theme={null} { "type": "start-step" } ``` ### `finish-step` Emitted at the end of a processing step. ```json theme={null} { "type": "finish-step" } ``` ### `finish` Emitted once when generation is complete. Carries the finish reason and Chatbase-specific metadata — see [Metadata](#metadata). ```json theme={null} { "type": "finish", "finishReason": "stop", "messageMetadata": { "messageId": "msg_abc123", "userMessageId": "msg_xyz789", "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123", "usage": { "credits": 2 } } } ``` ### `error` Emitted if an error occurs during generation. The stream may have been partially delivered. ```json theme={null} { "type": "error", "errorText": "An error occurred during generation" } ``` ## Metadata The `finish` event carries the finish reason and, nested under `messageMetadata`, the Chatbase-specific metadata: ```json theme={null} { "type": "finish", "finishReason": "stop", "messageMetadata": { "messageId": "msg_abc123", "userMessageId": "msg_xyz789", "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123", "usage": { "credits": 2 } } } ``` Why the model stopped generating: * `"stop"` — normal completion * `"error"` — an error occurred * `"tool-calls"` — the agent invoked a client action — submit the result and continue Other values (`"length"`, `"content-filter"`, `"other"`, `"unknown"`) are possible but rare. Unique ID of the assistant message. The ID of the user message that triggered this response. For continuation responses, this is the last user message in the conversation. The conversation ID. Use this for follow-up messages. The user ID associated with this conversation, or `null` if none. Credits consumed by this request. The protocol also allows standalone `message-metadata` events mid-stream, with the same object nested under a `messageMetadata` key. Handle them if present, but expect the metadata on the `finish` event. The stream terminates with `data: [DONE]`. ## Code Examples ```javascript Node.js theme={null} const response = await fetch( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ message: "Explain quantum computing", stream: true, // conversationId: "a1b2c3d4-...", // omit to start a new conversation // userId: "user_abc123", // associate a user with the conversation }), } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); let conversationId; let userId; while (true) { const { done, value } = await reader.read(); if (done) break; const lines = decoder.decode(value, { stream: true }).split("\n"); for (const line of lines) { if (!line.startsWith("data: ")) continue; const data = line.slice("data: ".length); if (data === "[DONE]") continue; const event = JSON.parse(data); switch (event.type) { case "start": console.log("Message ID:", event.messageId); break; case "text-delta": process.stdout.write(event.delta); break; case "tool-input-available": console.log("\nClient action requested:", event.toolName, event.input); // Handle client action — see Client Actions guide break; case "finish": conversationId = event.messageMetadata.conversationId; userId = event.messageMetadata.userId; console.log("\nFinish reason:", event.finishReason); console.log("Credits used:", event.messageMetadata.usage.credits); break; case "error": console.error("Stream error:", event.errorText); break; } } } ``` ```python Python theme={null} import requests import json response = requests.post( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "message": "Explain quantum computing", "stream": True, # "conversationId": "a1b2c3d4-...", # omit to start a new conversation # "userId": "user_abc123", # associate a user with the conversation }, stream=True, ) conversation_id = None user_id = None for line in response.iter_lines(): if not line: continue line = line.decode() if not line.startswith("data: "): continue data = line[len("data: "):] if data == "[DONE]": continue event = json.loads(data) if event["type"] == "start": print(f"Message ID: {event['messageId']}") elif event["type"] == "text-delta": print(event["delta"], end="", flush=True) elif event["type"] == "tool-input-available": print(f"\nClient action requested: {event['toolName']}", event["input"]) # Handle client action — see Client Actions guide elif event["type"] == "finish": metadata = event["messageMetadata"] conversation_id = metadata["conversationId"] user_id = metadata["userId"] print(f"\nFinish reason: {event['finishReason']}") print(f"Credits used: {metadata['usage']['credits']}") elif event["type"] == "error": print(f"Stream error: {event['errorText']}") ``` ```bash curl theme={null} curl -N -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "message": "Explain quantum computing", "stream": true, "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123" }' ``` ## Non-Streaming Mode When `stream` is set to `false`, the API returns a standard JSON response with the complete message: ```json theme={null} { "data": { "id": "msg_abc123", "role": "assistant", "parts": [ { "type": "text", "text": "Quantum computing is a type of computation..." } ], "metadata": { "userMessageId": "msg_xyz789", "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123", "finishReason": "stop", "usage": { "credits": 2 } } } } ``` When a client action is invoked, the response includes `tool-call` parts and `finishReason: "tool-calls"`: ```json theme={null} { "data": { "id": "msg_abc123", "role": "assistant", "parts": [ { "type": "text", "text": "Let me look up that order for you." }, { "type": "tool-call", "toolCallId": "call_abc123", "toolName": "lookupOrder", "input": { "orderId": "ORD-123" } } ], "metadata": { "userMessageId": "msg_xyz789", "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123", "finishReason": "tool-calls", "usage": { "credits": 2 } } } } ``` See [Client Actions](/docs/api-v2/client-actions) for how to submit the result and continue the conversation. # User Conversations Source: https://chatbase.co/docs/api-v2/user-conversations Associate users with conversations, manage per-user history, and export full conversation data across all sources. ## Overview Tag conversations with a `userId` to track per-user chat history. Once a conversation is associated with a user, you can list all of that user's conversations and continue any of them by passing the `conversationId`. ## Setting a User ID Pass `userId` when creating a new conversation. The ID must follow these constraints: | Constraint | Value | | ------------------ | -------------------------------------------------------------- | | Max length | 128 characters | | Allowed characters | `a-z`, `A-Z`, `0-9`, `.`, `_`, `-` | | When applied | Only on conversation creation (no `conversationId` in request) | | Mutability | Immutable — cannot be changed or removed after creation | A conversation's `userId` is set once at creation and cannot be changed. If you send `userId` with a `conversationId`, the `userId` field is ignored. ```javascript Node.js theme={null} const response = await fetch( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ message: "Hello!", stream: true, userId: "user_abc123", }), } ); ``` ```python Python theme={null} import requests response = requests.post( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "message": "Hello!", "stream": True, "userId": "user_abc123", }, stream=True, ) ``` The response metadata includes the `userId`: ```json theme={null} { "type": "finish", "finishReason": "stop", "messageMetadata": { "messageId": "msg_abc123", "userMessageId": "msg_xyz789", "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "userId": "user_abc123", "usage": { "credits": 2 } } } ``` ## Continuing a Conversation To send follow-up messages in the same conversation, pass the `conversationId` from a previous response: ```javascript Node.js theme={null} const response = await fetch( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ message: "Tell me more about that.", stream: true, conversationId: "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", }), } ); ``` ```python Python theme={null} response = requests.post( "https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "message": "Tell me more about that.", "stream": True, "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", }, stream=True, ) ``` The `conversationId` is returned in the streaming `finish` event's `metadata` or in the non-streaming response's `metadata` object. See [Streaming](/docs/api-v2/streaming) for details. If the conversation has ended (e.g. after a human takeover), the API returns a `CHAT_CONVERSATION_NOT_ONGOING` error. Start a new conversation instead. ## Listing a User's Conversations Retrieve all conversations for a specific user with `GET /api/v2/agents/{agentId}/users/{userId}/conversations`. ### Path Parameters | Parameter | Type | Description | | --------- | -------- | -------------------------------------- | | `agentId` | `string` | The agent ID. | | `userId` | `string` | The user ID to list conversations for. | ### Query Parameters | Parameter | Type | Default | Description | | --------- | --------- | ------- | ------------------------------------------------------------------------- | | `cursor` | `string` | — | Opaque cursor from a previous response. Omit to start from the beginning. | | `limit` | `integer` | `20` | Number of items per page. Range: 1–100. | ### Response ```json theme={null} { "data": [ { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "title": "Quantum computing basics", "createdAt": 1770681600, "updatedAt": 1770681900, "userId": "user_abc123", "status": "ongoing" }, { "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e", "title": "Pricing questions", "createdAt": 1770595200, "updatedAt": 1770595500, "userId": "user_abc123", "status": "ended" } ], "pagination": { "cursor": "eyJ0IjoiMjAyNC0wMS0xNVQxMDozMDowMC4wMDBaIiwiaWQiOiJhYmMxMjMifQ==", "hasMore": true, "total": 42 } } ``` ### Response Fields | Field | Type | Description | | ----------- | ---------------- | --------------------------------------------------------- | | `id` | `string` | Conversation ID. | | `title` | `string \| null` | Conversation title. | | `createdAt` | `number` | Unix epoch timestamp (seconds). | | `updatedAt` | `number` | Unix epoch timestamp (seconds) of last activity. | | `userId` | `string \| null` | The user ID associated with this conversation. | | `status` | `string` | Conversation status: `ongoing`, `ended`, or `taken_over`. | ### Pagination Examples ```javascript Node.js theme={null} async function fetchUserConversations(agentId, userId, apiKey) { const conversations = []; let cursor = undefined; do { const params = new URLSearchParams({ limit: "100" }); if (cursor) params.set("cursor", cursor); const response = await fetch( `https://www.chatbase.co/api/v2/agents/${agentId}/users/${userId}/conversations?${params}`, { headers: { Authorization: `Bearer ${apiKey}` }, } ); const { data, pagination } = await response.json(); conversations.push(...data); cursor = pagination.cursor; } while (cursor); return conversations; } ``` ```python Python theme={null} import requests def fetch_user_conversations(agent_id: str, user_id: str, api_key: str): conversations = [] cursor = None while True: params = {"limit": 100} if cursor: params["cursor"] = cursor response = requests.get( f"https://www.chatbase.co/api/v2/agents/{agent_id}/users/{user_id}/conversations", headers={"Authorization": f"Bearer {api_key}"}, params=params, ) body = response.json() conversations.extend(body["data"]) cursor = body["pagination"]["cursor"] if not cursor: break return conversations ``` ## Full Example Send the first message with a `userId` to associate the conversation: ```bash theme={null} curl -N -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "message": "What is quantum computing?", "stream": true, "userId": "user_abc123" }' ``` Save the `conversationId` from the `finish` event. Continue the conversation by passing the `conversationId`: ```bash theme={null} curl -N -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "message": "How does it differ from classical computing?", "stream": true, "conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" }' ``` Retrieve all conversations for the user: ```bash theme={null} curl 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/users/user_abc123/conversations?limit=20' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` ## Exporting All Conversations The [Export conversations](/docs/api-v2/conversations/export-conversations) endpoint returns **all conversations with full message history**, regardless of source. This is different from the list endpoints above, which only return API-created conversations. [Get a conversation](/docs/api-v2/conversations/get-a-conversation) also only returns conversations created through the API. If you request a conversation that exists but came from another source, its 404 response names the source and points you to the export endpoint below instead. ### Key differences from list endpoints | | List conversations | Export conversations | | ------------------- | ---------------------------- | -------------------------------------------- | | **Sources** | API-only | All (Widget, WhatsApp, Messenger, API, etc.) | | **Messages** | Not included (metadata only) | Full message history included | | **Tool results** | Not included (metadata only) | Sanitized — internal data stripped | | **Tool call input** | Not included (metadata only) | Omitted (not useful for export consumers) | ### Fetching a single conversation Pass `conversationId` as a query parameter to fetch one conversation instead of paging through the full export. This works for a conversation from any source, including ones created through the widget, WhatsApp, or other integrations, not just the API. ```bash theme={null} curl 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/conversations/export?conversationId=a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` The response keeps the normal paginated shape, with a single item in `data`: ```json theme={null} { "data": [ { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "...": "..." } ], "pagination": { "cursor": null, "hasMore": false, "total": 1 } } ``` If no conversation matches the ID, the response is a normal empty page (`data: []`, `total: 0`), not a 404. ### Conversation sources Exported conversations include a `source` field indicating where the conversation originated: `API`, `WhatsApp`, `Messenger`, `Instagram`, `Slack`, `Salesforce`, `Zendesk`, `Zendesk Messaging`, `Widget or Iframe`, `Iframe`, `Email`, `Agent page`, `Phone`, `Android SDK`, `iOS SDK`, `Chatbase site`, `Playground`, and others. ### Message format Each conversation includes a `messages` array. Messages contain `parts`, which can be: | Part type | Fields | Description | | ------------- | ------------------------------------------ | -------------------------------------------------------------- | | `text` | `type`, `text` | Text content from the user or assistant | | `tool-call` | `type`, `toolCallId`, `toolName` | A tool invocation by the agent (`input` is omitted in exports) | | `tool-result` | `type`, `toolCallId`, `toolName`, `output` | The sanitized result of a tool invocation | ### Tool result output shape All tool results in the export follow a unified shape, so you can handle them with a single `switch` on `status`: | Status | Shape | Description | | --------- | ------------------------------------- | ---------------------------------------------------------------------------------- | | `success` | `{ status: "success", data?: }` | Tool completed successfully. `data` is present when there is a meaningful payload. | | `error` | `{ status: "error", error?: string }` | Tool encountered an error. | | `pending` | `{ status: "pending" }` | Tool execution is still in progress. | | `ignored` | `{ status: "ignored" }` | Tool was skipped by the user. | ### Example response ```json theme={null} { "data": [ { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "title": "Order status inquiry", "createdAt": 1770681600, "updatedAt": 1770681900, "userId": "user_abc123", "source": "WhatsApp", "status": "ended", "messages": [ { "id": "msg_001", "role": "user", "parts": [ { "type": "text", "text": "What's the status of my order?" } ], "createdAt": 1770681600 }, { "id": "msg_002", "role": "assistant", "parts": [ { "type": "text", "text": "Let me look that up for you." }, { "type": "tool-call", "toolCallId": "call_abc123", "toolName": "lookupOrder" }, { "type": "tool-result", "toolCallId": "call_abc123", "toolName": "lookupOrder", "output": { "status": "success", "data": { "orderId": "ORD-123", "shipped": true } } }, { "type": "text", "text": "Your order ORD-123 has been shipped!" } ], "createdAt": 1770681605, "feedback": "positive", "metadata": { "score": 0.95 } } ] } ], "pagination": { "cursor": "eyJ0IjoiMjAyNC0wMS0xNVQxMDozMDowMC4wMDBaIiwiaWQiOiJhYmMxMjMifQ==", "hasMore": true, "total": 1250 } } ``` ### Paginating through all exports ```javascript Node.js theme={null} async function exportAllConversations(agentId, apiKey) { const conversations = []; let cursor = undefined; do { const params = new URLSearchParams({ limit: "100" }); if (cursor) params.set("cursor", cursor); const response = await fetch( `https://www.chatbase.co/api/v2/agents/${agentId}/conversations/export?${params}`, { headers: { Authorization: `Bearer ${apiKey}` }, } ); const { data, pagination } = await response.json(); conversations.push(...data); cursor = pagination.cursor; } while (cursor); return conversations; } ``` ```python Python theme={null} import requests def export_all_conversations(agent_id: str, api_key: str): conversations = [] cursor = None while True: params = {"limit": 100} if cursor: params["cursor"] = cursor response = requests.get( f"https://www.chatbase.co/api/v2/agents/{agent_id}/conversations/export", headers={"Authorization": f"Bearer {api_key}"}, params=params, ) body = response.json() conversations.extend(body["data"]) cursor = body["pagination"]["cursor"] if not cursor: break return conversations ``` The export endpoint can return large amounts of data. Use a smaller `limit` (e.g., 20) if you're processing messages as they arrive rather than collecting everything in memory. ## Related Learn about streaming responses and event types. How cursor-based pagination works across all list endpoints. Full API reference for the export endpoint. How tool calls and tool results work in conversations. # Voice Sessions Source: https://chatbase.co/docs/api-v2/voice Embed real-time voice conversations with your agent in your own app using the Voice Sessions API and the Chatbase Voice SDK. The Voice Sessions API lets you run your agent's voice mode inside your own web interface instead of the Chatbase widget. Your backend creates a session, your client joins it with the Chatbase Voice SDK, and the full voice pipeline runs on Chatbase: speech to text, the agent response with your training data and actions, text to speech, and natural interruption handling. Your client only publishes microphone audio and renders state. Transport is WebRTC rather than a plain WebSocket. This is what makes low latency and barge-in possible: the user can talk over the agent and it stops speaking immediately, with no extra code on your side. ## Try it first Paste your Agent ID and API key, start a session, and talk to your agent. No setup, nothing to install. The demo takes an API key in its UI so you can try it in a few seconds; the key is sent only to the demo's own backend, which proxies Chatbase. Your own app should keep it in server-side env vars instead, as shown below. Demo sessions are real: they use message credits and appear in your chat logs. ## Create a session Create sessions from your backend. Your API key must never reach a browser or mobile app, and the endpoint does not send CORS headers, so cross-origin browser calls are rejected by design. ```bash theme={null} curl -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/voice/sessions' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "userId": "user_abc123", "timezone": "Europe/Paris" }' ``` ## Request Body The body is required. Send `{}` when you have no options to set. Optional conversation UUID. Reuse a value to group multiple voice sessions into one conversation in chat logs; the agent continues with the earlier transcript as history. Omit to create a new conversation. A conversation belongs to the end-user who started it: when reusing, send that same `userId`, or omit `userId` to inherit it — a different `userId` is rejected with `CONVERSATION_USER_MISMATCH`. Your end-user ID. Max 128 chars, `[a-zA-Z0-9._-]` only. Send a stable ID so per-user voice limits apply; if omitted a random one is generated per session (or inherited from the conversation when reusing a `conversationId`). A `userId` alone never resumes an earlier conversation — each session without a `conversationId` is a new conversation owned by that user. IANA timezone of the end user, for example `Europe/Paris`. The agent uses it for time-aware answers. ## Response ```json theme={null} { "data": { "participantToken": "eyJhbGciOiJIUzI1NiJ9...", "sessionId": "81f59ffe-b937-4b00-816a-b50cf416cc7e", "roomName": "chatbot-AGENT_ID-CONVERSATION_ID-SESSION_ID", "maxDurationSeconds": 600, "conversationId": "b363c804-efb5-47f4-9e28-5417e978eb0b", "userId": "user_abc123" } } ``` Hand the `data` object to your client. The `participantToken` is scoped to this single session and expires with it, so it is safe to ship to the browser. Never cache this response. Each `participantToken` belongs to one session and expires with it, so a cached response makes every later visitor connect with a dead token. In Next.js App Router that means `cache: "no-store"` on the fetch and `export const dynamic = "force-dynamic"` in the route. ## Errors Failures use the standard API v2 error shape: ```json theme={null} { "error": { "code": "VOICE_NOT_AVAILABLE", "message": "Voice mode is not available on your current plan." } } ``` | Status | Code | Meaning | | ------ | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | | 401 | `AUTH_MISSING_API_KEY` | No `Authorization` header was sent. | | 401 | `AUTH_INVALID_API_KEY` | The API key is not valid for this workspace. | | 403 | `API_RESTRICTED_PLAN` | The plan does not include API access. | | 403 | `VOICE_NOT_AVAILABLE` | The plan does not include voice mode. | | 403 | `INSUFFICIENT_CREDITS` | Not enough message credits to start a session. | | 403 | `AGENT_CREDITS_LIMIT_REACHED` | The agent hit its own credit limit; raise it in the agent settings. | | 403 | `CONVERSATION_USER_MISMATCH` | The reused `conversationId` was created with a different `userId`. Send that same `userId`, or omit it to inherit the conversation's end-user. | | 404 | `AGENT_NOT_FOUND` | No such agent, or it belongs to another workspace. | | 404 | `CONVERSATION_NOT_FOUND` | The reused `conversationId` belongs to another agent or was deleted. | | 429 | `VOICE_LIMIT_EXCEEDED` | A voice session limit was hit. `details.reason` names which one: concurrency, per user, hourly, or daily. | | 429 | `RATE_LIMIT_TOO_MANY_REQUESTS` | Too many API requests; retry after a short delay. | | 500 | `SESSION_CREATION_FAILED` | The session could not be created. Retry the request. | | 503 | `SERVICE_UNDER_MAINTENANCE` | Chatbase is in maintenance; retry shortly. | A 429 from `VOICE_LIMIT_EXCEEDED` is worth surfacing to your user, since it clears on its own: ```json theme={null} { "error": { "code": "VOICE_LIMIT_EXCEEDED", "message": "Voice session limit exceeded. Please try again later or adjust the voice limits in settings.", "details": { "reason": "concurrent_exceeded" } } } ``` ### Example backend route A minimal Next.js App Router handler that your client calls instead of talking to Chatbase directly: ```ts app/api/voice-session/route.ts theme={null} export const dynamic = 'force-dynamic' import { NextResponse } from 'next/server' const CHATBASE_API_URL = 'https://www.chatbase.co/api/v2/agents' export async function POST(request: Request) { const { agentId, userId, timezone } = await request.json() const response = await fetch(`${CHATBASE_API_URL}/${agentId}/voice/sessions`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.CHATBASE_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ userId, timezone }), cache: 'no-store' }) const data = await response.json() // Pass Chatbase's status through so the client can tell a plan or limit // problem from a network failure. return NextResponse.json(data, { status: response.status }) } ``` ## Join from your client Install the Chatbase Voice SDK: ```bash theme={null} npm install @chatbase-co/voice-sdk ``` The agent joins the session automatically and speaks the configured greeting; its audio plays without any setup. ```js theme={null} import { ChatbaseVoice } from '@chatbase-co/voice-sdk' // Your backend proxies the create call and returns the session `data` const { data } = await fetch('/your-backend/voice-session').then((r) => r.json()) const voice = new ChatbaseVoice() // Agent state: initializing, listening, thinking, speaking voice.on('agentState', (state) => console.log('agent is', state)) // Live transcripts for both sides. Segments grow while spoken, so key your // UI on segmentId and replace that segment's text on every event. voice.on('transcript', ({ segmentId, speaker, text }) => { // your own UI update, e.g. setMessages((prev) => ({ ...prev, [segmentId]: { speaker, text } })) console.log(`[${speaker}] ${text}`) }) voice.on('sessionEnd', (reason) => console.log('session ended:', reason)) await voice.connect(data) // microphone goes live; the agent greets and listens // Optional: send text into the live session. The agent replies with speech. await voice.sendText('What are your opening hours?') // Microphone control; the session stays alive while muted await voice.mute() await voice.unmute() // End the session await voice.disconnect() ``` If the user declines microphone permission, the session continues in text mode: the SDK emits an `error` event, and `sendText` still gets spoken replies. ## SDK reference ### Methods and properties | Member | Description | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `new ChatbaseVoice()` | Creates an instance. One instance handles one session at a time. | | `connect(session)` | Joins the session. Pass the `data` object from the endpoint, or just the `participantToken` string. Resolves once connected; the microphone goes live and the agent greets. | | `disconnect()` | Ends the session. The agent hangs up and `sessionEnd` fires. | | `sendText(message)` | Sends text into the live session. The agent answers with speech, so this works as a typed alternative to speaking. | | `mute()` | Stops sending microphone audio. The session stays connected and the agent keeps talking. | | `unmute()` | Resumes sending microphone audio. | | `isMuted` | `boolean` — whether the microphone is currently muted. | | `localAudioStream` | The local microphone `MediaStream`, or `null` before connecting. Use it to draw a level meter or waveform. | | `on(event, cb)` | Subscribes to an event. Returns an unsubscribe function. | | `off(event, cb)` | Removes a previously registered listener. | Every method returns a promise except `on` and `off`; `isMuted` and `localAudioStream` are plain properties. ### Events | Event | Payload | Carries | | ----------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `connectionState` | `'connecting' \| 'connected' \| 'reconnecting' \| 'disconnected' \| 'error'` | Connection lifecycle of the session. | | `agentState` | `'initializing' \| 'listening' \| 'thinking' \| 'speaking'` | What the agent is doing right now. Drive your UI from this. | | `transcript` | `{ text, speaker, segmentId }` | Live transcripts of both sides. Segments grow while being spoken, so replace by `segmentId` rather than appending. | | `sessionEnd` | `reason?: string` | The session ended, with the reason when one is known. | | `error` | `Error` | Non-fatal problems such as an unavailable microphone, and connect failures. | ## Interruption Barge-in needs no client code. The agent detects the caller speaking over it and stops mid-sentence, when the "Allow interruptions" setting is enabled in the agent's voice settings. ## Lifecycle and billing A session ends when the client disconnects, when `maxDurationSeconds` elapses, after the configured silence timeout, or when credits run out. Enforcement happens server-side, so clients cannot extend a session past its limits. Voice minutes consume message credits exactly like widget voice sessions. Conversations, transcripts, and recordings appear in the dashboard chat logs with source API. Voice sessions require a plan with voice mode enabled. Session concurrency, per-user, hourly, and daily limits come from the agent's voice settings; exceeding one returns `VOICE_LIMIT_EXCEEDED` with the specific reason in `details.reason`. # WhatsApp Source: https://chatbase.co/docs/api-v2/whatsapp List the approved WhatsApp templates available to your agent and send them to any phone number. The WhatsApp API [sends approved message templates](/docs/api-v2/whatsapp/send-a-whatsapp-template-message) from the numbers connected to your agent. A template is the only way to open a conversation with someone who has not messaged you in the last 24 hours. Recipients are identified by phone number, with no Chatbase user id needed: a user is resolved from the `to` number or created, and replies arrive in that user's conversation through your agent's normal WhatsApp pipeline. Both endpoints return `WHATSAPP_NOT_CONNECTED` when the agent has no connected number. ## Listing templates [List WhatsApp templates](/docs/api-v2/whatsapp/list-whatsapp-templates) returns every approved template across all of the agent's WhatsApp Business Accounts, together with the numbers you can send them from. | Field | Meaning | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `templates[].wabaId` | The Business Account the template belongs to. | | `templates[].variables` | The values the template needs, grouped by component. | | `senders[]` | The agent's connected numbers. Each entry carries the `from` value to send with, its `wabaId`, and the display name Meta verified. | | `complete` | `false` when at least one Business Account could not be read. | | `unavailableWabaIds` | The Business Accounts missing from an incomplete listing. Retry to pick them up. | One Business Account failing does not fail the call, so check `complete` before treating the list as the full set. ## Selecting a template Templates are addressed by name. `template.language` is optional when the name has one approved variant and required when it has several, which otherwise returns `TEMPLATE_LANGUAGE_REQUIRED`. Unapproved variants never make the choice ambiguous; when none is approved the send returns `TEMPLATE_NOT_APPROVED` with the review status in `details.status`. A template whose buttons take a parameter cannot be sent from this API and returns `TEMPLATE_BUTTONS_UNSUPPORTED`: | Button | Sendable | | ------------------------------------ | -------- | | Quick reply | Yes | | URL with a fixed address | Yes | | URL containing a `{{1}}` placeholder | No | | Copy code | No | | One-time password | No | Spot these before sending: in the listing, an unsendable URL button has a `{{...}}` placeholder in its `url`. Campaigns cannot send them either, so edit the template in WhatsApp Manager to use a fixed address, or send a variant without the button. Templates with an image, video, or document header send the media approved with the template, so there is nothing to supply in the request. `MEDIA_UPLOAD_FAILED` means that media could not be uploaded to WhatsApp. ## Choosing the sender | `from` | Connected numbers | Result | | -------- | ----------------- | -------------------------------------------------------------------------------------------------------------------- | | Omitted | Exactly one | That number sends. | | Omitted | More than one | `PHONE_NUMBER_REQUIRED`. Pick a number from `senders`. | | Provided | Any | Matched on digits, so `+1 415-555-2671` and `14155552671` are equivalent. No match returns `PHONE_NUMBER_NOT_FOUND`. | A template is looked up on the Business Account of the number you send from, so pair the template's `wabaId` with a `senders` entry carrying the same `wabaId`. Sending from a number on a different account returns `TEMPLATE_NOT_FOUND` even though the template exists. ## Template variables Each component numbers its placeholders from `{{1}}` independently, so values are grouped by component. A template whose header reads `Order {{1}}` and body reads `Hi {{1}}, arriving {{2}}` is listed as `{"header": ["1"], "body": ["1", "2"]}` and takes three values, the header's `1` being separate from the body's. Send back exactly the keys the listing reported. For a named template, use the parameter names in place of the numbers. A value you leave out returns `MISSING_TEMPLATE_VARIABLES`, and one WhatsApp will not accept, meaning empty or containing a line break, a tab, or five or more consecutive spaces, returns `INVALID_TEMPLATE_VARIABLES`. Both name each slot as `component[key]`, such as `body[2]`. ## Delivery and conversations Meta accepts sends from a blocked Business Account and drops them afterwards, reporting the reason only on a status webhook. Chatbase checks first, turning that silent loss into `SEND_BLOCKED` with the reason in `details.reason`. It is most often a billing problem: resolve it in WhatsApp Manager and sends resume within about a minute. A `201` means WhatsApp accepted the message, not that it reached the recipient. It can still be dropped afterwards, most often because the recipient is not on WhatsApp, has blocked your business, or has already had its limit of marketing templates for the period. Match later webhooks against the returned `to`, which is the canonical WhatsApp id and can differ from what you sent. `conversationId` is the conversation the recipient's replies continue in, and the template is appended to it unless a human has taken the conversation over or it has ended. ## Error codes WhatsApp-specific error codes beyond the standard [authentication and rate-limiting errors](/docs/api-v2/error-handling):
Code HTTP Description
WHATSAPP\_NOT\_CONNECTED403The agent has no connected WhatsApp number. Connect one from the deploy page.
PHONE\_NUMBER\_REQUIRED400The agent has more than one connected number, so from must say which one sends.
PHONE\_NUMBER\_NOT\_FOUND404No number connected to this agent matches from.
TEMPLATE\_NOT\_FOUND404No template with that name, and language when given, exists on the Business Account of the sending number. Check that the template's wabaId matches the sender's.
TEMPLATE\_LANGUAGE\_REQUIRED400The template name has more than one approved language variant. Pass template.language.
TEMPLATE\_NOT\_APPROVED409The template exists but has no approved variant to send. details.status carries the Meta review status.
SEND\_BLOCKED409Meta has blocked business-initiated conversations for this Business Account. details.reason carries Meta's explanation.
MISSING\_TEMPLATE\_VARIABLES422The template declares variables that were not provided. details.missing lists them as component\[key].
INVALID\_TEMPLATE\_VARIABLES422A value is empty, or contains a line break, a tab, or five or more consecutive spaces. details.invalid names each offending slot and why.
TEMPLATE\_BUTTONS\_UNSUPPORTED422The template has a button that takes a parameter, which this API cannot send. details.buttons lists the button types.
TEMPLATE\_PARAMS\_REJECTED422WhatsApp rejected the parameters as not matching the approved template.
RECIPIENT\_INVALID422to is not a valid phone number for its country. Unassignable numbers, such as a 555 US area code, are rejected.
RECIPIENT\_NOT\_REACHABLE422WhatsApp reported the recipient as undeliverable. The number may not be on WhatsApp or may have blocked business messages.
MEDIA\_UPLOAD\_FAILED502The template has a media header and uploading its media to WhatsApp failed.
WHATSAPP\_SEND\_FAILED502WhatsApp returned an error that does not map to a more specific code.
# List WhatsApp templates Source: https://chatbase.co/docs/api-v2/whatsapp/list-whatsapp-templates /api-v2-openapi.json get /agents/{agentId}/whatsapp/templates Lists the approved WhatsApp templates available to the agent, across all of its connected WhatsApp Business Accounts. Each template's `variables` object is the shape a send request must provide. A template can only be sent from a number on its own Business Account, so pair its `wabaId` with a matching entry in `senders` to pick the `from` value. Check `complete` before treating the list as exhaustive: it is `false` when one of the agent’s Business Accounts could not be read. # Send a WhatsApp template message Source: https://chatbase.co/docs/api-v2/whatsapp/send-a-whatsapp-template-message /api-v2-openapi.json post /agents/{agentId}/whatsapp/messages/template Sends an approved WhatsApp template to a recipient from one of the agent's connected phone numbers. Recipients are identified by phone number only — no user ID is required. A Chatbase user is resolved or created from the `to` number automatically, and their reply flows through the agent's regular WhatsApp pipeline. The message is also appended to that conversation, unless a human has taken it over or it has ended — see `conversationId` in the response. # CLI Agents Source: https://chatbase.co/docs/cli/agents Create, inspect, update, train, clone, and delete Chatbase agents from the terminal. Use agent commands to manage the AI agents in your workspace. For REST details, see [Agents API](/docs/api-v2/agents). Authenticate first — see [CLI Auth](/docs/cli/auth). ## List and inspect List every agent in the workspace: ```bash theme={null} chatbase agents list ``` Show one agent by ID: ```bash theme={null} chatbase agents get agt_123 ``` Use `--json` or `--plain` for scripting. Set a default agent with [CLI Config](/docs/cli/config) so you can omit the ID on `get` and other commands. ## Create and configure Create a new agent: ```bash theme={null} chatbase agents create --name "Support Bot" --instructions "Be helpful" ``` Update name, instructions, model, and other fields: ```bash theme={null} chatbase agents update agt_123 --name "Support Bot v2" ``` Update chat widget appearance (theme, colors, etc.): ```bash theme={null} chatbase agents styles agt_123 --data '{"chat":{"theme":"dark"}}' ``` Pass a JSON file with `@styles.json` instead of inline JSON when you have many style properties. ## Train and duplicate Queue a training job after you add or change [sources](/docs/cli/sources): ```bash theme={null} chatbase agents train agt_123 ``` Enable automatic retraining when sources change: ```bash theme={null} chatbase agents auto-retrain agt_123 --enabled ``` Clone an agent and its sources (Notion sources are excluded): ```bash theme={null} chatbase agents clone agt_123 ``` ## Delete an agent Permanently remove an agent: ```bash theme={null} chatbase agents delete agt_123 ``` Deletion cannot be undone. In scripts and CI, pass `--confirm agt_123` to skip the interactive prompt. ## Commands | Command | Purpose | | ------------------------------ | ------------------------------------------------------------ | | `chatbase agents auto-retrain` | Enable or disable automatic retraining for an agent | | `chatbase agents clone` | Clone an agent, including all its sources (excluding Notion) | | `chatbase agents create` | Create a new agent | | `chatbase agents delete` | Permanently delete an agent (cannot be undone) | | `chatbase agents get` | Show one agent | | `chatbase agents list` | List all agents in the workspace | | `chatbase agents styles` | Update visual styles for an agent | | `chatbase agents train` | Queue a training job for an agent | | `chatbase agents update` | Update an existing agent | For every flag, run `chatbase agents --help`. # CLI API Source: https://chatbase.co/docs/cli/api Call any Chatbase API v2 endpoint from the terminal when no dedicated CLI command exists. Use `chatbase api` as an escape hatch for [API v2](/docs/api-v2/overview) endpoints that do not have a dedicated CLI command. Pass an HTTP method and a path relative to `/api/v2` — for example, `/agents` maps to `https://www.chatbase.co/api/v2/agents`. Authenticate first — see [CLI Auth](/docs/cli/auth). ## List resources Fetch a collection: ```bash theme={null} chatbase api GET /agents ``` Limit results with `--field`: ```bash theme={null} chatbase api GET /agents --field limit=5 ``` Add URL query parameters with `--query` (repeatable): ```bash theme={null} chatbase api GET /agents --query limit=5 --query status=active ``` ## Create a resource Send a JSON body inline: ```bash theme={null} chatbase api POST /agents --body '{"name":"Support Bot"}' ``` Set individual body fields instead of raw JSON: ```bash theme={null} chatbase api POST /agents --field name="Support Bot" ``` ## Update a resource Read the body from a file with `@`: ```bash theme={null} chatbase api PATCH /agents/agt_123 --body @patch.json ``` Pipe JSON from stdin with `@-`: ```bash theme={null} echo '{"name":"Renamed Bot"}' | chatbase api PATCH /agents/agt_123 --body @- ``` ## Request options | Flag | Purpose | | ---------------- | ----------------------------------------------------------- | | `--body` | JSON request body — inline JSON, `@file`, or `@-` for stdin | | `--field` / `-f` | Set a body field as `key=value` (repeatable) | | `--query` | Add a URL query parameter as `key=value` (repeatable) | Supported methods: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`. Use `--json` for raw API JSON in scripts. See [Chatbase CLI](/docs/cli/overview) for other global output flags. ## Commands | Command | Purpose | | -------------------------- | --------------------------------- | | `chatbase api METHOD PATH` | Call any API v2 endpoint directly | For every flag, run `chatbase api --help`. # CLI Auth Source: https://chatbase.co/docs/cli/auth Authenticate the Chatbase CLI with an API key or browser login, and inspect or remove stored credentials. Use auth commands to store credentials for interactive use. For CI, prefer the `CHATBASE_API_KEY` environment variable instead of a stored key — see [Chatbase CLI](/docs/cli/overview). ## Log in with the browser For interactive use, log in through your browser: ```bash theme={null} chatbase auth login --browser ``` The CLI opens a browser window and prints a short device code. Open [chatbase.co/activate](https://www.chatbase.co/activate), sign in if needed, and approve the code. When approval succeeds, the CLI stores the credential locally so later commands are authenticated. ## Log in with an API key Paste a key interactively: ```bash theme={null} chatbase auth login ``` Or pipe a key from a file or secret store: ```bash theme={null} cat key.txt | chatbase auth login --with-token ``` Create keys in **Workspace settings → API keys** (Standard plan or higher). ## Check status ```bash theme={null} chatbase auth status ``` Shows the active credential and where it comes from (stored key, environment, etc.). ## Log out ```bash theme={null} chatbase auth logout ``` Removes the stored API key. CLI-paired keys are revoked server-side when applicable. ## Commands | Command | Purpose | | ---------------------- | -------------------------------------------------------- | | `chatbase auth login` | Authenticate (paste key, `--with-token`, or `--browser`) | | `chatbase auth status` | Show active credential and source | | `chatbase auth logout` | Remove stored API key | For every flag, run `chatbase auth --help`. # CLI Chat Source: https://chatbase.co/docs/cli/chat Send messages to an agent, continue conversations, and retry assistant responses from the terminal. Use chat commands to send messages to an agent and read responses in your terminal. For REST details, see [User Conversations](/docs/api-v2/user-conversations) and [Streaming](/docs/api-v2/streaming). Authenticate first — see [CLI Auth](/docs/cli/auth). Pass an agent ID with `-a agt_123`, look one up with `--agent-name`, set `CHATBASE_AGENT_ID`, or configure a [default agent](/docs/cli/config). ## Send a message Send a one-shot message: ```bash theme={null} chatbase chat -a agt_123 -m "How do I reset my password?" ``` Pipe text from stdin instead of `-m`: ```bash theme={null} echo "summarize our refund policy" | chatbase chat -a agt_123 ``` If you omit both `-m` and stdin, the CLI starts an interactive REPL. By default, responses stream token-by-token to your terminal. See [Streaming](/docs/api-v2/streaming) for event types and how to parse them in scripts. ## Continue a conversation Pass a `conversationId` from a previous response to send a follow-up message: ```bash theme={null} chatbase chat -a agt_123 -m "and then?" --conversation conv_123 ``` Add `--resume` to replay the last few messages when continuing, so the agent has recent context without you re-sending it. Save the `conversationId` from a `--json` response or from the streaming `finish` event metadata. See [User Conversations](/docs/api-v2/user-conversations) for per-user history and listing conversations by user. ## Scripting output Wait for the complete response instead of streaming: ```bash theme={null} chatbase chat -a agt_123 -m "hi" --no-stream ``` Output raw API JSON for parsing in scripts: ```bash theme={null} chatbase chat -a agt_123 -m "hi" --json ``` Use `--plain` for tab-separated output. Combine with `--quiet` in CI pipelines. ## Retry a response Regenerate an assistant message and discard it plus everything after it in the conversation: ```bash theme={null} chatbase chat retry --conversation c_123 -a agt_123 --message-id msg_456 ``` Wait for the full retry response instead of streaming: ```bash theme={null} chatbase chat retry --conversation c_123 -a agt_123 --message-id msg_456 --no-stream ``` ## Commands | Command | Purpose | | --------------------- | ---------------------------------------------------------------------------------------------------------- | | `chatbase chat` | Send a message to an agent and print its response | | `chatbase chat retry` | Retry generating an assistant response (discards that message and everything after it in the conversation) | For every flag, run `chatbase chat --help` or `chatbase chat retry --help`. # CLI Config Source: https://chatbase.co/docs/cli/config Set and inspect Chatbase CLI defaults such as the active agent and request timeout. CLI config stores defaults so you do not need to pass `-a` on every command. ## Set a default agent ```bash theme={null} chatbase config set agent agt_123 ``` Omit the value to pick an agent interactively: ```bash theme={null} chatbase config set agent ``` ## Set timeout Timeout is in milliseconds: ```bash theme={null} chatbase config set timeout 60000 ``` ## Inspect config ```bash theme={null} chatbase config get agent chatbase config list ``` `get` and `list` show the resolved value and where it comes from (config file, environment, flag). ## Commands | Command | Purpose | | --------------------------------- | --------------------------------------- | | `chatbase config set KEY [VALUE]` | Set `agent` or `timeout` | | `chatbase config get KEY` | Print one resolved value and its source | | `chatbase config list` | List every resolved value and source | Supported keys: `agent`, `timeout`. You can also set `CHATBASE_AGENT_ID` in the environment. See [Chatbase CLI](/docs/cli/overview) for CI patterns. For every flag, run `chatbase config --help`. # CLI Conversations Source: https://chatbase.co/docs/cli/conversations List, inspect, export, and manage conversation history and message feedback from the terminal. Use conversation and message commands to inspect chat history, export transcripts, submit client-side tool results, and set feedback on assistant replies. For REST details, see [User Conversations](/docs/api-v2/user-conversations). Authenticate first — see [CLI Auth](/docs/cli/auth). Most commands require an agent ID (`-a agt_123`) or a [default agent](/docs/cli/config). ## List API-created conversations List conversations created programmatically through the API, newest first: ```bash theme={null} chatbase conversations list -a agt_123 ``` List conversations for a specific user: ```bash theme={null} chatbase conversations list -a agt_123 --user usr_456 ``` Fetch every page as JSON: ```bash theme={null} chatbase conversations list -a agt_123 --all --json ``` `conversations list` returns only API-created conversations. Conversations from the chat bubble and external integrations (Slack, WhatsApp, Instagram, Messenger, and the like) are not included and are not counted in `total`. Use `conversations export` to read conversations from every source. ## Get one conversation Show metadata for a single API-created conversation: ```bash theme={null} chatbase conversations get conv_123 -a agt_123 ``` You can pass the ID as an argument or with `--conversation`: ```bash theme={null} chatbase conversations get --conversation conv_123 -a agt_123 ``` ## Export all conversations Export conversations from every source with full message history embedded: ```bash theme={null} chatbase conversations export -a agt_123 ``` Write the full export to a file: ```bash theme={null} chatbase conversations export -a agt_123 --all -o export.json ``` Each exported item includes its own `messages` array, so you do not need follow-up `conversations get` or `messages list` calls. Export is the only way to read bubble and integration conversations from the CLI — `get` and `messages list` work only for API-created conversations. Use `--limit` (1–20, default 20) when processing large exports page by page. See [Exporting All Conversations](/docs/api-v2/user-conversations#exporting-all-conversations) for source types and message format. ## Submit client-side tool results When a chat response pauses on a client-side tool call, submit the result so the turn can continue: ```bash theme={null} chatbase conversations tool-result conv_123 --tool-call-id tc_1 --output '{"temperature": 72}' -a agt_123 ``` Pass JSON from a file with `@result.json`, or omit `--output` to send an empty result. See [Client Actions](/docs/api-v2/client-actions) for how tool calls and results work. ```bash theme={null} chatbase conversations tool-result conv_123 --tool-call-id tc_1 --output @result.json -a agt_123 ``` Send an empty result when the tool produced no output: ```bash theme={null} chatbase conversations tool-result conv_123 --tool-call-id tc_1 -a agt_123 ``` ## List messages List messages in an API-created conversation: ```bash theme={null} chatbase messages list --conversation conv_123 -a agt_123 ``` Fetch every page as JSON: ```bash theme={null} chatbase messages list --conversation conv_123 -a agt_123 --all --json ``` ## Set message feedback Rate an assistant message: ```bash theme={null} chatbase messages feedback msg_1 --conversation conv_123 --rating positive -a agt_123 ``` Clear existing feedback: ```bash theme={null} chatbase messages feedback --conversation conv_123 --message msg_1 --rating clear -a agt_123 ``` Ratings are `positive`, `negative`, or `clear`. ## Commands | Command | Purpose | | ------------------------------------ | ----------------------------------------------------------------- | | `chatbase conversations export` | Export conversations from every source, with full message history | | `chatbase conversations get` | Show one API-created conversation | | `chatbase conversations list` | List an agent's API-created conversations | | `chatbase conversations tool-result` | Submit a client-side tool result to a chat turn | | `chatbase messages feedback` | Set or clear user feedback on an assistant message | | `chatbase messages list` | List messages in a conversation | For every flag, run `chatbase conversations --help` or `chatbase messages --help`. # CLI Health Source: https://chatbase.co/docs/cli/health Verify that the Chatbase API is reachable from your terminal or CI pipeline. Use `chatbase health` to confirm the Chatbase API is reachable before running other commands — for example in CI preflight checks, after network or proxy changes, or when debugging authentication issues. No API key is required. ## Check reachability ```bash theme={null} chatbase health ``` Exits successfully when the API responds. ## Scripting output Output raw JSON for automated checks: ```bash theme={null} chatbase health --json ``` Combine with `--quiet` in CI pipelines. See [Chatbase CLI](/docs/cli/overview) for other global output flags. ## Commands | Command | Purpose | | ----------------- | ---------------------------------------- | | `chatbase health` | Check that the Chatbase API is reachable | For every flag, run `chatbase health --help`. # Chatbase CLI Source: https://chatbase.co/docs/cli/overview Install and use the official Chatbase CLI to manage agents, sources, conversations, helpdesk, and WhatsApp from your terminal or CI. The Chatbase CLI is the official command-line client for the [Chatbase API v2](/docs/api-v2/overview). Use it to manage agents, knowledge sources, conversations, helpdesk tickets, and WhatsApp templates from your terminal or CI pipelines. Requires **Node.js 20+**. Interactive login uses your Chatbase account in the browser (`chatbase auth login --browser`). API keys (Standard plan or higher) work for paste-login and CI — create them in **Workspace settings → API keys**. ## Install ```bash theme={null} npm install -g chatbase ``` Or run without installing: ```bash theme={null} npx chatbase ``` Check the version: ```bash theme={null} chatbase --version ``` ## Quick start ```bash theme={null} chatbase auth login --browser ``` This opens a browser window and shows a short code. Approve the code at [chatbase.co/activate](https://www.chatbase.co/activate). The CLI stores the credential for later commands. Prefer pasting an API key instead? Run `chatbase auth login` and paste a key from **Workspace settings → API keys**. See [CLI Auth](/docs/cli/auth) for all login options. ```bash theme={null} chatbase agents list ``` ```bash theme={null} chatbase chat -a agt_123 -m "How do I reset my password?" ``` ## Authenticate in CI In non-interactive environments, set an API key in the environment instead of running `auth login`: ```bash theme={null} export CHATBASE_API_KEY=cb_... chatbase agents list ``` Optionally pin a default agent: ```bash theme={null} export CHATBASE_AGENT_ID=agt_123 # or chatbase config set agent agt_123 ``` Never commit API keys. Prefer secrets managers or CI secret stores. ## Global output flags Most commands support: | Flag | Purpose | | ---------------- | -------------------------------- | | `--json` | Raw API JSON | | `--plain` | Tab-separated output for scripts | | `--quiet` / `-q` | Suppress non-essential output | | `--verbose` | Verbose diagnostics | | `--no-input` | Never prompt; fail instead | | `--no-color` | Disable colored output | ## Privacy The CLI sends no telemetry. Requests include a `chatbase-cli/` User-Agent so Chatbase can distinguish CLI traffic. The only network calls are the API calls you invoke. ## Commands Log in, log out, and inspect credentials. Create, update, train, clone, and delete agents. Manage knowledge sources (text, Q\&A, links, files). Send messages and stream responses. List, inspect, and export conversations. Manage helpdesk tickets and lookups. List templates and send template messages. Set default agent and timeout. Call any API v2 endpoint directly. Check that the API is reachable. ## Uninstall ```bash theme={null} npm uninstall -g chatbase rm -rf ~/.config/chatbase ~/.local/state/chatbase ~/.cache/chatbase rm -rf ~/Library/Caches/chatbase # macOS: update-check cache ``` For every flag on a command, run `chatbase --help`. # CLI Sources Source: https://chatbase.co/docs/cli/sources Add, list, update, delete, and restore knowledge sources for a Chatbase agent from the terminal. Use source commands to manage an agent's knowledge base — text, Q\&A pairs, links, and file uploads. For REST details, see [Sources API](/docs/api-v2/sources). Most commands require an agent ID (`-a agt_123`) or a [default agent](/docs/cli/config). ## Add sources Text snippet: ```bash theme={null} chatbase sources create --type text --name Guide --content "hello" -a agt_123 ``` Website link (crawl mode): ```bash theme={null} chatbase sources create --type link --url https://example.com --link-type crawl -a agt_123 ``` Q\&A pair: ```bash theme={null} chatbase sources create --type qna --data '{"questions":["Q1"],"answer":"A1"}' -a agt_123 ``` File upload: ```bash theme={null} chatbase sources create --file ./guide.pdf -a agt_123 ``` Link types also include `individual` (single page) and `sitemap`. ## List and inspect List sources for an agent: ```bash theme={null} chatbase sources list -a agt_123 ``` Show one source: ```bash theme={null} chatbase sources get src_123 -a agt_123 ``` View aggregated counts and sizes: ```bash theme={null} chatbase sources summary -a agt_123 ``` ## Update, delete, and restore Update a text, Q\&A, or link source: ```bash theme={null} chatbase sources update src_123 --data '{"type":"text","content":"updated"}' -a agt_123 ``` Replace a file source: ```bash theme={null} chatbase sources update src_123 --file ./updated.pdf -a agt_123 ``` Delete a source (restorable): ```bash theme={null} chatbase sources delete src_123 -a agt_123 ``` Restore a deleted source: ```bash theme={null} chatbase sources restore src_123 -a agt_123 ``` ## Train after changes Adding or updating sources does not retrain the agent automatically. Queue a training job when you are ready: ```bash theme={null} chatbase agents train -a agt_123 ``` See [CLI Agents](/docs/cli/agents) for training and auto-retrain options. ## Commands | Command | Purpose | | -------------------------- | ------------------------------------------------------ | | `chatbase sources create` | Create a source: text/qna/link (JSON) or a file upload | | `chatbase sources delete` | Delete a source (restorable via restore command) | | `chatbase sources get` | Show one source | | `chatbase sources list` | List sources for an agent | | `chatbase sources restore` | Restore a deleted source | | `chatbase sources summary` | Show aggregated source counts and sizes for an agent | | `chatbase sources update` | Update an existing source (text, qna, link, or file) | For every flag, run `chatbase sources --help`. # CLI Tickets Source: https://chatbase.co/docs/cli/tickets Create, triage, search, and reply to helpdesk tickets and look up teams and statuses from the terminal. Use ticket and helpdesk commands to manage support tickets and their message threads. For REST details, see [Helpdesk](/docs/api-v2/helpdesk). Authenticate first — see [CLI Auth](/docs/cli/auth). Most commands require an agent ID (`-a agt_123`) or a [default agent](/docs/cli/config). ## Create a ticket Open a ticket on behalf of a customer with a subject, description, and email: ```bash theme={null} chatbase tickets create --subject "Export failing" -f description="Customer cannot export." --customer-email jane@example.com -a agt_123 ``` Pass the full body as JSON instead of individual flags: ```bash theme={null} chatbase tickets create --subject "Export failing" --data '{"description":"Customer cannot export.","customer":{"email":"jane@example.com"}}' -a agt_123 ``` Use `--customer-name` when the email creates a new customer record. Set status, assignee, or team at creation time with `-f` or `--data` — see [Create a ticket](/docs/api-v2/helpdesk/create-a-ticket) for assignment rules. ## List and search tickets List tickets for an agent, newest first: ```bash theme={null} chatbase tickets list -a agt_123 ``` Filter by status category, assignee, team, channel, or date range: ```bash theme={null} chatbase tickets list -a agt_123 --status new,on_you --assignee-id none ``` Search ticket message content: ```bash theme={null} chatbase tickets search "refund not received" -a agt_123 ``` Fetch every page as JSON: ```bash theme={null} chatbase tickets list -a agt_123 --all --json ``` ## Get a ticket and read messages Show one ticket by its per-agent number: ```bash theme={null} chatbase tickets get 42 -a agt_123 ``` List the ticket's message thread: ```bash theme={null} chatbase tickets messages 42 -a agt_123 ``` Include internal notes or system events with `--types`: ```bash theme={null} chatbase tickets messages 42 -a agt_123 --types reply,note,event ``` ## Reply to a ticket Post a customer-visible reply attributed to a team member: ```bash theme={null} chatbase tickets reply 42 -m "On it" --author-email sam@example.com -a agt_123 ``` The message body is GitHub-flavored Markdown. A 201 means the reply was recorded, not that it reached the customer — delivery is asynchronous. ## Update status, assignee, or team Look up valid status IDs and team IDs before you update: ```bash theme={null} chatbase helpdesk statuses -a agt_123 chatbase helpdesk teams -a agt_123 ``` Close a ticket by status category: ```bash theme={null} chatbase tickets update 42 --data '{"statusCategory":"closed"}' -a agt_123 ``` Assign to a team member or set a specific status ID: ```bash theme={null} chatbase tickets update 42 -f assigneeEmail=sam@example.com -f statusId=sts_abc -a agt_123 ``` Use `statusCategory` to resolve to that category's default status, or `statusId` for a specific configured status. See [Statuses](/docs/api-v2/helpdesk#statuses) and [Update a ticket](/docs/api-v2/helpdesk/update-a-ticket). ## Look up teams and statuses List helpdesk teams (including the default): ```bash theme={null} chatbase helpdesk teams -a agt_123 ``` List configured ticket statuses with IDs and labels: ```bash theme={null} chatbase helpdesk statuses -a agt_123 ``` Use `--json` to pipe IDs into scripts. ## Commands | Command | Purpose | | ---------------------------- | ------------------------------------------------ | | `chatbase helpdesk statuses` | List ticket statuses for an agent | | `chatbase helpdesk teams` | List helpdesk teams for an agent | | `chatbase tickets create` | Create a helpdesk ticket | | `chatbase tickets get` | Show one helpdesk ticket | | `chatbase tickets list` | List helpdesk tickets for an agent | | `chatbase tickets messages` | List a ticket's message thread | | `chatbase tickets reply` | Post an agent reply to a ticket's message thread | | `chatbase tickets search` | Search tickets by message content | | `chatbase tickets update` | Update a ticket's status, assignee, and/or team | For every flag, run `chatbase tickets --help` or `chatbase helpdesk --help`. # CLI WhatsApp Source: https://chatbase.co/docs/cli/whatsapp List approved WhatsApp templates and send template messages to phone numbers from the terminal. Use WhatsApp commands to list approved templates and send outbound template messages. For REST details, see [WhatsApp](/docs/api-v2/whatsapp). Authenticate first — see [CLI Auth](/docs/cli/auth). Most commands require an agent ID (`-a agt_123`) or a [default agent](/docs/cli/config). Connect a WhatsApp number to your agent before using these commands — see [WhatsApp integration](/docs/user-guides/integrations/whatsapp) and [WhatsApp templates](/docs/user-guides/integrations/whatsapp-templates) in the user guide. ## List templates List every approved template across the agent's connected WhatsApp Business Accounts: ```bash theme={null} chatbase whatsapp templates -a agt_123 ``` Output includes template names, languages, variable placeholders grouped by component, and the connected numbers you can send from. A template can only be sent from a number on its own Business Account — match the template's WABA to a sender before sending. Fetch raw JSON for scripting: ```bash theme={null} chatbase whatsapp templates -a agt_123 --json ``` ## Send a template Send a template with no variables: ```bash theme={null} chatbase whatsapp send-template order_update --to 14155552671 -a agt_123 ``` The recipient number uses international format (digits with country code, no `+` required). When the agent has exactly one connected number, `--from` is optional. ## Send with variables Pass template variable values as JSON grouped by component: ```bash theme={null} chatbase whatsapp send-template order_update --to 14155552671 --language en_US --variables '{"body":{"1":"Jane"}}' -a agt_123 ``` Use `--language` when the template name has multiple approved language variants. Header and body placeholders are numbered independently — supply every key the template listing reported. See [Template variables](/docs/api-v2/whatsapp#template-variables) for format rules. Send from a specific connected number when the agent has more than one: ```bash theme={null} chatbase whatsapp send-template order_update --to 14155552671 --from 14155552671 -a agt_123 ``` A `201` means WhatsApp accepted the message. Delivery to the recipient is not guaranteed — see [Delivery and conversations](/docs/api-v2/whatsapp#delivery-and-conversations). ## Commands | Command | Purpose | | --------------------------------- | --------------------------------------------- | | `chatbase whatsapp send-template` | Send an approved WhatsApp template message | | `chatbase whatsapp templates` | List approved WhatsApp templates for an agent | For every flag, run `chatbase whatsapp --help`. # REST API Integration Source: https://chatbase.co/docs/developer-guides/api-integration Complete guide to integrating Chatbase AI Agents using our REST API for custom integrations and applications. **Looking for API v2?** The new Chatbase API v2 features structured error codes, cursor-based pagination, and SSE streaming. Note that API v2 is available starting from the Standard Plan. [Check out the API v2 Reference →](/docs/api-v2/overview) ## Overview The Chatbase REST API enables you to integrate AI-powered conversations into any application or workflow. Build custom chat experiences, automate customer interactions, and manage your AI agents programmatically. Chat with your AI agents and handle real-time streaming responses Create, configure, and update AI agents with custom training data Retrieve conversations, leads, and analytics from your AI interactions ## Quick Start Creating API key in Chatbase dashboard 1. Visit your [Chatbase Dashboard](https://www.chatbase.co/dashboard) 2. Go to **Workspace settings** → **API keys** 3. Click **Create API Key** and copy the generated key Store your API key securely and never expose it in client-side code. Finding Agent ID in Chatbase settings 1. Select your AI Agent in the dashboard 2. Go to **Settings** → **General** 3. Copy the **Agent ID** from the **Agent details** card Test your integration with a simple chat request: ```bash theme={null} curl -X POST 'https://www.chatbase.co/api/v1/chat' \ -H 'Authorization: Bearer YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "messages": [{"content": "Hello! How can you help me?", "role": "user"}], "chatbotId": "your-chatbot-id-here" }' ``` **Expected Response:** ```json theme={null} { "text": "Hello! I'm here to help answer your questions and assist with any information you need. What can I help you with today?" } ``` ### Chat API Streaming The [chat API](/docs/api-reference) supports real-time streaming responses for better user experience. ```javascript Node.js theme={null} // streamer.js const axios = require('axios') const {Readable} = require('stream') const apiKey = '' const chatId = '' const apiUrl = 'https://www.chatbase.co/api/v1/chat' const messages = [{content: '', role: 'user'}] const authorizationHeader = `Bearer ${apiKey}` async function readChatbotReply() { try { const response = await axios.post( apiUrl, { messages, chatId, stream: true, temperature: 0, }, { headers: { Authorization: authorizationHeader, 'Content-Type': 'application/json', }, responseType: 'stream', } ) const readable = new Readable({ read() {}, }) response.data.on('data', (chunk) => { readable.push(chunk) }) response.data.on('end', () => { readable.push(null) }) const decoder = new TextDecoder() let done = false readable.on('data', (chunk) => { const chunkValue = decoder.decode(chunk) // Process the chunkValue as desired // Here we just output it as in comes in without \n process.stdout.write(chunkValue) }) readable.on('end', () => { done = true }) } catch (error) { console.log('Error:', error.message) } } readChatbotReply() ``` ```python Python theme={null} ## streamer.py import requests api_url = 'https://www.chatbase.co/api/v1/chat' api_key = '' chat_id = '' messages = [ { 'content': '', 'role': 'user' } ] authorization_header = f'Bearer {api_key}' def read_chatbot_reply(): try: headers = { 'Authorization': authorization_header, 'Content-Type': 'application/json' } data = { 'messages': messages, 'chatId': chat_id, 'stream': True, 'temperature': 0 } response = requests.post(api_url, json=data, headers=headers, stream=True) response.raise_for_status() decoder = response.iter_content(chunk_size=None) for chunk in decoder: chunk_value = chunk.decode('utf-8') print(chunk_value, end='', flush=True) except requests.exceptions.RequestException as error: print('Error:', error) read_chatbot_reply() ``` ## Performance Best Practices **Optimization Strategies:** * Use streaming for chat responses to improve perceived performance * Cache agent responses when appropriate * Batch multiple operations when possible * Monitor and optimize conversation context length ## 🚀 Try It Live! Ready to see the magic in action? Dive straight into our interactive playground where you can test every API endpoint, experiment with real responses, and build your integration in real-time. Test APIs instantly • No setup required • Real-time responses • Copy working code snippets ### Key API Endpoints Send messages and receive AI responses with streaming support Create, update, and configure AI agents programmatically Access chat history and conversation analytics Create and manage contacts for your AI agents # Event Listeners Source: https://chatbase.co/docs/developer-guides/chatbot-event-listeners Listen for and respond to real-time chat events including user messages, AI responses, custom actions, and more to create interactive experiences. Event listeners allow you to monitor and react to everything happening in your AI Agent conversations. From user messages to custom actions, you can build rich, interactive experiences that respond dynamically to user interactions. ## Why Use Event Listeners? Create dynamic, responsive interactions: * Show contextual information based on conversation topic * Trigger UI changes based on user messages * Provide visual feedback for AI responses * Integrate chat with other page elements Connect your chat with external systems: * Send data to CRM or analytics platforms * Trigger email campaigns or notifications * Update user profiles or preferences * Sync conversation data with support systems ### Prerequisites A website with the Chatbase embed script already installed and working. New to Chatbase? Check out [Your First Agent](/docs/user-guides/quick-start/your-first-agent) to get started with the embed script first. ## Available Events Listen for these events to monitor and respond to chat activity: **Track conversation flow** Triggered when a user sends a message **Payload:** `{ data: { content: string }, type: "user-message" }`\ **Use cases:** Analytics, message validation, auto-suggestions Triggered when your AI Agent responds **Payload:** `{ data: { content: string }, type: "assistant-message" }`\ **Use cases:** UI updates, satisfaction surveys, follow-up actions ```javascript theme={null} // Example: Track conversation topics window.chatbase.addEventListener('user-message', (event) => { console.log('User asked:', event.data.content); // Track in analytics analytics.track('Chat Message Sent', { message_length: event.data.content.length, timestamp: new Date().toISOString() }); }); window.chatbase.addEventListener('assistant-message', (event) => { console.log('AI responded:', event.data.content); // Show satisfaction survey after response if (event.data.content.includes('solution') || event.data.content.includes('help')) { showSatisfactionSurvey(); } }); ``` **Monitor custom actions and tools** Triggered when a custom action or tool is called **Payload:** `{ data: { args: object, id: string, name: string, type: string }, type: 'tool-call' }`\ **Use cases:** Backend API calls, form submissions, third-party integrations Triggered when a tool returns results **Payload:** `{ data: { name: string, result: object, toolCallId: string, type: string }, type: 'tool-result' }`\ **Use cases:** UI updates, error handling, success notifications ```javascript theme={null} // Example: Handle custom actions window.chatbase.addEventListener('tool-call', (event) => { console.log('Tool called:', event.data.name, event.data.args); if (event.data.name === 'schedule-meeting') { // Show calendar widget showCalendarWidget(event.data.args.preferredTime); } else if (event.data.name === 'get-pricing') { // Track pricing interest analytics.track('Pricing Inquiry', event.data.args); } }); window.chatbase.addEventListener('tool-result', (event) => { if (event.data.name === 'schedule-meeting' && event.data.result.success) { // Show confirmation message showNotification('Meeting scheduled successfully!'); } }); ``` ## Basic Event Listener Usage ### Adding Event Listeners Add event listeners using the simple syntax: ```javascript theme={null} window.chatbase.addEventListener(eventName, callbackFunction); ``` Must be one of the event names listed in Available Event Types. Function to be called when the event is fired. The event payload is passed as an argument. ### Removing Event Listeners Remove listeners when they're no longer needed to prevent memory leaks: ```javascript Basic Removal theme={null} // Store reference to callback function const myEventHandler = (event) => { console.log('Event received:', event); }; // Add listener window.chatbase.addEventListener('user-message', myEventHandler); // Remove listener later window.chatbase.removeEventListener('user-message', myEventHandler); ``` ```javascript React Component Example theme={null} // In React, clean up listeners on unmount useEffect(() => { const handleUserMessage = (event) => { setLastMessage(event.data.content); }; window.chatbase.addEventListener('user-message', handleUserMessage); // Cleanup on unmount return () => { window.chatbase.removeEventListener('user-message', handleUserMessage); }; }, []); ``` ## Event Management Best Practices ## Troubleshooting **Problem:** Event listeners aren't being called **Solutions:** * **Check script loading**: Verify that the Chatbase embed script has loaded completely before adding event listeners. The `window.chatbase` object should be available. * **Verify event names**: Double-check that you're using the correct event names. Valid events include: `user-message`, `assistant-message`, `tool-call`, and `tool-result`. Typos in event names will prevent listeners from firing. * **Check browser console**: Look for JavaScript errors that might prevent your listener functions from being registered or executed properly. **Problem:** Application slowing down over time **Solutions:** * **Remove unused listeners**: Always remove event listeners when they're no longer needed using `removeEventListener` with the same function reference used in `addEventListener`. * **Clean up on page unload**: Remove all event listeners before the user navigates away from the page to prevent memory leaks in single-page applications. * **Handle route changes**: In single-page applications, ensure you clean up event listeners when routes change, not just on full page reloads. * **Use cleanup patterns**: Create cleanup functions that remove all your event listeners and call them at appropriate lifecycle points in your application. **Problem:** removeEventListener not working **Solutions:** * **Avoid inline functions**: Don't use anonymous or inline functions as event handlers if you need to remove them later. Inline functions create new function references each time, making them impossible to remove. * **Store function references**: Create named functions or store function references in variables before passing them to `addEventListener`. Use the same reference when calling `removeEventListener`. * **Test removal**: Verify that your event listeners are actually being removed by checking if they still fire after calling `removeEventListener`. ## Next Steps Create dynamic, personalized initial messages for users Display floating messages over the chat bubble # Client-Side Custom Actions Source: https://chatbase.co/docs/developer-guides/client-side-custom-actions Execute custom actions directly in your user's browser with full control and seamless integration Client-side custom actions allow you to execute code directly in your user's browser, giving you complete control over the execution environment and enabling seamless integration with your existing frontend systems. ## Benefits of Client-Side Actions Integrate seamlessly with your existing frontend architecture and user systems Access user-specific information and browser APIs not available on the server Create interactive, responsive experiences with immediate feedback and smooth workflows Use your existing authentication, state management, and API integration patterns ## How Client-Side Actions Work When a user interacts with your agent and triggers a client-side action: 1. The Agent sends an event to your website window with action details 2. Your registered tool function executes in the browser 3. The result is sent back to the Agent 4. The conversation continues with the action response ## Setup Guide ### Prerequisites A website with the Chatbase embed script already installed and working. New to Chatbase? Check out [Your First Agent](/docs/user-guides/quick-start/your-first-agent) to get started with the embed script first. Create a new custom action in your Chatbase dashboard: 1. Go to Chatbase dashboard [dashboard](https://chatbase.co/dashboard) page 2. Select the agent you want to create the custom action for 3. Navigate to **Build > Actions** → **Create action** → **Custom action** 4. Fill in the action details: * **Name**: A unique identifier (e.g., `get_weather`) * **Description**: What the action does * **Parameters**: Define any data needed to have the Agent collect from the user 5. **Important**: Select **"Client"** as the action type to enable client-side execution 6. Click on the **Save and Continue** button and enable the action. Custom action form Use the `registerTools` method to provide the actual implementation for your actions: ```javascript theme={null} window.chatbase("registerTools", { get_weather: async (args, user) => { try { // Access the parameters defined in your action configuration const { location } = args; // Make API requests to your backend const response = await fetch(`/api/weather?location=${location}`); if (!response.ok) { throw new Error('Failed to fetch weather data'); } const weatherData = await response.json(); return { status: "success", data: { temperature: weatherData.temperature, condition: weatherData.condition, location: location } }; } catch (error) { return { status: "error", error: error.message }; } }, send_notification: async (args, user) => { try { // Show a simple alert with data collected from the user by the Ai agent alert(`${args.title}\n\n${args.message}`); return { status: "success", data: "Alert shown successfully" }; } catch (error) { return { status: "error", error: "Failed to show alert" }; } } }); ``` Register all your tools in a single `registerTools` call. Multiple calls will override previously registered tools. The action names created in the dashboard must exactly match the function names you register with `registerTools`. ## Function Parameters Every client-side action function receives two parameters: Contains all the parameters defined in your custom action configuration. The structure matches exactly what you defined in the dashboard. Contains user information that varies depending on your identity verification setup. Unique identifier for the authenticated user as provided during the identify call. Hash of the user\_id used for verification (generated server-side). Internal anonymous user identifier. You can ignore this field. Internal Chatbase anonymous identifier. You can ignore this field. Custom user data passed during the identify call (e.g., name, email, company). This field is only present if metadata was provided during identification. Internal anonymous user identifier. You can ignore this field. Internal Chatbase anonymous identifier. You can ignore this field. Custom user data passed during any identify calls. This field is only present if metadata was provided during identification. The anonymous IDs (`anon_user_id` and `chatbase_anon_id`) are internal identifiers used by Chatbase and can be safely ignored in your custom form implementations. ## Response Format Your action functions must return responses in a specific format: When your action succeeds, return both `status` and `data`: ```javascript theme={null} { status: "success", data: responseData // Can be string, object, array, etc. } ``` **Examples:** ```javascript Object Response theme={null} { status: "success", data: { temperature: 72, condition: "sunny", humidity: 45, forecast: ["Clear skies", "Light breeze"] } } ``` ```javascript String Response theme={null} { status: "success", data: "The weather in New York is currently 72°F and sunny with light winds." } ``` ```javascript Array Response theme={null} { status: "success", data: [ { name: "Product 1", price: 29.99 }, { name: "Product 2", price: 49.99 } ] } ``` When an error occurs, return `status` and `error`: ```javascript theme={null} { status: "error", error: "Descriptive error message" } ``` **Examples:** ```javascript theme={null} // API failure { status: "error", error: "Unable to connect to weather service. Please try again." } // Validation error { status: "error", error: "Location parameter is required" } // Authentication error { status: "error", error: "User must be logged in to perform this action" } ``` ## Advanced Examples This example shows client-side actions utilizing the browser geolocation API to get the user's zip code. Advanced example of a client-side action using the browser geolocation API ```javascript Browser Integration theme={null} window.chatbase("registerTools", { get_zip_code: async (args, user) => { try { // Use browser geolocation API const position = await new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject); }); const { latitude, longitude } = position.coords; const response = await fetch(`/api/location-info?lat=${latitude}&lon=${longitude}`); const { zip_code } = await response.json(); return { status: "success", data: { zip_code: zip_code, } }; } catch (error) { return { status: "error", error: "Unable to access location information" }; } } }); ``` Advanced example of a client-side action using the browser geolocation API result ## Best Practices Always wrap your action logic in try-catch blocks and return meaningful error messages: ```javascript theme={null} window.chatbase("registerTools", { my_action: async (args, user) => { try { // Validate input parameters if (!args.requiredParam) { return { status: "error", error: "Required parameter is missing" }; } // Your action logic here const result = await performAction(args); return { status: "success", data: result }; } catch (error) { // Log for debugging. console.error('Action failed:', error); return { status: "error", error: "Action failed. Please try again." }; } } }); ``` Always validate user inputs and handle edge cases: ```javascript theme={null} window.chatbase("registerTools", { calculate_shipping: async (args, user) => { const { weight, destination, shippingMethod } = args; // Validate required parameters if (!weight || weight <= 0) { return { status: "error", error: "Valid weight is required" }; } if (!destination || destination.length < 2) { return { status: "error", error: "Valid destination is required" }; } try { const result = await calculateShipping(weight, destination, shippingMethod); return { status: "success", data: result }; } catch (error) { return { status: "error", error: "Shipping calculation failed" }; } } }); ``` * Cache frequently used data in browser storage * Use appropriate timeouts for external API calls * Minimize the size of returned data ```javascript theme={null} window.chatbase("registerTools", { get_cached_data: async (args, user) => { const cacheKey = `data_${args.type}`; const cached = localStorage.getItem(cacheKey); if (cached) { const { data, timestamp } = JSON.parse(cached); const isStale = Date.now() - timestamp > 300000; // 5 minutes if (!isStale) { return { status: "success", data }; } } // Fetch fresh data if not cached or stale const freshData = await fetchData(args.type); localStorage.setItem(cacheKey, JSON.stringify({ data: freshData, timestamp: Date.now() })); return { status: "success", data: freshData }; } }); ``` **Environment Limitations**: Client-side custom forms will not function in: * Chatbase Playground environment * Action Preview mode * Compare features Testing this action should be done in your actual website environment. Embed the [JavaScript script](/docs/developer-guides/javascript-embed) in your website and test the action. **Response Size Limits:** Keep your response data under reasonable size limits to ensure good performance. Very large responses may be truncated or cause timeouts. ## Troubleshooting **Problem:** Console shows "Tool \[name] not found" **Solutions:** * Ensure action names match exactly between dashboard and `registerTools` * Check that `registerTools` is called after the agent loads * Verify the action is marked as "client-side" in dashboard **Problem:** Action executes but agent doesn't receive response **Solutions:** * Check browser console for JavaScript errors * Ensure you're returning the correct response format * Verify async functions are properly awaited * Check for uncaught exceptions in your action code **Problem:** User parameter is null when expected **Solutions:** * Verify [identity verification](/docs/developer-guides/identity-verification) is properly configured * Test with and without authenticated users in your implementation * Add fallback logic for when user context is unavailable ## Next Steps Add interactive forms and data collection to your chat Programmatically control the chat interface Learn to listen for and respond to chat events in real-time Create dynamic, personalized initial messages for users # Client-Side Custom Forms Source: https://chatbase.co/docs/developer-guides/client-side-custom-forms Create dynamic, interactive forms in your agent using client-side JavaScript configuration ## Overview Client-side custom forms enable you to create dynamic, interactive forms that run directly in the user's browser. Server-side custom form configuration is not currently available. All custom forms must be configured using client-side JavaScript. ### Key Benefits * **Real-time validation**: Instant feedback as users fill out forms * **Enhanced UX**: Smooth interactions without server round trips * **Full customization**: Complete control over form appearance and behavior ### Prerequisites A website with the Chatbase embed script already installed and working. New to Chatbase? Check out [Your First Agent](/docs/user-guides/quick-start/your-first-agent) to get started with the embed script first. ## Setup Guide Set up the form configuration in your Chatbase dashboard: 1. Navigate to **Build > Actions** → **Create action** → **Custom form** Custom form creation interface 2. Enter a unique name for your form. 3. Configure the form when to use. 4. Click on the **Save and Continue** button. 5. Enable the action. Custom form when to use interface **Environment Limitations**: Client-side custom forms will not function in: * Chatbase Playground environment * Action Preview mode * Compare features Testing this action should be done in your actual website environment. Embed the [JavaScript script](/docs/developer-guides/javascript-embed) in your website and test the action. On your website, register your form schema by calling the `registerFormSchema` method anywhere in your JavaScript code, with the name of the action you created in the dashboard. Register the form in a root page of your website, or in a component that is loaded on every page. ```javascript theme={null} window.chatbase.registerFormSchema({ "learn_more_form": async (args, user) => { return { fields: [ { name: "name", label: "Full Name", type: "text", placeholder: "Enter your full name", validation: { required: { value: true, message: "Name is required" } } }, { name: "email", label: "Email Address", type: "email", placeholder: "Enter your email", validation: { required: { value: true, message: "Email is required" } } }, { name: "message", label: "Message", type: "textarea", placeholder: "How can we help you?", validation: { required: { value: true, message: "Please enter your message" } } } ], submitButtonText: "Send Message", successMessage: "Thank you! We'll get back to you soon.", errorMessage: "Failed to send message. Please try again." }; } }); ``` **Multiple Registration Override**: Calling `registerFormSchema` multiple times will completely replace all previously registered forms. Always include all your forms in a single registration call. You can also configure webhooks to receive real-time notifications when users submit your custom forms. For detailed configuration instructions, see [Webhooks Integration](#webhooks-integration). Webhook configuration interface ## Function Parameters Each custom form function receives two parameters that provide context and data: Contains all the arguments defined in your custom form configuration. These are the values the ai agent generated and passed from the AI action when the form is triggered. Custom form args interface Contains user information that varies depending on your identity verification setup. Unique identifier for the authenticated user as provided during the identify call. Hash of the user\_id used for verification (generated server-side). Internal anonymous user identifier. You can ignore this field. Internal Chatbase anonymous identifier. You can ignore this field. Custom user data passed during the identify call (e.g., name, email, company). This field is only present if metadata was provided during identification. Internal anonymous user identifier. You can ignore this field. Internal Chatbase anonymous identifier. You can ignore this field. Custom user data passed during any identify calls. This field is only present if metadata was provided during identification. The anonymous IDs (`anon_user_id` and `chatbase_anon_id`) are internal identifiers used by Chatbase and can be safely ignored in your custom form implementations. ## Complete Example Here's a comprehensive example showing a user profile form with various field types and validation rules: The function name in your JavaScript code (e.g., `userProfileForm`) must exactly match the name you assign to your AI Action in the Chatbase dashboard. ```javascript userProfileForm.js theme={null} window.chatbase.registerFormSchema({ userProfileForm: async (args, user) => { // Pre-populate form with user data if available const defaultName = user?.user_metadata?.name || args.name || ''; const defaultEmail = user?.user_metadata?.email || ''; return { fields: [ { name: "name", label: "First Name", type: "text", defaultValue: defaultName, placeholder: "Enter your first name", validation: { required: { value: true, message: "Name is required" }, minLength: { value: 2, message: "Name must be at least 2 characters" }, maxLength: { value: 50, message: "Name cannot exceed 50 characters" } } }, { name: "email", label: "Email Address", type: "email", defaultValue: defaultEmail, validation: { required: { value: true, message: "Email is required" }, pattern: { value: "^[^\s@]+@[^\s@]+\.[^\s@]+$", message: "Please enter a valid email address" } } }, { name: "officeLocation", type: "groupselect", label: "Office Location", options: { "North America": [ { value: "nyc", label: "New York City" }, { value: "sf", label: "San Francisco" }, { value: "toronto", label: "Toronto" } ], "Europe": [ { value: "london", label: "London" }, { value: "berlin", label: "Berlin" }, { value: "paris", label: "Paris" } ], "Asia Pacific": [ { value: "tokyo", label: "Tokyo" }, { value: "singapore", label: "Singapore" } ] }, validation: { required: { value: true, message: "Please select your office location" } } }, { name: "skills", type: "multiselect", label: "Technical Skills", options: [ { value: "javascript", label: "JavaScript" }, { value: "python", label: "Python" }, { value: "react", label: "React" }, { value: "nodejs", label: "Node.js" }, { value: "sql", label: "SQL" } ] }, { name: "bio", label: "Bio", type: "textarea", placeholder: "Tell us about yourself...", validation: { maxLength: { value: 500, message: "Bio cannot exceed 500 characters" } } }, { name: "profileImage", label: "Profile Image", type: "image", placeholder: "Click or drop your profile image here" } ], submitButtonText: "Update Profile", showLabels: true, successMessage: "Profile updated successfully!", errorMessage: "Failed to update profile. Please try again." }; } }); ``` Example custom form in agent interface ## API Reference ### Form Schema The `registerFormSchema` function returns a schema object that defines your form's structure and behavior: Array of form field definitions. Each field must conform to the Field Schema specifications below. Text displayed on the form's submit button. Controls whether field labels are displayed above form inputs. Message shown to users when the form is successfully submitted. Message displayed when form submission fails. ### Field Schema Each field in the `fields` array supports the following properties: Unique identifier for the form field. This name is used to reference the field's value in form submissions. Specifies the input type. Must be one of the supported field types listed below. Display text shown to users for this field. Placeholder text displayed inside the input field. If not provided, the label text is used as placeholder. Pre-filled value for the field. Type depends on the field type (string for text, number for numeric fields, etc.). Whether the field should be read-only and non-interactive. Validation rules for the field. See Validation Rules section below for detailed specifications. Required for selection fields (`select`, `multiselect`, `groupselect`, `groupmultiselect`). **For `select` and `multiselect`**: Array of objects with `label` and `value` properties: ```javascript theme={null} options: [ { value: "option1", label: "Option 1" }, { value: "option2", label: "Option 2" } ] ``` **For `groupselect` and `groupmultiselect`**: Object where keys are group names and values are arrays of options: ```javascript theme={null} options: { "Group 1": [ { value: "item1", label: "Item 1" }, { value: "item2", label: "Item 2" } ], "Group 2": [ { value: "item3", label: "Item 3" } ] } ``` ### Field Types **`text`** - Single-line text input * Supports: `required`, `minLength`, `maxLength`, `pattern` validation * Best for: Names, titles, short descriptions **`textarea`** - Multi-line text input * Supports: `required`, `minLength`, `maxLength` validation * Best for: Comments, descriptions, long-form text **`email`** - Email address input with built-in format validation * Supports: `required`, `pattern` validation * Automatically validates email format **`phone`** - Phone number input * Must follow format: `+[country code][number]` (e.g., +1234567890) * Supports: `required`, `pattern` validation * Built-in international format validation **`number`** - Numeric input * Supports: `required`, `min`, `max` validation * Only accepts numeric values * Best for: Ages, quantities, prices **`select`** - Single selection dropdown * Requires: `options` array with `{ value, label }` objects * Supports: `required` validation * Best for: Categories, single choice selections **`multiselect`** - Multiple selection dropdown * Requires: `options` array with `{ value, label }` objects * Supports: `required` validation * Best for: Tags, multiple choice selections **`groupselect`** - Grouped single selection dropdown * Requires: `options` object with group names as keys * Each group contains array of `{ value, label }` objects * Supports: `required` validation * Best for: Categorized options (e.g., locations by region) **`groupmultiselect`** - Grouped multiple selection dropdown * Requires: `options` object with group names as keys * Each group contains array of `{ value, label }` objects * Supports: `required` validation * Best for: Multiple selections from categorized options **`image`** - Image file upload with drag & drop * Accepts: JPEG, JPG, PNG, GIF, WebP formats * Maximum size: 2MB per file * Supports: `required` validation * Features: Drag & drop, preview, format validation ### Validation Rules Each validation rule is defined as an object with `value` and `message` properties: **`required`** - Makes field mandatory ```javascript theme={null} validation: { required: { value: true, message: "This field is required" } } ``` **`pattern`** - Regex pattern validation ```javascript theme={null} validation: { pattern: { value: "^[A-Za-z]+$", // Only letters message: "Only letters are allowed" } } ``` **`minLength`** - Minimum character count ```javascript theme={null} validation: { minLength: { value: 3, message: "Must be at least 3 characters" } } ``` **`maxLength`** - Maximum character count ```javascript theme={null} validation: { maxLength: { value: 100, message: "Cannot exceed 100 characters" } } ``` **`min`** - Minimum numeric value ```javascript theme={null} validation: { min: { value: 18, message: "Must be at least 18" } } ``` **`max`** - Maximum numeric value ```javascript theme={null} validation: { max: { value: 120, message: "Cannot exceed 120" } } ``` **`defaultErrorMessage`** - Fallback error message ```javascript theme={null} validation: { min: { value: 18 }, // No custom message defaultErrorMessage: "Please enter a valid value" } ``` This message is shown when validation fails but no specific message is provided for the failed rule. ## Advanced Configuration ### Webhooks Integration Configure webhooks to receive real-time notifications when users submit your custom forms: * In the action settings, click on the **Webhooks** tab. * Write the webhook URL and click on the **Create Webhook** button. Webhook configuration interface Webhook configuration interface Set up your webhook endpoint to receive form submission data: ```javascript webhook-handler.js theme={null} // Example webhook handler (Node.js/Express) app.post('/form-webhook', (req, res) => { const { formData, userId, timestamp } = req.body; // Process the form submission console.log('Form submitted:', formData); // Respond with success res.status(200).json({ success: true }); }); ``` ## Troubleshooting **Possible causes:** * Function name mismatch between dashboard and code * Chatbase script not loaded before `registerFormSchema` call * JavaScript errors preventing form registration **Solutions:** 1. Verify the function name matches exactly (case-sensitive) 2. Ensure proper script loading order 3. Check browser console for JavaScript errors **Possible causes:** * Incorrect validation rule syntax * Missing required properties in validation objects **Solutions:** 1. Ensure validation rules have both `value` and `message` properties 2. Check field type compatibility with validation rules 3. Verify regex patterns are valid JavaScript regex strings **Possible causes:** * Incorrect options format * Missing `options` property **Solutions:** 1. Ensure options follow the correct format for your field type 2. Verify all option objects have both `value` and `label` properties 3. For grouped selections, check the nested object structure **Best Practices**: * Test your forms thoroughly in your actual website environment * Keep form schemas simple and focused on specific use cases * Use clear, descriptive field names and validation messages * Implement proper error handling for form submissions ## Next Steps Programmatically control the chat interface Learn to listen for and respond to chat events in real-time Create dynamic, personalized initial messages for users Display floating messages over the chat bubble # Chat bubble Control Source: https://chatbase.co/docs/developer-guides/control-widget Programmatically control your chat bubble with JavaScript methods to open, close, reset conversations, and override configured options at runtime. The Chatbase embed script exposes the `window.chatbase` object with methods to control your chat bubble programmatically. ## Methods ### open(options?) Opens the chat bubble. Optionally sends a message when it opens. ```javascript theme={null} window.chatbase.open(); ``` **Parameters** A message to send automatically when the chat bubble opens. When `true`, the sent message is hidden and the chat bubble stays closed until the bot **starts replying** — so it looks like the assistant reached out proactively. Only applies when `message` is set. ```javascript Open and send a visible message theme={null} window.chatbase.open({ message: "What is Chatbase's pricing?" }); ``` ```javascript Send a hidden message (proactive) theme={null} window.chatbase.open({ message: "What is Chatbase's pricing?", hideMessage: true, }); ``` ### close() Closes the chat bubble. ```javascript theme={null} window.chatbase.close(); ``` ### resetChat() Clears the current conversation and starts a new session. ```javascript theme={null} window.chatbase.resetChat(); ``` Your chat bubble configuration and [custom initial messages](/docs/developer-guides/custom-initial-messages) are preserved after reset. ## Runtime Options Override a bounded set of your agent's configured options for the current page load — the chat bubble's display name, footer, message placeholder, dismissible notice, initial messages, and suggested messages. Overrides are never persisted: reloading the page or calling `resetOptions` returns the chat bubble to its dashboard configuration. ### setOptions(options) ```javascript theme={null} window.chatbase.setOptions({ displayName: "Acme Support", footer: "Powered by Acme", messagePlaceholder: "Ask us anything…", dismissibleNotice: "Chats may be recorded for quality purposes.", initialMessages: ["Hi!", "How can I help you today?"], suggestedMessages: ["Track my order", "Talk to a human"], }); ``` All keys are optional — pass only the ones you want to override. **Parameters** Overrides the chat bubble header title. Also updates the launcher button's accessibility labels so assistive technology announces the same name. Maximum 100 characters. Overrides the footer text. Maximum 1000 characters. Overrides the message input placeholder. Maximum 100 characters. Overrides the dismissible notice shown above the message input. Maximum 500 characters. Overrides the agent's initial messages. Array of non-empty strings, limited to 1000 characters in total. Applies immediately if the conversation hasn't started; otherwise it takes effect on the next fresh conversation (for example after `resetChat()`). Writes the same setting as [`setInitialMessages`](/docs/developer-guides/custom-initial-messages) — the last call wins, whichever method made it. Replaces the dashboard-configured suggested message chips. Up to 4 entries, each a non-empty string of at most 200 characters. Suggestions the AI generates during the conversation still take precedence over this override. Invalid keys or values are skipped with a `console.error`; valid keys in the same call still apply. `setOptions` never truncates — an oversize value is rejected. (The legacy `setInitialMessages` method instead truncates to 1000 characters, preserving its documented behavior.) ### resetOptions(fields?) Clears runtime overrides, returning those options to the agent's dashboard configuration. ```javascript theme={null} window.chatbase.resetOptions(); // clear every override window.chatbase.resetOptions({ displayName: true, footer: true }); // clear specific keys ``` **Parameters** An object mapping option keys to `true` for each override to clear. When omitted, every runtime override is cleared. ### Per-field methods Each option also has a dedicated setter that behaves exactly like `setOptions` with that single key: ```javascript theme={null} window.chatbase.setDisplayName("Acme Support"); window.chatbase.setFooterText("Powered by Acme"); window.chatbase.setMessagePlaceholder("Ask us anything…"); window.chatbase.setDismissibleNotice("Chats may be recorded."); window.chatbase.setSuggestedMessages(["Track my order", "Talk to a human"]); window.chatbase.setInitialMessages(["Hi!"]); // legacy alias — see Custom Initial Messages ``` ## Examples Combine these methods with [event listeners](/docs/developer-guides/chatbot-event-listeners) to build powerful, context-aware chat experiences. ### Custom Buttons Trigger chat bubble actions from your own UI elements: ```javascript theme={null} document.getElementById("help-button").addEventListener("click", () => { window.chatbase.open(); }); document.getElementById("close-button").addEventListener("click", () => { window.chatbase.close(); }); document.getElementById("new-chat-button").addEventListener("click", () => { window.chatbase.resetChat(); }); ``` ### Answer FAQ Questions Turn static FAQ entries into live answers — open the chat bubble with the question pre-filled: ```javascript theme={null} document.querySelectorAll(".faq-question").forEach((item) => { item.addEventListener("click", () => { window.chatbase.open({ message: item.dataset.question }); }); }); ``` Chat Bubble Open Proactive ### Proactive Message on Intent Reach out automatically when a visitor lingers on a high-intent page. The message is hidden until the bot replies, so it feels like the assistant started the conversation. ```javascript theme={null} // On the /pricing page: if the user hasn't acted after 10 minutes, reach out setTimeout(() => { window.chatbase.open({ message: "Do you have any questions about our pricing?", hideMessage: true, }); }, 10 * 60 * 1000); ``` ### Time-Based Reset The 24-hour example uses `localStorage` to persist the last message time across page reloads. ```javascript Reset After 5 Minutes of Inactivity theme={null} let inactivityTimer; function startInactivityTimer() { clearTimeout(inactivityTimer); inactivityTimer = setTimeout( () => window.chatbase.resetChat(), 5 * 60 * 1000 ); } window.chatbase.addEventListener("user-message", startInactivityTimer); window.chatbase.addEventListener("assistant-message", startInactivityTimer); ``` ```javascript Reset 24 Hours After Last Message theme={null} const STORAGE_KEY = "chatbase_last_message"; const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000; function updateLastMessageTime() { localStorage.setItem(STORAGE_KEY, Date.now().toString()); } // Check on page load const lastMessage = localStorage.getItem(STORAGE_KEY); if (lastMessage && Date.now() - parseInt(lastMessage) > TWENTY_FOUR_HOURS) { window.chatbase.resetChat(); updateLastMessageTime(); // Reset the timer after clearing } // Update timestamp on every message window.chatbase.addEventListener("user-message", updateLastMessageTime); window.chatbase.addEventListener("assistant-message", updateLastMessageTime); ``` ### Reset After Tool Completion ```javascript After Transaction theme={null} let resetTimer; window.chatbase.addEventListener("tool-result", (event) => { const resetTools = ["complete-booking", "process-payment", "create-ticket"]; if (resetTools.includes(event.data.name) && event.data.result?.success) { clearTimeout(resetTimer); // 2 second delay before resetting the chat resetTimer = setTimeout(() => window.chatbase.resetChat(), 2000); } }); ``` ```javascript After Support Ticket theme={null} let resetTimer; window.chatbase.addEventListener("tool-result", (event) => { if (event.data.name === "create-ticket") { clearTimeout(resetTimer); // 2 second delay before resetting the chat resetTimer = setTimeout(() => window.chatbase.resetChat(), 2000); } }); ``` ### Reset on Keywords Always add a delay before resetting so users can read the final AI response. ```javascript User Says Goodbye theme={null} let resetTimer; window.chatbase.addEventListener("user-message", (event) => { const goodbyePhrases = ["goodbye", "bye", "that's all", "start over"]; const message = event.data.content.toLowerCase(); // Use word boundaries to avoid matching substrings (e.g., "nearby" containing "bye") const matchesPhrase = goodbyePhrases.some((phrase) => { const regex = new RegExp(`\\b${phrase}\\b`); return regex.test(message); }); if (matchesPhrase) { clearTimeout(resetTimer); // 2 second delay before resetting the chat resetTimer = setTimeout(() => window.chatbase.resetChat(), 2000); } }); ``` ```javascript AI Confirms Completion theme={null} let resetTimer; window.chatbase.addEventListener("assistant-message", (event) => { const donePhrases = ["order confirmed", "booking complete", "ticket created"]; const message = event.data.content.toLowerCase(); const matchesPhrase = donePhrases.some((phrase) => { const regex = new RegExp(`\\b${phrase}\\b`); return regex.test(message); }); if (matchesPhrase) { clearTimeout(resetTimer); // 2 second delay before resetting the chat resetTimer = setTimeout(() => window.chatbase.resetChat(), 2000); } }); ``` ### Reset on Navigation Start fresh conversations when users enter specific sections of your site. ```javascript Single-Page App theme={null} const resetOnRoutes = ["/checkout", "/new-project", "/support"]; function checkRouteAndReset() { if (resetOnRoutes.includes(window.location.pathname)) { window.chatbase.resetChat(); } } // Call this from your router's navigation callback // e.g., router.afterEach(checkRouteAndReset) checkRouteAndReset(); ``` ```javascript Multi-Page App theme={null} // Add this script to pages where you want fresh conversations window.chatbase.resetChat(); ``` ## Best Practices * **Debounce rapid calls** — Avoid calling methods in quick succession * **Add delays before reset** — Give users time to read the final response * **Respect dismissals** — Don't immediately reopen a closed chat bubble * **Use contextual triggers** — Open chat at moments when help is most relevant ## Next Steps Learn to listen for and respond to chat events in real-time Create dynamic, personalized initial messages for users Display floating messages over the chat bubble # Custom Domains Source: https://chatbase.co/docs/developer-guides/custom-domains On this page, you can configure your AI agent to integrate with your own domain. This allows you to hide the Chatbase branding, making it appear as if the AI agent is built entirely by your workspace rather than using a third-party tool. Chatbase Embed Code Example To set this up, enter the desired URL for your bot, and then configure a DNS record with your provider. Common DNS providers include Cloudflare, OpenDNS, and Quad9. You will need to add a CNAME record with the specific values provided on the custom domain page in your dashboard. Please note that it may take up to 6 hours for the records to fully propagate and update. ### What "Custom Domain" Means on Chatbase? When we say you can add a custom domain, it means you can host your AI agent on a subdomain that belongs to your company or brand, instead of Chatbase's default domain. For example, instead of your AI agent appearing on a URL like chatbase.co/yourbot, it could be hosted on yourbot.yourdomain.com. This feature enhances your brand's professionalism and trustworthiness by keeping everything under your domain. By adding a custom subdomain: 1. Your AI agent becomes an integrated part of your website. 2. Visitors' traffic requests won't be redirected to an external Chatbase URL. 3. It improves the user experience with consistent branding across your website and AI agent interactions. ### Step-by-Step Guide to Adding a Custom Subdomain to Your AI agent on Chatbase 1. **Log Into Your Chatbase Account**\ First, sign in to your Chatbase account using your credentials. If you don't have an account yet, you can easily create one by following the sign-up process on the website. Chatbase Embed Code Example 2. **Navigate to Your AI agent Settings**\ Once you're logged in, locate the AI agent you want to associate with a custom subdomain. This could be a newly created bot or an existing one. Open the agent, then click **Settings** in the left sidebar. Chatbase Embed Code Example 3. **Locate the Domain Customization Option**\ In the Settings tab bar, select **Custom domains**. Chatbase Embed Code Example 4. **Enter Your Custom Subdomain**\ This is where you type in the subdomain (e.g., support.yourbusiness.com) that you own or have control over. Chatbase currently supports subdomains only, so you'll need to ensure you're using a subdomain on your website. Adding a custom subdomain gives your AI agent a professional look by branding it with your website's URL instead of Chatbase's default domain. 5. **Configure DNS Settings**\ You might need to configure additional DNS settings like CNAME records. This step will link the custom subdomain to your AI agent, ensuring it works correctly when users visit the URL. Chatbase will provide specific DNS instructions for setting this up, which usually includes pointing the subdomain to Chatbase's servers. 6. **Save and Test Your AI agent**\ Once you've successfully configured the domain settings and DNS records, save your changes. It may take some time for the changes to propagate across the web (usually within a few minutes to 24 hours). Test the custom subdomain by entering it into a browser to ensure your AI agent loads correctly. # Custom Initial Messages Source: https://chatbase.co/docs/developer-guides/custom-initial-messages Create personalized welcome experiences by setting custom initial messages that greet users when your AI Agent first loads, with support for dynamic content and user personalization. ### Prerequisites A website with the Chatbase embed script already installed and working. New to Chatbase? Check out [Your First Agent](/docs/user-guides/quick-start/your-first-agent) to get started with the embed script first. ## Setting Up Custom Initial Messages Configure initial messages using the JavaScript embed script to create personalized welcome experiences: ### Personalized Messages Add user-specific content to your greetings by combining user identification with custom messages for personalized experiences: ```javascript theme={null} // Get user information (from your auth system) const user = getCurrentUser(); // Set personalized messages window.chatbase.setInitialMessages([ `Hi ${user.name}!`, "I remember our last conversation about your project.", "How can I help you today?" ]); ``` Personalized messages ### Dynamic Content Examples Create context-aware messages based on user behavior or current page: ```javascript theme={null} // Based on current page const currentPage = window.location.pathname; let messages = ["Hello! I'm here to help."]; if (currentPage.includes('/pricing')) { messages = [ "Looking at our pricing?", "I can help you choose the right plan for your needs." ]; } else if (currentPage.includes('/support')) { messages = [ "Need technical support?", "I'm here to help resolve any issues you're experiencing." ]; } window.chatbase.setInitialMessages(messages); ``` ## Method Reference Initial messages can be set two ways — through the [runtime options API](/docs/developer-guides/control-widget#runtime-options) or the dedicated `setInitialMessages` method. Both write the same setting, and the last call wins whichever method made it. ### setOptions() The runtime options API accepts initial messages alongside the widget's other overridable options: ```javascript theme={null} window.chatbase.setOptions({ initialMessages: ["Hi!", "How can I help you today?"], }); ``` Array of non-empty strings containing the messages to display in sequence **Requirements:** * Must be an array of non-empty strings * Total character count limited to 1000 characters — oversize input is rejected with a `console.error`, never truncated ### setInitialMessages() Set the messages displayed when the agent first loads: Array containing the messages to display in sequence **Requirements:** * Must be an array of strings * Total character count limited to 1000 characters — input over the limit is truncated ### Clearing custom initial messages To remove your custom initial messages and return to the agent's configured ones, clear the override through [`resetOptions`](/docs/developer-guides/control-widget#resetoptions-fields): ```javascript theme={null} window.chatbase.resetOptions({ initialMessages: true }); ``` Custom initial messages are shown only once per session. If a user refreshes the page or navigates to another page during the same session, the messages won't appear again to avoid creating an intrusive experience. ## Best Practices **Write effective initial messages** * **Keep messages concise**: Use short, clear messages that guide users effectively * **Avoid lengthy paragraphs**: Break long content into multiple shorter messages * **Be specific**: Mention what you can help with rather than generic greetings * **Use action-oriented language**: Encourage users to engage with specific questions **Use user data thoughtfully** * **Respect privacy**: Only use information users have explicitly shared * **Add value**: Personalization should enhance the experience, not just show off data * **Handle missing data**: Always have fallback messages for when user data isn't available * **Test thoroughly**: Verify personalized messages work with different user states **Optimize when messages are set** * **Set early**: Configure initial messages as soon as possible in your application lifecycle * **Wait for embed script**: Ensure Chatbase script has loaded before calling `setInitialMessages` * **Consider async operations**: If fetching user data, handle loading states gracefully * **Cache when appropriate**: Store computed messages to avoid recalculating on every visit # Floating Initial Messages Source: https://chatbase.co/docs/developer-guides/floating-initial-messages Create eye-catching floating messages that appear above your chat widget to welcome visitors and boost engagement ### Prerequisites A website with the Chatbase embed script already installed and working. New to Chatbase? Check out [Your First Agent](/docs/user-guides/quick-start/your-first-agent) to get started with the embed script first. ## Setting Up Floating Initial Messages This feature takes the initial messages you've configured in your Chatbase dashboard and displays them in an attention-grabbing floating format to welcome visitors and encourage interaction. ### Configuration Set up floating initial messages using the JavaScript configuration object: ```javascript theme={null} window.chatbaseConfig = { showFloatingInitialMessages: true, // Enable floating messages floatingInitialMessagesDelay: 2, // Show after 2 seconds floatingMessagesOncePerSession: true // Show once per session (default) or on every page load }; ``` ## Configuration Reference ### chatbaseConfig Properties Configure floating initial messages using these parameters in your `chatbaseConfig` object: Controls whether initial messages appear in a floating window above the chat widget **Requirements:** * Must be set before the Chatbase script loads * Displays the initial messages configured in your Chatbase dashboard as floating bubbles Delay in seconds before displaying floating initial messages **Requirements:** * Minimum value: 0 (immediate display) * Maximum recommended: 10 seconds Controls whether floating messages appear once per session or on every page load **Behavior:** * `true` (default): Messages appear only once per session. They won't reappear if users refresh the page or navigate to other pages during the same session. * `false`: Messages appear on every page load/refresh. By default, floating initial messages are displayed only once per user session to maintain a non-intrusive experience. Set `floatingMessagesOncePerSession` to `false` if you want messages to appear on every page load. ## Best Practices **Optimize when floating messages appear** * **User attention span**: Show messages within 2-4 seconds for best engagement * **Page context**: Use longer delays on content-heavy pages, shorter on simple pages * **Mobile considerations**: Account for slower loading on mobile devices **Create effective floating experiences** * **Keep messages concise**: Floating messages should be brief and attention-grabbing * **Maintain brand voice**: Ensure floating messages match your overall messaging tone * **Test across devices**: Verify messages display well on different screen sizes # Help Page Proxy Source: https://chatbase.co/docs/developer-guides/help-page-proxy This guide explains how to use rewrites (also known as proxies) to display your Chatbase help page on your own domain. This provides a seamless and professional experience for your users, as they can access help content without leaving your site. The goal is to make your Chatbase help page, normally available at `https://chatbase.co/{agentId}/help`, appear on a path like `https://your-domain.com/help`. This Help Page proxy method is a free way to show your Help Page on your own domain. It's separate from the Custom Domain add-on, which white-labels the embed script and iframe. If you already have the add-on, your custom domain applies to your Help Page automatically and you can skip these steps. ## The Core Concept: Rewrites A rewrite acts as a proxy. When a user visits the `source` path on your domain, your server fetches the content from the `destination` URL and serves it to the user. Crucially, the URL in the user's browser bar does not change. * **Source**: The path on your website that you want to use. * **Destination**: The full URL of your Chatbase help center. Remember to replace `{agentId}` with your actual Chatbase Agent ID. You can find this ID under the agent’s **Settings → General → Agent details**. **Required Routes** For the help center to function correctly, you must proxy these paths: * `/help` and `/help/*` - The help center pages * `/__cb/*` - Static assets (JavaScript, CSS, images) * `/api/chat/{agentId}/*` - Chat API endpoints for features like lead submission Replace `{agentId}` with your actual Agent ID in all rules. ## Implementation Examples Choose the tab below that corresponds to your website's framework or hosting platform. For projects using the Next.js framework, you can configure rewrites in your `next.config.js` file. This is the recommended method for Next.js applications. 1. Open or create the `next.config.js` file at the root of your project. 2. Add the `rewrites` function to the configuration object. ```javascript theme={null} // next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { async rewrites() { return [ { source: "/help", destination: "https://chatbase.co/{agentId}/help", }, // This rule is needed to correctly proxy sub-pages of your help center. { source: "/help/:path*", destination: "https://chatbase.co/{agentId}/help/:path*", }, // Proxy static assets (JavaScript, CSS, images) { source: "/__cb/:path*", destination: "https://chatbase.co/__cb/:path*", }, // Proxy chat API endpoints for your agent { source: "/api/chat/{agentId}/:path*", destination: "https://chatbase.co/api/chat/{agentId}/:path*", }, ]; }, }; module.exports = nextConfig; ``` After adding this configuration, restart your Next.js development server to apply the changes. If you host your site on Vercel (regardless of the framework), you can use a `vercel.json` file to configure rewrites at the platform level. 1. Create a `vercel.json` file at the root of your project if it doesn't already exist. 2. Add a `rewrites` array to the file. ```json theme={null} // vercel.json { "rewrites": [ { "source": "/help", "destination": "https://chatbase.co/{agentId}/help" }, { "source": "/help/:path*", "destination": "https://chatbase.co/{agentId}/help/:path*" }, { "source": "/__cb/:path*", "destination": "https://chatbase.co/__cb/:path*" }, { "source": "/api/chat/{agentId}/:path*", "destination": "https://chatbase.co/api/chat/{agentId}/:path*" } ] } ``` Vercel will automatically apply these rules on your next deployment. For sites hosted on Netlify, you can configure rewrites in your `netlify.toml` file. 1. Create or open the `netlify.toml` file at the root of your project. 2. Add a `[[rewrites]]` rule. ```toml theme={null} # netlify.toml [[rewrites]] from = "/help/*" to = "https://chatbase.co/{agentId}/help/:splat" status = 200 # A 200 status indicates a rewrite, not a redirect [[rewrites]] from = "/help" to = "https://chatbase.co/{agentId}/help" status = 200 # Proxy static assets (JavaScript, CSS, images) [[rewrites]] from = "/__cb/*" to = "https://chatbase.co/__cb/:splat" status = 200 # Proxy chat API endpoints for your agent [[rewrites]] from = "/api/chat/{agentId}/*" to = "https://chatbase.co/api/chat/{agentId}/:splat" status = 200 ``` Commit and push this file to your repository, and Netlify will apply the rule on the next build. If you are running a custom Node.js server with Express, you can use the `http-proxy-middleware` package to create a rewrite. 1. First, install the necessary packages: ```bash theme={null} npm install express http-proxy-middleware ``` 2. Then, set up the proxy in your Express application. ```javascript theme={null} // server.js const express = require("express"); const { createProxyMiddleware } = require("http-proxy-middleware"); const app = express(); const PORT = process.env.PORT || 3000; // The agentId should be stored securely, e.g., in environment variables const AGENT_ID = process.env.CHATBASE_AGENT_ID || "{agentId}"; // Proxy for help center pages const helpProxy = createProxyMiddleware({ target: `https://chatbase.co`, changeOrigin: true, pathRewrite: { [`^/help`]: `/${AGENT_ID}/help`, }, proxyTimeout: 5000, }); // Proxy for static assets (JavaScript, CSS, images) const assetsProxy = createProxyMiddleware({ target: `https://chatbase.co`, changeOrigin: true, proxyTimeout: 5000, }); // Proxy for chat API endpoints (scoped to your agent only) const chatApiProxy = createProxyMiddleware({ target: `https://chatbase.co`, changeOrigin: true, proxyTimeout: 5000, }); // Apply proxies to routes app.use("/help", helpProxy); app.use("/__cb", assetsProxy); app.use(`/api/chat/${AGENT_ID}`, chatApiProxy); // Your other routes... app.get("/", (req, res) => { res.send("Your ACME Inc. Homepage"); }); app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); }); ``` **Sitemaps** Your proxied help center content will not be automatically included in your primary domain's sitemap. You may need to add these URLs manually if SEO for your help content is a priority. # HIPAA Conversation Webhook Source: https://chatbase.co/docs/developer-guides/hipaa-webhooks Receive HIPAA conversations at your own endpoint before Chatbase deletes them under the retention window. On a HIPAA-compliant workspace, conversations are automatically deleted once they go idle for more than 24 hours or reach 7 days old. The HIPAA conversation webhook lets you keep that data: Chatbase sends each conversation to an endpoint you control, as JSON, just before it is deleted. You configure one webhook per workspace, covering every AI agent in it. The webhook delivery is the only copy of the conversation you will get. After deletion, Chatbase retains only the **redacted** version, so the unredacted content of a conversation that was never delivered cannot be recovered or resent. Verify your endpoint before conversations start flowing, and keep your signing secret in sync. For the retention rules themselves, see [Conversation auto-end rules](/docs/user-guides/workspace/hipaa-compliance#conversation-auto-end-rules). ## Requirements * A **HIPAA-compliant workspace** — Enterprise plan with a signed BAA. See [HIPAA compliance](/docs/user-guides/workspace/hipaa-compliance). * An **HTTPS** endpoint that accepts `POST` requests. Plain `http://` URLs are rejected. * Permission to edit workspace settings. Workspace **Owners** have this by default; it can be granted to other members through a custom role. ## Configure your endpoint Go to **Settings → HIPAA** in your dashboard and find the **Webhook configuration** card. The HIPAA settings page only appears on workspaces where HIPAA compliance is enabled. Enter your endpoint in the **Webhook endpoint** field and click **Save**. **Enter the final URL — redirects are not followed.** PHI must only ever reach the endpoint you verified, and a redirect to `http://` would put it on the wire in cleartext. Redirects are almost always accidental. The usual causes: * a trailing slash your framework normalises (Next.js, Django's `APPEND_SLASH`, Rails) * `example.com` → `www.example.com` canonicalisation * a path that moved, leaving a `301` behind * platform-level rules — Vercel or Netlify redirects, Cloudflare Page Rules Verification fails if either probe is redirected, and a delivery that is redirected is retried and eventually abandoned, the same as any other failure. Saving a URL for the first time generates a **signing secret** — a 64-character hex string — and shows it in a one-time modal. The secret is shown **once**. Copy it into your secrets manager before closing the modal. Afterwards the dashboard displays only the last four characters, and the only way to get a usable value again is to regenerate it. Click **Verify endpoint**. Your endpoint must pass this check before any conversation is delivered — see [Endpoint verification](#endpoint-verification) below. **Verify endpoint** stays disabled until there is a saved URL and a signing secret, and while the URL field has unsaved edits. Save your changes first, then verify. ## Endpoint verification Verification proves your endpoint is safe to receive PHI. Clicking **Verify endpoint** sends **two** `POST` requests in sequence to the same URL: | Probe | Signed with | Your endpoint must | | :---- | :----------------------- | :----------------- | | **1** | your real signing secret | return **2xx** | | **2** | a throwaway key | return **non-2xx** | Both must hold for verification to pass. The second probe is the point of the design. An endpoint that returns `200` to anything would look perfectly healthy while accepting forged patient data from anyone who guessed its URL. Requiring a rejection proves your receiver actually checks the signature — and it only asks for behaviour you need in production anyway, so there is no verification-only code to write and later remove. Both probes carry `"test": true`, which real deliveries never do. Acknowledge them and do not store them. They also deliberately use **different** `deliveryId` values, so a correctly idempotent receiver does not discard the second one as a duplicate. If probe 1 fails, probe 2 is never sent — so an endpoint that rejects everything shows only a single request in its own logs. ### Verification failure reasons | Reason | What it means | | :--------------------------- | :------------------------------------------------------------------------------ | | `rejected_signed_request` | The correctly signed probe got a non-2xx response. | | `accepted_invalid_signature` | The forged probe got a 2xx response — your endpoint is not checking signatures. | | `redirect` | Either probe was redirected. Configure the final URL directly. | | `timeout` | No response within 10 seconds. | | `dns` | The hostname could not be resolved. | | `refused` | The connection was refused. | Until verification passes, the card shows **Endpoint not verified** and nothing is delivered. Conversations that reach their retention threshold in the meantime are held and retried — but they spend [retry attempts](#retries) while they wait, so verify early. ## The delivery request Each conversation is sent as its own `POST` request with a JSON body. ### Headers | Header | Value | | :----------------------- | :-------------------------------------------------------------------------------------------------------- | | `Content-Type` | `application/json` | | `X-Chatbase-Signature` | `v1=` — HMAC-SHA256 of the payload. See [Verify the signature](#verify-the-signature). | | `X-Chatbase-Timestamp` | Unix timestamp in **seconds**. Part of the signed input. | | `X-Chatbase-Delivery-Id` | UUID for this delivery attempt. Also present in the body as `deliveryId`. Use it as your idempotency key. | ### Payload Every key in the payload is **camelCase**. ```json theme={null} { "deliveryId": "b7c1e0a4-3f52-4d81-9a6c-2e4f8d0b1c73", "event": "conversation.deleted", "deletedAt": "2026-08-17T03:00:00.000Z", "deletionReason": "idle_24h", "conversation": { "id": "d41f8a92-6b3c-4e17-8f5a-9c0d2b7e4a16", "createdAt": "2026-08-16T14:02:09.000Z", "chatbotId": "c8e2f1b6-5a94-4d03-b7e8-1f6a3c9d0e52", "leads": null, "source": "Widget or Iframe", "minScore": 0, "country": "US", "messages": [], "accountId": "a3d7c5e1-8b62-4f09-9c4d-7e2b1a8f6d30", "lastMessageAt": "2026-08-16T14:02:15.000Z", "sentiment": "neutral", "anonymousId": null, "userId": "patient-4821", "title": "Rescheduling an appointment" } } ``` ### Envelope fields | Field | Type | Description | | :--------------- | :----- | :--------------------------------------------------------------------------------------------------------------------------- | | `deliveryId` | string | UUID for this delivery attempt. Matches the `X-Chatbase-Delivery-Id` header. Reused across retries of the same conversation. | | `event` | string | Always `conversation.deleted` today. Switch on it anyway so future event types do not break your receiver. | | `deletedAt` | string | ISO 8601 timestamp of the deletion. | | `deletionReason` | string | `idle_24h` — idle for more than 24 hours, or `max_age_7d` — older than 7 days. | | `conversation` | object | The conversation itself. See below. | Field **names** are camelCase, but field **values** are unchanged — `deletionReason` is still `idle_24h` or `max_age_7d`, and `event` is still `conversation.deleted`. Match on the values exactly as shown. ### Conversation fields | Field | Type | Description | | :-------------- | :------------- | :---------------------------------------------------------------------------------------------- | | `id` | string | Conversation ID. Appears in at most one delivery. | | `createdAt` | string | When the conversation started. | | `chatbotId` | string | ID of the AI agent that handled the conversation. | | `accountId` | string | ID of your workspace. | | `title` | string \| null | Generated conversation title. | | `source` | string | Channel the conversation came from. See [Source values](#source-values). | | `country` | string \| null | Country code, when available. | | `minScore` | number | Lowest confidence score across the agent's answers in this conversation. | | `sentiment` | string \| null | `positive`, `negative`, `neutral`, or `unspecified`, when sentiment analysis produced a result. | | `userId` | string \| null | Your own user identifier, if the end user was identified. | | `anonymousId` | string \| null | Anonymous visitor identifier, when the end user was not identified. | | `leads` | object \| null | Lead and form data collected during the conversation, if any. | | `lastMessageAt` | string | Timestamp of the most recent message. | | `messages` | array | The full message history. See [Message shape](#message-shape). | Route on `conversation.chatbotId` if several of your agents share the same webhook — there is no separate agent object in the envelope. ### Source values `source` records the channel the conversation arrived through. On a HIPAA-compliant workspace you can expect: | Value | Channel | | :------------------------------------------------------- | :----------------------------------- | | `Widget or Iframe` | Chat bubble embedded on your site | | `Iframe` | Agent embedded directly as an iframe | | `Agent page` | Hosted help page | | `API` | Chat API | | `Phone` | Voice call | | `Android SDK` / `iOS SDK` | Mobile SDKs | | `Zendesk` / `Zendesk Messaging` / `Salesforce` / `Slack` | Connected integrations | | `Email` | Email channel | | `Unspecified` | Channel could not be determined | Treat the list as open-ended: new channels add new values, so route with a fallback rather than an exhaustive match. ### Message shape `messages` holds the conversation history, oldest first. Message keys are camelCase, like the rest of the payload. The one exception anywhere in a delivery is an assistant message's `revised_answer`, which is `snake_case`. #### Message fields These can appear on a message of any role. Every field except `role` is optional, so check for presence rather than assuming a fixed shape. | Field | Type | Description | | :----------- | :-------------- | :------------------------------------------------------------------------------------------------------ | | `id` | string | Message identifier. | | `role` | string | `user`, `assistant`, or `tool`. | | `createdAt` | string | When the message was created. | | `type` | string | On assistant messages, `text` or `tool-call`. Defaults to `text` and may be absent. | | `content` | string \| array | Message text, or an array of parts. See [Content parts](#content-parts). | | `actionType` | string | On `tool` messages, names the action that produced the result. Open-ended — new actions add new values. | | `feedback` | string | `up` or `down`, when the end user rated the message. | **Assistant messages** may also carry: | Field | Type | Description | | :--------------- | :------ | :------------------------------------------------------------------------ | | `score` | number | Confidence score for the answer. | | `source` | string | Where the answer came from: `llm`, `qna`, `outbound`, or `story_context`. | | `matchedSources` | array | Knowledge-base entries used, each `{ type, name }`. | | `procedureRun` | object | `{ toolCallId, procedure }` when the message was part of a procedure. | | `revised_answer` | string | Revised answer text, when one was supplied. | | `thumbsDown` | boolean | Whether the answer was marked unhelpful. | | `imageUrl` | string | Image returned with the answer. | **User messages** may also carry: | Field | Type | Description | | :---------------- | :----- | :------------------------------------------------------------ | | `name` | string | Display name of the end user. | | `userMessageType` | string | `audio` when the message came from speech. | | `attachments` | array | Files the end user uploaded. See [Attachments](#attachments). | `source` means two different things at two different levels. `conversation.source` is the **channel** (`Widget or Iframe`, `API`, …); a message's `source` is where that **answer** came from (`llm`, `qna`, …). They share a name but not a value set. #### Content parts `content` is a string on plain text messages and an **array** on tool-call and tool-result messages. Calling something like `String(content)` breaks on any conversation where the agent used an action. | Field | Type | Description | | :----------- | :----- | :---------------------------------------------------------------------------------- | | `type` | string | `tool-call` or `tool-result`. | | `toolName` | string | The action invoked. | | `toolCallId` | string | Pairs a `tool-call` with its matching `tool-result`. | | `input` | any | On `tool-call` parts — the arguments the agent passed. Shape depends on the action. | | `output` | any | On `tool-result` parts — what the action returned. Shape depends on the action. | `input` and `output` are action-specific and, for custom actions and forms, contain whatever your own integration returned. Treat them as opaque JSON unless you know the action. #### Attachments Files the end user uploaded during the conversation. Each entry carries the file's metadata and, when a link could be issued, a URL to download the file itself. | Field | Type | Description | | :----------------- | :----- | :------------------------------------------------- | | `originalFileName` | string | Name of the file as the end user uploaded it. | | `mediaType` | string | MIME type, e.g. `application/pdf`. | | `fileSize` | number | Size in bytes. | | `summary` | string | Generated description of the file, when available. | | `fileName` | string | Unique stored name for the file. | | `downloadUrl` | string | Signed URL to download the file. | | `expiresAt` | string | When `downloadUrl` stops working. | **Download attachment files before the link expires.** `downloadUrl` is valid for **24 hours** from the moment the delivery is sent, and the file itself is deleted on the same schedule. An expired link cannot be reissued and the file is gone, so fetch and store the bytes as part of processing the delivery rather than later. * Each delivery attempt carries a **freshly signed** URL, so a delivery that only succeeds on a retry still gets a full 24 hours. `expiresAt` therefore differs between attempts of the same delivery — use the value from the attempt you are processing. * `downloadUrl` and `expiresAt` appear **together or not at all**. An attachment that arrives without them is metadata-only; the file is not retrievable, and retrying will not produce a link. * The URL needs no authentication and no Chatbase headers — issue a plain `GET`. * Treat `downloadUrl` as **opaque**: use it exactly as given. Its host and path are not part of this contract, so do not hardcode, rebuild, or parse them. #### Parsing notes * **`createdAt` is historically inconsistent.** Conversations backfilled through the API may use a space instead of `T`, or omit the minutes in the UTC offset. Parse it defensively. * **Ignore fields you do not recognise** rather than treating them as an error, so a future addition does not break your receiver. #### Example ```json theme={null} "messages": [ { "id": "msg_7f2a", "role": "user", "content": "I need to reschedule my appointment. Here is my referral.", "createdAt": "2026-08-16T14:02:11.000Z", "attachments": [ { "fileName": "V1StGXR8Z5jdHi6B.pdf", "originalFileName": "referral.pdf", "mediaType": "application/pdf", "fileSize": 20481, "summary": "A referral letter", "downloadUrl": "https:///object/sign/chat-attachments/...?token=...", "expiresAt": "2026-08-18T03:00:12.000Z" } ] }, { "id": "msg_8b3c", "role": "assistant", "type": "tool-call", "createdAt": "2026-08-16T14:02:13.000Z", "content": [ { "type": "tool-call", "toolName": "lookup_appointment", "toolCallId": "tc_4d81", "input": { "patientRef": "ref_88231" } } ] }, { "id": "msg_9c4d", "role": "tool", "actionType": "custom-action", "createdAt": "2026-08-16T14:02:14.000Z", "content": [ { "type": "tool-result", "toolName": "lookup_appointment", "toolCallId": "tc_4d81", "output": { "type": "json", "value": { "status": "success", "data": { "appointmentId": "apt_5512", "currentDate": "2026-08-18T10:00:00.000Z" } } } } ] }, { "id": "msg_a5e2", "role": "assistant", "type": "text", "content": "I can move you to the 20th at 09:00 or 11:30. Which works?", "createdAt": "2026-08-16T14:02:15.000Z", "score": 0.94, "feedback": "up", "source": "llm", "matchedSources": [{ "type": "file", "name": "clinic-hours.pdf" }] } ] ``` ## Verify the signature Every request carries an HMAC-SHA256 signature. Recompute it and reject anything that does not match — otherwise anyone who learns your endpoint URL can post fabricated patient data to it. The signature is computed over the timestamp, a literal `.`, and the raw request body: ``` signature = "v1=" + hex(HMAC_SHA256(secret, timestamp + "." + rawBody)) ``` The `v1=` prefix identifies the scheme, so it can change in future without breaking existing receivers. Compare the full `v1=…` string, prefix included. **Verify against the raw request body.** This is by far the most common integration failure. The signature covers the exact bytes on the wire, so if your framework parses the JSON and you re-serialize it to hash, key order or whitespace shifts and the HMAC never matches. * **Express** — `express.raw({ type: 'application/json' })`, not `express.json()` * **Next.js (App Router)** — `await request.text()`, not `request.json()` * **Next.js (Pages Router)** — `export const config = { api: { bodyParser: false } }` plus `raw-body` * **Flask** — `request.get_data()`, not `request.get_json()` Your receiver should, in this order: 1. **Reject missing headers** with a 4xx, rather than letting them fall through and look like a signature mismatch. 2. **Check the timestamp is recent** — within about 5 minutes. The timestamp is part of the signed input, but only checking it makes replay protection real; without this check, a captured request stays valid forever. 3. **Take the timestamp from the header**, not from your own clock. A locally generated one will never match. 4. **Recompute the HMAC and compare in constant time.** 5. **Only then parse and trust the body.** Never act on payload contents before the signature checks out. ```javascript Node.js (Express) theme={null} const crypto = require('node:crypto') const express = require('express') const app = express() const SECRET = process.env.CHATBASE_HIPAA_WEBHOOK_SECRET const MAX_AGE_SECONDS = 300 app.post( '/webhooks/chatbase-hipaa', // Raw body, NOT express.json() — the signature covers the exact bytes sent. express.raw({type: 'application/json'}), (req, res) => { const timestamp = req.get('X-Chatbase-Timestamp') const signature = req.get('X-Chatbase-Signature') // Reject missing headers explicitly, so they don't look like a bad signature. if (!timestamp || !signature) { return res.status(400).json({error: 'missing_headers'}) } // Replay protection: the timestamp is signed, but only checking it makes // the protection real. const age = Math.abs(Date.now() / 1000 - Number(timestamp)) if (!Number.isFinite(age) || age > MAX_AGE_SECONDS) { return res.status(400).json({error: 'stale_timestamp'}) } // Feed the raw Buffer straight in, so the bytes are never transcoded. const hmac = crypto.createHmac('sha256', SECRET) hmac.update(`${timestamp}.`) hmac.update(req.body) const expected = `v1=${hmac.digest('hex')}` // timingSafeEqual throws when lengths differ, so check length first. const received = Buffer.from(signature, 'utf8') const computed = Buffer.from(expected, 'utf8') if ( received.length !== computed.length || !crypto.timingSafeEqual(received, computed) ) { return res.status(401).json({error: 'invalid_signature'}) } // Verified — now it is safe to parse and trust the payload. const event = JSON.parse(req.body.toString('utf8')) // Verification probes carry test: true. Acknowledge without storing. if (event.test) { return res.status(200).json({ok: true}) } // Acknowledge first, then process. Chatbase times out after 10 seconds. res.status(200).json({ok: true}) queueForProcessing(event) } ) ``` ```typescript Next.js (App Router) theme={null} import crypto from 'node:crypto' const SECRET = process.env.CHATBASE_HIPAA_WEBHOOK_SECRET! const MAX_AGE_SECONDS = 300 export async function POST(request: Request) { // Read the raw body as text, NOT request.json() — the signature covers the // exact bytes sent. const rawBody = await request.text() const timestamp = request.headers.get('x-chatbase-timestamp') const signature = request.headers.get('x-chatbase-signature') // Reject missing headers explicitly, so they don't look like a bad signature. if (!timestamp || !signature) { return Response.json({error: 'missing_headers'}, {status: 400}) } // Replay protection: the timestamp is signed, but only checking it makes // the protection real. const age = Math.abs(Date.now() / 1000 - Number(timestamp)) if (!Number.isFinite(age) || age > MAX_AGE_SECONDS) { return Response.json({error: 'stale_timestamp'}, {status: 400}) } const expected = `v1=${crypto .createHmac('sha256', SECRET) .update(`${timestamp}.${rawBody}`) .digest('hex')}` // timingSafeEqual throws when lengths differ, so check length first. const received = Buffer.from(signature, 'utf8') const computed = Buffer.from(expected, 'utf8') if ( received.length !== computed.length || !crypto.timingSafeEqual(received, computed) ) { return Response.json({error: 'invalid_signature'}, {status: 401}) } // Verified — now it is safe to parse and trust the payload. const event = JSON.parse(rawBody) // Verification probes carry test: true. Acknowledge without storing. if (event.test) { return Response.json({ok: true}) } // Keep this fast — Chatbase times out after 10 seconds. await queueForProcessing(event) return Response.json({ok: true}) } ``` ```python Python (Flask) theme={null} import hashlib import hmac import json import os import time from flask import Flask, jsonify, request app = Flask(__name__) SECRET = os.environ["CHATBASE_HIPAA_WEBHOOK_SECRET"].encode() MAX_AGE_SECONDS = 300 @app.post("/webhooks/chatbase-hipaa") def chatbase_hipaa_webhook(): # Raw bytes, NOT request.get_json() — the signature covers the exact bytes sent. raw_body = request.get_data() timestamp = request.headers.get("X-Chatbase-Timestamp") signature = request.headers.get("X-Chatbase-Signature") # Reject missing headers explicitly, so they don't look like a bad signature. if not timestamp or not signature: return jsonify(error="missing_headers"), 400 # Replay protection: the timestamp is signed, but only checking it makes # the protection real. try: age = abs(time.time() - int(timestamp)) except ValueError: return jsonify(error="stale_timestamp"), 400 if age > MAX_AGE_SECONDS: return jsonify(error="stale_timestamp"), 400 signed_input = f"{timestamp}.".encode() + raw_body expected = "v1=" + hmac.new(SECRET, signed_input, hashlib.sha256).hexdigest() # compare_digest is the constant-time comparison. if not hmac.compare_digest(signature, expected): return jsonify(error="invalid_signature"), 401 # Verified — now it is safe to parse and trust the payload. event = json.loads(raw_body) # Verification probes carry test: true. Acknowledge without storing. if event.get("test"): return jsonify(ok=True), 200 # Keep this fast — Chatbase times out after 10 seconds. queue_for_processing(event) return jsonify(ok=True), 200 ``` Each example above accepts a correctly signed request and rejects a forged one, so it passes verification as written. A plain `===` (or `==`) on strings stops at the first byte that differs, so how long the comparison takes leaks how many leading bytes matched. In principle an attacker can send many requests, measure the response times, and recover a valid signature one byte at a time — turning an infeasible search into roughly a thousand guesses. In practice, network jitter dwarfs the timing difference, so this is hardening rather than a likely attack path. But it costs nothing: use `crypto.timingSafeEqual` in Node, `hmac.compare_digest` in Python, or your language's equivalent. If your platform has no constant-time primitive, hash both values again with a random per-request key and compare those results normally. An attacker cannot steer timing against a key they do not know. ## Responding * Return any **2xx** status to acknowledge the delivery. Any other status is treated as a failure and retried. * Chatbase closes the connection after **10 seconds**. Acknowledge first and process asynchronously — slow processing turns into timeouts, which turn into duplicate deliveries. * Your response body is ignored. ## Retries If a delivery fails, Chatbase retries it on a widening schedule: | After failed attempt | Next attempt in | | :------------------- | :-------------- | | 1 | 15 minutes | | 2 | 1 hour | | 3 | 3 hours | | 4 | 6 hours | | 5 | 12 hours | That is **6 attempts over roughly 22 hours**. Each wait is jittered by ±20%, so a batch of deliveries that fails together — one outage, one bad deploy — does not come back as a synchronised burst. A failure is any non-2xx response, a timeout, or a connection, DNS, or TLS error. After the sixth failed attempt the delivery is abandoned, and because the conversation has already been deleted, its content is gone. There is currently no manual retry. An endpoint that is down for an evening will recover on its own. One that is down for a full day will lose data. Attempts are also consumed while the webhook itself is not ready to receive: a delivery waiting on an **unverified endpoint**, or on a **missing signing secret**, uses up an attempt each time it is tried. Verifying your endpoint before conversations start reaching their retention thresholds is what keeps the ladder available for real failures. ## Idempotency Delivery is **at-least-once**, so your receiver must tolerate duplicates. Retries reuse the same `X-Chatbase-Delivery-Id`. A delivery can also arrive twice legitimately — if your endpoint processed a request but the acknowledgement was lost on the way back, Chatbase never recorded the success and will send it again. Deduplicate on `deliveryId`, or on `conversation.id`, which appears in at most one conversation's worth of deliveries. Record the ID in the same transaction that stores the conversation so a crash between the two cannot lose or double-count it. ## Changing your endpoint or secret | Action | Verification status | Conversations awaiting delivery | | :-------------------------------- | :---------------------- | :----------------------------------------------------------- | | **Regenerate** the signing secret | Preserved | Signed with the new secret on their next attempt | | **Save** a different endpoint URL | **Cleared** — re-verify | Held, and spending attempts, until verification passes again | | **Remove webhook** | Cleared | Not delivered | Two rules explain the whole table: * **The current secret is used at the moment of each attempt.** Rotating is a security action — if you rotate because you believe the old secret leaked, the very next delivery must not still be signed with it. So rotation takes effect immediately, including for conversations already waiting. * **Verification attests to one specific endpoint.** A different URL has not proved anything, so changing it clears verification and you must verify again. To rotate without downtime, accept **both** the old and the new secret for a short window: deploy a receiver that tries the current secret and falls back to the previous one, regenerate in the dashboard, then remove the old value once traffic confirms the new one is in use. **Remove webhook** deletes the endpoint URL *and* the signing secret. Conversations stop being delivered anywhere, and anything still awaiting delivery will not arrive. You can configure a new webhook later, but it is issued a fresh secret — the old one cannot be recovered. ## Troubleshooting Your endpoint returned 2xx to a request with a deliberately invalid signature. Either it is not checking the signature at all, or it returns a response before the check runs — a common shape is an early `return res.status(200)` for health checks or an `OPTIONS`/`POST` handler that acknowledges first and validates later. Check that an invalid signature produces a non-2xx status, and that the check happens before anything else responds. Your endpoint returned a non-2xx to a correctly signed request. The usual cause is raw-body handling — see the warning in [Verify the signature](#verify-the-signature). Also confirm the endpoint is publicly reachable over HTTPS and is not behind authentication, an IP allowlist, or a WAF rule that blocks unknown callers. Your endpoint answered with a `3xx` instead of handling the request. Redirects are not followed, so the URL you save has to be the one that actually serves the webhook. Most often this is a trailing slash or `www` canonicalisation rather than anything you configured deliberately — see the full list of causes under [Configure your endpoint](#configure-your-endpoint). Sending a `POST` to your saved URL with `curl -i` and checking for a `Location` header is the quickest way to confirm it. In order of likelihood: 1. **The body was re-serialized.** A JSON body parser ran before you computed the HMAC. Use the raw bytes. 2. **The timestamp came from the wrong place.** It must be read from the `X-Chatbase-Timestamp` header, not generated locally. 3. **The signed input is malformed.** It is `timestamp + "." + rawBody` — a literal period between the two, and nothing else. 4. **The secret has stray whitespace.** A trailing newline picked up when pasting into an environment file or secrets manager will change every digest. 5. **The `v1=` prefix was dropped.** Compare the whole header value, including `v1=`. The first probe failed, so the second was never sent. Fix the failure reason shown in the dashboard and verify again. Expected behaviour — delivery is at-least-once. Deduplicate on `deliveryId`. See [Idempotency](#idempotency). That is a verification probe, not a real conversation. Acknowledge it with a 2xx and do not store it, or you will save a fake conversation into your records. Check, in order: 1. The **Webhook configuration** card shows **Endpoint verified**. If it shows **Endpoint not verified**, nothing is being delivered. 2. Conversations have actually reached a retention threshold — a conversation is only delivered when it is deleted, so nothing arrives for conversations that are still active or idle for less than 24 hours. 3. Your endpoint URL is still correct, and saving it did not silently reset verification. ## Notes and limits * **One webhook per workspace**, covering every AI agent in it. Use `conversation.chatbotId` to tell them apart. * **One conversation per request.** Deliveries are never batched, so each conversation gets its own status code and can succeed or fail independently. * **HTTPS only.** * **Deletion is never delayed.** Conversations are deleted on schedule whether or not delivery succeeds, so your endpoint being down does not extend the retention window. * **Chatbase does not log the conversation content of a delivery.** Delivery attempts are recorded for support and audit purposes with only the outcome, response status, and error reason. Your endpoint's hostname is recorded in audit events; the full URL and the signing secret never are. Retention rules, redaction, disabled features, and the shared responsibility model for HIPAA-compliant workspaces. # Identity Verification Source: https://chatbase.co/docs/developer-guides/identity-verification Authenticate users in your AI Agent widget just like they're authenticated on your website. Identity verification allows you to securely authenticate your users in your AI Agent widget. When an end user is logged into your website, you can identify them to your AI Agent so the widget knows who they are and can provide personalized, authenticated experiences. Chatbase agents can be configured to verify the identity of your users. This can be done with a JWT or by hashing the User ID. You can also send additional metadata to the agent that can be used to personalize the agent experience. ## When to Use Identity Verification Make your AI Agent recognize logged-in users so it can: * Greet users by name instead of saying "Hello there" * Access their account information and preferences * Show content relevant to their subscription or role * Provide support based on their history with your service When you need actions that require specific user information from their contact record: * Custom actions that need to access user details (name, email, subscription info, etc.) * Stripe actions (billing, subscriptions, invoices) [Learn more about Stripe actions](/docs/user-guides/chatbot/actions/stripe-action). These actions work by matching the authenticated user's ID with a Contact record that contains their detailed information. By sending user contact information in the JWT, you can always keep contact information up to date instead of sending contact information separately via the API. ## Implementation Guide ### Prerequisites A website with the Chatbase embed script already installed and working. New to Chatbase? Check out [Your First Agent](/docs/user-guides/quick-start/your-first-agent) to get started with the embed script first. ### Get Your Secret Key Navigate to your Chatbase Dashboard to get your verification secret: Go to [Chatbase Dashboard](https://www.chatbase.co/dashboard) and select your AI Agent. Navigate to **Channels** → click **Manage** on the **Chat bubble** card → click **Deploy** (top-right) → **Website widget**. Copy the verification secret key shown in the embed code section. Chatbase embed code with identity verification secret ## Method 1: JWT (Recommended) #### JWT Overview With a JSON Web Token (JWT), you can securely pass a contact's information to Chatbase. This process, known as identification, serves two purposes: it **identifies the user** to the agent and **updates the contact's information** in Chatbase. #### Generating the JWT Payload The payload of the JWT contains the sensitive information you want to pass. When you provide contact details like email, name, or Stripe information, Chatbase will use it to update or create the user's contact profile. The only required field in the JWT payload is `user_id` or `sub`. All other fields are optional. ```javascript Node.js theme={null} const jwt = require("jsonwebtoken"); // Run this on your server and send the returned token to your frontend. function generateChatbaseToken(user) { // Secret key from the Chatbase dashboard. Read it from an environment const secret = process.env.CHATBASE_SECRET; // The payload contains all the user information you want to pass. const payload = { user_id: user.id, // A unique identifier for the user (required), e.g. "user_12345" email: user.email, // User's email address name: user.name, // User's full name phonenumber: user.phone, // User's phone number, e.g. "+15551234567" custom_attributes: { "plan": user.plan }, // Custom attributes defined in your contacts schema stripe_accounts: [{ "label": "Default Account", "stripe_id": user.stripeCustomerId }], // Stripe information for integration exp: Math.floor(Date.now() / 1000) + (60 * 60) // Token expiration time (e.g., 1 hour from now) }; // Sign the token with the HS256 algorithm and return it return jwt.sign(payload, secret, { algorithm: 'HS256' }); } ``` ```python Python theme={null} import jwt import os import time # Run this on your server and send the returned token to your frontend. def generate_chatbase_token(user): # Secret key from the Chatbase dashboard. Read it from an environment secret = os.getenv('CHATBASE_SECRET') # The payload contains all the user information you want to pass. payload = { "user_id": user["id"], # A unique identifier for the user (required), e.g. "user_12345" "email": user["email"], # User's email address "name": user["name"], # User's full name "phonenumber": user["phone"], # User's phone number, e.g. "+15551234567" "custom_attributes": {"plan": user["plan"]}, # Custom attributes defined in your contacts schema "stripe_accounts": [{"label": "Default Account", "stripe_id": user["stripe_customer_id"]}], # Stripe information for integration "exp": int(time.time()) + (60 * 60) # Token expiration time (e.g., 1 hour from now) } # Sign the token with the HS256 algorithm and return it return jwt.encode(payload, secret, algorithm='HS256') ``` ```php PHP theme={null} $user['id'], // A unique identifier for the user (required), e.g. "user_12345" 'email' => $user['email'], // User's email address 'name' => $user['name'], // User's full name 'phonenumber' => $user['phone'], // User's phone number, e.g. "+15551234567" 'custom_attributes' => ['plan' => $user['plan']], // Custom attributes defined in your contacts schema 'stripe_accounts' => [['label' => 'Default Account', 'stripe_id' => $user['stripe_customer_id']]], // Stripe information for integration 'exp' => time() + (60 * 60) // Token expiration time (e.g., 1 hour from now) ]; // Sign the token with the HS256 algorithm and return it return JWT::encode($payload, $secret, 'HS256'); } ?> ``` ```ruby Ruby theme={null} require 'jwt' # Run this on your server and send the returned token to your frontend. def generate_chatbase_token(user) # Secret key from the Chatbase dashboard. Read it from an environment secret = ENV['CHATBASE_SECRET'] # The payload contains all the user information you want to pass. payload = { user_id: user[:id], # A unique identifier for the user (required), e.g. "user_12345" email: user[:email], # User's email address name: user[:name], # User's full name phonenumber: user[:phone], # User's phone number, e.g. "+15551234567" custom_attributes: { "plan" => user[:plan] }, # Custom attributes defined in your contacts schema stripe_accounts: [{ "label" => "Default Account", "stripe_id" => user[:stripe_customer_id] }], # Stripe information for integration exp: Time.now.to_i + (60 * 60) # Token expiration time (e.g., 1 hour from now) } # Sign the token with the HS256 algorithm and return it JWT.encode(payload, secret, 'HS256') end ``` For a complete end-to-end example — a login endpoint that returns this token, plus the frontend code that consumes it — see [Complete JWT Implementation Flow](#complete-jwt-implementation-flow). #### Identifying the User Once you have the signed JWT on your frontend, you can identify the user to your AI Agent in two ways: **Dynamically identify end users** Data in the token (such as stripe IDs or dates of birth) are not visible to the agent to maintain privacy. However, the agent can use them to perform actions with your configured integrations. They are passed securely to maintain privacy. ```javascript theme={null} // Get the signed JWT from your server const token = await getJWTFromBackend(); // After end user logs in or when you have their information window.chatbase("identify", { // The token contains sensitive data which is protected. token: token, // These public attributes ARE visible to the Chatbot context. "name": user.firstName, "age": user.age }); ``` This call identifies the user to the agent and syncs their contact information. **Set end user identity before the Chatbase script loads** ```html theme={null} ``` Attributes passed outside of the JWT are visible to the agent. To protect user privacy, never include sensitive information outside of the token. #### Logging out Users When a user logs out, call the `resetUser` method to clear their identity from the agent session: ```javascript theme={null} // When the user logs out window.chatbase("resetUser"); ``` #### How Contact Updates Work * **Adding/Updating Fields:** New fields will be added, and existing ones will be updated. ```javascript theme={null} // This payload will add or update the user's Stripe information. const jwt_payload = { user_id: 123, stripe_accounts: [{ "label": "account1", "stripe_id": "cust123" }] }; ``` * **Ignoring Fields:** If you don't include a field in the payload, it will be ignored, and the existing value will be preserved. ```javascript theme={null} // This payload will not change the user's existing Stripe information. const jwt_payload = { user_id: 123 }; ``` * **Deleting Fields:** To delete a field, pass `null` as its value. ```javascript theme={null} // This payload will delete the user's Stripe information. const jwt_payload = { user_id: 123, stripe_accounts: null }; ``` ## Complete JWT Implementation Flow This example shows the complete JWT flow: generating JWT tokens with user data, then using identity verification to enable personalized AI responses and automatic contact updates. ### Step 1: Generate JWT Token on User Login When users log in, generate a JWT token on your server with their contact information: ```javascript Node.js theme={null} const jwt = require("jsonwebtoken"); // Login endpoint app.post('/api/login', async (req, res) => { const { email, password } = req.body; // Authenticate user with your existing logic const user = await authenticateUser(email, password); if (!user) { return res.status(401).json({ error: 'Invalid credentials' }); } // Create JWT payload with user information const payload = { user_id: user.id, // Required: unique user identifier. email: user.email, // User's email name: user.name, // User's full name phonenumber: user.phone, // User's phone number stripe_accounts: [ // Stripe integration { "label": "Default Account", "stripe_id": user.stripe_customer_id } ], custom_attributes: { // Custom user data "signup_date": user.signup_date, "support_tier": user.support_tier, "company": user.company }, exp: Math.floor(Date.now() / 1000) + (60 * 60) // 1 hour expiration }; // Sign the JWT with your Chatbase secret const token = jwt.sign(payload, process.env.CHATBASE_SECRET, { algorithm: 'HS256' }); res.json({ user: user, token: token // Send JWT to frontend }); }); ``` ```python Python theme={null} import jwt import time from datetime import datetime, timedelta # Login endpoint @app.route('/api/login', methods=['POST']) def login(): data = request.get_json() email = data.get('email') password = data.get('password') # Authenticate user with your existing logic user = authenticate_user(email, password) if not user: return jsonify({'error': 'Invalid credentials'}), 401 # Create JWT payload with user information payload = { 'user_id': user.id, # Required: unique user identifier 'email': user.email, # User's email 'name': user.name, # User's full name 'phonenumber': user.phone, # User's phone number 'stripe_accounts': [ # Stripe integration { "label": "Default Account", "stripe_id": user.stripe_customer_id } ], 'custom_attributes': { # Custom user data "signup_date": user.signup_date, "support_tier": user.support_tier, "company": user.company }, 'exp': int(time.time()) + (60 * 60) # 1 hour expiration } # Sign the JWT with your Chatbase secret token = jwt.encode(payload, os.getenv('CHATBASE_SECRET'), algorithm='HS256') return jsonify({ 'user': user, 'token': token # Send JWT to frontend }) ``` ```php PHP theme={null} 'Invalid credentials']); exit; } // Create JWT payload with user information $payload = [ 'user_id' => $user['id'], // Required: unique user identifier 'email' => $user['email'], // User's email 'name' => $user['name'], // User's full name 'phonenumber' => $user['phone'], // User's phone number 'stripe_accounts' => [ // Stripe integration [ "label" => "Default Account", "stripe_id" => $user['stripe_customer_id'] ] ], 'custom_attributes' => [ // Custom user data "signup_date" => $user['signup_date'], "support_tier" => $user['support_tier'], "company" => $user['company'] ], 'exp' => time() + (60 * 60) // 1 hour expiration ]; // Sign the JWT with your Chatbase secret $token = JWT::encode($payload, $_ENV['CHATBASE_SECRET'], 'HS256'); echo json_encode([ 'user' => $user, 'token' => $token // Send JWT to frontend ]); } ?> ``` ```ruby Ruby theme={null} require 'jwt' # Login endpoint post '/api/login' do data = JSON.parse(request.body.read) email = data['email'] password = data['password'] # Authenticate user with your existing logic user = authenticate_user(email, password) if !user status 401 return { error: 'Invalid credentials' }.to_json end # Create JWT payload with user information payload = { user_id: user.id, # Required: unique user identifier email: user.email, # User's email name: user.name, # User's full name phonenumber: user.phone, # User's phone number stripe_accounts: [ # Stripe integration { "label" => "Default Account", "stripe_id" => user.stripe_customer_id } ], custom_attributes: { # Custom user data "signup_date" => user.signup_date, "support_tier" => user.support_tier, "company" => user.company }, exp: Time.now.to_i + (60 * 60) # 1 hour expiration } # Sign the JWT with your Chatbase secret token = JWT.encode(payload, ENV['CHATBASE_SECRET'], 'HS256') { user: user, token: token # Send JWT to frontend }.to_json end ``` ### Step 2: Identify User in Frontend Use the JWT token to identify the user to Chatbase widget: ```javascript Frontend JWT Identity Verification theme={null} // After successful login async function loginUser() { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'user@example.com', password: 'password' }) }); const { user, token } = await response.json(); // Identify user to Chatbase and also update/insert this contact window.chatbase("identify", { token: token, // JWT contains all user data name: user.name // public metadata sent to the chatbot }); } ``` *** ## Method 2: User Hash (deprecated) Using user hash is not recommended as JWT offers better security and lessens the need to update contacts via API ### Generate End User Hash on Your Server **Security Critical:** End user hashes must be generated on your server, never in client-side JavaScript, to keep your secret key secure. ```javascript Node.js theme={null} const crypto = require('crypto'); // Run this on your server and send the returned hash to your frontend. function generateChatbaseUserHash(userId) { // Your verification secret key. Read it from an environment variable — // never hardcode it or expose it to the browser. const secret = process.env.CHATBASE_SECRET; // userId is a string UUID that identifies your user return crypto.createHmac('sha256', secret).update(userId).digest('hex'); } ``` ```python Python theme={null} import hmac import hashlib import os # Run this on your server and send the returned hash to your frontend. def generate_chatbase_user_hash(user_id): # Your verification secret key. Read it from an environment variable — # never hardcode it or expose it to the browser. secret = os.getenv('CHATBASE_SECRET') # user_id is a string UUID that identifies your user. You can also use 'sub' instead of 'user_id' return hmac.new(secret.encode('utf-8'), user_id.encode('utf-8'), hashlib.sha256).hexdigest() ``` ```php PHP theme={null} ``` ```ruby Ruby theme={null} require 'openssl' # Run this on your server and send the returned hash to your frontend. def generate_chatbase_user_hash(user_id) # Your verification secret key. Read it from an environment variable — # never hardcode it or expose it to the browser. secret = ENV['CHATBASE_SECRET'] # user_id is a string UUID that identifies your user OpenSSL::HMAC.hexdigest('sha256', secret, user_id) end ``` ### Identify End Users to Your AI Agent + Update Contact Once you've generated the end user hash on your server, you can identify the end user to your AI Agent in two ways: **Dynamically identify end users** ```javascript theme={null} // After end user logs in or when you have their information window.chatbase("identify", { user_id: "user-123", user_hash: "generated-hash-from-server", user_metadata: { "name": "John Doe", "email": "john@example.com", "company": "Acme Inc" } }); ``` **Set end user identity before the Chatbase script loads** ```html theme={null} ``` ## Identity Parameters Unique identifier for the user from your authentication system. This tells your AI Agent which end user is currently authenticated. You can use 'sub' instead of 'user\_id' and it will work identically. **Format:** Any string (UUID recommended)\ **Example:** `"end-user-12345"`, `"550e8400-e29b-41d4-a716-446655440000"` To enable personalized responses and actions, create a Contact record with `external_id` matching this `user_id` using the [Contacts API](/docs/api-reference/contacts/create-contacts-for-a-chatbot). HMAC-SHA256 hash of the user\_id using your Chatbase secret key. This proves to Chatbase that the end user is authentically logged in. Must be generated on your server for security. **Format:** 64-character hexadecimal string\ **Example:** `"a1b2c3d4e5f6..."` Additional session-specific information about the authenticated end user. This provides context to the AI Agent about the current session. **Character limit:** 1000 characters total across all fields\ **Use for:** Session state, temporary preferences, current page context, authentication level **Do not include confidential information** in user\_metadata such as passwords, social security numbers, credit card details, or other sensitive data. If your AI Agent needs access to confidential user information, store it securely in [Contacts](/docs/user-guides/chatbot/contacts/contacts-overview) instead. ```javascript theme={null} user_metadata: { "current_session": "mobile_app", "last_page_visited": "/dashboard", "auth_level": "premium_user", "session_preferences": { "theme": "dark" } } ``` ## Security & Best Practices **Always generate end user hashes on your server**, never in client-side JavaScript: ✅ **Secure:** Generate hash in your backend API\ ✅ **Secure:** Use environment variables for Chatbase secret keys\ ❌ **Insecure:** Generate hash in browser JavaScript\ ❌ **Insecure:** Include secret key in client-side code **Use consistent, unique end user identifiers:** ✅ **Good:** UUIDs (`550e8400-e29b-41d4-a716-446655440000`)\ ❌ **Avoid:** Emails or usernames that might change **Keep end user metadata relevant and concise:** ✅ **Include:** Information that helps personalize AI responses\ ✅ **Include:** Context that aids in customer support\ ❌ **Avoid:** Sensitive data like passwords or SSNs\ ❌ **Avoid:** Excessive data that exceeds 1000 character limit **Secure JWT implementation and management:** ✅ **Secure:** Generate JWTs on your server with proper expiration times\ ✅ **Secure:** Use strong, unique secret keys stored in environment variables\ ✅ **Secure:** Include only necessary user data in JWT payload\ ✅ **Secure:** Implement proper token refresh mechanisms\ ❌ **Insecure:** Generate JWTs in client-side JavaScript\ ❌ **Insecure:** Use excessively long expiration times (keep under 24 hours) ## Troubleshooting **Symptoms:** End user identity not recognized, actions using Contact data fail **Solutions:** * Verify secret key matches the one from Chatbase Dashboard * Ensure user\_id used for hashing exactly matches the one sent * Check that hash is generated using HMAC-SHA256 * Confirm user\_id is a string, not a number * Confirm user\_id is the same as the one used in the Contact record ```javascript theme={null} // ❌ Wrong - user_id as number const endUserId = 12345; // ✅ Correct - user_id as string const endUserId = "12345"; ``` **Symptoms:** End user is verified but Contact data isn't accessible, actions using Contact info fail **Solutions:** * Verify a Contact exists with `external_id` matching the end user's `user_id` * Check Contact was created using Contacts API * Ensure `user_id` and Contact `external_id` match exactly (case-sensitive) * Confirm Contact has required fields populated (e.g., Stripe accounts for payment actions) **Symptoms:** End user identity lost between page loads, Contact data not maintained **Solutions:** * Use `chatbaseUserConfig` for page-load identification * Call `identify()` early in your application lifecycle * Ensure end user hash is available before calling identify * Check browser console for JavaScript errors **Symptoms:** Expected end user information not available to AI Agent **Solutions:** * Use Contact data for permanent end user information * Use `user_metadata` only for session-specific context * Reduce metadata size to under 1000 characters * Store comprehensive end user data in Contact custom attributes ## Complete User Hash Implementation Flow This example shows the complete flow: creating Contacts with custom attributes, then using identity verification to enable personalized AI responses. ### Step 1: Create Contact on User Registration/Updates When users sign up or their data changes, create a Contact record in Chatbase with custom attributes and Stripe customer ID: ```javascript Contact Creation API Call theme={null} const axios = require('axios'); // When user signs up or data changes async function createChatbaseContact(userData) { const contactData = { "users": [ { "external_id": userData.id, // Your user ID "name": userData.name, "email": userData.email, "phonenumber": userData.phone, "stripe_accounts": [ { "label": "Default Account", "stripe_id": userData.stripe_customer_id // Stripe customer ID } ], "custom_attributes": { "signup_date": userData.signup_date, "support_tier": userData.support_tier } } ] }; // Create contact via Chatbase API const response = await axios.post( `https://www.chatbase.co/api/v1/chatbot/${process.env.AGENT_ID}/contact`, contactData, { headers: { 'Authorization': `Bearer ${process.env.CHATBASE_API_KEY}`, 'Content-Type': 'application/json' } } ); console.log('Contact created:', response.data); return response.data; } ``` ### Step 2: Generate Hash on User Login When users log in, generate the identity hash on your server: ```javascript Server-Side Hash Generation theme={null} const crypto = require('crypto'); function generateUserHash(userId, secret) { return crypto.createHmac('sha256', secret).update(userId).digest('hex'); } // Login endpoint app.post('/api/login', async (req, res) => { const { email, password } = req.body; // Authenticate user with your existing logic const user = await authenticateUser(email, password); if (!user) { return res.status(401).json({ error: 'Invalid credentials' }); } // Generate secure hash for identity verification const userHash = generateUserHash(user.id, process.env.CHATBASE_SECRET); res.json({ user: user, userHash: userHash // Send to frontend for identify call }); }); ``` ### Step 3: Identify User in Frontend Use the hash to identify the user to Chatbase widget: ```javascript Frontend Identity Verification theme={null} // After successful login async function loginUser() { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'user@example.com', password: 'password' }) }); const { user, userHash } = await response.json(); // Identify user to Chatbase - enables access to Contact data window.chatbase("identify", { user_id: user.id, user_hash: userHash, user_metadata: { "name": user.name, "email": user.email, "current_page": "dashboard" } }); console.log('User identified - AI Agent can now access Contact data and perform Stripe actions'); } ``` ### Step 4: Unlock Powerful Custom Actions with Contact Data 🚀 Note: The JWT method allows you to insert and update agent contacts without the need for seperate API calls to the Contacts API. Now that your AI Agent has access to rich contact data, it can perform incredibly sophisticated custom actions that were previously impossible! Learn how to build powerful custom actions that leverage your contact data for personalized user experiences. ### Step 5: Unlock Stripe Actions 💳 Here's where the magic really happens! By adding `stripe_accounts` to your contacts, you've just unlocked the full power of our Stripe integration. Your AI Agent can now handle complex billing operations seamlessly without any additional coding on your part. **Game Changer Alert**: Your customers can now say things like "Cancel my subscription", "Show me my last invoice", or "Update my payment method" and your AI Agent will handle these requests intelligently with full context about their account! **What This Means for Your Business:** * **Reduced Support Tickets**: Common billing questions are handled instantly * **Improved Customer Experience**: No more "let me transfer you to billing" * **Increased Efficiency**: One AI Agent handles both support AND billing operations * **Personalized Service**: Every interaction is tailored to the customer's specific account details Learn how to use Stripe actions to handle billing, subscriptions, and invoices. ## Next Steps Learn how to create and manage Contact records that link to verified end users Store additional end user data in Contact custom attributes for personalized experiences Call backend actions from the client side Add interactive forms and data collection to your chat # JavaScript Embed Script Source: https://chatbase.co/docs/developer-guides/javascript-embed Complete guide to embedding Chatbase AI Agents in your web application with advanced customization options. The JavaScript embed script is perfect for web applications that need rich chat functionality with minimal setup. Add a powerful AI agent to your website in minutes. ## What You Can Do * **Simple embed** - Add a chat widget to your website in minutes * **Identity verification** - Add advanced capabilities and customizations to your agent, by leveraging contacts and actions * **Widget control** - Programmatically open/close the chat interface * **Event listeners** - React to user messages and AI responses * **Actions** - Create interactive forms and actions directly in the chat interface * **Dynamic content** - Show personalized initial messages ## Quick Start Guide 1. Go to your [Chatbase Dashboard](https://www.chatbase.co/dashboard) 2. Select your AI Agent → **Channels** → click **Manage** on the **Chat bubble** card 3. Click **Deploy** (top-right) and choose **Website widget** 4. Copy the JavaScript embed script Deploy embed tab Paste the code in your website's `` section or before the closing `` tag. Place in `` for faster loading, or before `` if you have loading performance concerns. Visit your website and look for the chat bubble. Click it to test! Your AI Agent should respond based on your training data. Enhance your integration with identity verification, custom events, or styling. ```javascript theme={null} // Example: Listen for user messages window.chatbase.addEventListener("user-message", (event) => { console.log("User said:", event.content); // Your custom logic here }); ``` ## JavaScript Embed Core Features **Secure user sessions with verified identities** Perfect for authenticated applications where you need to: * Verify user identity for actions * Pass user context (name, email, etc.) to AI Agent * Use data stored in contacts to perform actions. [Full Identity Verification Guide →](/docs/developer-guides/identity-verification) **React to chat events in real-time** Listen for and respond to: * User messages and AI responses * Actions calls and results [Event Listeners Documentation →](/docs/developer-guides/chatbot-event-listeners) **Programmatic control over chat interface** Control your chat widget with JavaScript: * Open/close programmatically * Customize initial messages * Show floating prompts over the chat bubble [Widget Control Guide →](/docs/developer-guides/control-widget) **Create interactive experiences** Build custom: * Action buttons that trigger your backend * Forms for lead capture [Custom Actions Guide →](/docs/developer-guides/client-side-custom-actions) [Client-Side Custom Forms Guide →](/docs/developer-guides/client-side-custom-forms) ## Best Practices ### Performance Optimization **Load the embed script asynchronously** to avoid blocking your page load. The provided embed code already handles this automatically. ```html theme={null} ``` ### User Experience * Test the chat widget on various mobile devices * Ensure the chat bubble doesn't interfere with mobile navigation * Consider using smaller initial messages on mobile screens * The widget includes ARIA labels and keyboard navigation * Ensure sufficient color contrast in custom styling * Test with screen readers for accessibility compliance * Pass relevant page/user context to provide better responses * Use identity verification for personalized experiences * Clear chat context when users navigate to different sections ### Security Considerations **Never expose sensitive data** through the embed script. Use [identity verification](/docs/developer-guides/identity-verification) instead of passing raw user data. ## Troubleshooting 1. Check that your agent ID is correct in the embed script 2. Verify the script is placed correctly in your HTML 3. Check browser console for JavaScript errors 4. Ensure your website domain is allowed in agent settings 1. Ensure event listeners are added after the chatbase script loads 2. Check that event names are spelled correctly 3. Verify the chatbase object is properly initialized 4. Use browser dev tools to debug event flow ## What's Next? Secure your agent for authenticated users Integrate Chatbase with your existing backend Call backend actions from the client side Add interactive forms and data collection to your chat # Developer Overview Source: https://chatbase.co/docs/developer-guides/overview Welcome to the Chatbase Developer Guide! Whether you're embedding a simple chat widget or building complex integrations, this guide will help you implement AI-powered conversations in your application.
Chatbase Logo Chatbase Logo
## Choose Your Integration Path Perfect for web developers who want to add a chat widget with custom behavior, event handling, and rich user experiences. Ideal for backend developers building custom chat interfaces, mobile apps, or server-to-server integrations. The latest API with structured errors, streaming via SSE, and cursor-based pagination. Manage agents, sources, conversations, and more from your terminal or CI. ## JavaScript Embed Integration Perfect for web developers who want rich chat functionality with minimal complexity. The JavaScript embed script provides: * **Simple Integration**: Add to any website with one script tag. * **Advanced Features**: Event listeners, custom actions, and custom initial message. * **Identity Verification**: Secure user sessions for authenticated apps and contact management. * **Real-time Events**: React to user messages and AI responses. Get the full implementation guide with examples, advanced features, and best practices → ## REST API Integration Ideal for backend developers who need complete control over AI conversations. The REST API provides: * **Chat API**: Send messages and receive AI responses with streaming support * **Agent Management**: Create, update, and configure AI agents programmatically * **Data Access**: Retrieve conversations, leads, and analytics * **Webhooks**: Real-time notifications for chat events Get the full API documentation with examples, authentication, and best practices → ## Common Integration Patterns **Perfect for online stores** * **Embed Script**: Chat bubble on product pages * **Identity Verification**: Logged-in customer context * **Custom Actions**: Order lookup, returns processing * **API Integration**: Sync with order management system **Help users succeed with your product** * **Embed Script**: Contextual help widget * **Event Listeners**: Track user interactions * **Custom Actions**: Feature tutorials, account management **Internal workspace support system** * **API Integration**: Custom internal dashboard * **Identity Verification**: Employee authentication and identification * **Contacts API**: Team directory integration * **Analytics**: Usage tracking and insights # Webhook API Guide Source: https://chatbase.co/docs/developer-guides/webhooks Guide to setting up webhooks to receive real-time notifications when users submit your custom forms. # Webhook API Guide The Webhook API guide allows you to set-up webhooks to receive a `POST` request on when an event or more is triggered. ## Create a webhook Webhooks are configured on the action that produces the event. For lead submissions, use the [Collect Leads](/docs/user-guides/chatbot/actions/collect-leads) action: 1. Go to **Build > Actions** and open your **Collect Leads** action. 2. Click the **Webhooks** tab in the action settings. 3. Enter the URL that should receive the `POST` request, then click **Create Webhook**. Other actions that emit events, such as [custom forms](/docs/developer-guides/client-side-custom-forms), have the same **Webhooks** tab. ## Payload | Key | Type | Description | | :------------ | :----- | :------------------------------------------------- | | **eventType** | string | [Event type](#event-types) | | **chatbotId** | string | Agent ID | | **payload** | Object | Payload of the event. [Learn more](#event-payload) | ## Event types[](#event-types) These are the list of events supported in webhooks: * `leads.submit` : When a customer submits their info (Name, Email, Phone, and any custom fields configured on the Collect Leads action) to your agent. * `{action name}_collect_data.submit` : When a customer submits the fields collected by a [Collect Data](/docs/user-guides/chatbot/actions/collect-data) action, where `{action name}` is the name of that action. ## Event payload[](#event-payload) The payload of each event: * `leads.submit` : ```json theme={null} { conversationId: string, customerEmail: string, customerName: string, customerPhone: string, customFields: object // optional, only present when the Collect Leads action has custom fields } ``` `customFields` is keyed by the field names configured on the Collect Leads action, e.g. `{ "Company name": "Acme", "Team size": 12 }`. It is only sent when the action collects custom fields (conversational mode). ## Receiving the request You can receive the payload by accessing the body same as any request. But it is recommended to to check the request header `x-chatbase-signature` for securing your endpoint from spam from anyone knows your endpoint. You can achieve this by using SHA-1 (Secure Hash Algorithm 1) function to generate a signature for the request and compare it with `x-chatbase-signature` found in the request headers. If the are identical then the request is from Chatbase. ```javascript Next.js theme={null} import crypto from 'crypto' import {NextApiRequest, NextApiResponse} from 'next' import getRawBody from 'raw-body' // Raw body is required. export const config = { api: { bodyParser: false, }, } async function webhookHandler(req: NextApiRequest, res: NextApiResponse) { if (req.method === 'POST') { const {SECRET_KEY} = process.env if (typeof SECRET_KEY != 'string') { throw new Error('No secret key found') } const rawBody = await getRawBody(req) const requestBodySignature = sha1(rawBody, SECRET_KEY) if (requestBodySignature !== req.headers['x-chatbase-signature']) { return res.status(400).json({message: "Signature didn't match"}) } const receivedJson = await JSON.parse(rawBody.toString()) console.log('Received:', receivedJson) /* Body example for leads.submit event { eventType: 'leads.submit', chatbotId: 'xxxxxxxx', payload: { conversationId: 'xxxxxxxx', customerEmail: 'example@chatbase.co', customerName: 'Example', customerPhone: '123', customFields: { 'Company name': 'Acme', 'Team size': 12 } } } */ res.status(200).end('OK') } else { res.setHeader('Allow', 'POST') res.status(405).end('Method Not Allowed') } } function sha1(data: Buffer, secret: string): string { return crypto.createHmac('sha1', secret).update(data).digest('hex') } export default webhookHandler ``` ```javascript Node.js theme={null} import crypto from 'crypto' import {Request, Response} from 'express' // Note: In this example json body parser is enabled in the app export async function webhookHandler(req: Request, res: Response) { if (req.method === 'POST') { const {SECRET_KEY} = process.env if (typeof SECRET_KEY != 'string') { throw new Error('No secret key found') } const receivedJson = req.body const rawBody = Buffer.from(JSON.stringify(receivedJson)) const bodySignature = sha1(rawBody, secretKey) if (requestBodySignature !== req.headers['x-chatbase-signature']) { return res.status(400).json({message: "Signature didn't match"}) } console.log('Received:', receivedJson) /* Body example for leads.submit event { eventType: 'leads.submit', chatbotId: 'xxxxxxxx', payload: { conversationId: 'xxxxxxxx', customerEmail: 'example@chatbase.co', customerName: 'Example', customerPhone: '123', customFields: { 'Company name': 'Acme', 'Team size': 12 } } } */ res.status(200).end('OK') } else { res.setHeader('Allow', 'POST') res.status(405).end('Method Not Allowed') } } function sha1(data: Buffer, secret: string): string { return crypto.createHmac('sha1', secret).update(data).digest('hex') } ``` # AI Widget Builder Source: https://chatbase.co/docs/developer-guides/widgets/ai-widget-builder Generate widgets from natural language descriptions or pre-built templates using the AI builder. The AI Widget Builder lets you create fully functional widgets using natural language. Describe what you want in plain English and the AI generates the code, schema, default example, and all supporting configuration for you. No manual coding required. Just describe your widget and refine it through conversation. ## Getting Started You have two ways to get started: * **Use a pre-built template.** Click one of the available templates to instantly generate a widget based on a common use case. * **Type your own description.** Enter a plain-language description of the widget you want to create (e.g., "a contact form with name, email, and message fields"). ## What the AI Generates When you submit a prompt or select a template, the AI generates a complete widget including: * **Code** -- the full widget implementation ready to render. * **Schema** -- the data schema that defines the widget's structure and input fields. * **Default example** -- a pre-populated example so you can see the widget in action immediately. * **Functions and states** -- relevant functions and UI states scaffolded for you automatically. The AI Builder handles the entire widget structure in one step. You do not need to configure code, schema, and example separately. ## Refining Your Widget After the initial generation, you can send follow-up messages to refine the widget. The AI Builder works as a conversation, so you can iterate naturally. Examples of refinement prompts: * "Make the button blue" * "Add a phone number field" * "Change the heading text to Welcome Back" * "Remove the email validation" Each follow-up updates the widget's code, schema, and example together. **Important: Stub functions and states** The AI Builder creates placeholder functions and states that require manual configuration: * **Functions** are created as dismiss functions by default. After generation, you need to update each function's type and configuration in the **Functions** tab. * **States** are created with simple always-visible or always-hidden visibility. After generation, you need to configure conditional visibility rules in the **States** tab. Always review the Functions and States tabs after generating or refining a widget. ## Add Images to Your Widget You can upload images directly in the Widget Builder and use them as part of your widget. This is useful for adding assets such as **logos, icons, and other images**. Go to **Build → Widgets → AI builder** and click the **paperclip** icon. Choose how you want to use the image before selecting the file: * **Add image to widget** -- Uploads and hosts the image, providing a URL that can be rendered directly in your widget. * **Add design reference** -- Provides the image to the AI as a visual reference without adding it to the widget. Use this when you want the AI to create or modify a widget based on an existing design. * **Manage widget images** -- View your uploaded images, upload new ones, copy an image URL, insert an image at the current cursor position, or delete an image. You choose whether an image is added to the widget or used as a design reference **before** selecting the file. Images are never hosted implicitly. Images are labeled **In widget** or **Reference**, so you can easily distinguish between hosted images available to your widget and images used only as visual references. You can also access **Manage widget images** from the JSX editor toolbar, allowing you to upload and insert images without using the AI Builder. ### Image limits * Up to **5 hosted images** per widget. * Supported formats: **PNG, JPG, and WebP**. * Maximum file size: **5 MB per image**. * **SVG files are not supported**. Images uploaded before the first save are retained when you save the widget. Hosted images also remain available when you close and reopen the widget, including in a new tab. ## Undo If a generation does not meet your needs, you can restore to the previous version. This lets you experiment freely without losing your earlier work. Use undo to roll back to the last known good version before trying a different prompt. ## Live Preview The preview panel on the right side of the builder updates in real time as the AI generates your widget. You can see changes appear as they are being written, giving you immediate visual feedback without waiting for the full generation to complete. # Code Editor Source: https://chatbase.co/docs/developer-guides/widgets/code-editor Write widget code, define schemas, and preview with examples using the code editor. The **Code** tab is the manual editor for writing and editing widget code and data. It is split into two sections: the **main editor** (top) where you write the widget's visual layout, and the **footer panel** (bottom) where you define the schema and manage examples. ## Main Editor The main editor is where you write the widget's visual layout using the built-in component library. It includes: * **Autocomplete and type hints** for all available components and their properties. * **Syntax highlighting** for readable, structured code. * A **Copy button** next to the JSON toggle for quick clipboard access. Use autocomplete to discover available components and their supported props without leaving the editor. ## Code Syntax The code editor uses a JSX-like syntax. Below are the key patterns for working with data in your widget code. ### Variables Reference data fields using curly braces. Each variable maps to a field defined in the schema. ```jsx theme={null} <Text value={description} size="sm" color="secondary" /> ``` ### Nested Data Access nested objects using dot notation. ```jsx theme={null} <Text value={speaker.name} /> <Text value={speaker.title} /> ``` ### Loops Repeat elements over an array using `.map()`. ```jsx theme={null} {speakers.map((speaker) => ( <Row key={speaker.id} gap={3}> <Image src={speaker.image} /> <Text value={speaker.name} size="sm" /> </Row> ))} ``` ### String Interpolation Combine static text with data fields using backticks and `${}` syntax. ```jsx theme={null} <Text value={`Tax (${taxPercent})`} /> ``` ## Schema The **Schema** editor lives in the footer panel. It defines the data fields the agent needs to provide when rendering the widget. Schemas are written using **Zod**. The footer panel includes a **Zod/JSON toggle**: * **Zod** -- the editable schema definition. * **JSON Schema** -- a read-only, auto-generated view derived from the Zod schema. <Info> The schema is how the agent knows what data to pass into the widget. Each field in the schema maps to a variable you can reference in the code. </Info> ## Default Example The **Default** tab in the footer panel contains the initial values for all schema fields. These values are used when the widget first renders in the preview. ```json theme={null} { "title": "Hello World", "description": "This is a sample widget" } ``` ## Named Examples Named examples let you visualize different data scenarios without changing the default values. Use them to test how the widget looks with varying data -- for example, 1 item vs 5 items, or an empty state vs a post-submission state. <Steps> <Step title="Create an example"> Click the **+** button in the footer panel to add a new named example. </Step> <Step title="Edit the name and values"> Each named example has an editable name and its own set of field values. </Step> <Step title="Switch between examples"> Click any example tab to update the preview with that example's data. </Step> </Steps> <Note> Named examples are for previewing in the builder only. At runtime, data comes from the action. See the [Overview](/docs/developer-guides/widgets/overview) page for details on data sources. </Note> # Data Display Source: https://chatbase.co/docs/developer-guides/widgets/components/data-display Components for displaying structured data — Table and Chart. ## Table A structured data table built from rows and cells. Use `TableRow` and `TableCell` to define the table structure declaratively. ```jsx theme={null} <Table> <TableRow header> <TableCell>Name</TableCell> <TableCell>Price</TableCell> </TableRow> <TableRow> <TableCell>{name}</TableCell> <TableCell>{price}</TableCell> </TableRow> </Table> ``` <Tip> Mark a `TableRow` with `header` to render it with bold text and a background color, making it easy to distinguish column headings from data rows. </Tip> ### TableRow Props | Prop | Type | Default | Description | | -------- | ------- | ------- | ------------------------------------------------------------- | | `header` | boolean | `false` | Render as a header row with bold text and background styling. | ### TableCell Props | Prop | Type | Default | Description | | --------- | ------------------------------------ | ------- | ----------------------------------------------------------------------------- | | `width` | number \| string | — | Custom cell width. | | `colSize` | `xs` \| `sm` \| `md` \| `lg` \| `xl` | — | Preset width. `xs`: 60px, `sm`: 100px, `md`: 160px, `lg`: 240px, `xl`: 320px. | | `colSpan` | number | — | Number of columns this cell spans. | | `rowSpan` | number | — | Number of rows this cell spans. | | `padding` | spacing | — | Cell padding. | | `align` | `start` \| `center` \| `end` | — | Horizontal alignment of the cell content. | | `vAlign` | `start` \| `center` \| `end` | — | Vertical alignment of the cell content. | *** ## Chart Data visualization component supporting bar, line, and area charts. You can combine multiple series in a single chart to overlay different visualization types. ```jsx theme={null} <Chart data={salesData} xAxis="month" series={[ { dataKey: "revenue", label: "Revenue", type: "bar", color: "#4f46e5" }, { dataKey: "target", label: "Target", type: "line", color: "#ef4444" } ]} /> ``` <Info> Each entry in the `series` array defines one data series. You can mix `bar`, `line`, and `area` types in the same chart to create composite visualizations like a bar chart with a trend line overlay. </Info> ### Props | Prop | Type | Default | Description | | ---------------- | ------------------------------------- | ------- | -------------------------------------------------------------------------------------- | | `data` | array of objects | — | The dataset to visualize. Each object represents one data point. | | `series` | array | — | Array of series definitions. See [series options](#series-options) below. | | `xAxis` | string \| `{dataKey, hide?, labels?}` | — | The data key for the x-axis, or an object for advanced configuration. | | `yAxis` | `{domain?}` | — | Y-axis configuration. `domain` accepts numbers, `"auto"`, `"dataMin"`, or `"dataMax"`. | | `showLegend` | boolean | `true` | Show or hide the chart legend. | | `showTooltip` | boolean | `true` | Show or hide tooltips on hover. | | `showYAxis` | boolean | `false` | Show or hide the y-axis labels. | | `barGap` | number | — | Gap between bars within the same category. | | `barCategoryGap` | number | — | Gap between bar categories. | | `width` | number \| string | — | Explicit chart width. | | `height` | number \| string | — | Explicit chart height. | | `minHeight` | number | `200` | Minimum chart height in pixels. | | `flex` | number \| string | — | Flex grow/shrink behavior. | ### Series Options Each object in the `series` array accepts: | Prop | Type | Description | | ----------- | ------------------------- | ------------------------------------------------------------------------------ | | `dataKey` | string | The key in the data objects for this series' values. | | `label` | string | Display label for the series in legend and tooltip. | | `type` | `bar` \| `line` \| `area` | Visualization type. | | `color` | string | Series color. | | `stack` | string | Optional stack group. Series with the same `stack` value are stacked together. | | `curveType` | string | Optional curve interpolation type for line and area charts. | # Form Inputs Source: https://chatbase.co/docs/developer-guides/widgets/components/form-inputs Form and input components for collecting user data — Form, Input, Textarea, Select, DatePicker, Checkbox, RadioGroup, and Slider. ## Common Form Input Props `Input`, `Textarea`, `Select`, `DatePicker`, `Checkbox`, `RadioGroup`, and `Slider` all share the following props for handling form data and interaction. | Prop | Type | Default | Description | | ---------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------- | | `name` | string | — | Field name used as the key in form submission data. | | `required` | boolean | `false` | Whether the field must be filled before the form can be submitted. | | `disabled` | boolean | `false` | Disables the input, preventing user interaction. | | `onChangeAction` | action | — | Function to run when the value changes. Available on `Select`, `DatePicker`, `Checkbox`, `RadioGroup`, and `Slider` only. | <Info> The `name` prop on a form input automatically creates a variable in the widget's data. For example, an `<Input name="email" />` creates an `email` variable that you can reference elsewhere in the widget using `{email}`, use in template tokens as `{{email}}`, or check in state conditions. </Info> <Tip> Make sure each `name` is unique within a `Form` to avoid collisions. </Tip> *** ## Form A container that groups input components and handles submission. Wrap your inputs inside a `Form` to collect their values together when the user submits. ```jsx theme={null} <Form onSubmitAction={{ functionName: "submitForm" }}> <Input name="email" placeholder="Enter your email" required /> <Button label="Submit" submit /> </Form> ``` ### Props `Form` accepts all [Box props](/docs/developer-guides/widgets/components/layout#box) plus: | Prop | Type | Default | Description | | ---------------- | ------ | ------- | -------------------------------------------------------------------------------------- | | `onSubmitAction` | action | — | Function to run when the form is submitted. Receives all field values keyed by `name`. | <Info> Place a `Button` with the `submit` prop inside the `Form` to trigger submission. All inputs within the form will have their values collected automatically. </Info> *** ## Input A single-line text input for collecting short-form data like emails, names, or numbers. ```jsx theme={null} <Input name="email" inputType="email" placeholder="you@example.com" required /> ``` ### Props In addition to all [common form input props](#common-form-input-props), `Input` accepts: | Prop | Type | Default | Description | | ------------------------- | ------------------------------------------------------------------------ | --------- | ---------------------------------------------------------------------------------------------- | | `inputType` | `text` \| `email` \| `password` \| `number` \| `tel` \| `url` | `text` | The type of data the input accepts. Controls keyboard layout on mobile and browser validation. | | `placeholder` | string | — | Hint text displayed when the input is empty. | | `defaultValue` | string | — | Initial value of the input. | | `variant` | `soft` \| `outline` | `outline` | Visual style of the input. | | `size` | `3xs` \| `2xs` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `2xl` \| `3xl` | `md` | Controls the overall size of the input. | | `gutterSize` | `2xs` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` | — | Inner horizontal padding of the input. | | `pattern` | string | — | A regex pattern the input value must match for validation. | | `pill` | boolean | `false` | Renders the input with fully rounded corners. | | `autoFocus` | boolean | `false` | Automatically focuses the input when the widget loads. | | `autoSelect` | boolean | `false` | Selects all text in the input when it receives focus. | | `allowAutofillExtensions` | boolean | `false` | Allows browser autofill extensions to interact with the input. | *** ## Textarea A multi-line text input for collecting longer-form content like messages or descriptions. ```jsx theme={null} <Textarea name="message" placeholder="Type your message..." rows={4} /> ``` ### Props In addition to all [common form input props](#common-form-input-props), `Textarea` accepts: | Prop | Type | Default | Description | | ------------------------- | ------------------------------------------------------------------------ | --------- | ------------------------------------------------------------------------------- | | `placeholder` | string | — | Hint text displayed when the textarea is empty. | | `defaultValue` | string | — | Initial value of the textarea. | | `rows` | number | — | Number of visible text lines. | | `autoResize` | boolean | `false` | Automatically adjusts the height as the user types. | | `maxRows` | number | — | Maximum number of rows the textarea can expand to when `autoResize` is enabled. | | `variant` | `soft` \| `outline` | `outline` | Visual style of the textarea. | | `size` | `3xs` \| `2xs` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `2xl` \| `3xl` | `md` | Controls the overall size of the textarea. | | `gutterSize` | `2xs` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` | — | Inner horizontal padding of the textarea. | | `autoFocus` | boolean | `false` | Automatically focuses the textarea when the widget loads. | | `autoSelect` | boolean | `false` | Selects all text in the textarea when it receives focus. | | `allowAutofillExtensions` | boolean | `false` | Allows browser autofill extensions to interact with the textarea. | *** ## Select A dropdown for choosing one option from a list. Supports search, clearing, and custom option descriptions. ```jsx theme={null} <Select name="country" placeholder="Choose a country" options={countries} /> ``` ### Props In addition to all [common form input props](#common-form-input-props), `Select` accepts: | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------------------ | --------- | ----------------------------------------------------------------- | | `options` | `{label, value, disabled?, description?}[]` | — | The list of options to display in the dropdown. | | `placeholder` | string | — | Hint text displayed when no option is selected. | | `defaultValue` | string | — | The initially selected value. | | `variant` | `soft` \| `outline` \| `ghost` | `outline` | Visual style. `ghost` renders a minimal, borderless appearance. | | `size` | `3xs` \| `2xs` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `2xl` \| `3xl` | `md` | Controls the overall size of the select. | | `block` | boolean | `false` | Makes the select stretch to fill the full width of its container. | | `pill` | boolean | `false` | Renders the select with fully rounded corners. | | `clearable` | boolean | `false` | Shows a clear button to reset the selection. | | `searchable` | boolean | `false` | Enables a search field within the dropdown to filter options. | <Note> Each option in the `options` array requires a `label` (displayed text) and a `value` (submitted data). You can optionally include `disabled` to gray out an option or `description` to show helper text below the label. </Note> *** ## DatePicker A calendar-based date selector rendered inside a popover. Use it for collecting dates with optional min/max constraints. ```jsx theme={null} <DatePicker name="startDate" placeholder="Pick a date" min="2025-01-01" max="2025-12-31" /> ``` ### Props In addition to all [common form input props](#common-form-input-props), `DatePicker` accepts: | Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------------------ | --------- | ---------------------------------------------------------------------- | | `placeholder` | string | — | Hint text displayed when no date is selected. | | `defaultValue` | string (`yyyy-MM-dd`) | — | The initially selected date. | | `min` | string (`yyyy-MM-dd`) | — | The earliest selectable date. | | `max` | string (`yyyy-MM-dd`) | — | The latest selectable date. | | `variant` | `soft` \| `outline` \| `ghost` | `outline` | Visual style. `ghost` shows a compact, minimal format. | | `size` | `3xs` \| `2xs` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `2xl` \| `3xl` | `md` | Controls the overall size of the date picker trigger. | | `side` | `top` \| `bottom` \| `left` \| `right` | — | Preferred side for the calendar popover to open. | | `align` | `start` \| `center` \| `end` | — | Alignment of the calendar popover relative to the trigger. | | `block` | boolean | `false` | Makes the date picker stretch to fill the full width of its container. | | `pill` | boolean | `false` | Renders the trigger with fully rounded corners. | | `clearable` | boolean | `false` | Shows a clear button to reset the selected date. | *** ## Checkbox A single toggle for boolean choices, rendered with an accompanying label. ```jsx theme={null} <Checkbox name="agree" label="I agree to the terms" /> ``` ### Props In addition to all [common form input props](#common-form-input-props), `Checkbox` accepts: | Prop | Type | Default | Description | | ---------------- | ----------------- | ------- | ------------------------------------------ | | `label` | string | — | Text displayed next to the checkbox. | | `defaultChecked` | boolean \| string | `false` | Whether the checkbox is initially checked. | *** ## RadioGroup A group of radio buttons for selecting exactly one option from a set. Supports horizontal or vertical layout. ```jsx theme={null} <RadioGroup name="plan" options={[ { label: "Free", value: "free" }, { label: "Pro", value: "pro" } ]} defaultValue="free" direction="col" /> ``` ### Props In addition to all [common form input props](#common-form-input-props), `RadioGroup` accepts: | Prop | Type | Default | Description | | -------------- | ----------------------------- | ------- | ------------------------------------------------------------------------- | | `options` | `{label, value, disabled?}[]` | — | The list of radio options to display. | | `defaultValue` | string | — | The initially selected value. | | `direction` | `col` \| `row` | `row` | Controls whether options are stacked vertically or laid out horizontally. | | `ariaLabel` | string | — | Accessible label for the radio group, used by screen readers. | *** ## Slider A draggable slider for picking a numeric value between a minimum and maximum — quantities, ratings, budgets, or parameter adjustment. The value is submitted as a number. ```jsx theme={null} <Slider name="budget" min={0} max={500} step={10} defaultValue={100} label="Budget" showValue minLabel="$0" maxLabel="$500" /> ``` ### Props In addition to all [common form input props](#common-form-input-props), `Slider` accepts: | Prop | Type | Default | Description | | -------------- | ---------------- | ------- | ------------------------------------------------------------------------------------------------- | | `min` | number | `0` | The lowest selectable value. | | `max` | number | `100` | The highest selectable value. | | `step` | number | `1` | The increment between selectable values. | | `defaultValue` | number | `min` | The initially selected value. Clamped into the `min`–`max` range. | | `label` | string | — | Label displayed above the slider track. | | `showValue` | boolean | `false` | Shows the live value to the right of the label, updating as the user drags. | | `minLabel` | string | — | Small caption displayed under the left end of the track. | | `maxLabel` | string | — | Small caption displayed under the right end of the track. | | `block` | boolean | `true` | Makes the slider stretch to fill the full width of its container. Set `block={false}` to opt out. | | `width` | number \| string | — | Explicit width for the slider. Takes precedence over `block`. | <Tip> `onChangeAction` fires once when the user releases the thumb (or finishes a keyboard adjustment), not on every tick while dragging — so it's safe to wire it to a server function. The current value is always available in the widget's data under the slider's `name`. </Tip> # Interactive Source: https://chatbase.co/docs/developer-guides/widgets/components/interactive Interactive components for user actions — Button. ## Button A clickable button that triggers a function when pressed. Buttons are the primary way users interact with your widget, whether submitting forms, navigating between views, or performing actions. ```jsx theme={null} <Button label="Submit" onClickAction={{ functionName: "submit" }} variant="solid" color="primary" /> ``` ### Props | Prop | Type | Default | Description | | --------------- | ---------------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------- | | `label` | string | — | Button text. | | `onClickAction` | action | — | Function to run when clicked. | | `variant` | `solid` \| `soft` \| `outline` \| `ghost` | `solid` | Visual style of the button. | | `color` | `primary` \| `secondary` \| `success` \| `danger` \| `warning` \| `info` \| `discovery` \| `caution` | `secondary` | Button color. | | `size` | `3xs` \| `2xs` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `2xl` \| `3xl` | `md` | Button size. | | `iconStart` | icon name | — | Icon displayed before the label. | | `iconEnd` | icon name | — | Icon displayed after the label. | | `iconSize` | `sm` \| `md` \| `lg` \| `xl` \| `2xl` | — | Size of the start and end icons. | | `submit` | boolean | `false` | Submit the parent form when clicked. | | `block` | boolean | `false` | Stretch the button to full width. | | `pill` | boolean | `false` | Apply fully rounded corners. | | `uniform` | boolean | `false` | Equal width and height, creating a square button. | | `disabled` | boolean | `false` | Disable the button, preventing interaction. | <Tip> The `onClickAction` prop accepts an object with a `functionName` key that maps to one of your widget's defined functions. You can also pass an `additionalInputs` object to send extra data along with the action. </Tip> *** ### Examples #### Basic Action Button A simple button that triggers a named function when clicked. ```jsx theme={null} <Button label="Refresh" onClickAction={{ functionName: "refresh" }} variant="solid" color="primary" /> ``` #### Form Submit Button Use the `submit` prop to make the button submit its parent form. Pair this with a `Card` that has `asForm` set to `true`. ```jsx theme={null} <Card asForm> <Col gap={3}> <TextInput name="email" label="Email" /> <Button label="Subscribe" submit variant="solid" color="success" /> </Col> </Card> ``` <Info> When `submit` is `true`, clicking the button collects all input values from the parent form and passes them to the function defined in the `Card`'s `confirm` action or the button's own `onClickAction`. </Info> #### Icon Button Add icons before or after the label using `iconStart` and `iconEnd`. Use the `uniform` prop to create a square icon-only button. ```jsx theme={null} <Button label="Download" onClickAction={{ functionName: "download" }} iconStart="arrow-down-to-line" variant="outline" color="info" /> ``` ```jsx theme={null} <Button label="" onClickAction={{ functionName: "settings" }} iconStart="gear" uniform variant="ghost" /> ``` #### Full-Width Button Set `block` to `true` to make the button span the entire width of its container. ```jsx theme={null} <Button label="Continue to Checkout" onClickAction={{ functionName: "checkout" }} variant="solid" color="primary" block /> ``` #### Button with Additional Inputs Pass extra data alongside the action using `additionalInputs`. This is especially useful when rendering buttons in a loop, where each button needs to reference a specific item. ```jsx theme={null} {items.map((item) => ( <Button label={item.name} onClickAction={{ functionName: "selectItem", additionalInputs: { itemId: item.id } }} variant="outline" /> ))} ``` <Tip> The `additionalInputs` object is merged with any form data when the action is triggered. Use it to attach contextual identifiers like IDs, indexes, or metadata to button clicks. </Tip> # Layout Source: https://chatbase.co/docs/developer-guides/widgets/components/layout Layout components for structuring widget content — Card, Box, Col, Row, Spacer, Divider, ListView, and ListViewItem. ## Common Layout Props `Box`, `Col`, and `Row` all share the following props for controlling spacing, sizing, and alignment. | Prop | Type | Description | | ------------ | ------------------------------------------------------------------------------ | -------------------------------------------------------------- | | `padding` | spacing | Inner spacing. | | `border` | border | Border width, color, and style. | | `radius` | radius | Corner rounding. | | `background` | color | Background color. | | `width` | number \| string | Explicit width. | | `height` | number \| string | Explicit height. | | `minWidth` | number \| string | Minimum width constraint. | | `maxWidth` | number \| string | Maximum width constraint. | | `minHeight` | number \| string | Minimum height constraint. | | `maxHeight` | number \| string | Maximum height constraint. | | `gap` | number \| string | Spacing between children. | | `align` | `start` \| `center` \| `end` \| `baseline` \| `stretch` | Cross-axis alignment. | | `justify` | `start` \| `center` \| `end` \| `between` \| `around` \| `evenly` \| `stretch` | Main-axis distribution. | | `flex` | number \| string | Flex grow/shrink behavior. | | `flush` | boolean | Extend to parent edges, ignoring padding. Defaults to `false`. | | `scrollable` | boolean | Enable scrolling when content overflows. Defaults to `false`. | <Tip> These common props let you control layout behavior consistently across `Box`, `Col`, and `Row` without needing to remember different APIs for each. </Tip> *** ## Card The root container for widget content. Every widget code starts with a `Card` component as the outermost wrapper. ```jsx theme={null} <Card size="md"> <Title value={title} size="sm" /> <Text value={description} color="secondary" /> </Card> ``` ### Props | Prop | Type | Default | Description | | ------------ | --------------------------------------------- | ------- | --------------------------------------------------- | | `size` | `sm` \| `md` \| `lg` \| `full` | `md` | Controls the overall width of the card. | | `padding` | spacing | — | Inner spacing of the card. | | `background` | color | — | Background color. | | `border` | border | — | Border width, color, and style. | | `status` | `{text, icon?}` or `{text, favicon?, frame?}` | — | Displays a status indicator at the top of the card. | | `confirm` | `{label, action}` | — | Adds a confirm button to the card footer. | | `cancel` | `{label, action}` | — | Adds a cancel button to the card footer. | | `asForm` | boolean | `false` | Wraps the card content in a form element. | | `collapsed` | boolean | `false` | Renders the card in a collapsed state. | | `theme` | `light` \| `dark` | — | Forces a specific color theme for the card. | <Note> When `confirm` or `cancel` are provided, the card automatically renders action buttons in the footer. If `asForm` is `true`, the confirm button acts as the form submit button. </Note> *** ## Box A generic flex container for arranging child elements in any direction. ```jsx theme={null} <Box direction="row" align="center" gap={3} padding={4}> <Icon name="star" /> <Text value="Featured" /> </Box> ``` ### Props In addition to all [common layout props](#common-layout-props), `Box` accepts: | Prop | Type | Default | Description | | ------------- | ------------------------------------ | ------- | ------------------------------------------------------------------ | | `direction` | `row` \| `col` | — | Sets the flex direction of the container. | | `wrap` | `nowrap` \| `wrap` \| `wrap-reverse` | — | Controls whether children wrap to new lines. | | `size` | number \| string | — | Shorthand for setting both `width` and `height` to the same value. | | `minSize` | number \| string | — | Shorthand for setting both `minWidth` and `minHeight`. | | `maxSize` | number \| string | — | Shorthand for setting both `maxWidth` and `maxHeight`. | | `aspectRatio` | number \| string | — | Sets a fixed aspect ratio for the container. | *** ## Col A vertical flex container. This is a shorthand for `Box` with a column direction, making it the go-to choice for stacking elements vertically. ```jsx theme={null} <Col gap={2}> <Title value={title} size="sm" /> <Text value={subtitle} color="secondary" /> </Col> ``` ### Props `Col` accepts all [common layout props](#common-layout-props) and the same additional props as `Box` (`wrap`, `size`, `minSize`, `maxSize`, `aspectRatio`), except `direction`, which is always set to column. *** ## Row A horizontal flex container. This is a shorthand for `Box` with a row direction, making it the go-to choice for placing elements side by side. ```jsx theme={null} <Row gap={3} align="center"> <Image src={avatar} size={40} radius="full" /> <Text value={name} weight="semibold" /> <Spacer /> <Button label="View" variant="outline" /> </Row> ``` ### Props `Row` accepts all [common layout props](#common-layout-props) and the same additional props as `Box` (`wrap`, `size`, `minSize`, `maxSize`, `aspectRatio`), except `direction`, which is always set to row. <Info> Combine `Row` with `Spacer` to push elements to opposite ends of a container — a common pattern for headers, toolbars, and list items. </Info> *** ## Spacer A flexible empty space that expands to fill available room along the main axis. Use it to push sibling elements apart within a `Row` or `Col`. ```jsx theme={null} <Row> <Text value="Left" /> <Spacer /> <Text value="Right" /> </Row> ``` ### Props | Prop | Type | Default | Description | | --------- | ---------------- | ------- | ------------------------------------------------------------------------------- | | `minSize` | number \| string | — | Sets a minimum size for the spacer, ensuring it never shrinks below this value. | *** ## Divider A horizontal line separator for visually breaking content into sections. ```jsx theme={null} <Col> <Text value="Section 1" /> <Divider /> <Text value="Section 2" /> </Col> ``` ### Props | Prop | Type | Default | Description | | --------- | ---------------- | ------- | --------------------------------------------------------- | | `spacing` | number \| string | — | Vertical space above and below the divider. | | `color` | color | — | Color of the divider line. | | `size` | number \| string | — | Thickness of the divider line. | | `flush` | boolean | `false` | Extend the divider to the parent edges, ignoring padding. | *** ## ListView A scrollable list container for rendering collections of items. Use with `ListViewItem` to define each entry. ```jsx theme={null} <ListView orientation="vertical" gap={2} limit={5}> <ListViewItem> <Text value={itemName} /> </ListViewItem> </ListView> ``` ### Props | Prop | Type | Default | Description | | ------------- | --------------------------------------------- | ------- | ------------------------------------------------- | | `orientation` | `horizontal` \| `vertical` | — | Scroll direction of the list. | | `gap` | number | — | Spacing between list items. | | `limit` | number \| `"auto"` | — | Maximum number of visible items before scrolling. | | `status` | `{text, icon?}` or `{text, favicon?, frame?}` | — | Displays a status indicator on the list. | | `theme` | `light` \| `dark` | — | Forces a specific color theme for the list. | <Tip> Set `limit` to control how many items are visible at once. Items beyond the limit become accessible through scrolling, keeping the widget compact. </Tip> *** ## ListViewItem An individual item inside a `ListView`. Items can be made interactive by providing an `onClickAction`. ```jsx theme={null} <ListViewItem onClickAction={{ functionName: "selectItem" }} gap={3} align="center"> <Image src={thumbnail} size={40} /> <Text value={itemName} /> </ListViewItem> ``` ### Props | Prop | Type | Default | Description | | --------------- | ---------- | ------- | ----------------------------------------------------------------------- | | `align` | flex align | — | Cross-axis alignment of the item's children. | | `gap` | number | — | Spacing between child elements within the item. | | `onClickAction` | action | — | Action to execute when the item is clicked. Makes the item interactive. | <Info> When `onClickAction` is set, the item renders as a clickable element with hover and focus styles applied automatically. </Info> # Media & Visual Source: https://chatbase.co/docs/developer-guides/widgets/components/media Visual components for icons, images, badges, and animations. ## Icon Displays an icon from the [Lucide](https://lucide.dev/icons) icon library. All \~1,600+ Lucide icons are supported, referenced by their kebab-case name. Use icons to add visual context to labels, buttons, cards, and other elements. ```jsx theme={null} <Icon name="map-pin" size="xl" color="primary" /> ``` ### Props | Prop | Type | Default | Description | | :--------- | :------------------------------------------------------------------- | :-------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **name** | `string` | — | The icon to display. Accepts any [Lucide icon name](https://lucide.dev/icons) in kebab-case (e.g. `"heart"`, `"calendar-days"`, `"arrow-right"`) or a [custom alias](#custom-icon-aliases). | | **size** | `"xs"` \| `"sm"` \| `"md"` \| `"lg"` \| `"xl"` \| `"2xl"` \| `"3xl"` | `"md"` | Controls the rendered size of the icon. | | **stroke** | `number` | `2` | Stroke width of the icon. | | **fill** | `string` | `"transparent"` | Fill color of the icon. Use `"currentColor"` for a filled appearance. | | **color** | `string` | — | Sets the icon color. Accepts theme tokens like `primary`, `secondary`, `success`, `danger`, etc. | ### Icon field format When specifying an icon in component props that accept an icon value, you can use either format: * **A plain string** -- just the icon name: ```json theme={null} "heart" ``` * **An object** -- with optional styling overrides: ```json theme={null} { "name": "heart", "stroke": 1.5, "fill": "currentColor" } ``` ### Custom icon aliases In addition to the full Lucide set, the following semantic aliases are available for convenience: | Alias | Lucide Icon | | :-------------------- | :------------------- | | `agent` | `bot` | | `analytics` | `chart-bar` | | `batch` | `layers` | | `bolt` | `zap` | | `book-clock` | `book-marked` | | `check-circle-filled` | `circle-check` | | `circle-question` | `circle-help` | | `confetti` | `party-popper` | | `lifesaver` | `life-buoy` | | `maps` | `map` | | `mobile` | `smartphone` | | `name` | `user` | | `notebook-pencil` | `notebook-pen` | | `page-blank` | `file` | | `profile` | `user` | | `profile-card` | `id-card` | | `reload` | `refresh-cw` | | `settings-slider` | `sliders-horizontal` | | `sparkle-double` | `sparkles` | | `sparkle` | `sparkles` | | `square-code` | `code` | | `square-image` | `image` | | `square-text` | `text` | | `star-filled` | `star` | | `suitcase` | `briefcase` | | `wreath` | `award` | | `write` | `pencil` | | `write-alt` | `pen-tool` | | `write-alt2` | `square-pen` | | `close` | `x` | | `add` | `plus` | | `remove` | `minus` | | `delete` | `trash-2` | | `edit` | `pencil` | | `success` | `circle-check` | | `error` | `circle-x` | | `warning` | `triangle-alert` | | `caution` | `triangle-alert` | | `danger` | `octagon-alert` | | `discovery` | `sparkles` | | `back` | `arrow-left` | | `forward` | `arrow-right` | | `up` | `arrow-up` | | `down` | `arrow-down` | | `stop` | `square` | | `paste` | `clipboard` | | `attachment` | `paperclip` | | `external` | `external-link` | | `rain` | `cloud-rain` | | `snow` | `snowflake` | | `arrow-down-az` | `arrow-down-az` | | `arrow-down-za` | `arrow-down-za` | | `arrow-up-az` | `arrow-up-az` | | `arrow-up-za` | `arrow-up-za` | <Tip> Browse the full icon set at [lucide.dev/icons](https://lucide.dev/icons). Any icon listed there can be used by its kebab-case name. </Tip> *** ## Image Displays an image with flexible sizing, fitting, and theme-aware source support. ```jsx theme={null} <Image src={productImage} width={120} height={120} radius="md" fit="cover" /> ``` You can also provide separate images for light and dark themes: ```jsx theme={null} <Image src={{ light: lightLogo, dark: darkLogo }} width={200} height={60} fit="contain" /> ``` ### Props | Prop | Type | Default | Description | | :---------------- | :----------------------------------------------------------------------------------------------------------------------------------- | :--------- | :------------------------------------------------------------------------------------------------------------------- | | **src** | `string` \| `{ light: string, dark: string }` | — | Image source URL. Pass an object with `light` and `dark` keys to display different images based on the active theme. | | **alt** | `string` | — | Alternative text for accessibility. | | **size** | `number` | — | Square shorthand — sets both `width` and `height` to the same value. | | **width** | `number` | — | Image width in pixels. | | **height** | `number` | — | Image height in pixels. | | **minWidth** | `number` | — | Minimum width constraint. | | **maxWidth** | `number` | — | Maximum width constraint. | | **minHeight** | `number` | — | Minimum height constraint. | | **maxHeight** | `number` | — | Maximum height constraint. | | **minSize** | `number` | — | Minimum size shorthand (applies to both dimensions). | | **maxSize** | `number` | — | Maximum size shorthand (applies to both dimensions). | | **aspectRatio** | `number` | — | Aspect ratio for the image container (e.g., `16/9`). | | **radius** | `string` | — | Border radius token (e.g., `"sm"`, `"md"`, `"lg"`, `"full"`). | | **background** | `string` | — | Background color behind the image. | | **flex** | `number` | — | Flex grow/shrink value for layout sizing. | | **fit** | `"cover"` \| `"contain"` \| `"fill"` \| `"scale-down"` \| `"none"` | — | How the image fills its container, matching the CSS `object-fit` property. | | **position** | `"center"` \| `"top"` \| `"bottom"` \| `"left"` \| `"right"` \| `"top left"` \| `"top right"` \| `"bottom left"` \| `"bottom right"` | `"center"` | Alignment of the image within its container when `fit` causes cropping. | | **frame** | `boolean` | — | When `true`, wraps the image in a subtle border frame. | | **flush** | `boolean` | — | When `true`, removes default padding around the image. | | **onClickAction** | `string` | — | Function name to invoke when the image is clicked. | <Info> Use `fit="cover"` with a fixed `width` and `height` to crop images into consistent thumbnails. Use `fit="contain"` when you need to show the full image without cropping. </Info> *** ## Badge A small label used to indicate status, categories, or tags. ```jsx theme={null} <Badge label="Active" color="success" variant="soft" /> ``` ```jsx theme={null} <Badge label="Overdue" color="danger" variant="solid" pill /> ``` ### Props | Prop | Type | Default | Description | | :---------- | :------------------------------------------------------------------------------------- | :------------ | :------------------------------------------------------------------------------------------------------------------ | | **label** | `string` | — | The text displayed inside the badge. | | **color** | `"secondary"` \| `"success"` \| `"danger"` \| `"warning"` \| `"info"` \| `"discovery"` | `"secondary"` | Semantic color of the badge. | | **variant** | `"solid"` \| `"soft"` \| `"outline"` | `"soft"` | Visual style. `solid` uses a filled background, `soft` uses a tinted background, and `outline` shows only a border. | | **size** | `"sm"` \| `"md"` \| `"lg"` | `"sm"` | Controls the size of the badge. | | **pill** | `boolean` | — | When `true`, applies fully rounded corners for a pill shape. | <Tip> Combine badges with layout components to build tag lists or status indicators inside cards and tables. </Tip> *** ## Transition Wraps a child element with a fade-in and fade-out animation. Use this to add polish when content appears or disappears — for example, when toggling visibility with states. ```jsx theme={null} <Transition> <Text value="This fades in" /> </Transition> ``` The animation applies a 0.2-second fade with a slight vertical slide. There are no configurable props — simply wrap any element to enable the effect. <Info> Transition works well with [States](/docs/developer-guides/widgets/states) to animate content that conditionally appears based on user input or data changes. </Info> # Text Source: https://chatbase.co/docs/developer-guides/widgets/components/text Text components for displaying content — Text, Title, Caption, Label, and Markdown. Text components handle all readable content in your widget — from body copy and headings to form labels and Markdown-formatted blocks. Five components cover the full range of text needs: **Text**, **Title**, **Caption**, **Label**, and **Markdown**. ## Common Props The **Text**, **Title**, and **Caption** components share a set of common props for controlling content and appearance. | Prop | Type | Default | Description | | ----------- | ---------------------------- | ------- | --------------------------------------------------------------------- | | `value` | `string` | — | The text content to display. | | `color` | `color` | — | Text color. | | `textAlign` | `start` \| `center` \| `end` | — | Horizontal text alignment. | | `truncate` | `boolean` | `false` | Truncate overflowing text with an ellipsis. | | `maxLines` | `number` | — | Maximum number of visible lines. Content beyond this limit is hidden. | *** ## Text The most common component for displaying body text. Use it for dynamic content such as descriptions, paragraphs, and inline values. ```jsx theme={null} <Text value={description} size="sm" color="secondary" maxLines={3} /> ``` ### Props In addition to the [common props](#common-props), `Text` supports: | Prop | Type | Default | Description | | ------------- | -------------------------------------------- | -------- | ------------------------------------------------------------ | | `size` | `xs` \| `sm` \| `md` \| `lg` \| `xl` | `md` | Font size. | | `weight` | `normal` \| `medium` \| `semibold` \| `bold` | `normal` | Font weight. | | `width` | `number` | — | Fixed width for the text element. | | `italic` | `boolean` | — | Render text in italic. | | `lineThrough` | `boolean` | — | Apply a strikethrough style. | | `tabularNums` | `boolean` | — | Use tabular (monospaced) number figures for aligned columns. | | `minLines` | `number` | — | Minimum number of lines the element occupies. | <Tip> Use `tabularNums` when displaying numbers in tables or lists — it ensures digits are evenly spaced so columns stay aligned. </Tip> *** ## Title Heading text with larger, bolder sizing. Use it for section headers, card titles, and any prominent label. ```jsx theme={null} <Title value="Order Summary" size="lg" /> ``` ### Props In addition to the [common props](#common-props), `Title` supports: | Prop | Type | Default | Description | | ------------- | ------------------------------------------------------------------------------------------- | ------- | ---------------------------------------- | | `size` | `xs` \| `sm` \| `md` \| `base` \| `lg` \| `xl` \| `2xl` \| `3xl` \| `4xl` \| `5xl` \| `6xl` | `md` | Font size. | | `weight` | `normal` \| `medium` \| `semibold` \| `bold` | `bold` | Font weight. | | `width` | `number` | — | Fixed width for the title element. | | `tabularNums` | `boolean` | — | Use tabular (monospaced) number figures. | *** ## Caption Smaller secondary text for annotations, timestamps, and supplementary details. Caption preserves line breaks in the provided value. ```jsx theme={null} <Caption value="Last updated 2 minutes ago" size="sm" color="secondary" /> ``` ### Props In addition to the [common props](#common-props), `Caption` supports: | Prop | Type | Default | Description | | -------- | -------------------------------------------- | -------- | ------------ | | `size` | `sm` \| `md` \| `lg` | `md` | Font size. | | `weight` | `normal` \| `medium` \| `semibold` \| `bold` | `normal` | Font weight. | <Info> Caption automatically preserves line breaks (`\n`) in the value string, so you can pass multi-line content without additional formatting. </Info> *** ## Label A text label designed for form fields. Place it directly above an `Input`, `Select`, or other form control to provide a visible, accessible label. ```jsx theme={null} <Label value="Email address" fieldName="email" /> <Input name="email" placeholder="you@example.com" /> ``` ### Props | Prop | Type | Default | Description | | ----------- | -------------------------------------------- | ------- | ------------------------------------------------------ | | `value` | `string` | — | The label text. | | `fieldName` | `string` | — | The `name` of the input this label is associated with. | | `size` | `xs` \| `sm` \| `md` \| `lg` \| `xl` | `md` | Font size. | | `weight` | `normal` \| `medium` \| `semibold` \| `bold` | — | Font weight. | <Tip> Always set `fieldName` to match the `name` prop of the corresponding input. This links the label to the field for accessibility and click-to-focus behavior. </Tip> *** ## Markdown Renders Markdown-formatted text, including headings, lists, links, code blocks, and inline formatting. ```jsx theme={null} <Markdown value={instructions} /> ``` ### Props | Prop | Type | Default | Description | | ------- | -------- | ------- | ------------------------------- | | `value` | `string` | — | The Markdown content to render. | # Functions Source: https://chatbase.co/docs/developer-guides/widgets/functions Configure what happens when users interact with widget elements — API calls, messages, navigation, and data updates. Functions define the behavior behind interactive widget elements like buttons and forms. You attach a function to an element by referencing its **function name**, and the function's **type** determines what happens when a user triggers it. ## Function Types Each function type serves a different purpose. Select the type that matches the action you want to perform. <AccordionGroup> <Accordion title="Server Function"> Makes a request to an external API. The configuration is never visible to the end user. | Setting | Description | | :-------------------- | :---------------------------------------------------------------------------------------------- | | **URL** | The endpoint to send the request to. Supports [template tokens](#template-tokens). | | **Method** | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`. | | **Headers** | Key-value pairs sent as request headers. Supports [template tokens](#template-tokens). | | **Parameters** | Query parameters appended to the URL. Supports [template tokens](#template-tokens). | | **Body** | Request body (for `POST`, `PUT`, `PATCH`). Supports [template tokens](#template-tokens). | | **Return Fields** | Fields to extract from the response for use in follow-up actions. | | **On Success** | [Follow-up action](#after-a-function-runs) when the request succeeds. | | **On Failure** | [Follow-up action](#after-a-function-runs) when the request fails. | | **Additional Inputs** | Extra data passed in at the call site in the code. See [Additional Inputs](#additional-inputs). | </Accordion> <Accordion title="Client Function"> Sends a message to the parent webpage. This is designed for widgets embedded inside iframes that need to communicate with the host page. | Setting | Description | | :-------------------- | :---------------------------------------------------------------------------------------------- | | **Wait for Response** | Whether to wait for a response from the parent page (up to 60 seconds). | | **Inputs** | Key-value pairs sent in to the client side code. Supports [template tokens](#template-tokens). | | **Return Fields** | Fields to extract from the client side code's response. | | **On Success** | [Follow-up action](#after-a-function-runs) when the parent responds successfully. | | **On Failure** | [Follow-up action](#after-a-function-runs) when the communication fails. | | **Additional Inputs** | Extra data passed in at the call site in the code. See [Additional Inputs](#additional-inputs). | </Accordion> <Accordion title="Send Message Function"> Sends a message into the current conversation. | Setting | Description | | :-------------------- | :----------------------------------------------------------------------------------------------------- | | **Message Template** | The message content. Use `{{fieldName}}` [template tokens](#template-tokens) to insert dynamic values. | | **Hide Message** | When enabled, the message is sent in the background and not displayed to the user. | | **On Execute** | [Follow-up action](#after-a-function-runs) that runs after the message is sent. | | **Additional Inputs** | Extra data passed in at the call site in the code. See [Additional Inputs](#additional-inputs). | </Accordion> <Accordion title="Link Function"> Opens a URL in a new browser tab. | Setting | Description | | :-------------------- | :---------------------------------------------------------------------------------------------- | | **URL** | The URL to open. Supports [template tokens](#template-tokens). | | **On Execute** | [Follow-up action](#after-a-function-runs) that runs after the link is opened. | | **Additional Inputs** | Extra data passed in at the call site in the code. See [Additional Inputs](#additional-inputs). | </Accordion> <Accordion title="Dismiss Function"> Closes the widget. There are two ways to use this: 1. **Directly** — Attach it to a button so the user can close the widget on click. 2. **As a follow-up** — Use it as the follow-up action on another function (e.g., close the widget after a successful API call). <Note> Dismissal state is persisted. If a user dismisses a widget, it stays dismissed even after a page refresh. </Note> </Accordion> <Accordion title="Set Variables Function"> Updates widget data values without making any external calls. Useful for storing user selections or transforming data between steps. | Setting | Description | | :-------------------- | :---------------------------------------------------------------------------------------------- | | **Variables** | Key-value pairs to set. Values support [template tokens](#template-tokens). | | **Additional Inputs** | Extra data passed in at the call site in the code. See [Additional Inputs](#additional-inputs). | </Accordion> </AccordionGroup> ## Loading Behavior When a function runs, you can control how the UI indicates progress. | Value | Behavior | | :------------ | :----------------------------------------- | | **None** | No loading indicator is shown. | | **Self** | The triggering element displays a spinner. | | **Container** | The entire widget shows a loading overlay. | ## Additional Inputs Sometimes a function needs extra context that depends on where it is called. For example, you might have a list of classes, each with a "Book" button that should pass a different `classId` to the same function. ```jsx theme={null} {classes.map((item) => ( <Button label={item.name} onClickAction={{ functionName: "bookClass", additionalInputs: { classId: item.id } }} /> ))} ``` Once provided, you can reference additional inputs as [template tokens](#template-tokens) anywhere the function accepts them — in the URL, headers, body, or parameters. For the example above, use `{{classId}}` to insert the value. <Warning> Additional inputs are **not** variables. They only exist for the duration of the function execution. If you need to persist a value, use a **Set Variables** follow-up action to save it after the function runs. </Warning> ## After a Function Runs Every function supports a follow-up action that runs after it completes. * **Server Function** and **Client Function** provide two follow-up slots: **On Success** and **On Failure**. * **Send Message**, **Link**, **Dismiss**, and **Set Variables** functions provide a single **On Execute** slot. Each follow-up action can do one of the following: | Action | Description | | :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | | **Dismiss** | Closes the widget. The dismissal is persisted across page refreshes. | | **Set Variables** | Updates widget data values. For server and client function follow-ups, you can reference response data using [template tokens](#template-tokens). | ## Template Tokens Template tokens are placeholders written as `{{fieldName}}` that get replaced with current values at runtime. You can use them in any setting that supports dynamic content, including URLs, headers, body content, messages, and variables. <Tip> For follow-up actions on **Server** and **Client** functions, template tokens can also reference fields from the response data. This lets you capture API results and store them as widget variables for use elsewhere. </Tip> ## Results Every function produces one of two outcomes: | Outcome | Description | | :---------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Success** | The function completed. For server and client functions, the result may include response data that can be referenced in follow-up actions via [template tokens](#template-tokens). | | **Error** | The function failed. The result includes an error message describing what went wrong. | # Widgets Overview Source: https://chatbase.co/docs/developer-guides/widgets/overview Build interactive UI components that your AI agent can display inline during conversations — forms, cards, tables, charts, and more. ## What are Widgets? Widgets are interactive UI components that your AI agent can display inline during conversations. Instead of responding with plain text, the agent renders rich elements — forms, cards, tables, charts, buttons, and more — directly in the chat. This lets your agent collect structured input, present data visually, and trigger actions, all without leaving the conversation. ## What You Can Do with Widgets <CardGroup> <Card title="Collect Structured Input" icon="input-text"> Build forms with text inputs, dropdowns, date pickers, checkboxes, and other controls to gather data from users. </Card> <Card title="Display Rich Content" icon="table-layout"> Show cards, tables, charts, images, and Markdown-formatted text to present information clearly. </Card> <Card title="Trigger Actions" icon="bolt"> Connect buttons and form submissions to API calls, chat messages, URL navigation, or data updates. </Card> <Card title="React to User Input" icon="arrows-split-up-and-left"> Use conditions to show, hide, or switch views based on the current values in the widget. </Card> <Card title="Import and Export" icon="file-import"> Share widgets across agents and teams by exporting and importing `.widget` files. </Card> <Card title="AI-Assisted Building" icon="wand-magic-sparkles"> Generate widgets from natural language descriptions or start from pre-built templates. </Card> </CardGroup> ## Key Concepts Understanding these core concepts will help you build and configure widgets effectively. | Concept | Description | | ------------------- | ------------------------------------------------------------------------------------ | | **Code** | The visual layout of the widget, written using a built-in component library. | | **Schema** | Defines the data fields the widget expects from the agent and their types. | | **Default Example** | Initial values for all fields when the widget first renders. | | **Named Examples** | Saved data presets for previewing different scenarios in the builder. | | **Functions** | Actions attached to interactive elements that define what happens on interaction. | | **States** | Named wrappers whose visibility is controlled by conditions based on current values. | <Info> The **Schema** is how the agent knows what data to pass into the widget. Each field in the schema maps to a variable you can reference in the widget code. </Info> ## Connecting Widgets to Actions Widgets are always attached to an **action**. You create and manage widgets from within the [Custom Action](/docs/user-guides/chatbot/actions/custom-action) configuration page. When creating a custom action, select the **Server with UI (Widget)** or **Widget only (UI only)** action type to attach a widget. The action type determines how data flows into the widget. There are two types: <Tabs> <Tab title="Widget-Only Actions"> These actions have **no API URL** configured. The widget receives data directly from the action's input fields. You can either sync inputs with the widget schema automatically or define them manually. **Best suited for:** * Forms that collect user input * Informational cards and menus * Interactive elements that don't need external data </Tab> <Tab title="Server Actions with Widgets"> These actions have an **API URL** configured. The action calls your API first, then displays the widget using the response data. **Best suited for:** * Data lookups (order status, account details) * Live data displays (inventory, analytics) * Multi-step workflows that depend on server-side logic </Tab> </Tabs> ### Data Flow for Server Actions <Steps> <Step title="Agent triggers the action"> The AI agent decides to trigger the action and provides the required input data. </Step> <Step title="Action calls the API"> The action sends a request to your configured API URL with the input data. </Step> <Step title="API returns a response"> Your server processes the request and returns a JSON response. </Step> <Step title="Response is merged with action input"> The API response is combined with the original action input data. If both contain the same field, the API response takes priority. </Step> <Step title="Widget renders with combined data"> The widget receives the merged data and renders the UI accordingly. </Step> </Steps> ## Where Widget Data Comes From When a widget renders, its data can come from multiple sources. Higher-priority sources override lower ones. | Priority | Source | Description | | ----------- | ------------------- | ------------------------------------------------------ | | 1 (lowest) | **Default example** | The widget's default values defined in the builder. | | 2 | **Action input** | Data from the action's configured input fields. | | 3 (highest) | **API response** | Data returned from the API call (server actions only). | <Note> If a field is present in both the action input and the API response, the API response value wins. Default example values are only used when no other source provides the field. </Note> ## AI Response Transform Sometimes the data returned by your API doesn't match the widget's schema exactly. The **AI Response Transform** uses AI to automatically map the API response fields to the widget's expected schema. <Tip> The AI Response Transform is especially useful when you're connecting to third-party APIs where you don't control the response format, or when your API returns nested or differently-named fields that need to be flattened into the widget schema. </Tip> ## Import and Export You can share widgets between agents, teams, or projects using `.widget` files. <AccordionGroup> <Accordion title="Exporting a Widget"> 1. Open the widget in the builder. 2. Click the **more options** menu (three dots) in the top-right corner. 3. Select **Export** to download the widget as a `.widget` file. The exported file contains the widget's code, schema, default example, named examples, functions, and states. </Accordion> <Accordion title="Importing a Widget"> 1. Navigate to **Build > Widgets**. 2. Click the **Import** button. 3. Upload a `.widget` file from your computer. The imported widget will appear in your widgets list and can be attached to any action. </Accordion> </AccordionGroup> <Warning> Imported widgets do not include action configurations. After importing, you'll need to attach the widget to an action and configure the data flow. </Warning> # States Source: https://chatbase.co/docs/developer-guides/widgets/states Conditionally show or hide parts of your widget based on data values using states and conditions. ## What are States? States let you conditionally show or hide parts of your widget based on current data values. Each state has a **name**, a **visibility condition**, and wraps a section of content in the widget code. When a state is active, the content inside it is visible. When inactive, the content is hidden. ## Using States in the Code To use a state, wrap the components you want to control in a tag that matches the state name. For example, a state named "Loading" wraps content in a `<Loading>` tag: ```jsx theme={null} <Card size="md"> <Loading> <Text value="Please wait..." /> </Loading> <Title value={title} size="sm" /> <Text value={description} /> </Card> ``` When the "Loading" state is active, the `<Text value="Please wait..." />` element is visible. The rest of the widget renders normally regardless of the state. ## Multiple Active States Multiple states can be active at the same time. Each state independently controls the visibility of its own wrapped content. ```jsx theme={null} <Card size="md"> <LoggedIn> <Text value={`Welcome back, ${userName}`} /> </LoggedIn> <HasItems> <Text value={`You have ${itemCount} items in your cart`} /> </HasItems> <Button label="Continue" onClickAction={{ functionName: "next" }} /> </Card> ``` In this example, if both "LoggedIn" and "HasItems" states are active, the user sees the welcome message, the item count, and the button. If only "LoggedIn" is active, the item count is hidden but the welcome message and button still appear. ## Visibility Modes Each state has a visibility mode that determines when its content is shown. | Mode | Behavior | | ------------------ | ---------------------------------------------------------------- | | **Always visible** | The state is always active. Wrapped content is always shown. | | **Always hidden** | The state is never active. Wrapped content is always hidden. | | **Conditional** | The state is active only when its configured conditions are met. | <Tip> Use **Always visible** and **Always hidden** modes to quickly toggle sections on and off during development without removing conditions. </Tip> ## Operators When using conditional visibility, each condition compares a data field against a value using an operator. | Operator | Description | | ---------------- | --------------------------------------------------------------- | | **equal to** | Exact match against the comparison value. | | **not equal to** | Does not match the comparison value. | | **contains** | The field contains the comparison value as a substring. | | **not contains** | The field does not contain the comparison value as a substring. | | **greater than** | The field is greater than the comparison value. | | **less than** | The field is less than the comparison value. | | **is empty** | The field has no value. No comparison value is needed. | | **is not empty** | The field has a value. No comparison value is needed. | ## Combining Conditions You can combine multiple conditions using **AND** and **OR** connectors. * **AND** — All conditions must be true for the state to be active. * **OR** — At least one condition must be true for the state to be active. Each condition after the first specifies its connector to the previous condition. This lets you build expressions like: > `status` equal to "active" **AND** `role` equal to "admin" <Info> The connector (AND/OR) is set on each condition individually, starting from the second condition onward. The first condition has no connector. </Info> ## Condition Groups For more complex logic, you can nest conditions into groups. Each group is evaluated as a unit, and groups are connected to each other with AND or OR. This lets you express logic like: > (`status` equal to "active" **AND** `role` equal to "admin") **OR** (`status` equal to "active" **AND** `role` equal to "editor") In this example, the state is active when the status is "active" and the role is either "admin" or "editor." ## States Tab in the Builder You manage states from the **States** tab in the widget builder. Each state is displayed as a card with the following controls: * **Name** — The state name, which must match the tag used in the widget code. * **Visibility dropdown** — Choose between Always visible, Always hidden, or Conditional. * **Conditions** — When set to Conditional, configure one or more conditions with fields, operators, values, and connectors. * **Cancel / Done** — Discard or save your changes to the state. <Note> States are different from **Named Examples**. Named Examples are data presets used for previewing different scenarios in the builder. States control conditional visibility of widget content at runtime based on actual data values. </Note> # Frequently Asked Questions Source: https://chatbase.co/docs/faq/faq Find answers to common questions about Chatbase AI Agents, pricing, features, and technical implementation. Get quick answers to the most common questions about Chatbase. Can't find what you're looking for? [Contact our support team](https://www.chatbase.co/help) for personalized assistance. ## Getting Started <AccordionGroup> <Accordion title="What is Chatbase?"> Chatbase is a powerful AI platform that lets you create intelligent AI Agents trained on your specific data. Whether it's your website content, documents, or custom text, Chatbase transforms your information into an intelligent assistant that can: * **Handle customer support** 24/7 with accurate, relevant responses * **Capture and qualify leads** through intelligent conversations * **Provide instant answers** to frequently asked questions * **Integrate seamlessly** into websites, apps, or messaging platforms Think of it as creating your own custom ChatGPT, but trained specifically on your business information. </Accordion> <Accordion title="How quickly can I get started?"> You can have a fully functional AI Agent live on your website in **under 5 minutes**! Our [Quick Start guide](/docs/user-guides/quick-start/your-first-agent) walks you through each step. </Accordion> <Accordion title="Do I need technical skills to use Chatbase?"> **Not at all!** Chatbase is designed for non-technical users: ✅ **No coding required** - Simple copy-paste embed codes\ ✅ **Drag-and-drop** training data upload\ ✅ **Visual interface** for all configurations That said, developers love our powerful [API](/docs/api-reference/chat/chat-with-a-chatbot) for custom integrations. </Accordion> </AccordionGroup> ## Features & Capabilities <AccordionGroup> <Accordion title="What languages does Chatbase support?"> Chatbase supports **95+ languages** with intelligent language detection: * **Automatic detection:** Your AI Agent will respond in the same language users ask questions in * **Multi-language training:** Train with content in one language, get responses in another * **Popular languages include:** English, Spanish, French, German, Portuguese, Italian, Dutch, Russian, Chinese, Japanese, Korean, Arabic, and many more The AI automatically adapts to your users' preferred language, making it perfect for global businesses. </Accordion> <Accordion title="What types of data can I use to train my AI Agent?"> You can train your AI Agent with various data sources: <Tabs> <Tab title="Websites"> **Automatic crawling of your entire website** * Paste any URL and we'll crawl all linked pages * Perfect for businesses with existing websites * Automatically updates with new content </Tab> <Tab title="Documents"> **Upload files directly** * **Supported formats:** PDF, DOC, DOCX, TXT * **Use cases:** Manuals, FAQs, product docs, policies </Tab> <Tab title="Text snippets"> **Direct text input** * Paste content directly into the platform * Ideal for structured information </Tab> <Tab title="Q&A"> **Structured question and answer pairs** * Add specific questions with exact answers * Perfect for consistent responses to common queries * Helps ensure accurate answers to frequently asked questions * Easy to update and maintain specific information </Tab> <Tab title="Notion Integration"> **Connect your Notion workspace** * Sync with your existing knowledge base * Automatic updates when Notion content changes * Perfect for workspaces already using Notion </Tab> </Tabs> </Accordion> </AccordionGroup> ## Pricing & Credits <AccordionGroup> <Accordion title="How do message credits work?"> Message credits power your AI Agent conversations. Each response from your AI Agent consumes credits based on the AI model used: **Credit consumption per response:** * **GPT-5.2 | GPT 5.6 Terra | Gemini 2.5 Pro | Gemini 3.1 Pro | Gemini 3.5 Flash | Gemini 3.6 Flash | GLM 5.2 | Mistral Medium 3.5:** 2 credits ⚡ (Fast & efficient) * **Grok 3 | Claude 4.5 Sonnet | Claude 4.6 Sonnet:** 3 credits ⚡ (Enhanced performance, balanced power & speed) * **Grok 4 | GPT-5.5:** 4 credits ⚡ (Advanced reasoning) * **Claude 4.5 Opus | Claude 4.6 Opus:** 5 credits ⚡ (Deep analysis & long-form reasoning) * **Claude 4.7 Opus | Claude 4.8 Opus:** 6 credits ⚡ (Enhanced deep analysis & advanced reasoning) * **All other models**: 1 credit 💰 (Most economical) </Accordion> <Accordion title="When do my credits reset?"> Message credits renew **monthly on the 1st of each month**, regardless of when you subscribed. **Example:** If you subscribe on March 15th, your credits will renew on April 1st. </Accordion> <Accordion title="What happens if I run out of credits?"> When credits are exhausted, your AI Agent will display: *"This AI Agent is currently unavailable. If you are the owner, please check your account."* You can monitor usage on the **Usage** page in your dashboard. </Accordion> <Accordion title="Can I upgrade or downgrade my plan anytime?"> **Yes!** You can change your plan anytime: </Accordion> </AccordionGroup> ## Technical Questions <AccordionGroup> <Accordion title="Where is my data stored and is it secure?"> Your data security is our top priority: **Storage & Security:** * **AWS servers** with enterprise-grade security * **Encrypted in transit** and at rest * **SOC 2 compliance** * **GDPR compliant** data handling **Data Usage:** * Your data is **never used** to train other models * **Isolated per account** - your data stays private * **Delete anytime** - full data portability Read our full [Privacy Policy](https://www.chatbase.co/legal/privacy) for complete details. </Accordion> <Accordion title="How do I check my training data character count?"> When uploading training data, Chatbase automatically displays the character count. </Accordion> <Accordion title="Can I use my own custom domain?"> **Yes!** Custom domains let you brand your AI Agent URLs: **What it includes:** * Custom embedding URLs (e.g., `chat.yourcompany.com`) * Branded sharing links for your AI Agent * Professional appearance for enterprise customers check out our [Custom Domains](/docs/developer-guides/custom-domains) guide for more information. <Warning> You'll need to configure DNS records to point your domain to Chatbase servers. </Warning> </Accordion> <Accordion title="Can I integrate Chatbase with my existing tools?"> Absolutely! Chatbase offers multiple integration options: **Direct Integrations:** * **Slack, WhatsApp, Messenger** - Native messaging platform support * **Stripe** - Handle billing and payment customer support * **Zapier, Make.com** - Connect to 5,000+ apps * **WordPress** - E-commerce and CMS plugins **Developer Tools:** * **REST API** - Build custom integrations * **Webhooks** - Real-time event notifications * **JavaScript Embed** - Advanced embed customization Explore our [Integrations](/docs/user-guides/integrations/webflow) section for setup guides. </Accordion> </AccordionGroup> ## Troubleshooting <AccordionGroup> <Accordion title="My AI Agent isn't responding correctly. What can I do?"> If your AI Agent isn't performing as expected, try these steps: **1. Review your training data:** * Ensure content is clear and well-structured * Add more specific information about common topics * Remove outdated or irrelevant content **2. Test different questions:** * Try variations of the same question * Check if the issue is with specific topics or general responses **3. Adjust settings:** * Lower temperature for more consistent responses * Try a different AI model * Add custom instructions for behavior **4. Add more training data:** * Include FAQs with question/answer pairs * Add examples of preferred responses * Cover more topics your users ask about </Accordion> <Accordion title="The chat bubble isn't appearing on my website"> If your chat bubble isn't showing up, check these common issues: **1. Verify the embed code:** * Ensure you copied the complete script tag * Check that your AI Agent is enabled * Confirm the agent ID matches your AI Agent **2. Check website integration:** * Script should be in `<head>` or before closing `</body>` tag * No JavaScript errors in browser console * Test on different browsers/devices **3. Cache issues:** * Clear browser cache and refresh * Check if your website uses caching plugins * Try viewing in incognito/private mode **4. Content blockers:** * Ad blockers may prevent the widget from loading * Test with ad blockers disabled Need technical help? Our [support team](https://www.chatbase.co/help) can help debug integration issues. </Accordion> </AccordionGroup> ## Still Need Help? Can't find the answer you're looking for? We're here to help! <CardGroup> <Card title="Contact Support" icon="headset" href="https://www.chatbase.co/help"> Get personalized help from our support team </Card> </CardGroup> # ChatResponse Source: https://chatbase.co/docs/ios-sdk/chat-response Reference for ChatResponse, Message, MessagePart, FinishReason, and Usage, the types returned by send, retry, and sendNonStreaming. ## ChatResponse `struct ChatResponse: Sendable` What `send`, `retry`, and `sendNonStreaming` give you back. ```swift theme={null} public struct ChatResponse: Sendable { public let message: Message public let conversationId: String public let userMessageId: String? public let finishReason: FinishReason public let usage: Usage } ``` <ResponseField name="message" type="Message"> The agent's reply. See [Message](#message). </ResponseField> <ResponseField name="conversationId" type="String"> The conversation this reply belongs to. Pass it to your next `send` to continue. </ResponseField> <ResponseField name="userMessageId" type="String?"> The server's ID for the user message that prompted this reply. </ResponseField> <ResponseField name="finishReason" type="FinishReason"> Why the reply ended. See [FinishReason](#finishreason). </ResponseField> <ResponseField name="usage" type="Usage"> How many credits it used. See [Usage](#usage). </ResponseField> ```swift theme={null} let response = try await client.send("Hello") print(response.message.text) // the whole reply print(response.message.id) // pass to retry(messageId:) print(response.conversationId) // pass to the next send print(response.usage.credits) ``` <Note> When the agent uses tools, the reply takes several rounds. `message.text` is all the text from every round joined together, and `message.id` is the ID of the final message. </Note> ## Message `struct Message: Identifiable, Sendable` Used both for the reply inside `ChatResponse` and for each item from [`listMessages`](/docs/ios-sdk/conversations#listmessages). ```swift theme={null} public struct Message: Identifiable, Sendable { public var id: String public var text: String public var sender: MessageSender public var date: Date public var feedback: MessageFeedback? public var score: Double? public var parts: [MessagePart] } ``` <ResponseField name="id" type="String"> The message ID. </ResponseField> <ResponseField name="text" type="String"> All the text joined together, which is handy for a plain bubble. </ResponseField> <ResponseField name="sender" type="MessageSender"> `.user` or `.agent`. </ResponseField> <ResponseField name="date" type="Date"> When the message was created. Falls back to the current time if the server does not send one. </ResponseField> <ResponseField name="feedback" type="MessageFeedback?"> `.positive`, `.negative`, or `nil`. Set for messages loaded from history. </ResponseField> <ResponseField name="score" type="Double?"> A score from the server, when there is one. </ResponseField> <ResponseField name="parts" type="[MessagePart]"> The message broken into pieces: text, tool calls, and tool results, in order. </ResponseField> <Tip> Use `text` for a simple chat log. Use `parts` when you want to show tool activity in the conversation. `ConversationState` uses `parts`. See [SwiftUI](/docs/ios-sdk/swiftui#uimessage). </Tip> ## MessagePart ```swift theme={null} public enum MessagePart: Sendable { case text(String) case toolCall(toolCallId: String, toolName: String, input: JSONValue) case toolResult(toolCallId: String, toolName: String, output: JSONValue) } ``` <Tabs> <Tab title="text"> ### .text Text written by the agent, or sent by the user. ```swift theme={null} case text(String) ``` The value is the text itself. </Tab> <Tab title="toolCall"> ### .toolCall The agent asking for a tool. ```swift theme={null} case toolCall(toolCallId: String, toolName: String, input: JSONValue) ``` <ResponseField name="toolCallId" type="String"> An ID for this tool call. It matches the `toolCallId` on the matching `.toolResult`. </ResponseField> <ResponseField name="toolName" type="String"> The tool's name, which matches the Custom Action name. </ResponseField> <ResponseField name="input" type="JSONValue"> What the agent passed to the tool. An empty object if it passed nothing. See [JSONValue](/docs/ios-sdk/json-value). </ResponseField> </Tab> <Tab title="toolResult"> ### .toolResult What the tool returned. ```swift theme={null} case toolResult(toolCallId: String, toolName: String, output: JSONValue) ``` <ResponseField name="toolCallId" type="String"> Matches the `.toolCall` it belongs to. </ResponseField> <ResponseField name="toolName" type="String"> The tool's name. </ResponseField> <ResponseField name="output" type="JSONValue"> The tool's result. An object with an `error` key means the tool failed. See [JSONValue](/docs/ios-sdk/json-value). </ResponseField> </Tab> </Tabs> ```swift theme={null} for part in message.parts { switch part { case .text(let text): renderBubble(text) case .toolCall(let id, let name, let input): beginToolCard(id: id, name: name, input: input) case .toolResult(let id, _, let output): completeToolCard(id: id, output: output) } } ``` ## MessageSender ```swift theme={null} public enum MessageSender: Sendable { case user case agent } ``` Anything that is not from the user counts as `.agent`, including messages typed by a person who has taken over the conversation. ## MessageFeedback ```swift theme={null} public enum MessageFeedback: String, Codable, Sendable { case positive // "positive" case negative // "negative" } ``` ## FinishReason ```swift theme={null} public enum FinishReason: String, Sendable { case stop // "stop" finished normally case error // "error" something went wrong case toolCalls // "tool-calls" waiting for tool results } ``` <Note> After `send` or `retry`, this is almost always `.stop`, because the SDK runs the tools for you and waits for the real answer. You will see `.toolCalls` from [`sendNonStreaming`](/docs/ios-sdk/streaming#sendnonstreaming), which skips tools: the agent wanted one and never got an answer. Any finish reason the SDK does not recognize is treated as `.stop`. </Note> ## Usage ```swift theme={null} public struct Usage: Sendable { public let credits: Double } ``` <ResponseField name="credits" type="Double"> How many message credits this reply used. `0` if the server did not report any. </ResponseField> ## Related <CardGroup> <Card title="Streaming" icon="wave-pulse" href="/docs/ios-sdk/streaming"> The methods that return a ChatResponse </Card> <Card title="Conversation & Pagination" icon="list" href="/docs/ios-sdk/conversation-models"> Conversation, status, and paging types </Card> <Card title="JSONValue" icon="brackets-curly" href="/docs/ios-sdk/json-value"> Reading tool data </Card> <Card title="Streaming Types" icon="bolt" href="/docs/ios-sdk/streaming-events"> Callbacks and stream types </Card> </CardGroup> # Client-Side Tools Source: https://chatbase.co/docs/ios-sdk/client-side-tools Let your Chatbase agent run functions on the device during a conversation. ## What Are Client-Side Tools? Client-side tools let your agent run functions on the device. You register a handler, and the SDK does the rest. When the agent asks for the tool, your handler runs, the result goes back to the agent, and the reply continues, all inside the same `send(...)` call. <Note> Client-side tools match the **Custom Actions** set up on your agent in the [Chatbase Dashboard](https://www.chatbase.co/dashboard). The name you register must match the action's name. </Note> ## tool ```swift theme={null} public func tool(_ name: String, handler: @escaping ToolHandler) ``` ```swift theme={null} public typealias ToolHandler = @Sendable (JSONValue) async throws -> JSONValue ``` Registers a tool handler. Registering the same name twice replaces the old handler. <ParamField type="String"> The tool name. Must match a Custom Action on your agent. </ParamField> <ParamField type="@Sendable (JSONValue) async throws -> JSONValue"> An async closure. It receives the tool's input as a [`JSONValue`](/docs/ios-sdk/json-value) and returns the result as a `JSONValue`. </ParamField> ```swift theme={null} client.tool("get_weather") { input in guard let city = input["city"]?.stringValue else { return .object(["error": .string("Missing 'city'")]) } let forecast = try await WeatherService.fetch(city: city) return .object([ "city": .string(city), "temperature": .string(forecast.temperature), "condition": .string(forecast.condition) ]) } ``` Register your tools once, right after creating the client, before the first `send`: ```swift theme={null} let client = ChatbaseClient(agentId: "YOUR_AGENT_ID") client.tool("get_weather") { ... } client.tool("lookup_order") { ... } ``` <Warning> Tool results can be at most **20 KB** of JSON. Anything larger fails with a `400` `VALIDATION_INVALID_BODY` error. Return only the fields the agent needs. Never return a whole API response. </Warning> ## How the Tool Loop Works One `send` call can go back and forth with the server several times: <Steps> <Step title="You send a message"> `client.send("What's the weather in Tokyo?")` opens the connection. </Step> <Step title="The agent asks for a tool"> The SDK runs your `onToolCall` callback and looks up your handler. </Step> <Step title="Your handler runs"> The SDK waits for it, sends the result to the server, and runs `onToolResult`. </Step> <Step title="The reply continues"> The SDK reconnects to the same conversation. The agent can now see the tool result, and either answers or asks for another tool. </Step> <Step title="Repeat until finished"> This continues until the agent finishes without asking for a tool. `send` then returns the `ChatResponse`. </Step> </Steps> All of this happens inside that one `await`. Text from every round is joined together into `response.message.text`. ### Tool loop limit There is a limit so a confused agent cannot loop forever. The default is 10 rounds, and you can change it per client: ```swift theme={null} let client = ChatbaseClient(agentId: "YOUR_AGENT_ID", maxToolLoopSteps: 20) ``` Going over the limit throws `ChatError.toolLoopLimitExceeded(limit:)`: ```swift theme={null} do { _ = try await client.send("Do the thing") } catch ChatError.toolLoopLimitExceeded(let limit) { print("The agent used more than \(limit) tool steps, so we stopped") } ``` <Tip> Hitting the limit usually means the agent keeps calling a tool because the result does not answer its question. Check that your handler returns what the action's description promises. </Tip> ### Automatic retries Sending a tool result is retried up to **3 times**, waiting 300 ms, then 600 ms, then 1.2 s. This covers the short gap before the server is ready for the result. You do not need to retry yourself. ## When a Tool Fails Return an object with an `error` key to tell the agent the tool failed, so it can try something else or explain the problem to the user: ```swift theme={null} client.tool("lookup_order") { input in guard let id = input["order_id"]?.stringValue else { return .object(["error": .string("Missing order_id")]) } guard let order = try await OrderService.fetch(id: id) else { return .object(["error": .string("No order found with ID \(id)")]) } return .object(["status": .string(order.status)]) } ``` **Thrown errors become the same thing.** If your handler throws, the SDK sends `{"error": "<the error's description>"}` instead of failing the whole `send` call, so one broken tool does not kill the reply. <Warning> Because these errors are shown to the agent, they can end up in the conversation. Do not throw errors whose description contains tokens, signed URLs, internal IDs, or stack traces. Return a message you are happy for a user to read. </Warning> `CancellationError` is the one exception. It is passed through, so cancelling the `Task` cancels the whole reply instead of reporting a failed tool. ### Tools with no handler If the agent asks for a tool you never registered, the SDK sends back `{"error": "No handler registered for tool 'name'"}`. The agent can then apologize or try something else, instead of hanging. ## Tools That Ask the User Handlers are `async`, so they can wait for the user and return their answer as the tool result. This is how you build confirmation prompts, pickers, and in-chat forms. ```swift theme={null} @MainActor @Observable final class ColorPickerCoordinator { var pending: CheckedContinuation<String, Never>? var isPresented = false func request() async -> String { await withCheckedContinuation { continuation in pending = continuation isPresented = true } } func choose(_ color: String) { isPresented = false pending?.resume(returning: color) pending = nil } } ``` ```swift theme={null} client.tool("pick_color") { _ in let color = await coordinator.request() // waits until the user taps return .object(["color": .string(color)]) } ``` ```swift theme={null} struct ChatView: View { @State var coordinator: ColorPickerCoordinator var body: some View { MessageList() .sheet(isPresented: $coordinator.isPresented) { ColorGrid { color in coordinator.choose(color) } } } } ``` <Warning> Always call `resume` exactly once, on every path, including when the user dismisses the sheet. If you never resume it, the tool waits forever and `send` never returns. When the user cancels, resume with a default value or an `error` result. </Warning> ## Watching Tools Run Use `onToolCall` and `onToolResult` to show progress: ```swift theme={null} let response = try await client.send("What's the weather in Tokyo?") { cb in cb.onToolCall = { info in print("Calling \(info.toolName) with \(info.input)") } cb.onToolResult = { info in print("\(info.toolName) returned \(info.output)") } cb.onTextDelta = { print($0, terminator: "") } } ``` Both callbacks also run for tools the **server** handles, such as server-side Custom Actions and integrations, not just your own handlers. That means one piece of UI can show every tool the agent uses. See [`ToolCallInfo`](/docs/ios-sdk/streaming-events#toolcallinfo) and [`ToolResultInfo`](/docs/ios-sdk/streaming-events#toolresultinfo). <Tip> [`ConversationState`](/docs/ios-sdk/swiftui) turns these callbacks into tool cards in the message list, with a running, finished, or failed state, using the `error` key rule above. Start there if you want tool UI without writing it. </Tip> ## Reading Tool Input Input arrives as a [`JSONValue`](/docs/ios-sdk/json-value). Read it with the subscript and the typed properties: ```swift theme={null} client.tool("book_table") { input in let party = input["party_size"]?.intValue ?? 2 let name = input["name"]?.stringValue let vip = input["vip"]?.boolValue ?? false let tags = input["tags"]?.arrayValue?.compactMap(\.stringValue) ?? [] // ... } ``` For bigger inputs, decode into your own type. `JSONValue` works with `Codable`: ```swift theme={null} struct BookingInput: Decodable { let partySize: Int let name: String let tags: [String] } client.tool("book_table") { input in let data = try JSONEncoder().encode(input) let booking = try JSONDecoder().decode(BookingInput.self, from: data) // ... } ``` ## Related <CardGroup> <Card title="Streaming" icon="wave-pulse" href="/docs/ios-sdk/streaming"> The send method and its callbacks </Card> <Card title="JSONValue" icon="brackets-curly" href="/docs/ios-sdk/json-value"> Reading and writing tool data </Card> <Card title="SwiftUI" icon="swift" href="/docs/ios-sdk/swiftui"> Tool cards you get for free </Card> <Card title="Error Handling" icon="triangle-exclamation" href="/docs/ios-sdk/error-handling"> Handling errors while tools run </Card> </CardGroup> # Conversation & Pagination Source: https://chatbase.co/docs/ios-sdk/conversation-models Reference for Conversation, ConversationStatus, and PaginatedResponse, the types used for conversation history. ## Conversation `struct Conversation: Identifiable, Hashable, Sendable` What [`listConversations`](/docs/ios-sdk/conversations#listconversations) returns. ```swift theme={null} public struct Conversation: Identifiable, Hashable, Sendable { public let id: String public let title: String? public let createdAt: Date public let updatedAt: Date public let userId: String? public let status: ConversationStatus } ``` <ResponseField name="id" type="String"> The conversation ID. Pass it to `listMessages` or `send`. </ResponseField> <ResponseField name="title" type="String?"> A title the server made or set. `nil` for conversations that do not have one yet, so show something like "New conversation" instead. </ResponseField> <ResponseField name="createdAt" type="Date"> When the conversation started. </ResponseField> <ResponseField name="updatedAt" type="Date"> When the last message arrived. Sort your list on this. </ResponseField> <ResponseField name="userId" type="String?"> The signed-in user this conversation belongs to, or `nil` if it belongs to a device. </ResponseField> <ResponseField name="status" type="ConversationStatus"> See [ConversationStatus](#conversationstatus). </ResponseField> <Note> `createdAt` and `updatedAt` arrive from the server as numbers and the SDK turns them into Swift `Date` values, so there is nothing to convert. </Note> `Conversation` works with `ForEach`, `List`, and `NavigationLink` without any extra work: ```swift theme={null} List(conversations) { conversation in NavigationLink(value: conversation) { VStack(alignment: .leading) { Text(conversation.title ?? "New conversation") Text(conversation.updatedAt, style: .relative) .font(.caption) .foregroundStyle(.secondary) } } } ``` ## ConversationStatus ```swift theme={null} public enum ConversationStatus: String, Decodable, Sendable { case ongoing // "ongoing" active case ended // "ended" finished case takenOver = "taken_over" // a person took over } ``` Only `.ongoing` conversations take new messages. Sending to any other one fails with `403` `CHAT_CONVERSATION_NOT_ONGOING`. See [Error Handling](/docs/ios-sdk/error-handling). ```swift theme={null} if conversation.status == .ongoing { showComposer() } else { showReadOnlyBanner() } ``` <Note> Any status the SDK does not recognize is read as `.ongoing`, so a new status added later will not break your app. </Note> ## Message `Message` is used for both replies and history. See [ChatResponse → Message](/docs/ios-sdk/chat-response#message) for the full reference, along with [`MessagePart`](/docs/ios-sdk/chat-response#messagepart), [`MessageSender`](/docs/ios-sdk/chat-response#messagesender), and [`MessageFeedback`](/docs/ios-sdk/chat-response#messagefeedback). ## PaginatedResponse `struct PaginatedResponse<T: Sendable>: Sendable` What `listConversations()` and `listMessages()` return. ```swift theme={null} public struct PaginatedResponse<T: Sendable>: Sendable { public let data: [T] public let hasMore: Bool public let total: Int public func loadMore() async throws -> PaginatedResponse<T>? } ``` <ResponseField name="data" type="[T]"> The items on this page. </ResponseField> <ResponseField name="hasMore" type="Bool"> Whether there are more pages. </ResponseField> <ResponseField name="total" type="Int"> How many items there are in total. </ResponseField> ### loadMore ```swift theme={null} public func loadMore() async throws -> PaginatedResponse<T>? ``` Gets the next page, or `nil` when `hasMore` is `false`. Each page remembers its own position and the `limit` you started with, so pages stay a consistent size and you have nothing to keep track of. <Warning> The page you get back holds **only the next page's items**. It does not build up a full list. Add `next.data` to your own array yourself. </Warning> ```swift theme={null} var page = try await client.listConversations(limit: 20) var all = page.data while let next = try await page.loadMore() { all.append(contentsOf: next.data) page = next } ``` <Note> There is no `cursor` property and no `canLoadMore`. Check `hasMore`, and let `loadMore()` handle the rest. </Note> ## Related <CardGroup> <Card title="Conversations & History" icon="messages" href="/docs/ios-sdk/conversations"> Listing conversations and loading history </Card> <Card title="ChatResponse" icon="brackets-curly" href="/docs/ios-sdk/chat-response"> Message, MessagePart, and reply types </Card> <Card title="SwiftUI" icon="swift" href="/docs/ios-sdk/swiftui"> ConversationListState pages for you </Card> <Card title="User Identity" icon="user" href="/docs/ios-sdk/user-identity"> How sign-in changes what you see </Card> </CardGroup> # Conversations & History Source: https://chatbase.co/docs/ios-sdk/conversations Manage conversations, load message history, and page through results with the Chatbase iOS SDK. ## Starting and Continuing Conversations <Steps> <Step title="Send a message"> Send a message with no `conversationId` to start a new conversation. The server creates one. ```swift theme={null} let response = try await client.send("Hello!") ``` </Step> <Step title="Keep the conversation ID"> ```swift theme={null} let conversationId = response.conversationId ``` You can also read it afterwards as `client.currentConversationId`. </Step> <Step title="Continue the conversation"> Pass the ID to the next call: ```swift theme={null} let followUp = try await client.send( "Tell me more", conversationId: conversationId ) ``` </Step> </Steps> <Warning> Passing `conversationId: nil` **always starts a new conversation**. It does not fall back to `currentConversationId`. Pass the ID yourself, or use [`ConversationState`](/docs/ios-sdk/swiftui), which keeps it for you. ```swift theme={null} // Wrong: two separate conversations _ = try await client.send("My name is Alice.") _ = try await client.send("What is my name?") // Right: one conversation let first = try await client.send("My name is Alice.") _ = try await client.send("What is my name?", conversationId: first.conversationId) ``` </Warning> ## newConversation ```swift theme={null} public func newConversation() ``` Clears `currentConversationId`. Use it if you track the current conversation through the client rather than your own state. ```swift theme={null} client.newConversation() _ = try await client.send("Brand new conversation!") ``` <Tip> `ConversationState` has its own [`clear()`](/docs/ios-sdk/swiftui#clear), which also empties the message list. Use that in UI code. </Tip> ## listConversations ```swift theme={null} public func listConversations( cursor: String? = nil, limit: Int? = nil ) async throws -> PaginatedResponse<Conversation> ``` Lists the current user's (or device's) conversations, newest first. <ParamField type="String?"> A cursor from an earlier page. Leave it out to start at the beginning. Prefer `loadMore()` over passing cursors yourself. </ParamField> <ParamField type="Int?"> How many per page, from 1 to 100. The server uses 20 if you leave it out. </ParamField> ```swift theme={null} let page = try await client.listConversations(limit: 20) for conversation in page.data { print("\(conversation.id): \(conversation.title ?? "Untitled")") print(" Status: \(conversation.status)") print(" Updated: \(conversation.updatedAt.formatted())") } print("Total: \(page.total)") print("Has more: \(page.hasMore)") ``` <Note> Only conversations created through the mobile SDKs are listed. Widget, API, and integration conversations are left out. Which ones you get depends on identity: the signed-in user's conversations if there is one, otherwise the device's. See [User Identity](/docs/ios-sdk/user-identity). </Note> See [`Conversation`](/docs/ios-sdk/conversation-models#conversation) for the full type. ## listMessages ```swift theme={null} public func listMessages( conversationId: String, cursor: String? = nil, limit: Int? = nil ) async throws -> PaginatedResponse<Message> ``` Loads the messages in a conversation. <ParamField type="String"> The conversation to load messages from. </ParamField> <ParamField type="String?"> A cursor from an earlier page. Leave it out to start with the newest messages. </ParamField> <ParamField type="Int?"> How many per page, from 1 to 100. The server uses 20 if you leave it out. </ParamField> <Note> Pages go backwards in time. The first page holds the newest messages, and each `loadMore()` gets older ones. Inside a page, messages run oldest to newest, so you can add a page to a chat view as it is. When you load an older page, add it to the top. </Note> ```swift theme={null} let page = try await client.listMessages(conversationId, limit: 50) for message in page.data { let who = message.sender == .user ? "You" : "Agent" print("\(who): \(message.text)") } ``` Each `Message` has both a plain `text` value (all the text joined together) and a `parts` list, so you can show tool activity inline with the conversation: ```swift theme={null} for part in message.parts { switch part { case .text(let text): renderBubble(text) case .toolCall(_, let toolName, let input): renderToolCard(toolName, input: input) case .toolResult(_, _, let output): attachToolOutput(output) } } ``` <Note> Messages with no parts are skipped, so a page can hold fewer items than `limit` even when `hasMore` is `true`. Base your "load more" button on `hasMore`, never on `data.count`. </Note> See [`Message`](/docs/ios-sdk/conversation-models#message) for the full type. ## PaginatedResponse ```swift theme={null} public struct PaginatedResponse<T: Sendable>: Sendable { public let data: [T] public let hasMore: Bool public let total: Int public func loadMore() async throws -> PaginatedResponse<T>? } ``` <ResponseField name="data" type="[T]"> The items on this page. </ResponseField> <ResponseField name="hasMore" type="Bool"> Whether there are more pages. </ResponseField> <ResponseField name="total" type="Int"> How many items there are in total. </ResponseField> ### loadMore ```swift theme={null} public func loadMore() async throws -> PaginatedResponse<T>? ``` Gets the next page, or `nil` when `hasMore` is `false`. The page keeps its own cursor, so you have nothing to pass along. <Warning> `loadMore()` returns **only the next page's items**. It does not build up a full list. Add `next.data` to your own array yourself, at the top or bottom depending on the list. </Warning> ```swift theme={null} var page = try await client.listConversations(limit: 20) var all = page.data while let next = try await page.loadMore() { all.append(contentsOf: next.data) page = next } print("Loaded \(all.count) of \(page.total)") ``` The `limit` you passed the first time is reused for every later page, so page sizes stay the same. <Tip> [`ConversationListState`](/docs/ios-sdk/swiftui#conversationliststate) and [`ConversationState`](/docs/ios-sdk/swiftui#loadhistory) build up the list for you, and skip messages you already have. Use them unless you need something custom. </Tip> ### Infinite scroll in SwiftUI ```swift theme={null} struct ConversationList: View { @State var state: ConversationListState var body: some View { List { ForEach(state.conversations) { conversation in ConversationRow(conversation) } if state.hasMore { ProgressView() .task { await state.loadMore() } } } .task { await state.load() } } } ``` ## Conversation Status A conversation that has ended, or that a person has taken over, cannot take new messages. Sending to one fails with `403` `CHAT_CONVERSATION_NOT_ONGOING`. Check before showing a text field: ```swift theme={null} if conversation.status == .ongoing { showComposer() } else { showReadOnlyBanner() } ``` | Status | What it means | | ------------ | -------------------------------------- | | `.ongoing` | Active, and takes new messages. | | `.ended` | Closed. Start a new conversation. | | `.takenOver` | A person took over from the dashboard. | ## Related <CardGroup> <Card title="Conversation & Pagination" icon="list" href="/docs/ios-sdk/conversation-models"> The full type reference </Card> <Card title="SwiftUI" icon="swift" href="/docs/ios-sdk/swiftui"> Ready-made state for lists and history </Card> <Card title="Streaming" icon="wave-pulse" href="/docs/ios-sdk/streaming"> Send messages and stream replies </Card> <Card title="User Identity" icon="user" href="/docs/ios-sdk/user-identity"> Tie conversations to users </Card> </CardGroup> # Error Handling Source: https://chatbase.co/docs/ios-sdk/error-handling Error types, codes, and handling patterns for the Chatbase iOS SDK. ## The Two Error Types The SDK throws two kinds of error. Both give you a readable `localizedDescription`. | Type | Covers | | ----------- | ----------------------------------------------------------------------- | | `APIError` | Network problems and error responses from the Chatbase server. | | `ChatError` | Problems the SDK finds on its own, before or instead of a server reply. | Swift errors are not arranged in a hierarchy, so there is no single type that catches both. Match each one, and keep a final `catch` for anything else, such as a `CancellationError` or an error from your own tool handler. ## APIError ```swift theme={null} public enum APIError: Error, LocalizedError { case invalidResponse case httpError(statusCode: Int, detail: APIErrorDetail) case networkError(Error) } ``` <ResponseField name="invalidResponse" type="case"> The server sent something that was not an HTTP response. Rare. Treat it like a network problem. </ResponseField> <ResponseField name="httpError(statusCode:detail:)" type="case"> The server returned an error status. `detail` holds the code you can check in your app. </ResponseField> <ResponseField name="networkError(Error)" type="case"> The request never got through: no connection, DNS failure, or a timeout. The value inside is the underlying `URLError`. </ResponseField> ### Shortcuts ```swift theme={null} public var statusCode: Int? // nil unless it is .httpError public var apiCode: String? // the server's error code, nil unless it is .httpError ``` ```swift theme={null} catch let error as APIError { switch error.statusCode { case 401: promptSignIn() case 402: showUpgradePrompt() case 429: backOffAndRetry() default: showGenericError() } } ``` ### APIErrorDetail ```swift theme={null} public struct APIErrorDetail: Decodable, Sendable { public let code: String public let message: String public let details: [String: String]? } ``` <ResponseField name="code" type="String"> The error code. Check this in your app, never the `message`. </ResponseField> <ResponseField name="message" type="String"> A description written for developers. </ResponseField> <ResponseField name="details" type="[String: String]?"> Which fields were wrong, when the server tells you. </ResponseField> <Warning> `message` is written for developers. It is not translated and not meant for your users. Turn `code` into your own wording instead of showing `localizedDescription` on screen. </Warning> If the error body cannot be read, the SDK still throws `.httpError` with `code` set to `"UNKNOWN"`, so you never lose the status code. ## ChatError ```swift theme={null} public enum ChatError: Error, LocalizedError { case noContent case decodingFailed(String) case invalidURL(String) case toolLoopLimitExceeded(limit: Int) } ``` | Case | What happened | What to do | | -------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | `.noContent` | The agent asked for a tool before there was a conversation to attach the result to. | Send the message again. | | `.decodingFailed(String)` | A reply did not look the way the SDK expected. | Update to the latest SDK version. If it keeps happening, contact support. | | `.invalidURL(String)` | The client was created with a `baseURL` that is not a valid URL. | Leave `baseURL` at its default. Every request fails until you do. | | `.toolLoopLimitExceeded(limit:)` | The agent asked for more tool rounds than `maxToolLoopSteps` allows. | See [Client-Side Tools](/docs/ios-sdk/client-side-tools#tool-loop-limit). | ```swift theme={null} catch ChatError.toolLoopLimitExceeded(let limit) { print("Stopped after \(limit) tool steps") } ``` ## Error Codes These are the codes you can get from `APIError.apiCode`: <table> <thead> <tr> <th>Status</th> <th>Code</th> <th>Description</th> </tr> </thead> <tbody> <tr><td>400</td><td><code>VALIDATION\_INVALID\_BODY</code></td><td>The request was not valid. <code>details</code> says which fields were wrong. You also get this when a tool result is over 20 KB.</td></tr> <tr><td>400</td><td><code>VALIDATION\_INVALID\_JSON</code></td><td>The request body was not valid JSON.</td></tr> <tr><td>400</td><td><code>VALIDATION\_MISSING\_USER\_IDENTIFIER</code></td><td>The device ID header was missing. You should not see this, since the SDK always sends it.</td></tr> <tr><td>400</td><td><code>AUTH\_INVALID\_USER\_AGENT</code></td><td>The SDK's <code>User-Agent</code> header was missing or not recognized. You should only see this if something rewrites your headers.</td></tr> <tr><td>400</td><td><code>CHAT\_RETRY\_NO\_USER\_MESSAGE</code></td><td>The message you passed to <code>retry()</code> has no user message before it to answer.</td></tr> <tr><td>401</td><td><code>AUTH\_INVALID\_JWT</code></td><td>The token you passed to <code>identify()</code>, or the saved token on a later request, is invalid or expired. You also get this when identity verification is not set up for the agent. See <a href="/docs/ios-sdk/user-identity">User Identity</a>.</td></tr> <tr><td>402</td><td><code>CHAT\_CREDITS\_EXHAUSTED</code></td><td>The workspace has no message credits left. Upgrade the plan or wait for credits to reset.</td></tr> <tr><td>402</td><td><code>CHAT\_AGENT\_CREDITS\_EXHAUSTED</code></td><td>This agent has used up its share of credits.</td></tr> <tr><td>403</td><td><code>AUTH\_OWNERSHIP\_MISMATCH</code></td><td>The conversation belongs to a different user or device. <code>retry()</code> and <code>listMessages()</code> also return this when the conversation does not exist.</td></tr> <tr><td>403</td><td><code>CHAT\_CONVERSATION\_MISMATCH</code></td><td>The conversation does not belong to this agent.</td></tr> <tr><td>403</td><td><code>CHAT\_MODEL\_NOT\_ALLOWED</code></td><td>The agent uses a model that the current plan does not include.</td></tr> <tr><td>403</td><td><code>CHAT\_CONVERSATION\_NOT\_ONGOING</code></td><td>The conversation has ended, or a person took it over, so it cannot take new messages. Start a new one.</td></tr> <tr><td>404</td><td><code>AGENT\_NOT\_FOUND</code></td><td>No agent has that ID, or the <strong>iOS SDK channel is turned off</strong> for the agent. See <a href="/docs/ios-sdk/overview#quick-start">Quick Start</a>.</td></tr> <tr><td>404</td><td><code>RESOURCE\_NOT\_FOUND</code></td><td>The conversation or message does not exist.</td></tr> <tr><td>404</td><td><code>CHAT\_RETRY\_MESSAGE\_NOT\_FOUND</code></td><td>The message ID you gave <code>retry()</code> was not found.</td></tr> <tr><td>404</td><td><code>RESOURCE\_TOOL\_CALL\_NOT\_FOUND</code></td><td>The tool call was not found, or it expired. This can come up during the tool loop.</td></tr> <tr><td>404</td><td><code>RESOURCE\_TOOL\_CALL\_MISMATCH</code></td><td>The tool call belongs to a different conversation.</td></tr> <tr><td>404</td><td><code>RESOURCE\_TOOL\_RESULT\_NOT\_PENDING</code></td><td>The server was not waiting for this tool result. Usually it was sent twice.</td></tr> <tr><td>429</td><td><code>RATE\_LIMIT\_TOO\_MANY\_REQUESTS</code></td><td>Too many requests (the limit is 1,000 every 10 seconds per device). Wait and try again. The response includes a <code>Retry-After</code> header.</td></tr> <tr><td>500</td><td><code>CHAT\_STREAMING\_ERROR</code></td><td>The reply failed on the server. Safe to try again.</td></tr> <tr><td>500</td><td><code>INTERNAL\_SERVER\_ERROR</code></td><td>Something went wrong on the server. Try again, or contact support if it keeps happening.</td></tr> </tbody> </table> <Note> `AGENT_NOT_FOUND` looks the same whether the agent does not exist or the iOS SDK channel is turned off. If you are sure the agent ID is right, check **Deploy** → **iOS SDK** first. </Note> ## Handling Errors <Tabs> <Tab title="async/await" icon="code"> ```swift theme={null} do { let response = try await client.send("Hello", conversationId: conversationId) render(response) } catch let error as APIError { switch (error.statusCode, error.apiCode) { case (401, _): try await refreshIdentity() case (402, _): show("You're out of message credits.") case (403, "CHAT_CONVERSATION_NOT_ONGOING"): startNewConversation() case (404, "AGENT_NOT_FOUND"): assertionFailure("Check the agent ID and that the iOS SDK channel is on") case (429, _): await backOff() default: show("Something went wrong. Please try again.") } } catch let error as ChatError { switch error { case .toolLoopLimitExceeded: show("That took too many steps. Try rewording it.") default: show("Something went wrong. Please try again.") } } catch is CancellationError { // The user stopped it. Nothing to show. } catch { show("Something went wrong. Please try again.") } ``` </Tab> <Tab title="Network problems" icon="wifi"> Connection problems come back as `.networkError`, wrapping a `URLError`: ```swift theme={null} catch let error as APIError { if case .networkError(let underlying) = error { switch (underlying as? URLError)?.code { case .notConnectedToInternet, .networkConnectionLost: show("You appear to be offline.") case .timedOut: show("The request timed out. Try again.") default: show("Couldn't reach Chatbase.") } } } ``` Change timeouts with the `URLSessionConfiguration` you pass to `ChatbaseClient`. See [Overview](/docs/ios-sdk/overview#init). </Tab> <Tab title="SwiftUI state" icon="swift"> `ConversationState` and `ConversationListState` never throw. Errors go into `error`: ```swift theme={null} .alert( "Something went wrong", isPresented: .init( get: { state.error != nil }, set: { if !$0 { state.clearError() } } ) ) { Button("OK") { state.clearError() } } message: { Text(userFacingMessage(for: state.error)) } ``` The failed bubble is also marked `isError`, so you can show a retry button in the list instead of an alert. See [SwiftUI](/docs/ios-sdk/swiftui). </Tab> <Tab title="Rate limits" icon="gauge"> Wait before trying again, and make each wait longer than the last: ```swift theme={null} func withRetry<T>( attempts: Int = 3, _ operation: () async throws -> T ) async throws -> T { var delay: Duration = .milliseconds(500) for attempt in 1...attempts { do { return try await operation() } catch let error as APIError where error.statusCode == 429 && attempt < attempts { try await Task.sleep(for: delay + .milliseconds(.random(in: 0...200))) delay *= 2 } } throw APIError.invalidResponse } ``` The small random amount keeps many devices from retrying at the same moment. <Note> Tool results are already retried inside the SDK, 3 times with a growing wait. Do not add your own retry around tool handlers. </Note> </Tab> </Tabs> ## Errors Inside Tool Handlers An error thrown by a tool handler does **not** come out of `send`. The SDK turns it into `{"error": "..."}` and gives it to the agent, so the agent can recover. See [When a Tool Fails](/docs/ios-sdk/client-side-tools#when-a-tool-fails). `CancellationError` is the exception. It is passed through, so cancelling the `Task` cancels the reply. ## What to Report The SDK already logs each request and response under `com.chatbase.sdk`. See [Logging](/docs/ios-sdk/overview#logging). When you report a problem, include the `apiCode`, the `statusCode`, and the time. That is enough to find the request on the server. <Warning> Do not send tokens or message text to a crash reporting service. `APIError.localizedDescription` is safe. It contains only the code, the message, and the status. </Warning> ## Related <CardGroup> <Card title="Streaming" icon="wave-pulse" href="/docs/ios-sdk/streaming"> Where most errors show up </Card> <Card title="User Identity" icon="user" href="/docs/ios-sdk/user-identity"> Handling expired and rejected tokens </Card> <Card title="Client-Side Tools" icon="bolt" href="/docs/ios-sdk/client-side-tools"> Reporting failures back to the agent </Card> <Card title="Overview" icon="book-open" href="/docs/ios-sdk/overview"> Setup and configuration </Card> </CardGroup> # JSONValue Source: https://chatbase.co/docs/ios-sdk/json-value Reference for JSONValue, the type the SDK uses for tool input and output. ## Overview `enum JSONValue: Sendable, Equatable, Codable` Tool input and output can be any JSON, so the SDK uses `JSONValue` instead of `Any`. That means you can read it without casting, and pass it between threads safely. ```swift theme={null} public enum JSONValue: Sendable, Equatable, Codable { case string(String) case int(Int) case number(Double) case bool(Bool) case object([String: JSONValue]) case array([JSONValue]) case null } ``` You will run into it in four places: | Where | What you do | | ----------------------------------------- | ----------- | | A tool handler's input | Read it | | A tool handler's return value | Write it | | `ToolCallInfo.input` | Read it | | `ToolResultInfo.output` and message parts | Read it | ## Reading Values ### Looking up a key ```swift theme={null} public subscript(key: String) -> JSONValue? { get } ``` Looks up a key. Returns `nil` if the key is missing or the value is not an object, so you can chain safely: ```swift theme={null} let city = input["location"]?["city"] ``` ### Getting a Swift type ```swift theme={null} public var stringValue: String? { get } public var intValue: Int? { get } public var numberValue: Double? { get } public var boolValue: Bool? { get } public var objectValue: [String: JSONValue]? { get } public var arrayValue: [JSONValue]? { get } ``` Each one returns `nil` if the value is a different type: ```swift theme={null} client.tool("book_table") { input in let name = input["name"]?.stringValue ?? "Guest" let party = input["party_size"]?.intValue ?? 2 let vip = input["vip"]?.boolValue ?? false let tags = input["tags"]?.arrayValue?.compactMap(\.stringValue) ?? [] // ... } ``` <Note> `numberValue` is the forgiving one. It works for whole numbers and decimals alike, so both `9` and `9.0` read cleanly. `intValue` is stricter and returns `nil` for `9.0`. If a value might arrive either way, read it with `numberValue`. </Note> ### Handling every case To cover all the possibilities, switch on the value: ```swift theme={null} func describe(_ value: JSONValue) -> String { switch value { case .string(let s): return s case .int(let i): return String(i) case .number(let d): return String(d) case .bool(let b): return b ? "yes" : "no" case .array(let a): return a.map(describe).joined(separator: ", ") case .object(let o): return o.map { "\($0): \(describe($1))" }.joined(separator: "; ") case .null: return "-" } } ``` ## Writing Values Build results from the cases: ```swift theme={null} return .object([ "status": .string("shipped"), "eta_days": .int(2), "cost": .number(14.99), "expedited": .bool(true), "items": .array([.string("SKU-1"), .string("SKU-2")]), "note": .null ]) ``` ### Reporting a failure An **object with an `error` key** is how you report a problem anywhere in the SDK. The agent sees the tool as failed, and [`ConversationState`](/docs/ios-sdk/swiftui#toolcallcard) shows the card as failed too: ```swift theme={null} return .object(["error": .string("No order found with that ID")]) ``` See [When a Tool Fails](/docs/ios-sdk/client-side-tools#when-a-tool-fails). ## Using Your Own Types `JSONValue` works with `Codable`, so you can convert to and from your own types with `JSONEncoder` and `JSONDecoder`. ### Reading input into a struct ```swift theme={null} struct BookingInput: Decodable { let name: String let partySize: Int let tags: [String] enum CodingKeys: String, CodingKey { case name case partySize = "party_size" case tags } } client.tool("book_table") { input in let booking = try JSONDecoder().decode( BookingInput.self, from: JSONEncoder().encode(input) ) // booking.partySize, booking.tags, ... } ``` ### Returning a struct ```swift theme={null} struct BookingResult: Encodable { let confirmationCode: String let time: String } client.tool("book_table") { input in let result = BookingResult(confirmationCode: "AB12", time: "19:30") return try JSONDecoder().decode( JSONValue.self, from: JSONEncoder().encode(result) ) } ``` <Tip> A small helper makes both directions easier to read: ```swift theme={null} extension JSONValue { init<T: Encodable>(encoding value: T) throws { self = try JSONDecoder().decode(JSONValue.self, from: JSONEncoder().encode(value)) } func decoded<T: Decodable>(as type: T.Type = T.self) throws -> T { try JSONDecoder().decode(T.self, from: JSONEncoder().encode(self)) } } ``` ```swift theme={null} client.tool("book_table") { input in let booking: BookingInput = try input.decoded() return try JSONValue(encoding: BookingResult(confirmationCode: "AB12", time: "19:30")) } ``` Throwing here is fine. The SDK turns it into an `error` result for the agent instead of failing the whole reply. Just keep the message safe to show a user. </Tip> ## How Values Are Read The SDK tries the cases in this order: null, `Bool`, `Int`, `Double`, `String`, object, array. Two things follow from that: * A whole number is always read as `.int`, never `.number`. If the agent might send either, read it with `numberValue`. * Anything that matches none of the cases is read as `.null` instead of failing, so an odd tool result will not break the reply. ## Size Limit Tool results can be at most **20 KB** of JSON. Anything larger fails with `400` `VALIDATION_INVALID_BODY`. <Warning> Tool results are passed on exactly as they are, including to HIPAA conversation webhooks. Never put tokens, signed URLs, file paths, internal IDs, or stack traces in a `JSONValue` you return. Return only what the agent needs to answer. </Warning> ## Related <CardGroup> <Card title="Client-Side Tools" icon="bolt" href="/docs/ios-sdk/client-side-tools"> Where you use JSONValue most </Card> <Card title="Streaming Types" icon="list" href="/docs/ios-sdk/streaming-events"> ToolCallInfo and ToolResultInfo </Card> <Card title="ChatResponse" icon="brackets-curly" href="/docs/ios-sdk/chat-response"> Message parts </Card> <Card title="SwiftUI" icon="swift" href="/docs/ios-sdk/swiftui"> Showing tool input and output </Card> </CardGroup> # iOS SDK Overview Source: https://chatbase.co/docs/ios-sdk/overview Introduction to the Chatbase iOS SDK, a Swift library for building conversational AI experiences on iOS and macOS. <Info> **Beta Release.** The Chatbase iOS SDK is currently in beta (v0.1.0-beta.1). APIs may change in future releases. </Info> <Warning> Conversation methods apply exclusively to conversations created through the mobile SDKs (iOS and Android). Conversations generated through the widget, the API, or external integrations cannot be accessed using the SDK. A user identified on both platforms sees their iOS and Android SDK conversations together. </Warning> ## What is the Chatbase iOS SDK? The Chatbase iOS SDK is a Swift library that lets you add Chatbase agents to your iOS or macOS app. It gives you: * **Real-time streaming** with `async`/`await` and per-chunk callbacks * **Client-side tools** that let the agent run functions on the device * **User identity** with JWT sign-in and an automatic device ID * **Conversation management** with paginated history * **Ready-made SwiftUI state** through `ConversationState` and `ConversationListState` * **Typed errors** for everything that can go wrong **Requirements:** | Requirement | Minimum | | ----------- | ----------------------------------------------------------- | | iOS | 17.0 | | macOS | 14.0 | | Swift | 6.0 | | Xcode | 16 | | SwiftUI | Not required. The SDK works with UIKit or any UI framework. | <Note> Everything in the SDK lives in one module, `ChatbaseSDK`. A single `import ChatbaseSDK` gives you every type in these docs. </Note> ## Installation The SDK ships as a Swift Package. <Tabs> <Tab title="Xcode"> 1. **File** → **Add Package Dependencies…** 2. Paste the repository URL: ``` https://github.com/Chatbase-co/chatbase-ios-sdk.git ``` 3. Choose version `0.1.0-beta.1` (or **Up to Next Minor**) and add the **ChatbaseSDK** library to your app target. </Tab> <Tab title="Package.swift"> ```swift theme={null} // Package.swift dependencies: [ .package( url: "https://github.com/Chatbase-co/chatbase-ios-sdk.git", from: "0.1.0-beta.1" ) ], targets: [ .target( name: "YourApp", dependencies: [ .product(name: "ChatbaseSDK", package: "chatbase-ios-sdk") ] ) ] ``` </Tab> </Tabs> Then import it: ```swift theme={null} import ChatbaseSDK ``` <Note> No `Info.plist` changes are needed. The SDK talks to `https://www.chatbase.co` over HTTPS, which iOS allows by default. </Note> ## Quick Start <Steps> <Step title="Get your Agent ID"> 1. Go to the [Chatbase Dashboard](https://www.chatbase.co/dashboard) 2. Select your agent 3. Go to **Settings** → **General** 4. Copy the **Agent ID** </Step> <Step title="Enable the iOS SDK channel"> In the dashboard, go to **Deploy** → **iOS SDK** and enable the channel for your agent. <Warning> If the iOS SDK channel is not enabled, every SDK request fails with a `404` `AGENT_NOT_FOUND` error, even when the agent ID is correct. </Warning> </Step> <Step title="Create a client"> ```swift theme={null} import ChatbaseSDK let client = ChatbaseClient(agentId: "YOUR_AGENT_ID") ``` Create the client once and keep it around, in a view model, an app-level dependency, or a `@State` property. A new client starts anonymous, tied to a device ID that stays the same across launches. </Step> <Step title="Send your first message"> ```swift theme={null} let response = try await client.send("Hello! How can you help me?") { cb in cb.onTextDelta = { chunk in // Runs for each chunk of text as it arrives print(chunk, terminator: "") } } print(response.message.text) print("Conversation: \(response.conversationId)") print("Credits used: \(response.usage.credits)") ``` </Step> <Step title="Continue the conversation"> ```swift theme={null} let followUp = try await client.send( "Tell me more", conversationId: response.conversationId ) ``` For UI code, use [`ConversationState`](/docs/ios-sdk/swiftui) instead. It keeps the conversation ID for you, along with the message list. </Step> </Steps> <Tip> There is no `close()` or cleanup call. The client shuts down its network session when it goes out of scope. </Tip> ## ChatbaseClient `final class ChatbaseClient` The main entry point. You can call it from any task or actor. ### init ```swift theme={null} public init( agentId: String, baseURL: String = "https://www.chatbase.co/api/sdk", configuration: URLSessionConfiguration = .default, maxToolLoopSteps: Int = 10 ) ``` <ParamField type="String"> The Chatbase agent ID to connect to. </ParamField> <ParamField type="String"> The Chatbase API address. Leave this at its default. </ParamField> <ParamField type="URLSessionConfiguration"> The `URLSessionConfiguration` used for every request. Set timeouts and caching here. </ParamField> <ParamField type="Int"> How many times a single `send` or `retry` may run tools before giving up. Going over throws `ChatError.toolLoopLimitExceeded(limit:)`. See [Client-Side Tools](/docs/ios-sdk/client-side-tools#tool-loop-limit). </ParamField> ```swift theme={null} // Custom timeouts let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 30 config.timeoutIntervalForResource = 300 let client = ChatbaseClient( agentId: "YOUR_AGENT_ID", configuration: config, maxToolLoopSteps: 20 ) ``` <Tip> `timeoutIntervalForRequest` measures the gap between pieces of data, not the length of the whole response. A long streaming reply will not be cut off by a 30 second timeout as long as data keeps arriving. </Tip> ### Properties | Property | Type | Description | | ----------------------- | ----------- | ------------------------------------------------------------- | | `deviceId` | `String` | The device ID. Always available. | | `authState` | `AuthState` | `.anonymous` or `.identified(token:)`. | | `currentConversationId` | `String?` | The last conversation the client saw, or `nil`. | | `currentUserId` | `String?` | The user ID the server confirmed on the last completed reply. | ### Methods | Method | Description | | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `send(_:conversationId:configure:)` | Send a message, stream the reply, run tools. See [Streaming](/docs/ios-sdk/streaming#send). | | `retry(conversationId:messageId:configure:)` | Ask the agent to answer again. See [Streaming](/docs/ios-sdk/streaming#retry). | | `sendNonStreaming(_:conversationId:)` | Get the whole reply at once, with no streaming and no tools. See [Streaming](/docs/ios-sdk/streaming#sendnonstreaming). | | `tool(_:handler:)` | Register a tool the agent can run. See [Client-Side Tools](/docs/ios-sdk/client-side-tools). | | `identify(token:)` | Sign a user in with a JWT. See [User Identity](/docs/ios-sdk/user-identity). | | `logout()` | Go back to anonymous. See [User Identity](/docs/ios-sdk/user-identity#logout). | | `newConversation()` | Clear `currentConversationId`. See [Conversations](/docs/ios-sdk/conversations#newconversation). | | `listConversations(cursor:limit:)` | List past conversations. See [Conversations](/docs/ios-sdk/conversations#listconversations). | | `listMessages(conversationId:cursor:limit:)` | Load a conversation's messages. See [Conversations](/docs/ios-sdk/conversations#listmessages). | ## Logging The SDK writes to Apple's logging system under the subsystem `com.chatbase.sdk`, in three categories: | Category | What it logs | | ------------------- | --------------------------------------------------------------- | | `APIClient` | Each request and response: method, path, status, duration, size | | `ChatService` | Stream decoding failures and tool result retries | | `ConversationState` | Skipped retries and similar UI state notes | View them in Console.app, or run `log stream --predicate 'subsystem == "com.chatbase.sdk"'`. Message text is never logged. ## Rate Limits Chatbase allows **1,000 requests every 10 seconds** per device. Going over throws an `APIError.httpError` with status `429`. See [Error Handling](/docs/ios-sdk/error-handling). ## Next Steps <CardGroup> <Card title="Streaming" icon="wave-pulse" href="/docs/ios-sdk/streaming"> Stream replies with async/await and callbacks </Card> <Card title="SwiftUI" icon="swift" href="/docs/ios-sdk/swiftui"> Ready-made state for chat screens </Card> <Card title="Client-Side Tools" icon="bolt" href="/docs/ios-sdk/client-side-tools"> Let the agent run functions on the device </Card> <Card title="Conversations" icon="messages" href="/docs/ios-sdk/conversations"> Conversations, history, and pagination </Card> <Card title="User Identity" icon="user" href="/docs/ios-sdk/user-identity"> Sign users in with JWT tokens </Card> <Card title="Error Handling" icon="triangle-exclamation" href="/docs/ios-sdk/error-handling"> Error types and how to handle them </Card> </CardGroup> # Streaming Source: https://chatbase.co/docs/ios-sdk/streaming How to stream real-time replies from the Chatbase iOS SDK with async/await and callbacks. ## How Streaming Works The SDK has one streaming method. `send(_:conversationId:configure:)` is an `async throws` function. It calls your callbacks as text arrives, then returns the finished [`ChatResponse`](/docs/ios-sdk/chat-response) when the reply is complete. * **While it runs:** your `onTextDelta`, `onToolCall`, and `onToolResult` callbacks fire. * **When it succeeds:** it returns a `ChatResponse`. * **When it fails:** it throws. The same call also runs your tools. If the agent asks for a tool, the SDK runs your handler, sends the result back, and continues the reply. See [Client-Side Tools](/docs/ios-sdk/client-side-tools). <Tip> If you are building a SwiftUI chat screen, you usually do not call `send` yourself. [`ConversationState`](/docs/ios-sdk/swiftui) connects these callbacks to a message list for you. </Tip> ## send ```swift theme={null} public func send( _ message: String, conversationId: String? = nil, configure: @Sendable (inout StreamCallbacks) -> Void = { _ in } ) async throws -> ChatResponse ``` Sends a message, streams the reply, runs any registered tools, and returns the finished `ChatResponse`. <ParamField type="String"> The message to send to the agent. </ParamField> <ParamField type="String?"> Continue an existing conversation. `nil` **always starts a new conversation**. </ParamField> <ParamField type="@Sendable (inout StreamCallbacks) -> Void"> A closure where you set the callbacks you want. Set only the ones you need. </ParamField> <Warning> Unlike the Android SDK, passing `conversationId: nil` does **not** fall back to `currentConversationId`. It starts a new conversation. To continue one, pass the ID yourself, or use [`ConversationState`](/docs/ios-sdk/swiftui), which keeps track of it. </Warning> ```swift theme={null} let response = try await client.send("Tell me a story") { cb in cb.onTextDelta = { chunk in print(chunk, terminator: "") } cb.onToolCall = { info in print("Agent is calling: \(info.toolName)") } cb.onToolResult = { info in print("Got a result from: \(info.toolName)") } } print("\nMessage ID: \(response.message.id)") print("Finish reason: \(response.finishReason)") ``` ### StreamCallbacks ```swift theme={null} public struct StreamCallbacks: Sendable { public var onTextDelta: (@Sendable (String) async -> Void)? public var onToolCall: (@Sendable (ToolCallInfo) async -> Void)? public var onToolResult: (@Sendable (ToolResultInfo) async -> Void)? } ``` | Callback | When it runs | | -------------- | ---------------------------------------------------------------------------------- | | `onTextDelta` | For each chunk of text as it arrives. | | `onToolCall` | When the agent asks for a tool, before your handler runs. | | `onToolResult` | When a tool result is ready, whether it came from your handler or from the server. | Callbacks you do not set are ignored. There is no `onStart`, `onFinish`, or `onError` callback. The `async throws` signature covers all three: ```swift theme={null} do { let response = try await client.send("Hello") { cb in cb.onTextDelta = { print($0, terminator: "") } } // Same as onFinish handle(response) } catch { // Same as onError show(error) } ``` <Warning> Callbacks do not run on the main thread. Switch to the main actor before touching your UI: ```swift theme={null} cb.onTextDelta = { @Sendable chunk in await MainActor.run { self.text += chunk } } ``` The SDK waits for each callback to finish before reading more of the reply, so a slow callback slows the whole stream. Keep them short. </Warning> ### Showing text as it arrives ```swift theme={null} @MainActor @Observable final class ChatViewModel { var text = "" var isSending = false private let client: ChatbaseClient private var conversationId: String? init(client: ChatbaseClient) { self.client = client } func send(_ message: String) async { isSending = true defer { isSending = false } text = "" do { let response = try await client.send(message, conversationId: conversationId) { cb in cb.onTextDelta = { [weak self] chunk in await self?.append(chunk) } } conversationId = response.conversationId } catch { text = "Something went wrong. Please try again." } } private func append(_ chunk: String) { text += chunk } } ``` `ChatViewModel` is marked `@MainActor`, so `await self?.append(chunk)` moves to the main thread for you. ## Stopping a Reply Cancelling the `Task` around `send` closes the connection. ```swift theme={null} var streamTask: Task<Void, Never>? func start(_ message: String) { streamTask = Task { do { _ = try await client.send(message) { cb in cb.onTextDelta = { chunk in await self.append(chunk) } } } catch is CancellationError { // The user stopped it. Keep the text received so far. } catch { self.show(error) } } } func stop() { streamTask?.cancel() } ``` <Note> Cancelling stops your app from reading the reply. The agent may still finish on the server, and the partial message is saved. The text you already received is still correct, and it will be there when you next call [`listMessages`](/docs/ios-sdk/conversations#listmessages). </Note> ## Continuing a Conversation The client remembers the last conversation in `currentConversationId`, but you have to pass it back in to continue: ```swift theme={null} // First message, starts a new conversation let first = try await client.send("My name is Alice.") print(first.conversationId) // "conv_abc123" // Continue it let second = try await client.send( "What is my name?", conversationId: first.conversationId ) // The agent remembers: "Alice" ``` To start fresh, pass `nil` (the default), or clear the saved ID: ```swift theme={null} client.newConversation() _ = try await client.send("Fresh start!") ``` <Tip> See [Conversations & History](/docs/ios-sdk/conversations) for listing conversations and loading old messages, and [SwiftUI](/docs/ios-sdk/swiftui) for state that tracks the conversation ID for you. </Tip> ## retry ```swift theme={null} public func retry( conversationId: String, messageId: String, configure: @Sendable (inout StreamCallbacks) -> Void = { _ in } ) async throws -> ChatResponse ``` Ask the agent to answer again. Streams and runs tools exactly like `send`. <ParamField type="String"> The conversation the message belongs to. </ParamField> <ParamField type="String"> The ID of the agent message to redo. </ParamField> <ParamField type="@Sendable (inout StreamCallbacks) -> Void"> The same callbacks as `send`. </ParamField> ```swift theme={null} let response = try await client.send("Hello") // Later, from a "Regenerate" button: let retried = try await client.retry( conversationId: response.conversationId, messageId: response.message.id ) { cb in cb.onTextDelta = { print($0, terminator: "") } } ``` <Note> The old message and everything after it are replaced. Remove those messages from your UI before the new reply starts. [`ConversationState.retry(messageId:)`](/docs/ios-sdk/swiftui#retry) does this for you. </Note> ## sendNonStreaming ```swift theme={null} public func sendNonStreaming( _ message: String, conversationId: String? = nil ) async throws -> ChatResponse ``` Sends a message and returns the whole reply at once. No callbacks, and **no tools**. <ParamField type="String"> The message to send to the agent. </ParamField> <ParamField type="String?"> Continue an existing conversation. `nil` starts a new one. </ParamField> ```swift theme={null} let response = try await client.sendNonStreaming("Summarize my last order") print(response.message.text) print(response.finishReason) // .stop, .error, or .toolCalls print(response.usage.credits) ``` <Warning> Your registered tools do **not** run. If the agent asks for a tool, you get back `finishReason == .toolCalls` and no answer. Use `send` for any agent that has client-side Custom Actions. </Warning> Use `sendNonStreaming` when you do not need to show text as it arrives, such as a background summary or a scripted first message. ## Which Method to Use | | `send` | `retry` | `sendNonStreaming` | | ------------------------- | ------------------------------ | -------------- | ------------------------------ | | Streams text | Yes | Yes | No | | Runs your tools | Yes | Yes | No | | Callbacks | Yes | Yes | No | | Starts a new conversation | When `conversationId` is `nil` | Never | When `conversationId` is `nil` | | Returns | `ChatResponse` | `ChatResponse` | `ChatResponse` | ## Related <CardGroup> <Card title="Client-Side Tools" icon="bolt" href="/docs/ios-sdk/client-side-tools"> Let the agent run functions on the device </Card> <Card title="Streaming Types" icon="list" href="/docs/ios-sdk/streaming-events"> StreamCallbacks, ToolCallInfo, and more </Card> <Card title="ChatResponse" icon="brackets-curly" href="/docs/ios-sdk/chat-response"> What a finished reply contains </Card> <Card title="Error Handling" icon="triangle-exclamation" href="/docs/ios-sdk/error-handling"> Error types and how to handle them </Card> </CardGroup> # Streaming Types Source: https://chatbase.co/docs/ios-sdk/streaming-events Reference for StreamCallbacks, ToolCallInfo, ToolResultInfo, StreamEvent, and related streaming types. ## StreamCallbacks `struct StreamCallbacks: Sendable` The callbacks you pass to `send(_:conversationId:configure:)` and `retry(conversationId:messageId:configure:)`. ```swift theme={null} public struct StreamCallbacks: Sendable { public var onTextDelta: (@Sendable (String) async -> Void)? public var onToolCall: (@Sendable (ToolCallInfo) async -> Void)? public var onToolResult: (@Sendable (ToolResultInfo) async -> Void)? public init() } ``` <ResponseField name="onTextDelta" type="(@Sendable (String) async -> Void)?"> Runs for each chunk of text. Add it to the current bubble. </ResponseField> <ResponseField name="onToolCall" type="(@Sendable (ToolCallInfo) async -> Void)?"> Runs when the agent asks for a tool, before your handler runs. </ResponseField> <ResponseField name="onToolResult" type="(@Sendable (ToolResultInfo) async -> Void)?"> Runs when a tool result is ready, whether it came from your handler or from the server. </ResponseField> Callbacks you do not set are ignored: ```swift theme={null} let response = try await client.send("Hello") { cb in cb.onTextDelta = { chunk in await self.append(chunk) } // onToolCall and onToolResult not set } ``` <Note> There is no `onStart`, `onFinish`, or `onError` callback. The `async throws` signature covers all three: the call returns a `ChatResponse` when it works and throws when it does not. See [Streaming](/docs/ios-sdk/streaming#streamcallbacks). </Note> <Warning> Callbacks do not run on the main thread. Use `await MainActor.run { ... }`, or call into a `@MainActor` type, before touching your UI. The SDK waits for each callback before reading more of the reply, so keep them quick. </Warning> ## ToolCallInfo `struct ToolCallInfo: Sendable` Passed to `onToolCall`. ```swift theme={null} public struct ToolCallInfo: Sendable { public let toolCallId: String public let toolName: String public let input: JSONValue } ``` <ResponseField name="toolCallId" type="String"> An ID for this tool call. Use it to match this call with its `ToolResultInfo`. </ResponseField> <ResponseField name="toolName" type="String"> The tool's name, which matches the Custom Action on your agent. </ResponseField> <ResponseField name="input" type="JSONValue"> Everything the agent passed to the tool. See [JSONValue](/docs/ios-sdk/json-value). </ResponseField> ```swift theme={null} cb.onToolCall = { info in let city = info.input["city"]?.stringValue await self.showToolCard(id: info.toolCallId, name: info.toolName, city: city) } ``` ## ToolResultInfo `struct ToolResultInfo: Sendable` Passed to `onToolResult`. ```swift theme={null} public struct ToolResultInfo: Sendable { public let toolCallId: String public let toolName: String public let output: JSONValue } ``` <ResponseField name="toolCallId" type="String"> Matches the `toolCallId` on the `ToolCallInfo` it belongs to. </ResponseField> <ResponseField name="toolName" type="String"> The tool's name. </ResponseField> <ResponseField name="output" type="JSONValue"> What the tool returned. An object with an `error` key means it failed. See [JSONValue](/docs/ios-sdk/json-value). </ResponseField> ```swift theme={null} cb.onToolResult = { info in let failed = info.output["error"] != nil await self.completeToolCard(id: info.toolCallId, failed: failed) } ``` <Tip> Both callbacks also run for tools the server handles, not just your own, so one piece of UI can show every tool the agent uses. </Tip> ## ToolHandler ```swift theme={null} public typealias ToolHandler = @Sendable (JSONValue) async throws -> JSONValue ``` The shape of a tool handler you register with `client.tool(_:handler:)`. See [Client-Side Tools](/docs/ios-sdk/client-side-tools). ## Lower-Level Types The types below are the pieces a reply is made of. The SDK handles them for you and gives you the results through `StreamCallbacks` and `ChatResponse`, so you do not work with them directly. They are public so you can read what a reply contains and name the types in your own code. <Warning> There is no way to read these events as they arrive. `ChatbaseClient` has no Combine publisher and no `AsyncSequence`, so there is no equivalent of Android's `sendMessageStream`. Use `send` with callbacks. If the callbacks do not give you what you need, contact support. </Warning> ### StreamEvent ```swift theme={null} public enum StreamEvent: Sendable { case messageStarted(id: String) case textChunk(String) case toolCall(ToolCall) case toolOutput(toolCallId: String, output: JSONValue) case finished(StreamFinishInfo) } ``` | Case | What it means | | --------------------------------- | -------------------------------------------------------- | | `.messageStarted(id:)` | The server created the agent's message. | | `.textChunk(String)` | A chunk of text. You get this as `onTextDelta`. | | `.toolCall(ToolCall)` | The agent asked for a tool and sent everything it needs. | | `.toolOutput(toolCallId:output:)` | The server finished a tool. | | `.finished(StreamFinishInfo)` | The reply is done and the details are final. | ### ToolCall ```swift theme={null} public struct ToolCall: Sendable { public let toolCallId: String public let toolName: String public let input: JSONValue } ``` The raw tool call inside `.toolCall`. `ToolCallInfo` is the version you get in callbacks. ### StreamFinishInfo The details that arrive when a reply ends. Everything is optional, since the server may leave any of it out. ```swift theme={null} public struct StreamFinishInfo: Sendable { public let conversationId: String? public let messageId: String? public let userMessageId: String? public let userId: String? public let finishReason: FinishReason? public let usage: Usage? } ``` <ResponseField name="conversationId" type="String?"> The conversation this reply belongs to. On a new conversation, this is where the ID first arrives. </ResponseField> <ResponseField name="messageId" type="String?"> The agent's final message ID. </ResponseField> <ResponseField name="userMessageId" type="String?"> The server's ID for the user's message. </ResponseField> <ResponseField name="userId" type="String?"> Who the reply belongs to. This fills in `client.currentUserId`. </ResponseField> <ResponseField name="finishReason" type="FinishReason?"> See [FinishReason](/docs/ios-sdk/chat-response#finishreason). Treated as `.stop` when missing. </ResponseField> <ResponseField name="usage" type="Usage?"> Credits used. Treated as `0` when missing. </ResponseField> These become the matching fields on the [`ChatResponse`](/docs/ios-sdk/chat-response) that `send` returns. <Note> Anything in a reply that the SDK does not recognize is skipped rather than treated as an error, so a shipped app keeps working as Chatbase adds new capabilities. A reply that cannot be read at all ends with `ChatError.decodingFailed`. </Note> ## Related <CardGroup> <Card title="Streaming" icon="wave-pulse" href="/docs/ios-sdk/streaming"> Using the callbacks in practice </Card> <Card title="Client-Side Tools" icon="bolt" href="/docs/ios-sdk/client-side-tools"> Registering tools the agent can run </Card> <Card title="ChatResponse" icon="brackets-curly" href="/docs/ios-sdk/chat-response"> What a finished reply contains </Card> <Card title="JSONValue" icon="code" href="/docs/ios-sdk/json-value"> Reading tool data </Card> </CardGroup> # SwiftUI Source: https://chatbase.co/docs/ios-sdk/swiftui Build a chat screen with ConversationState and ConversationListState, ready-made state that streams into your views. ## Why Use These? Building a chat list by hand means handling placeholder bubbles, tool cards, empty slots between tool calls, paging through history, and error recovery. The SDK ships two classes that do all of that for you: | Type | Use it for | | ------------------------------------------------- | ------------------------------------------------------------ | | [`ConversationState`](#conversationstate) | One chat screen: messages, streaming, tools, history, retry. | | [`ConversationListState`](#conversationliststate) | A list of past conversations, with paging. | Both update on the main thread and work with `@Observable`, so SwiftUI redraws when they change. Keep them in `@State`, in a view model, or in the environment, whichever your app already does. ## ConversationState `@MainActor @Observable final class ConversationState` ### init ```swift theme={null} public init(client: ChatbaseClient, conversationId: String? = nil) ``` <ParamField type="ChatbaseClient"> The client to send through. Register your tools on it first. </ParamField> <ParamField type="String?"> Reopen an existing conversation. Leave it out for a new one. </ParamField> ### A complete chat screen ```swift theme={null} import SwiftUI import ChatbaseSDK struct ChatScreen: View { @State private var state: ConversationState @State private var input = "" init(client: ChatbaseClient) { _state = State(initialValue: ConversationState(client: client)) } var body: some View { VStack(spacing: 0) { ScrollViewReader { proxy in List { if state.hasMoreHistory { ProgressView() .frame(maxWidth: .infinity) .task { await state.loadMoreHistory() } } ForEach(state.messages) { message in MessageRow(message: message) { Task { await state.retry(messageId: $0) } } .id(message.id) } } .onChange(of: state.messages.count) { withAnimation { proxy.scrollTo(state.messages.last?.id) } } } Composer(text: $input, isSending: state.isSending) { let text = input input = "" Task { await state.sendMessage(text) } } } .alert( "Something went wrong", isPresented: .init( get: { state.error != nil }, set: { if !$0 { state.clearError() } } ) ) { Button("OK") { state.clearError() } } message: { Text(state.error?.localizedDescription ?? "") } } } ``` Notice what you did not have to write: no placeholder handling, no joining text chunks together, no tool loop tracking. ### Showing a message ```swift theme={null} struct MessageRow: View { let message: ConversationState.UiMessage let onRetry: (String) -> Void var body: some View { switch message.kind { case .text(let text): TextBubble(text: text, isUser: message.sender == .user) .opacity(message.isStreaming && text.isEmpty ? 0.5 : 1) .overlay(alignment: .trailing) { if message.isError, let id = message.messageId { Button("Retry") { onRetry(id) } } } case .toolCall(let card): ToolCard( name: card.toolName, status: card.status, output: card.output ) } } } ``` ### What you can read | Property | Type | Description | | ------------------ | ------------- | ---------------------------------------------------------- | | `messages` | `[UiMessage]` | The messages to show, oldest first. | | `isSending` | `Bool` | A message or retry is in progress. Disable the text field. | | `isLoadingHistory` | `Bool` | A page of history is loading. | | `hasMoreHistory` | `Bool` | There are older messages to load. | | `conversationId` | `String?` | Tracked for you after the first message. | | `error` | `Error?` | The last error. Clear it with `clearError()`. | You cannot set these directly. Use the methods below. ### sendMessage ```swift theme={null} public func sendMessage(_ text: String) async ``` Adds the user's message, streams the reply into a new bubble, runs the tools, and tidies up at the end. It **never throws**. Errors go into `error`, and the failed bubble is marked with `isError`. ```swift theme={null} Task { await state.sendMessage(text) } ``` Empty text is ignored, and so is a call made while `isSending` is `true`, so you do not have to guard the button yourself (though disabling it is nicer). The conversation ID is taken from the first reply and reused after that. ### retry ```swift theme={null} public func retry(messageId: String) async ``` Asks the agent to answer again. That message and everything after it are removed from `messages`, then the new reply streams in. ```swift theme={null} Button("Regenerate") { Task { await state.retry(messageId: id) } } ``` Pass the **server's** ID from `UiMessage.messageId`, not `UiMessage.id`. The call is ignored if a message is already being sent, if there is no conversation yet, or if that ID is not in the list. ### loadHistory ```swift theme={null} public func loadHistory(conversationId: String, limit: Int = 20) async ``` Replaces `messages` with the newest page of an existing conversation and switches to it. Use it when opening a conversation from a list: ```swift theme={null} .task { await state.loadHistory(conversationId: conversation.id) } ``` ### loadMoreHistory ```swift theme={null} public func loadMoreHistory() async ``` Loads the next page of older messages and adds them to the top, skipping any you already have. Does nothing when `hasMoreHistory` is `false` or a load is already running. ### clear ```swift theme={null} public func clear() ``` Resets everything: messages, conversation ID, history, and error. Call it when the user signs out, together with `client.logout()`, or when starting a new chat: ```swift theme={null} Button("New chat") { state.clear() } ``` ### clearError and setConversationId ```swift theme={null} public func clearError() public func setConversationId(_ id: String?) ``` `clearError()` dismisses the last error. `setConversationId(_:)` points the state at a conversation without loading its messages, which is useful if you already have them from somewhere else. ## UiMessage `struct ConversationState.UiMessage: Identifiable, Sendable` One row on screen. A single message from the server can become several `UiMessage` values, one per part, so text and tool cards appear in the order the agent made them. ```swift theme={null} public struct UiMessage: Identifiable, Sendable { public enum Kind: Sendable { case text(String) case toolCall(ToolCallCard) } public var id: String public var messageId: String? public var kind: Kind public var sender: MessageSender public var date: Date public var isStreaming: Bool public var isError: Bool public var feedback: MessageFeedback? } ``` <ResponseField name="id" type="String"> A stable ID for `ForEach`. Made locally for new rows, and from the server's message for older ones. </ResponseField> <ResponseField name="messageId" type="String?"> The server's message ID, filled in once the reply finishes. Pass this to `retry(messageId:)`. </ResponseField> <ResponseField name="kind" type="Kind"> `.text(String)` for a bubble, `.toolCall(ToolCallCard)` for a tool card. </ResponseField> <ResponseField name="sender" type="MessageSender"> `.user` or `.agent`. Tool cards are always `.agent`. </ResponseField> <ResponseField name="date" type="Date"> When the row was made, or when the message was sent. </ResponseField> <ResponseField name="isStreaming" type="Bool"> `true` while text is still arriving in this bubble. Use it to show a typing dot or a cursor. </ResponseField> <ResponseField name="isError" type="Bool"> `true` when the reply failed. Show a retry button. </ResponseField> <ResponseField name="feedback" type="MessageFeedback?"> `.positive`, `.negative`, or `nil`. Set for messages loaded from history. </ResponseField> <Warning> `id` and `messageId` are different on purpose. `id` exists as soon as a row appears, so SwiftUI can animate it. `messageId` only exists once the server has given the message an ID. Use `id` for `ForEach` and `scrollTo`, and `messageId` for `retry`. </Warning> ## ToolCallCard `struct ConversationState.ToolCallCard: Sendable` ```swift theme={null} public struct ToolCallCard: Sendable { public enum Status: Sendable { case executing, success, failure } public var toolCallId: String public var toolName: String public var input: JSONValue public var output: JSONValue? public var status: Status } ``` A card appears as `.executing` as soon as the agent asks for the tool, then becomes `.success` or `.failure` when the result arrives. <Note> The status follows the SDK's usual rule: a result that is an **object with an `error` key** counts as `.failure`, and anything else counts as `.success`. This is the same rule your handlers use to report a problem. See [Client-Side Tools](/docs/ios-sdk/client-side-tools#when-a-tool-fails). If the whole reply fails, every card still showing `.executing` is switched to `.failure`, so no card spins forever. </Note> ```swift theme={null} struct ToolCard: View { let name: String let status: ConversationState.ToolCallCard.Status let output: JSONValue? var body: some View { HStack { switch status { case .executing: ProgressView() case .success: Image(systemName: "checkmark.circle.fill").foregroundStyle(.green) case .failure: Image(systemName: "xmark.circle.fill").foregroundStyle(.red) } Text(name).font(.footnote.monospaced()) } } } ``` ## ConversationListState `@MainActor @Observable final class ConversationListState` A list of the user's past conversations, loaded a page at a time. ```swift theme={null} public init(client: ChatbaseClient) ``` | Property | Type | Description | | --------------- | ---------------- | ---------------------------------------------- | | `conversations` | `[Conversation]` | The conversations loaded so far, newest first. | | `isLoading` | `Bool` | A page is loading. | | `hasMore` | `Bool` | There are more pages. | | `error` | `Error?` | The last error. Clear it with `clearError()`. | ### load ```swift theme={null} public func load(limit: Int = 20) async ``` Loads the first page and **replaces** `conversations`. Use it for the first load and for pull to refresh. ### loadMore ```swift theme={null} public func loadMore() async ``` Adds the next page to the list. Does nothing when `hasMore` is `false` or a page is already loading. ### clearError ```swift theme={null} public func clearError() ``` ```swift theme={null} struct ConversationsScreen: View { @State private var state: ConversationListState init(client: ChatbaseClient) { _state = State(initialValue: ConversationListState(client: client)) } var body: some View { List { ForEach(state.conversations) { conversation in NavigationLink(conversation.title ?? "New conversation") { ChatScreen(conversationId: conversation.id) } } if state.hasMore { ProgressView() .task { await state.loadMore() } } } .task { await state.load() } .refreshable { await state.load() } } } ``` ## Using UIKit Neither class is tied to SwiftUI. From UIKit you can watch them with `withObservationTracking`, or skip them and call `client.send(_:conversationId:configure:)` yourself, switching to the main thread inside the callbacks: ```swift theme={null} Task { do { let response = try await client.send(text) { cb in cb.onTextDelta = { chunk in await MainActor.run { self.appendToBubble(chunk) } } } await MainActor.run { self.finalize(response) } } catch { await MainActor.run { self.showError(error) } } } ``` ## Related <CardGroup> <Card title="Streaming" icon="wave-pulse" href="/docs/ios-sdk/streaming"> The send and callback API underneath </Card> <Card title="Client-Side Tools" icon="bolt" href="/docs/ios-sdk/client-side-tools"> What fills in the tool cards </Card> <Card title="Conversations & History" icon="messages" href="/docs/ios-sdk/conversations"> The paging behind these classes </Card> <Card title="Error Handling" icon="triangle-exclamation" href="/docs/ios-sdk/error-handling"> Turning `state.error` into a good message </Card> </CardGroup> # User Identity Source: https://chatbase.co/docs/ios-sdk/user-identity How to sign users in with JWT tokens and work with device identity in the Chatbase iOS SDK. ## Overview The SDK has two levels of identity: | Level | How it works | What conversations belong to | | ----------------- | ------------------------------------- | ---------------------------- | | **Device ID** | Automatic, created on first use | The device | | **User identity** | Optional, you call `identify(token:)` | The user | The SDK works anonymously out of the box. Call `identify(token:)` to tie conversations to a specific user. Every request includes the device ID in an `X-Device-Id` header. Once the user is signed in, requests also include the JWT in `X-User-Token`. The SDK sets both headers for you. ## Device ID Every install gets a device ID the first time the SDK needs one: ```swift theme={null} public var deviceId: String { get } ``` ```swift theme={null} let client = ChatbaseClient(agentId: "YOUR_AGENT_ID") print(client.deviceId) // "A1B2C3D4-E5F6-..." ``` <Note> The device ID is a `UUID` saved in `UserDefaults.standard` under the key `com.chatbase.sdk.deviceId`. It stays the same across app launches and across clients, and it is created only once per install, even if you create several clients at the same time on a cold start. </Note> <Warning> Because it lives in `UserDefaults`, the device ID does **not** survive a reinstall, and it is included in device backups, so restoring a backup on a new device reuses the same ID. Anonymous conversations follow that ID. If you want conversations to survive a reinstall, sign the user in with a JWT. </Warning> ## identify ```swift theme={null} public func identify(token: String) async throws ``` Checks a JWT with the Chatbase server and signs the user in. Later requests belong to that user, and the token is saved so the user stays signed in after the app restarts. <ParamField type="String"> An HS256 JWT created by your backend and signed with your agent's identity verification secret. The payload needs a `user_id` (or `sub`) claim. </ParamField> <Steps> <Step title="Create a JWT on your backend"> Sign a JWT with your agent's identity verification secret, with the user ID in the payload. See [Identity Verification](/docs/developer-guides/identity-verification) for the token format and where to find the secret. <Warning> Never put the identity verification secret in your app. Anyone can pull it out of an app bundle. Create tokens on your server and fetch them through your own API. </Warning> </Step> <Step title="Pass the token to the SDK"> ```swift theme={null} do { try await client.identify(token: jwt) } catch { // The token was rejected. See Error Handling. } ``` Conversations now belong to this user. </Step> <Step title="Check that it worked"> ```swift theme={null} if case .identified = client.authState { print("Signed in") } print(client.currentUserId) // set after the first reply finishes ``` </Step> </Steps> `identify(token:)` throws if the token is invalid, expired, signed with the wrong secret, or if identity verification is not set up for the agent. When it throws, the SDK's sign-in state does not change, so a failed call cannot leave you half signed in. <Info> When sign-in succeeds, the server also moves conversations created anonymously on this device into the user's account, so history from before sign-in is kept. The server does this in the background. A [`listConversations()`](/docs/ios-sdk/conversations#listconversations) call made right after `identify` returns may not show them yet. Refresh a moment later, or the next time the screen appears. </Info> ## AuthState ```swift theme={null} public enum AuthState: Sendable, Equatable { case anonymous case identified(token: String) } ``` ```swift theme={null} public var authState: AuthState { get } ``` ```swift theme={null} switch client.authState { case .anonymous: showSignInPrompt() case .identified: showAccountBadge() } ``` <Note> There is no `isIdentified` property. Check `authState`, or add your own shortcut: ```swift theme={null} extension ChatbaseClient { var isIdentified: Bool { if case .identified = authState { return true } return false } } ``` </Note> ## Staying Signed In The token is saved in the **Keychain** (service `com.chatbase.sdk`, account `userToken`), and it can be read after the device is first unlocked. A new `ChatbaseClient` loads it when it is created, so the user stays signed in across app launches without calling `identify` again: ```swift theme={null} let client = ChatbaseClient(agentId: "YOUR_AGENT_ID") if case .identified = client.authState { // Loaded from the Keychain, already signed in } ``` <Warning> The SDK does not check when the token expires. An expired token stays in `authState` until a request fails with `401` `AUTH_INVALID_JWT`. Handle that by getting a new token and calling `identify(token:)` again: ```swift theme={null} do { _ = try await client.send(text, conversationId: conversationId) } catch let error as APIError where error.statusCode == 401 { try await client.identify(token: await AuthAPI.freshChatbaseToken()) _ = try await client.send(text, conversationId: conversationId) } ``` Calling `identify(token:)` on every launch where the user is already signed in is cheap, and it keeps the saved token fresh. </Warning> ## Identity Properties | Property | Type | Description | | --------------- | ----------- | ------------------------------------------------------------------------------- | | `deviceId` | `String` | The device ID. Always available. | | `authState` | `AuthState` | `.anonymous`, or `.identified(token:)` after a successful `identify`. | | `currentUserId` | `String?` | The user ID the server confirmed on the last finished reply. `nil` before that. | <Note> `currentUserId` comes from the end of a reply, so it appears after the first `send` or `retry` finishes, not right after `identify`. It is also set for anonymous users once the server assigns a user record to the device. </Note> ## What Identity Changes <Info> Once signed in, conversations belong to the user, so `listConversations()` returns that user's conversations from every device they have signed in on. Without sign-in, conversations belong to the device. </Info> ## logout ```swift theme={null} public func logout() ``` Removes the saved token and goes back to anonymous. There is no network call. ```swift theme={null} client.logout() print(client.authState) // .anonymous print(client.currentUserId) // nil print(client.currentConversationId) // nil print(client.deviceId) // unchanged ``` `logout()` also deletes the token from the Keychain and clears `currentUserId` and `currentConversationId`, so the next message starts a new anonymous conversation. <Warning> `logout()` does not clear message lists you are already showing. Call [`ConversationState.clear()`](/docs/ios-sdk/swiftui#clear), or reset your own state, at the same time, so the previous user's messages are not left on screen. ```swift theme={null} client.logout() state.clear() ``` </Warning> ## Switching Users To switch from one user to another, log out first so nothing carries over: ```swift theme={null} client.logout() state.clear() try await client.identify(token: newUserToken) ``` ## Related <CardGroup> <Card title="Identity Verification" icon="key" href="/docs/developer-guides/identity-verification"> Creating signed JWTs on your backend </Card> <Card title="Conversations & History" icon="messages" href="/docs/ios-sdk/conversations"> List conversations and load old messages </Card> <Card title="Error Handling" icon="triangle-exclamation" href="/docs/ios-sdk/error-handling"> Handling expired and rejected tokens </Card> <Card title="Overview" icon="book-open" href="/docs/ios-sdk/overview"> Setup and configuration </Card> </CardGroup> # Chatbase Experts Program Source: https://chatbase.co/docs/user-guides/chatbase-experts/experts-program The Chatbase Experts Program is built for agencies, consultants and freelancers who create AI agents for clients. It enables you to design, test, and configure agents in one place, then seamlessly copy them to your clients' own Chatbase workspaces when they're ready to go live. ## Overview Here's what you'll learn in this guide: <Steps> <Step title="Apply to Chatbase Experts Program"> Apply to join the Experts Program and get approved </Step> <Step title="Build agents"> Access Pro features to build agents for clients </Step> <Step title="Copy Agents to Clients"> Use Remix Links to hand off agents to your clients' workspaces </Step> <Step title="Earn Commissions"> Get rewarded for bringing new customers to Chatbase </Step> </Steps> ## Apply to Chatbase Experts Program Joining the Experts Program requires approval. ### How to Apply <Steps> <Step title="Visit the Application Page"> Go to the [Apply for the experts program](https://www.chatbase.co/experts-program/apply) page. </Step> <Step title="Submit the Application Form"> Complete the form with details about your business and how you plan to use Chatbase. </Step> </Steps> ### What Happens Next <Info> Your application will be reviewed by the Chatbase team. You'll receive an email notification once your application is approved or declined. </Info> ## Your Agency Workspace Once approved, a dedicated workspace on "Agency" plan is added to your Chatbase account. ### What You Get <CardGroup> <Card title="Pro Features" icon="star"> Full access to all Chatbase Pro features </Card> <Card title="More agents" icon="arrow-up"> Effectively manage more agents for different clients </Card> <Card title="Multi-Client Support" icon="users"> Ability to copy agents to clients when they are production-ready </Card> </CardGroup> ### Agency Workspace Limits Your Agency workspace includes: | Resource | Limit | | ---------------- | --------------- | | **Credits** | 1,000 per month | | **Agents** | Up to 20 | | **Team members** | Up to 10 | | **Source size** | Up to 60 MB | | **Actions** | Up to 15 | <Warning> **Not for production use.** Agents created in an Agency workspace should be copied to a client's workspace before being used in production. The credits provided are intended for development and testing only. </Warning> ## Copying Agents to Clients Chatbase uses **Remix Links** to copy agents from your Agency workspace to a client. <Info> A Remix Link creates an exact copy of your agent at the time the copy process began and allows your client to import it into their own workspace. </Info> ### Create a Remix Link <Steps> <Step title="Go to Your Agents Page"> Navigate to your Agents page in the Agency workspace. </Step> <Step title="Locate the Agent"> Find the agent you want to copy to your client. </Step> <Step title="Open the Menu"> Click the three dots (**...**) button on the agent card. </Step> <Step title="Copy the Remix Link"> Select **Copy remix link** from the menu. </Step> <Step title="Share with Your Client"> Send the link to your client via email, messaging, or your preferred communication channel. </Step> </Steps> ### When a Client Uses a Remix Link When your client confirms the Remix: * A copy of the agent is added to the client's workspace * The new agent becomes fully owned and managed by the client * The agency and client agents operate independently ## Additional Setup After Copying Some extra setup may be **needed by the client** after importing the agent: <AccordionGroup> <Accordion title="Webhook Secret Keys"> We create new secrets for your webhooks. If you use the webhook secrets to verify the sender identity, you need to update them with the new secrets. Learn more about [webhook configuration](/docs/developer-guides/webhooks). </Accordion> <Accordion title="Deployments"> Deployment integrations such as WhatsApp, Slack, Instagram, or other channels are not copied and must be manually connected by the client. </Accordion> <Accordion title="Add-ons"> Add-ons (e.g., remove branding, auto-recharge credits) must be purchased separately as needed. Learn more about [workspace usage and add-ons](/docs/user-guides/workspace/usage). </Accordion> <Accordion title="Training"> The agent's sources will be copied but the agent won't be trained on them yet. The client needs to trigger the agent's training after import. </Accordion> </AccordionGroup> ### What's Not Copied While most agent settings are copied, the following are **not** included: * **Deployment integrations** such as WhatsApp, Zendesk, Instagram, Email channel, etc. * **Slack Notify action** as Slack workspaces can't be connected to multiple agents at the same time * **Shopify actions** as Shopify stores can't be connected to multiple agents at the same time * **Notion sources** as Notion workspaces can't be connected to multiple accounts ## Important Things to Know <Warning> **Remix links expire after 7 days.** Generate a new link if your client needs more time. </Warning> Keep these key points in mind: * Clients must be on a subscription plan that supports the agent's features (e.g., number of actions, source size limits, ...) * Changes made to the original agent **do not** affect the client's copy * Deleting the original agent **does not** impact copied agents * Each copy creates a completely independent agent ### Working Together After Remix If you need to continue collaborating with a client after the remix, you can: * Create and share a new Remix Link with an updated version of the agent. The client can import it alongside the existing agent. * Have the client invite you as a collaborator to their workspace. This gives you direct access to manage and update the agent together. ## Experts Commissions Chatbase Experts can earn commissions for bringing new customers to Chatbase. ### How Commissions Work <Info> You earn a commission when a **first-time paying Chatbase customer** imports your Remix Link. No commission is earned if the client already has a paid Chatbase account. </Info> ### Commission Details | Detail | Value | | ------------------- | -------------------------------- | | **Commission rate** | 30% of the client's subscription | | **Duration** | Paid for the first 12 months | | **Eligibility** | First-time paying customers only | ### Tracking & Payouts All commissions are tracked and paid through [Dub.co](https://dub.co). You can view your earnings and payout status: * In your Dub.co dashboard * Via your [rewards dashboard](https://www.chatbase.co/affiliate) <Info> **Need more help?** Contact our support team at [support@chatbase.co](mailto:support@chatbase.co) for assistance with the Experts Program. </Info> # Overview Source: https://chatbase.co/docs/user-guides/chatbot/actions/actions-overview AI actions let your agent do more than answer questions. During a conversation, the agent can trigger a task, pull in data, or hand off to a person, so it can actually resolve requests instead of just replying to them. Each action connects your agent to a specific tool or workflow. The available actions are below. Support and handoff * **Escalations**: Create a support ticket in your ticketing system when a customer needs human help. * **Chatbase live chat**: Hand off from the AI agent to a human agent in Chatbase. * **Salesforce live chat**: Hand off to a human agent in Salesforce. * **Sunshine live chat**: Hand off to a human agent in Sunshine. Commerce * **Stripe**: Handle billing, invoices, and subscription queries in chat. * **Shopify**: Recommend products, manage the cart, place orders and exchanges, and answer order and delivery questions. Lead capture * **Collect leads**: Capture user details as leads. * **Collect data**: Conversationally collect any custom fields you define from the user, mid-chat. * **Custom form**: Collect information from users with a custom form. Scheduling * **Cal**: Let customers check availability and book meetings without leaving the chat. * **Calendly**: Let customers check availability and book meetings without leaving the chat. Other * **Custom actions**: Call your API, run client-side code, and optionally show an interactive widget. * **Suggested messages**: Show suggested replies based on the conversation. * **Slack**: Send notifications and updates to your Slack channels. * **Web search**: Give your agent real-time web search to answer questions with live data. * **Custom button**: Add buttons that trigger your own links and redirects. <Note> Note that you can create more than one action of the same type.\ Example: Escalations on your website and Escalations on Instagram, in case they need separate "when to use" rules or different data to collect from the user before opening the ticket. </Note> <Frame> <img alt="Available AI Actions" /> </Frame> <Frame> <img alt="Available AI Actions" /> </Frame> ## Only use in procedures Every action has an **Only use in procedures** setting in its configuration. Turn it on when you want the action to run **only** as a step inside a [procedure](/docs/user-guides/chatbot/procedures/procedures-overview), never on the agent's own initiative. When enabled, the action stays fully functional, but the agent won't call it based on its own judgment; it fires only when a procedure step references it with `@action_name`. Because the agent no longer decides when to use it, its **When to use** field is hidden. Use it for high-control or sensitive tools (refunds, cancellations, escalations) that should fire only at the right point in a defined flow. See [How procedures run](/docs/user-guides/chatbot/procedures/how-procedures-run#procedure-only-actions) for how this behaves at runtime. <Frame> <img alt="The Only use in procedures setting on an action" /> </Frame> # Cal.com Source: https://chatbase.co/docs/user-guides/chatbot/actions/cal All you need to do to connect your Cal account is to add your Event URL under 'Cal.com Event URL'. You **do not** need an integration for Cal.com. First of all go to **Build > Actions**, **Create Action** then Select "Calcom Get Slots" **When to use** This is where you specify when exactly this action should be triggered or what type of customer queries would trigger it. You also need to give your Action (make sure it's descriptive as this helps the AI understand when to use it). <Info> You can choose to display Cal.com meeting times in a **12-hour format (AM/PM)** instead of the default 24-hour format. </Info> Finally add your Cal Event URL into the correct field. This tells which Event to making bookings into. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ### Examples:  "Call this action when the user mentions that he/she wants to book an appointment." "Check if the user booked an appointment or not from the tool result."  <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> # Calendly Source: https://chatbase.co/docs/user-guides/chatbot/actions/calendly ## Action Creation In order to create this action, you would first need to integrate with your Calendly account through the **Integrations** tab. Once connected go to the **Build > Actions** tab, **Create Action** and select the "Calendly Get Slots" Action. Next select the Event from the dropdown that you want your Agent to use for bookings. * **When to use**: This is where you specify when exactly this action should be triggered or what type of customer queries would trigger it. You can also add in some instructions that the bot should adhere to when this action is triggered. <Info> You can choose to display Calendly meeting times in a **12-hour format (AM/PM)** instead of the default 24-hour format. </Info> <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ## Examples "Use when the user mentions booking an appointment for Essay Feedback. If no date is specified, automatically set the window from today to 1 week from today and display these dates to the user without asking for confirmation. If a date window is specified, set the search window to that specific date window and display it to the user. After performing the search, respond with either "I have found available slots" or "I have not found available slots" Display the search window but do not provide a list of slots or links. After using the tool, check whether the user attempted to book an appointment. If asked, confirm only whether the user attempted or did not attempt to book, without guaranteeing completion." # Chatbase Live Chat Source: https://chatbase.co/docs/user-guides/chatbot/actions/chatbase-live-chat The Chatbase Live Chat action allows your AI agent to hand over conversations to a human support agent through the Chatbase Help Desk. When triggered, the conversation is routed directly to your Help Desk inbox so your team can continue assisting the user in real time. *** ## How It Works ### End-user experience When the AI agent determines that a user wants to speak with a human, the conversation is handed over to a live support agent. The user will see a confirmation message in the chat bubble indicating that a support agent will join shortly. **During this state:** * The AI agent stops handling the conversation * The chat is marked as a live chat request * The user remains connected in the widget while waiting for an agent to respond <Frame> <img alt="Supported Platforms" /> </Frame> ### Support Agents' experience Support agents are notified immediately when a conversation is escalated to live chat. Inside their inbox, the conversation is clearly labeled as a Live chat session so agents can prioritize and respond accordingly. <Frame> <img alt="Supported Platforms" /> </Frame> Agents can then: * Reply directly to the user in real time * Add internal notes * Continue the conversation from the existing thread * Take over seamlessly from the AI agent *** ## Best Practices * Only enable live chat if you have support agents available to respond. * Keep the trigger instructions strict to avoid unnecessary escalations. * Let the AI handle common questions before escalating to a human. * Use live chat for sensitive, urgent, or account-specific issues. # Collect Data Source: https://chatbase.co/docs/user-guides/chatbot/actions/collect-data The Collect Data action lets your AI agent gather any custom information you define from the user, conversationally, mid-chat. There's no form: the agent asks for the missing fields naturally in the conversation and saves the submission once it has everything required. You can create more than one Collect Data action on the same agent, each with its own name, fields, and destinations. For example, one action to collect a shipping address and a separate one to collect feedback details. **Action name:** A descriptive name for this action. It doubles as the identifier for this action's webhook events, so it must be unique across your agent's actions. **When to use:** Explain when the AI agent should collect this data from the user. Include a description of what information is collected and its purpose, and add example queries that should trigger this action. **Best Practices for Instructions** * Make sure to use natural language. * Keep the sentences short and simple. * Include examples that show the model what a good response looks like. * Focus on what you'd like the bot to do rather than what to avoid. Start your prompts with action-oriented verbs, e.g., generate, create, and provide. ## Fields In the Fields section, list the data the AI agent should collect from the user during the conversation. Each field has a name, a type (text, number, email, date, or boolean), a description that tells the AI what to ask for, and a required checkbox. You can add up to 20 fields. The AI asks for all required fields before saving the submission; optional fields are saved when the user provides them but never block the save. The AI never invents values: it only saves what the user has explicitly provided. Each time the agent completes a collection it is saved as its own submission, so if the action runs more than once in a conversation you get one submission per run. Collected data appears under **Activity > Collected data**, where each field gets its own column. Fields are also included in CSV and PDF exports and in the [`{action name}_collect_data.submit` webhook](/docs/developer-guides/webhooks). ## Destinations Use **Destinations** to specify where collected data should be sent. ### Webhooks Add one or more webhook endpoints to receive each submission as a `POST` request. To add a webhook: 1. Expand **Destinations**. 2. Enter the endpoint URL. 3. Click **Create webhook**. 4. Save your changes. You can also skip this step if you do not want to send collected data to an external endpoint. ### Email notifications Enable Email notification to receive an email every time data is collected through this action. You can add one or more email addresses, and each successful submission will trigger an email containing the collected data. <Note> Email notifications are not available for HIPAA accounts. On HIPAA accounts, collected field values are also redacted before they're stored. </Note> ## Channels Use **Channels** to control where the Collect Data action is available. Enable or disable the action for each configured channel, such as: * Chat bubble * Center stage * Side panel * Help page * Instagram * Messenger * WhatsApp Some channels may be incompatible with the action and will not be available for selection. After choosing the supported channels, click **Save**. *** After you're done editing, you can preview all your settings in the AI agent found on the Action page. Finally, press the **Save and enable** button and your action will be live ready for your agent to serve to users. # Collect Leads Source: https://chatbase.co/docs/user-guides/chatbot/actions/collect-leads Through the Collect Leads action, you will be able to customize when exactly does the 'Lead' form get triggered during the conversation that your customer is having with the bot. **When to use:** In this field, you specify when exactly you would like for the form to show during the conversation. You can also specify other instructions related to the action, such as 'Show only the leads form without listing the form's fields'. Previewing the action will help you spot the edits you may like to make. **Best Practices for Instructions** * Make sure to use natural language. * Keep the sentences short and simple. * Include examples that show the model what a good response looks like. * Focus on what you'd like the bot to do rather than what to avoid. Start your prompts with action-oriented verbs, e.g., generate, create, and provide. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ## Fields In the Fields section, you first choose how the agent collects the lead's details: * **Form**: the agent displays a form inside the chat bubble. * **Conversational**: the AI asks for the details naturally in chat, one message at a time, and saves the lead once it has everything required. This mode also supports custom fields. <Note> Whichever mode you pick, either E-mail or Phone Number must be enabled and set as required. This guarantees every saved lead has a way to be contacted, and the action cannot be saved without it. </Note> ### Form mode You can enable/disable any of the three available fields in the form (Name, E-mail and Phone Number). You also can set any of them (or all of them) to be a required field. <Note> you can only have a maximum of three fields in a Lead Form, and custom fields are not available in this mode. </Note> ### Conversational mode In conversational mode, the AI gathers the lead's details in chat on every channel. The fields table has two parts: * **Identity fields**: Name, E-mail, and Phone Number. Each can be toggled on or off and marked as required. Their types are fixed, and you can add a description to guide the AI on how to ask for them. * **Custom fields**: any extra details you want collected, such as company name or budget. Each custom field has a name, a type (text, number, email, date, or boolean), a description that tells the AI what to ask for, and a required checkbox. The AI asks for all required fields before saving the lead; optional fields are saved when the user provides them but never block the save. <Frame> <img alt="Conversational fields editor with identity and custom fields" /> </Frame> The AI never invents values: it only saves what the user has explicitly provided, and if the user shares more details later in the conversation, the lead is updated without losing what was already collected. Collected leads appear under **Activity > Leads**, where each custom field gets its own column. Custom fields are also included in CSV and PDF exports and in the [`leads.submit` webhook](/docs/developer-guides/webhooks). **Success Message:** Customize the message that gets displayed once the customer submits the form. **Dismiss Message:** Customize the message that shows once the customer dismisses the form by clicking on the 'X' button. This only applies to form mode, since conversational mode has no form to dismiss. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ## Destinations Use **Destinations** to specify where collected lead information should be sent. ### Webhooks Add one or more webhook endpoints to receive each collected lead as a `POST` request. To add a webhook: 1. Expand **Destinations**. 2. Enter the endpoint URL. 3. Click **Create webhook**. 4. Save your changes. You can also skip this step if you do not want to send collected leads to an external endpoint. ### Email notifications Enable Email notification to receive an email every time a lead is collected through the Collect Leads action. You can add one or more email addresses, and each successful lead submission will trigger an email containing the collected lead information. <Note> This is different from the **Daily leads** email notification available under **Settings → Notifications**. Email notifications configured here are sent **immediately for each collected lead**, whereas the daily leads notification sends a summary of leads collected throughout the day. </Note> ## Channels Use **Channels** to control where the Collect Leads action is available. Enable or disable the action for each configured channel, such as: * Chat bubble * Help page * Instagram * Messenger * WhatsApp Some channels may be incompatible with the action and will not be available for selection. After choosing the supported channels, click **Save**. *** After you're done editing, you can preview all your settings in the AI agent found on the Action page. Finally, press the **Save and enable** button and your form will be live ready for your agent to serve to users. # Custom Action Source: https://chatbase.co/docs/user-guides/chatbot/actions/custom-action ## Create Custom Action This action allows you to instruct the AI agent to provide any information that's included in the response of the API you use. ### Action Types When creating a custom action, you select a **type** that determines how the action behaves: | Type | Description | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Server** | Calls an external API and returns the response to the agent. The agent uses the response data in its reply. | | **Server with UI (Widget)** | Calls an external API, then displays a [widget](/docs/developer-guides/widgets/overview) inline in the chat with the response data. Use this to show rich, interactive UI after fetching data. | | **Client** | Executes code in the user's browser via the [JavaScript embed script](/docs/developer-guides/client-side-custom-actions). Useful for accessing browser APIs and frontend context. | | **Widget only (UI only)** | Displays a [widget](/docs/developer-guides/widgets/overview) inline in the chat without calling an API. The agent populates the widget from the conversation context. Use this for forms, info cards, and interactive menus. | <Info> **Server with UI** and **Widget only** actions let you attach a widget to the action. You can create and manage widgets directly from the action's configuration page. See the [Widgets documentation](/docs/developer-guides/widgets/overview) for details on building widgets. </Info> ### General * Action Name: This is a descriptive name for this action. This will help the AI agent know when to use it. * When to use: This is the area of instructions that should be provided as a detailed description explaining when the AI agent should use this action and API. It's recommended to include examples of the data this action provides and customer queries it helps answer. * All custom action requests must send a **JSON body**, and all custom action responses must be **JSON-formatted**. * You should click on the Save and Continue button after completing the above configuration. ### API * Collect data inputs from user: Here you should add the list of information the AI agent needs from the user to perform the action. * Name: Name of the data input. * Type: Type of the data input. * Description: A small sentence that describes to the AI agent the data input that it's expecting to use in the API. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> * API request: The API endpoint that should be called by the AI Agent to retrieve data or to send updates. You can include data inputs (variables) collected from the user in the URL or the request body. * Method: Choose the method that the API should use. * HTTPS URL: The URL of the API that the AI agent should use to retrieve the needed information. * Add variable: This button should be used when you want to add a variable that depends on the user's input. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> When the URL is added, the parameters, Headers and Body of the API should be added automatically. * Parameters: These are key-value pairs sent as part of the API request URL to provide input data or filter the response. * Headers: Metadata sent along with the API request to provide information about the request or client. * Body: The data sent as part of the request, typically for GET, POST, PUT, DELETE methods. The body should be **JSON-formatted**. You should click on the Save and Continue button after completing the above configuration. ### Test Response * Live response: Test with live data from the API to make sure it is configured correctly. * Example response: Use example JSON data if the API is not ready. * You should click on the Save and Continue button after completing the above configuration. ### Data Access * Full data access: Allow the AI agent to access all available information from the API's response, ensuring comprehensive responses based on complete data. * Limited data access: Limit the information the AI agent can access, providing more controlled and specific replies while protecting sensitive data. * You should click on the Save and Continue button after completing the above configuration. > **Notes:** > > 1. The maximum response size is 20KB. Anything exceeding that will return an error. > 2. The returned response must be JSON-formatted. ## Use Cases ### Upgrade Subscription In this example, we use an Upgrade Subscription to allow the user to ask from the AI agent to upgrade their subscription to the premium plan. In the General section, we added Update\_Subscription as the name of the action. We provided the "When to use" information for the AI agent to use this API whenever the user wants to upgrade the subscription. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the API section, we added the API used to retrieve the subscription. We added the status of the plan and new plan requested, and the description of the input as follows: Active or canceledif they want to upgrade to premium, send 'active'. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the API request section, we added the API URL ([https://demo-rhythmbox.chatbase.fyi/api/update-subscription](https://demo-rhythmbox.chatbase.fyi/api/update-subscription)) and set the method as GET. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the Test Response section, we tested the response of the API when we provided active and premium as a subscription upgrade example. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the Data Access section, we choose the Full Data Access option for the AI agent to access all the information from the API response. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Now, we're ready to ask the AI agent to upgrade or downgrade the subscription when the user asks about it in the Playground. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ### Weather API In this example, we use a Get Weather API to provide the weather information for the cities asked by the user to the AI agent. In the General section, we added Get\_Weather as a name of the action. We provided the When to use information for the AI agent to use this API whenever it's asked about the weather of any city. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the API section, we added the API used to retrieve the weather information. We added the name of the input as City, the type of the input is Text, and the description of the input as follows: The city that you want to know its weather. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the API request section, we added the API URL ([https://wttr.in/\\\\\{\\\\\{city}}?format=j1](https://wttr.in/\\\\\{\\\\\{city}}?format=j1)) and set the method as GET. The key value pair in the parameters is added automatically after entering the URL. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the Test Response section, we tested the response of the API when we provided London as a city example. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> In the Data Access section, we choose the Full Data Access option for the AI agent to access all the information from the API response. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Now, we're ready to ask the AI agent the weather of any city the user asks about in the Playground. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> # Custom Button Source: https://chatbase.co/docs/user-guides/chatbot/actions/custom-button ### Add Custom Button The Custom Button action allows the AI agent to send a clickable button to the user when he asks about a specific topic.  * Action name: This field is only showing the name of the action in the dashboard. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Next scroll donw and select the Custom Button. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Now give your Custom Button an Action name. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Next complete tell the AI when to use the custom button. This is the area of instructions that should be provided as a detailed description explaining when the AI agent should use this action. It's recommended to include examples of the data this action provides and customer queries it helps answer. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Button text: This is the text shown on the button provided to the users once asked about a specific topic. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> * URL: This is where to add the URL that the button should route the users to. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> After finishing the Custom Button configuration, you should click on the Save button. Then the action should be enabled from the top right corner in the page. You can find the Playground area where you try the action before enabling it. It's recommended to try sending a message in the Playground to ensure that the AI agent sends the button with the URL when the desired instructions are fulfilled before enabling the action. ## Example: "Provide the user a button when they ask about the pricing plans, the difference between any of Chatbase plans or the features available in each one. For example, when the user asks about the number of AI agents in the standard plan, you should let him know that the plan offers 5 AI agents and provide the button of the pricing page." <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> # Escalations Source: https://chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human This action allows the AI agent to escalate a conversation to a human support agent by creating a ticket in one of your integrated helpdesk platforms. Before creating this action, you must first enable chatbase helpdesk or connect your helpdesk platform from **Integrations** in the sidebar.<br /><br />Only platforms that are already integrated from **Integrations** will appear in the ticket platform dropdown. Supported platforms: * Chatbase * Zendesk * Salesforce * Intercom * Zoho Desk * Freshdesk * HubSpot * Help Scout * Gorgias <Frame> <img alt="Image" /> </Frame> *** ### General **Action Name:** A descriptive name for this action. This helps the AI Agent understand when to trigger it. **Example:** * create\_ticket * create\_ticket\_Meta * create\_ticket\_website * create\_ticket\_refunds **When to use:** Clearly explain when the AI Agent should use this action. **Example instructions:** Create a ticket when: * The user asks to speak to a human. * The user asks a question you don't know the answer to. * The user asks for billing disputes, account issues, complaints, or sensitive matters. Example user queries that should trigger escalation: * "I want to speak to a human." * "Connect me to support." * "This didn’t solve my issue." * "I need help with my billing." **Channels:** Specify the channels where this action can be used. For example: * Chat bubble * Help page * Whatsapp You should click on the Save & enable button after completing the above configuration. *** ## How It Works When triggered, the Escalate to Human action will: * Create a new ticket in the selected platform * Include user information (if available) *** ## For Zendesk Tickets **Conversation context:** Choose whether to include an **AI-generated summary** or the **full conversation transcript** in the created ticket. **Internal note:** When escalating a ticket to Zendesk, you can add an **internal note** that will be included with the ticket. Use variables to have the AI dynamically fill in relevant details from the conversation. **Custom Fields:** The AI agent can access and populate your Zendesk custom fields. ## Use Cases ### Explicit Human Request In this example, the AI agent is instructed to escalate when a user directly asks for human assistance. Example queries: * "I want to talk to a real person." * "Can someone from support contact me?" * "This is urgent, I need help." Once triggered, a ticket is created in the selected helpdesk platform, and your team can continue the conversation from there. <Note> When the ticket platform is Chatbase, you can collect the required user details conversationally instead of through a form. You can also mark which fields are required, meaning the AI must collect them from the user before opening the ticket. </Note> <Frame> <img alt="Image" /> </Frame> # Salesforce Actions Source: https://chatbase.co/docs/user-guides/chatbot/actions/salesforce-actions Create support tickets and connect users to live agents in Salesforce when your AI agent needs to escalate customer issues ## Overview Salesforce Actions enable your AI agent to seamlessly create support tickets (cases) and connect users to live support agents directly within the chat interface. These actions provide a smooth escalation path when the AI agent cannot resolve customer issues, ensuring users receive the appropriate level of support based on urgency and complexity. <Info> Before using Salesforce actions, you must [set up Salesforce integration](/docs/user-guides/integrations/salesforce) with your Chatbase account </Info> ## Available Salesforce Actions ### 1. Create Ticket Create a support ticket (case) in Salesforce when the AI agent cannot solve the user's problem and the issue does not require immediate assistance. This action allows users to receive follow-up support without needing real-time interaction. <Card title="Best for:" icon="ticket"> Handling non-urgent issues that can be resolved through asynchronous support, tracking customer inquiries, and ensuring all support requests are logged in Salesforce for proper follow-up. </Card> **Common Use Cases:** * "The AI agent couldn't answer my question about billing" * "I want to report a bug I found" * "Can someone follow up with me about this issue?" #### Setup Instructions <Steps> <Step title="Create the Action"> Navigate to **Build > Actions** → **Create action** and select **Create ticket**. </Step> <Step title="Configure Action Details"> **Action name:** Enter a unique name for the action. **Ticket platform:** Choose Salesforce **When to use:** Provide detailed instructions for when the AI should use this action. For example: * Use this action when you cannot answer the user's question or solve their problem * Use this action when the user explicitly requests to create a ticket or case * Use this action for non-urgent issues that don't require immediate human assistance * Do not use this action if the user needs immediate help or expresses urgency </Step> <Step title="Save and Enable"> Click **Save** and toggle the action to **Enabled** to make it available to your AI agent. </Step> </Steps> ### 2. Live Chat Connect the user to a real human support agent in Salesforce when the AI agent cannot solve the user's problems and the issue requires immediate resolution. This action enables real-time support escalation for urgent matters. <Card title="Best for:" icon="headset"> Handling urgent issues that require immediate human assistance, complex problems that need real-time troubleshooting, and situations where customers express frustration or need instant resolution. </Card> **Common Use Cases:** * "I need to speak to a human right now" * "This is urgent and I need immediate help" * "The AI agent isn't helping me, connect me to support" * "I have a critical issue that needs to be resolved immediately" #### Setup Instructions <Steps> <Step title="Configure Salesforce Org for Live Chat"> Set up your Salesforce org to enable messaging and live chat functionality. Complete the following configuration steps in order: **1. Enable Messaging Settings** Navigate to **Setup** in Salesforce. In the **Quick Find** box, search for "Messaging" and select **Messaging Settings**. Enable messaging by turning on the toggle. <Info> Messaging Settings must be enabled before you can create messaging channels or use Enhanced Chat features. </Info> **2. Set Up Omni-Channel** Configure Omni-Channel to enable intelligent routing of live chat sessions to available agents: 1. In **Setup**, search for "Omni-Channel" in the Quick Find box 2. Follow the Omni-Channel setup wizard to configure: * **Service Presence**: Set up agent presence statuses (Available, Busy, Offline) * **Routing Configurations**: Define how chats are routed to agents * **Service Channels**: Configure the chat channel for Omni-Channel routing * **Agent Workload**: Set the maximum number of simultaneous chats per agent <Info> For detailed Omni-Channel setup instructions, refer to the [Salesforce Omni-Channel preparation guide](https://help.salesforce.com/s/articleView?id=service.miaw_prepare_org_1.htm\&type=5). </Info> **3. Configure Enhanced Chat User Verification** Set up JSON Web Token (JWT) verification to securely authenticate users connecting through Chatbase: 1. In **Setup**, search for "Enhanced Chat User Verification" in the Quick Find box 2. Navigate to **JSON Web Keysets** 3. Click **New** to create a new keyset 4. Choose **Endpoint** as the type of the keyset 5. Enter the following URL in the **Endpoint URL** field: ``` https://chatbase.co/api/integrations/salesforce/keys?chatbotId=<YOUR_CHATBOT_ID> ``` Replace `<YOUR_CHATBOT_ID>` with your actual Chatbase AI agent ID (found in your Chatbase dashboard) 6. Click **Save** to store the keyset configuration <Tip> Your AI agent ID can be found in the Chatbase dashboard URL or in the agent settings. This keyset allows Salesforce to verify JWT tokens issued by Chatbase for secure user authentication. </Tip> **4. Create a Messaging Channel** 1. Return to the **Messaging Settings** page from step 1 2. Click **New Channel** to create a new messaging channel 3. Select **Enhanced Chat** as the channel type 4. Choose **Mobile** as the deployment type 5. Configure the routing settings based on your Omni-Channel setup from step 2 6. Click **Save** to create the channel 7. Select the **Add User Verification** checkbox 8. Click **Save** again 9. Return to the **Messaging Settings** page and open the newly created channel 10. Scroll down to find the **User Verification Configuration** section 11. Click **New**, select the keyset created in step 3, and enter a **Configuration Name** 12. Ensure **Active** is selected and click **Save** <Warning> Ensure authentication is enabled on the messaging channel to maintain secure communication between Chatbase and Salesforce. Without authentication, the action will not work. </Warning> **5. Create Embedded Service Deployment** Create a deployment for Enhanced Chat with Custom Client configuration: 1. In **Setup**, search for "Embedded Service Deployments" in the Quick Find box 2. Click **New Deployment** 3. Select **Enhanced Chat** as the service type 4. Choose **Custom Client** as the deployment type 5. Configure the deployment settings: * **Name**: Enter "Chatbase" * **API Name**: Enter "Chatbase" * **Messaging Channel**: Select the messaging channel created in step 4 6. Click **Save** to create the deployment 7. Click **Publish** and ensure the deployment status is set to **Active** 8. Click **Install Code Snippet** and save the **OrganizationId**, **DeveloperName**, and **Url** fields, as you will need them later <Info> For detailed instructions on creating a Custom Client deployment, refer to the [Salesforce Enhanced Chat Custom Client deployment guide](https://help.salesforce.com/s/articleView?id=service.miaw_deployment_custom.htm\&type=5). </Info> <Check> After completing all steps, verify that messaging is enabled, the messaging channel is active, Omni-Channel is configured, and the deployment is ready for use. You can test the setup by initiating a test chat session. </Check> </Step> <Step title="Create the Action"> Navigate to **Build > Actions** → **Create action** and select **Salesforce Live Chat**. </Step> <Step title="Configure Action Details"> **When to use:** Provide detailed instructions for when the AI should use this action. For example: * Use this action when you cannot solve the user's problem and they need immediate assistance * Use this action when the user explicitly requests to speak with a human agent * Use this action for urgent issues that require real-time support * Use this action when the user expresses frustration or indicates the issue is time-sensitive * Do not use this action for non-urgent issues that can be handled through a support ticket **Salesforce Live Chat API URL:** Enter the value from the **Url** field saved in step 1, section 5 (Create Embedded Service Deployment). **Developer Name:** Enter the value from the **DeveloperName** field saved in step 1, section 5 (Create Embedded Service Deployment). **Org ID:** Enter the value from the **OrganizationId** field saved in step 1, section 5 (Create Embedded Service Deployment). </Step> <Step title="Save and Test"> Save the configuration and test with a sample customer request in the embedded widget. <Check> Verify that live chat connections are properly established and routed to available support agents in Salesforce. </Check> </Step> </Steps> ## Best Practices <CardGroup> <Card title="Clear Escalation Criteria" icon="arrow-up"> Define clear criteria in the "When to use" field to help the AI agent determine when to create a ticket versus connecting to live chat. This ensures users receive the appropriate level of support. </Card> <Card title="Comprehensive Case Information" icon="file-text"> Configure case creation to include relevant conversation context, user information, and issue details to help support agents resolve issues efficiently. </Card> <Card title="Testing Coverage" icon="flask"> Thoroughly test all actions with various user scenarios, edge cases, and error conditions before going live. Test both urgent and non-urgent escalation paths. </Card> </CardGroup> # Shopify Actions Source: https://chatbase.co/docs/user-guides/chatbot/actions/shopify-actions Help customers browse products, manage their cart, place and exchange orders, track deliveries, and update their account through your AI agent ## Overview Shopify Actions enable your AI agent to provide comprehensive e-commerce support directly within the chat interface. These actions give your agent access to your store's product catalog, cart, order information, and customer data, allowing it to assist shoppers throughout their entire journey, from discovering products to placing an order and following up afterwards. <Tip> You can test Shopify actions and see how they will look using the Chatbase Shopify demo store [here](https://chatbase-demo-store.myshopify.com/) </Tip> <Info> **Prerequisite:** Before using Shopify Actions, you must [set up the Shopify integration](/docs/user-guides/integrations/shopify) with your Chatbase account. </Info> ## Available Shopify Actions | Action | What it does | | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | [Retrieve and display products](#1-retrieve-and-display-products) | Search your catalog and show products the shopper can add to their cart | | [Update cart](#2-update-cart) | Add, remove, or change the quantity of items in the cart | | [Get cart](#3-get-cart) | Show the current contents and total of the shopper's cart | | [Create order](#4-create-order) | Place an order from the cart or specific items, paid by checkout link, cash on delivery, or as a free order | | [Create exchange](#5-create-exchange) | Create an exchange draft order against a past order, approved by a human agent in the Helpdesk | | [Retrieve and display orders](#6-retrieve-and-display-orders) | Look up order status, tracking, and purchase history | | [Tag an order](#7-tag-an-order) | Add tags you choose to the signed-in customer's orders to record the outcome of a conversation | | [Check account and send activation email](#8-check-account-and-send-activation-email) | Check whether the customer is signed in and email an activation link if their account was never activated | | [Update customer profile](#9-update-customer-profile) | Change the signed-in customer's name, email, or phone number | | [Update customer billing address](#10-update-customer-billing-address) | Add or update the signed-in customer's billing address | ### 1. Retrieve and display products Search and display products from your Shopify catalog. Customers can browse by category, search for specific items, and add products directly to their cart. Shoppers can also search by image: when they send a photo as an [attachment](/docs/user-guides/chatbot/channels#attachments), the agent finds matching products from your catalog, even when the product name doesn't appear in the image. <Card title="Best for:" icon="magnifying-glass"> Helping customers discover products, answering questions about inventory, comparing items, and facilitating add-to-cart actions. </Card> **Common Use Cases:** * "Show me red dresses under \$50" * "What laptops do you have in stock?" * "How much is this?" (with a photo attached) #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Retrieve and display products**. The action opens as **Shopify get products**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Get\_Products. **When to use:** If the user ask about products, use this tool. Summarize the tool's result in your response, ensuring no images are included within the text response. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. <img alt="Image" title="Image" /> </Step> <Step title="Sync Your Products"> In the **Products** section, click **Sync products** to import your catalog. The initial sync may take some time depending on the size of your store. Once it finishes, the section shows how many products were synced. After the first sync, your products stay up to date automatically. If you ever need to, click **Re-sync products** to fetch the in-stock products again. Click **Continue**. <img alt="Image" title="Image" /> </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by asking your agent product-related questions to verify it returns accurate results. </Check> <img alt="Get Products" title="Get Products" /> <img alt="Get Products" title="Get Products" /> </Step> </Steps> <Info> Shopify action buttons, such as **Add to cart** and **Select options**, are automatically translated based on your localization settings. </Info> #### Keeping Your Theme's Cart Icon in Sync By default, when a customer adds a product to their cart through the chat bubble, your theme's cart icon doesn't update until the page is reloaded—the item is added, but the cart count still shows 0 until the customer refreshes. Chatbase dispatches custom DOM events whenever the agent changes the cart, so your theme can update its cart UI in real time. With a listener for these events in place, adding one product makes the cart count show 1 right away, with no refresh. The following events are fired: ```js theme={null} document.dispatchEvent(new CustomEvent('cart:updated', { detail: { newCart } })); document.dispatchEvent(new CustomEvent('cart-update', { detail: { newCart } })); document.dispatchEvent(new CustomEvent('cart:update', { detail: { newCart } })); ``` You can listen to any of these events in your theme's JavaScript to keep the cart UI **in sync**: ```js theme={null} document.addEventListener('cart:updated', (event) => { const cart = event.detail.newCart; // Update your theme's cart count, e.g.: document.querySelector('.cart-count').textContent = cart.item_count; }); ``` <Info> Multiple event names are dispatched to ensure compatibility across different Shopify themes. You only need to listen to one of them. </Info> #### How Product Sync Works To sync your catalog, open the **Products** section of the action and click **Sync products**. Chatbase will then retrieve all products from your Shopify store; this may take some time depending on the size of the store. After the initial import, Chatbase automatically listens for changes—whenever a product is added, updated, or deleted in your store, the data syncs in real time. This ensures your agent always has access to up-to-date product information. If you ever need to, click **Re-sync products** to fetch the in-stock products again. When you delete the action, Chatbase automatically removes its stored product data and stops syncing future updates. <Info> Note that once this action is in use, your agent already has your product data through the sync, so you can **exclude** product pages from your website training source. </Info> ### 2. Update cart Let shoppers manage their cart through the conversation: add products, remove them, or change quantities before checkout. <Card title="Best for:" icon="cart-plus"> Adjusting quantities, removing items the shopper no longer wants, and adding recommended products without leaving the chat. </Card> **Common Use Cases:** * "Add two of these to my cart" * "Remove the blue one from my cart" * "Change the quantity of the sneakers to 3" #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Shopify update cart**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Update\_Cart. **When to use:** Call this tool when the user wants to add a product to their cart, change the quantity of an existing line, or remove a line from the cart. After updating the cart, ask the user if they want to add more products or proceed with creating the order? To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by asking your agent to add a product to the cart, change its quantity, and remove it again. </Check> </Step> </Steps> <Tip> Pair **Update cart** with [Create order](#4-create-order). The default "When to use" prompt has the agent offer to proceed to the order as soon as the cart changes. </Tip> *** ### 3. Get cart Display the current contents of a customer's shopping cart, including items, quantities, prices, and totals. <Card title="Best for:" icon="cart-shopping"> Showing customers what's in their cart, displaying cart totals, and helping customers review items before checkout. </Card> **Common Use Cases:** * "What's in my cart?" * "Show me my cart total" * "How many items are in my cart?" #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Shopify get cart**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Get\_Cart. **When to use:** Call this tool when asked about the cart, including the items in the cart, the total price, the quantity of items. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by asking your agent to show cart contents. </Check> <img alt="Shopify Get Cart" title="Shopify Get Cart" /> <img alt="Shopify Get Cart" title="Shopify Get Cart" /> </Step> </Steps> ### 4. Create order Let your agent place a Shopify order for the shopper directly from the conversation. The order can be built from the shopper's cart or from specific items the agent (or a procedure) provides, and paid for with a Shopify checkout link, cash on delivery, or as a free order. Orders can be placed from any channel your agent is on: Chat bubble, Help page, Instagram, Messenger, and WhatsApp. <Card title="Best for:" icon="bag-shopping"> Completing a purchase without leaving the chat, "buy it now" flows, cash-on-delivery stores, and sending free replacement or gift orders. </Card> **Common Use Cases:** * "I'm ready to check out" * "Place the order for what's in my cart" #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Shopify create order**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Create\_Order. **When to use:** Call this tool when the user wants to place an order. If orders should only ever be placed as a step inside a [procedure](/docs/user-guides/chatbot/procedures/procedures-overview), and never on the agent's own initiative, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. </Step> <Step title="Configure Behavior"> The **Behavior** section controls how the order is built, how it is paid for, and how it is recorded in Shopify. **Order items**: where the items in the order come from. | Option | What it does | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Use the cart** (default) | Creates the order from whatever the shopper has added to their cart. The cart is emptied once the order is placed. The [Update cart](#2-update-cart) action must also be enabled so the agent can add items to the cart. | | **Skip the cart** | Creates the order from items the AI agent or a procedure provides. The cart is never read or changed. Usually used for replacements, gifts, and buy-it-now flows. | **Order payment**: how the shopper pays. | Option | What it does | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | **Online payment** (default) | Sends the shopper a secure Shopify-hosted checkout link. Shopify finalizes the order once they pay. | | **Cash on delivery** | Charges the shopper when the order arrives. | | **Free order** | Places the order at no cost to the shopper. No payment is collected and no checkout link is sent. Use this for replacements and free gifts. | **Shipping address phone number**: whether the agent collects a phone number for the shipping address. | Option | What it does | | ---------------------- | ----------------------------------------------------------------------------- | | **Required** (default) | The AI agent must collect a phone number before it places the order. | | **Don't include** | The AI agent never asks for a phone number. | | **Optional** | The AI agent asks for it, and still places the order if the shopper declines. | **Order tags**: tags added to every order this action creates, so you can find them in Shopify admin. Defaults to `chatbase`. Add or remove tags as needed. **Order note**: a note attached to the order in Shopify. Defaults to `Placed via Chatbase AI agent ( {{paymentModeLabel}} )`, where `{{paymentModeLabel}}` is replaced with the payment method used for the order. Click **Add variable** to insert other variables, or **Reset** to restore the default. Click **Save and continue**. <img alt="Image" title="Image" /> <img alt="Image" title="Image" /> </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by adding an item to the cart and asking your agent to place the order. With **Online payment** selected, the agent should reply with a Shopify checkout link. </Check> <Info> When testing from the Playground with **Online payment**, the AI agent isn't aware whether the payment was completed. On supported channels, the agent knows once the shopper pays. Updating the cart doesn't work in the Playground either, so test **Use the cart** orders from a live channel such as the Chat bubble. </Info> </Step> </Steps> <video /> <Tip> **You can create the Create order action more than once**, each with its own **Behavior** settings, and give each a distinct action name. For example, keep `Create_Order` (**Use the cart** + **Online payment**) for regular checkout, and add `Create_Replacement_Order` (**Skip the cart** + **Free order**) for replacements and goodwill orders. Then reference the right one from a [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) step with `@action_name`, so each flow places exactly the kind of order it should. Turn on **Only use in procedures** on the replacement variant so the agent never uses it outside that flow. </Tip> *** ### 5. Create exchange Handle exchange requests against a past order. The agent creates an exchange draft order that credits the returned items toward their replacements, then opens a Chatbase Helpdesk ticket so a human agent can approve or reject it before the order is placed. <Card title="Best for:" icon="right-left"> Size and color swaps, replacing a wrong or defective item, and any exchange where you want a person to approve before the replacement ships. </Card> **Common Use Cases:** * "I'd like to exchange these for a size 10" * "Can I swap this for the black version?" <Info> The exchange order isn't placed until a human agent approves it. The Chatbase Helpdesk ticket shows a summary of what is being returned and what it is being exchanged for; the human agent approves or rejects it with a single click, and approving pushes the exchange to Shopify. See the [Help Desk overview](/docs/user-guides/chatbot/help-desk/help-desk-overview) for how tickets are handled. </Info> Ticket Details: <img alt="Image" title="Image" /> By clicking on "Review action", the human agent will see the exchange details and they can approve or reject the request. <img alt="Image" title="Image" /> <img alt="Image" title="Image" /> #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Shopify create exchange**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Create\_Exchange. **When to use:** Call this tool when the user wants to do a product exchange. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. </Step> <Step title="Configure Behavior"> The **Behavior** section controls how the exchange draft order is recorded in Shopify. **Order tags**: tags added to the exchange order, so you can find it in Shopify admin. Defaults to `chatbase`. Add or remove tags as needed. **Order note**: a note attached to the exchange order that summarizes what is being returned, what it is exchanged for, and the resulting balance. The default is: ```text theme={null} Exchange for order {{oldOrderName}} Returning: {{exchangedItemsSummary}} Exchanging for: {{newItemsSummary}} Reason: {{reason}} ({{faultLabel}} → {{shippingLabel}} shipping) Items: {{itemsSettlement}} Shipping: {{shippingSettlement}} Tax: {{taxSettlement}} Net: {{netSettlement}} ``` Click **Add variable** to insert any of the available order variables, or **Reset** to restore the default. | Variable | Description | | --------------------------- | --------------------------------------------------------------------- | | `{{oldOrderName}}` | Name of the original order, for example `#1042` | | `{{exchangedItemsSummary}}` | The returned items, for example `Red tee (SKU-1) x2` | | `{{newItemsSummary}}` | The replacement items, in the same format | | `{{reason}}` | The shopper's exchange reason | | `{{faultLabel}}` | Whether the exchange is a `merchant fault` or a `customer request` | | `{{shippingLabel}}` | Whether shipping on the exchange is `free` or `paid` | | `{{itemsSettlement}}` | Settlement line for the item price difference | | `{{shippingSettlement}}` | Settlement line for the shipping cost | | `{{taxSettlement}}` | Settlement line for tax | | `{{netSettlement}}` | The authoritative net amount to collect from or refund to the shopper | | `{{conversationId}}` | The Chatbase conversation ID | For example, the default **Reason** line renders as `Reason: Wrong size (merchant fault → free shipping)`. Click **Save and continue**. <img alt="Image" title="Image" /> </Step> <Step title="Configure Details Collection (optional)"> Under **Collect additional details**, define the fields the AI gathers in conversation before it opens the exchange ticket in the Chatbase Helpdesk, for example an image of the product that needs to be replaced. Click **Add data input** and give each field a **Name**, a **Type** (for example, image), and a **Description** that tells the agent what to ask for. Leave **Required** checked to make the agent collect the field before it opens the exchange, or uncheck it to let the agent open the exchange without that field. Click **Save and continue**, or **Skip** if you don't need any extra details. <img alt="Image" title="Image" /> </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by asking your agent to exchange an item from a past order. A ticket should appear in your Helpdesk for approval, and the exchange order is placed only after an agent approves it. </Check> </Step> </Steps> *** ### 6. Retrieve and display orders Retrieve order information for customers. Customers can check order status, view their purchase history, and get details about specific orders using various filters. <Card title="Best for:" icon="box"> Answering order status inquiries, providing tracking information, displaying purchase history, and helping customers find specific order details. </Card> **Common Use Cases:** * "Where is my order?" * "Show me my recent orders" * "What's the status of order #1234?" <Info> **Order status:** The AI agent pulls order status directly from Shopify, so it reflects the latest information Shopify has available on the order status page. Shipped orders appear as "**On its way**". To display delivery confirmation, ensure your store uses a trackable carrier (USPS, UPS, FedEx, etc.) or a third-party app that provides delivery updates to Shopify. </Info> #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Retrieve and display orders**. The action opens as **Shopify get orders**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Get\_Orders. **When to use:** If the user ask about orders, use this tool. Summarize the tool's result in your response, ensuring no images are included within the text response. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by asking your agent about order status to verify it retrieves the correct information. </Check> <img alt="Show Order" title="Show Order" /> <img alt="Show Order" title="Show Order" /> </Step> </Steps> <Note> **Guest customers can look up orders using either:** * Checkout email + order number * Phone number + order number **For authenticated customers, order lookup is automatic**, no email address, phone number, or order number is required. Orders are retrieved directly from the signed-in account. </Note> *** ### 7. Tag an order Record the outcome of a conversation directly on the customer's order in Shopify. The agent adds tags you choose to the signed-in customer's own orders, so the result of the chat is visible on the order itself in Shopify admin. <Card title="Best for:" icon="tag"> Marking orders as, for example, "damaged", "missing item", or "address confirmed" straight from the chat, so your team and your Shopify workflows can act on them. </Card> **Common Use Cases:** * Flagging an order when the customer reports a damaged or missing item * Recording that the customer confirmed their delivery details * Marking an order for follow-up by your team #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Shopify tag order**. </Step> <Step title="Configure General Settings"> The fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** tag\_shopify\_order. **Allowed tags:** the tags the agent is allowed to apply to an order. Defaults to `chatbase`. Add the tags you want the agent to choose from, for example `damaged`, or `return-requested`, and remove any you don't want used. The agent only applies tags from this list. **When to use:** Call this tool when something the customer says about an order should be recorded on the order. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. <img alt="Image" title="Image" /> </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by signing in to your store, telling the agent something about one of your orders, and confirming the tag appears on that order in Shopify admin. </Check> <Info> **This action cannot be tested in the Action Preview on the dashboard, as it requires the user to be authenticated in order to work properly.** </Info> </Step> </Steps> <Tip> **Damaged or missing items.** A common procedure pairs this action with [Create order](#4-create-order): tag the original order (for example `damaged`) so the case is recorded on it in Shopify, then ship a free replacement with a Create order variant set to **Skip the cart** + **Free order**. </Tip> *** ### 8. Check account and send activation email Check whether the customer is signed in to your Shopify store and, if their account was never activated, email them a link to activate it. This helps shoppers get signed in before using actions that need an authenticated customer, such as updating their profile or billing address. <Card title="Best for:" icon="user-check"> Guiding guests toward a signed-in session, recovering customers who never activated their account, and unblocking account requests that require authentication. </Card> **Common Use Cases:** * "How do I log in to my account?" * "I never got an activation email" #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Check account & send activation email**. The action opens as **Shopify account access**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** check\_account\_access. **When to use:** Call this tool when the customer cannot sign in to their store account, or never received the email to activate it. If it succeeds, tell the user that if the account exists, we sent an email. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. <img alt="Image" title="Image" /> </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by telling your agent you can't sign in to your account. The agent should confirm that an activation email has been sent if the account exists. </Check> </Step> </Steps> *** ### 9. Update customer profile Enable signed-in customers to modify their account profile information through the agent. <Card title="Best for:" icon="user-pen"> Account management, updating contact information, and helping customers keep their profile current. </Card> **Common Use Cases:** * "Update my email address" * "Change my phone number" * "Update my account information" #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Update shopify customer profile**. The action opens as **Shopify update profile**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Update\_Profile. **When to use:** Call this tool when asked about changing customer profile, including first name, last name, email, or phone number. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by asking your agent to update profile information. </Check> <img alt="Update Profile" title="Update Profile" /> <img alt="Update Profile" title="Update Profile" /> <Info> **This action cannot be tested in the Action Preview on the dashboard, as it requires the user to be authenticated in order to work properly.** </Info> </Step> </Steps> *** ### 10. Update customer billing address Allow customers to add new billing addresses or update existing ones directly through the chat interface. <Card title="Best for:" icon="address-card"> Self-service address updates, helping customers correct billing information, and streamlining account management. </Card> **Common Use Cases:** * "Update my billing address" * "Change my payment address" * "I moved and need to update my address" * "I want to add a new address and set it as default" #### Setup Instructions <Steps> <Step title="Navigate to Actions"> Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent connected to your Shopify store. Click **Build > Actions** in the left sidebar. </Step> <Step title="Create the Action"> Click **Create Action** and choose **Update shopify customer billing address**. The action opens as **Shopify update address**. </Step> <Step title="Configure General Settings"> Both fields come pre-filled with working defaults. Leave them as-is unless you need to make a specific change. **Action Name:** Update\_Address. **When to use:** Call this tool when asked about adding or updating billing addresses or changing the default address. To restrict this action to [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) steps only, turn on [**Only use in procedures**](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures). Click **Save and continue**. </Step> <Step title="Choose Channels"> Use **Channels** to control where the action is available. This step is optional: toggle the action on or off for each configured channel, then click **Save**. Some channels may be incompatible with the action and won't be available for selection. </Step> <Step title="Enable and Test"> Ensure the action is toggled to **Enabled**. <Check> Test the action by asking your agent to update a billing address. </Check> <img alt="Change Address" title="Change Address" /> <Info> **This action cannot be tested in the Action Preview on the dashboard, as it requires the user to be authenticated in order to work properly.** </Info> </Step> </Steps> *** ## Best Practices <CardGroup> <Card title="Clear Action Triggers" icon="bullseye"> Write specific "When to use" descriptions to help the AI agent accurately determine when to trigger each action. Include example phrases customers might use. </Card> <Card title="Test Thoroughly" icon="flask"> Test each action with various customer queries before going live. Verify that product searches return accurate results. </Card> <Card title="Keep Products Synced" icon="rotate"> In case you notice discrepancies in available products, click **Re-sync products** in the action's **Products** section. </Card> <Card title="Use Procedures" icon="route"> For multi-step flows like exchanges or damaged-item replacements, build a [procedure](/docs/user-guides/chatbot/procedures/procedures-overview) that calls the right Shopify actions in order, so the agent doesn't improvise on high-stakes flows. </Card> </CardGroup> # Slack Source: https://chatbase.co/docs/user-guides/chatbot/actions/slack ### Slack message sending Enabling this action allows your AI Agent to send a message to your choosen Slack channel whenever the user mentions any topic that you want to be notified with.  Check the steps to integrate Slack with Chatbase through this page. 1. Click **Build > Actions** in the sidebar, then click **Create action**, select **Slack**, then **Start customizing**. 2. Choose the Slack workspace that you want to be connected with this Action: <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> 3. In the **When to use** section, provide a detailed description explaining when the AI agent should use this action. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> 4. Click on Save button. 5. Make sure to enable this action to allow the AI agent to send a message to your Slack channel. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Now, you can try this action in the Playground. It's recommended to try sending a message in the Action preview to ensure that the AI agent sends a message to your Slack channel when the desired instructions are fulfilled before enabling the action. Examples: "Call this tool to send a message in slack to the channel named: ai-actions-slack whenever the user mentions any of the following topics: late order" <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Once the user mentioned an issue with a "late order," a Slack notification is sent (with a direct link to the respective conversation) to the channel connected to this action: <Frame> <img alt="Slack notifications" /> </Frame> # Stripe Actions Source: https://chatbase.co/docs/user-guides/chatbot/actions/stripe-action Automate billing and subscription management with powerful Stripe actions ## Overview Stripe Actions enable your AI agent to seamlessly handle customer billing inquiries, subscription management, and account updates directly within the chat interface. These actions provide secure, real-time access to customer payment information, streamlining support operations and enhancing customer experience. <Info> **Prerequisites Required**: Before using Stripe Actions, you must: 1. [Set up Stripe integration](/docs/user-guides/integrations/stripe) with your Chatbase account 2. Configure [identity verification](/docs/developer-guides/identity-verification) for secure customer authentication 3. Set up [contacts](/docs/user-guides/chatbot/contacts/contacts-overview) with valid `stripe_account` fields for each customer </Info> ## How Stripe Actions Work Stripe Actions leverage Chatbase's identity verification system to securely access customer-specific data. Here's the workflow: 1. **User Authentication**: Customers must be identified using `window.chatbase("identify", {...})` with their unique user ID 2. **Contact Matching**: The system matches the authenticated user ID to a contact record containing their Stripe account id. 3. **Secure Data Access**: Actions retrieve only the data associated with the authenticated customer's Stripe account 4. **Real-time Responses**: AI agent provides immediate answers using live Stripe data <Warning> **Environment Limitations**: Stripe Actions will not function in: * Chatbase Playground environment * Action Preview mode * Compare features Testing this action should be done in your actual website environment. Embed the [JavaScript script](/docs/developer-guides/javascript-embed) in your website and test the action. </Warning> ## Available Stripe Actions ### 1. Get Subscription Information Retrieve and display customer subscription details including current plan, status, billing cycle, and pricing information. <Card title="Best for:" icon="credit-card"> Answering questions about current subscription status, plan details, renewal dates, and subscription history. </Card> **Common Use Cases:** * "What's my current plan?" * "When does my subscription renew?" * "How much am I paying monthly?" * "Is my subscription active?" #### Setup Instructions <Steps> <Step title="Create the Action"> Navigate to **Build > Actions** → **Create action** and select **Stripe Get Subscription Info**. <Frame> <img alt="Selecting get subscription action from Stripe options" /> </Frame> </Step> <Step title="Configure Action Details"> **Action Name:** Enter a unique name for the action. **When to use:** Provide detailed instructions for when the AI should use this action. </Step> <Step title="Save and Enable"> Click **Save** and toggle the action to **Enabled** to make it available to your AI agent. <Frame> <img alt="Configuring get subscription action with name and usage instructions" /> </Frame> <Check> Test the action in the embedded widget to ensure it correctly retrieves subscription data for authenticated users. </Check> </Step> </Steps> ### 2. Get Invoice History Retrieve and display customer invoice history, payment details, and billing records. <Card title="Best for:" icon="receipt"> Providing access to billing history, payment confirmations, invoice downloads, and payment troubleshooting. </Card> **Common Use Cases:** * "Show me my recent invoices" * "Was my payment processed?" * "Can you provide my billing history?" #### Setup Instructions <Steps> <Step title="Create the Action"> Select **Stripe Get Invoices** from the action creation dialog. <Frame> <img alt="Selecting get invoices action from Stripe options" /> </Frame> </Step> <Step title="Configure Action Details"> **Action Name:** Enter a unique name for the action. **When to use:** Provide detailed instructions for when the AI should use this action. </Step> <Step title="Save and Test"> Save the configuration and test with a sample customer request in the embedded widget. <Frame> <img alt="Configuring get invoices action with detailed usage instructions" /> </Frame> </Step> </Steps> ### 3. Manage Subscriptions Comprehensive subscription management including plan changes, upgrades, downgrades, and cancellations. <Card title="Best for:" icon="credit-card"> Complete subscription lifecycle management, plan changes, adding payment methods and cancellation handling. </Card> **Common Use Cases:** * "I want to upgrade my plan" * "Upgrade my plan to the pro" * "I need to cancel my subscription" * "What plans are available?" #### Setup Instructions <Steps> <Step title="Create the Action"> Select **Stripe** → **Manage Subscriptions** from the Stripe action options. </Step> <Step title="Configure Subscription Options"> **Action Name:** Enter a unique name for the action. **When to use:** Provide detailed instructions for when the AI should use this action. <Frame> <img alt="Configuring subscription management action with comprehensive options" /> </Frame> </Step> <Step title="Define Available Plans"> Configure which subscription plans and options are available for customers to choose from: <Tabs> <Tab title="Plan Configuration"> Set up available plans with their behavior. <Frame> <img alt="Configuring available subscription plans and options" /> </Frame> </Tab> <Tab title="Cancellation Settings"> Configure cancellation policies and refund handling. <Frame> <img alt="Configuring available subscription plans and options" /> </Frame> </Tab> </Tabs> </Step> <Step title="Test All Scenarios"> Thoroughly test various subscription management scenarios: <AccordionGroup> <Accordion title="Upgrade Testing"> Test upgrading from basic to premium plans with proper proration calculations. </Accordion> <Accordion title="Downgrade Testing"> Verify downgrades work correctly with appropriate billing adjustments. </Accordion> <Accordion title="Cancellation Flow"> Test the complete cancellation process. </Accordion> </AccordionGroup> <Frame> <img alt="Testing subscription management action with comprehensive options" /> </Frame> <Check> All subscription changes should be immediately reflected in both Stripe and the customer experience. </Check> </Step> </Steps> ### 4. Change Billing Information Allow customers to update their billing address and other account information. <Card title="Best for:" icon="address-card"> Self-service billing updates, address changes and other account information updates. </Card> **Common Use Cases:** * "I need to update my billing address" * "Update my billing email address" * "Update my billing phone number" #### Setup Instructions <Steps> <Step title="Create the Action"> Select **Stripe** → **Change customer information** from the available Stripe actions. <Frame> <img alt="Selecting change billing address action" /> </Frame> </Step> <Step title="Configure Action Details"> **Action Name:** Enter a unique name for the action. **When to use:** Provide detailed instructions for when the AI should use this action. </Step> <Step title="Test Security Measures"> Test the action with various scenarios to ensure only authenticated users can make changes. <Frame> <img alt="Testing change billing address action" /> </Frame> <Check> Verify that billing information updates are reflected in both Stripe and the customer's account. </Check> </Step> </Steps> ## Troubleshooting <AccordionGroup> <Accordion title="Action Not Triggering"> **Possible causes:** * Action is disabled in the dashboard * User is not properly authenticated * Contact record missing or invalid `stripe_account` * Insufficient "When to use" description **Solutions:** * Enable the action and verify configuration * Check identity verification implementation * Validate contact record has correct `stripe_account` field * Enhance action description with more specific use cases </Accordion> <Accordion title="No Data Returned"> **Possible causes:** * Invalid Stripe customer ID in contact record * Stripe account has no subscription or invoice data * Stripe API permissions insufficient * Network connectivity issues **Solutions:** * Verify Stripe customer ID exists and is active * Check Stripe account has relevant data * Review Stripe integration permissions * Test Stripe API connectivity directly </Accordion> <Accordion title="Authentication Errors"> **Possible causes:** * User hash validation failing * `external_id` doesn't match `user_id` * Contact record not found * Identity verification not called **Solutions:** * Verify hash generation matches expected format * Ensure `external_id` exactly matches authenticated `user_id` * Create contact record for the user * Implement proper identity verification flow </Accordion> </AccordionGroup> ## Best Practices <CardGroup> <Card title="Security First" icon="shield-check"> Always validate user identity before processing any billing-related requests. Never allow unauthenticated access to financial data. </Card> <Card title="Testing Coverage" icon="flask"> Thoroughly test all actions with various user scenarios, edge cases, and error conditions before going live. </Card> </CardGroup> # Suggested Messages Source: https://chatbase.co/docs/user-guides/chatbot/actions/suggested-messages Display clickable reply suggestions to help users navigate conversations more efficiently. The **Suggested Messages** action allows you to display clickable reply options to users during a conversation. Suggestions can be generated automatically by AI or manually configured to guide users toward specific actions and workflows. Suggested messages help reduce user effort, improve engagement, and create a more structured conversational experience. <Note> This action changes the suggestions dynamically as the conversation develops. For fixed wordings that do not change, use the **Suggested messages** control under **Playground → Display → Content**. See [Chat bubble display settings](/docs/user-guides/chatbot/channels#chat-bubble-display). </Note> ## Configuration ### Action name Provide a descriptive name for the action. This name is used internally to identify the action and is not visible to users. ### When to use Define when the action should be triggered and what type of suggestions should be shown. The instructions provided in this field help the AI determine: * When the action should appear * What suggestions should be displayed * How suggestions should relate to the current conversation The more specific your instructions, the more relevant the generated suggestions will be. ### Auto generate suggested messages When enabled, Chatbase automatically generates suggested messages based on: * The conversation context * The user's latest message * The instructions provided in the **When to use** field This option is recommended when you want suggestions to adapt dynamically to each conversation. ### Manual suggested messages When **Auto generate suggested messages** is disabled, you can manually configure up to **4 suggested messages**. Each suggested message: * Can contain up to 40 characters * Appears as a clickable option for users * Can be edited or removed at any time Manual suggestions are useful when you want complete control over the options presented to users. ### Disable input field When enabled, users cannot type custom responses while suggested messages are displayed. Instead, they must select one of the available options before continuing. This setting is useful for guided workflows where users should follow a predefined path. ### Generate after every message When enabled, Chatbase checks for suggested messages after every reply instead of letting the agent decide when to run the action. This is more reliable, particularly on smaller models, which are less consistent at triggering the action on their own. <Warning> This runs after every reply even when no suggestions fit, so each reply consumes your base model's credits. Only one action per agent can use this setting. </Warning> ## Channels You can control which channels can use this action from the **Channels** section. Currently supported channels include: * Chat bubble * Help page Disable a channel to prevent the action from appearing there. ## Best Practices <CardGroup> <Card title="Keep suggestions concise"> Use short, action-oriented messages that are easy to understand and select. </Card> <Card title="Be specific in your instructions"> Clearly describe when the action should appear and the type of suggestions that should be generated. </Card> <Card title="Use manual suggestions for guided flows"> Manually configured suggestions are ideal when users should follow a specific journey or workflow. </Card> <Card title="Restrict input only when necessary"> Enable the input restriction setting only when users must select from the available options. </Card> </CardGroup> # Transfer to phone number Source: https://chatbase.co/docs/user-guides/chatbot/actions/transfer-to-phone Transfer a live voice call from your AI Agent to a human by forwarding the caller to a phone number. The **Transfer to phone number** action allows your AI Agent to seamlessly hand off a live phone call to a human. When the action is triggered, Chatbase plays a configurable hand-off message to the caller and transfers the call to the phone number you've configured. <Warning> This action is only supported on the <b>Phone</b> channel. </Warning> <Frame> <img alt="Action Configuration" /> </Frame> ## How it works <Steps> <Step title="The AI decides a transfer is needed"> The AI Agent determines that a human should handle the conversation based on the instructions you've provided in the **When to use** field. </Step> <Step title="The caller hears the hand-off message"> Chatbase automatically plays your configured **Message to caller** before initiating the transfer. </Step> <Step title="The call is transferred"> The live call is forwarded to the configured phone number. </Step> <Step title="Transfer complete"> Once the transfer begins, the AI Agent leaves the call and cannot resume the conversation. </Step> </Steps> *** ## Setting up the action <AccordionGroup> <Accordion title="General"> ### Action name Give the action a descriptive name. **Example:** Transfer\_To\_Support If you have multiple departments, you can create multiple transfer actions. **Examples:** * Transfer\_To\_Sales * Transfer\_To\_Support * Transfer\_To\_Billing *** ### When to use Describe exactly when the AI should perform the transfer. **Example:** Use when the caller asks to speak to a real person on the phone. Call this tool to transfer the ongoing phone call to the configured phone number only when the caller explicitly requests to talk to a real person, or when you cannot resolve their issue. This transfers the live call to the configured phone number and ends your part of the call. Do not announce the transfer yourself—the system speaks the configured hand-off message to the caller and then performs the transfer. Only call this tool on phone calls. <Tip> Be as specific as possible. Good instructions help your AI determine exactly when a transfer should occur. </Tip> </Accordion> <Accordion title="Configuration"> ### Phone number Enter the phone number that should receive transferred calls. The phone number must use **E.164 format**. **Example:** +12125551234 Only the following are supported: * **Twilio phone numbers** * **SIP trunks** <Info> If you're using a SIP trunk, make sure both <b>SIP REFER</b> and <b>PSTN</b> are enabled on the trunk before using this action. Otherwise, call transfers will not work. </Info> *** ### Message to caller Configure the message that is played to the caller immediately before the transfer begins. *** ### Message if the transfer fails Configure the message the AI Agent should say if the transfer cannot be completed. After this message, the AI Agent continues the conversation. <Info> If the transfer fails, the AI Agent will say this message and continue assisting the caller. If this field is left empty, the default failure message will be used. </Info> </Accordion> <Accordion title="Channels"> This action currently supports the **Phone** channel. Click **Setup** next to **Phone** to configure the required phone integration. Once configured, click **Save & enable**. <Warning> If the Phone channel hasn't been configured, this action cannot be used. </Warning> </Accordion> </AccordionGroup> *** ## Best practices <CardGroup> <Card title="Be explicit"> Clearly define when the AI should transfer the caller instead of trying to solve the issue itself. </Card> <Card title="Use descriptive names"> If you have multiple transfer actions, give each one a meaningful name like **Transfer\_To\_Sales** or **Transfer\_To\_Billing**. </Card> <Card title="Write a natural hand-off message"> Keep the message short so callers know they're being connected. </Card> <Card title="Configure a fallback"> Always provide a friendly fallback message in case the transfer cannot be completed. </Card> </CardGroup> *** ## Limitations * Once a transfer begins, the AI Agent cannot resume the conversation. * This action only works for live phone calls and is not available on chat-based channels. # Web Search Source: https://chatbase.co/docs/user-guides/chatbot/actions/web-search The Web Search action allows the AI Agent to browse the web for information and feed the results back to the AI Agent. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> #### When to use This is where you specify the name of the Action and when exactly this action should be triggered or what type of customer queries would trigger it. You can also add in some instructions that the bot should adhere to when this action is triggered. The web search action can be used as an additional source of information where the AI agent can get some information that isn't available in the sources. It's recommended to add websites that are related to your business field.  #### Include images This allows the AI agent to provide images as replies to the users elaborating the answer provided. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> #### Included domains This option allows you to add specific domains that the AI agent can use to search the answer. If you didn't add any domains, the AI agent will search over the whole web.  Once you're done, press "Save and enable" and your action will be live and ready for your Agent to use. # Activity Source: https://chatbase.co/docs/user-guides/chatbot/activity This section shows the chat logs of the conversations your users had with your AI agent and the Lead forms filled by your users. ## Conversations The chat logs provides a detailed view of all user interactions with your AI agent. It allows you to review individual conversations and evaluate your agent's responses. Each log includes user messages, agent responses, and any triggered actions, helping you identify issues, optimize responses, and improve overall user experience. <Frame> <img alt="AI agent Activity Filters" /> </Frame> The chat logs can be filtered by the following: * Channel * Topics * Date range * Confidence Score * Feedback * Contains voice sessions * Sentiment * Contact ID or email <Frame> <img alt="AI agent Activity Filters" /> </Frame> <br /> ### Revise Answer This feature allows you adjust the AI Agent's response if it wasn't accurate or satisfactory. When you click the Revise Answer button, a form appears showing the user's original question, the AI Agent's response, and a field where you can enter the expected answer. Once the answer is updated, the question and answer are added automatically to the Q\&A section of your sources.  <Frame> <img alt="Improve Answer Feature" /> </Frame> **Matched Q\&A** When a response matches a Q\&A source, you can now click the Matched Q\&A to open the corresponding Q\&A directly, without having to manually search for it in your sources. <Frame> <img alt="Improve Answer Feature" /> </Frame> ### Confidence Score This indicates how confident the AI Agent is in its response based on the sources you've trained it on. You can review responses with low confidence scores and revise them to improve their accuracy. ### Exporting Conversations You can export the conversations in the chats log directly from the dashboard using the Export button. The export can be downloaded as JSON, PDF, and CSV. <Frame> <img alt="Exporting Conversations" /> </Frame> ## Leads This section shows the collected leads along with their submission date. Custom fields configured on the Collect Leads action each get their own column. You can filter leads by date and export them as CSV or PDF. The leads form can be configured **Build > Actions** and creating [the Collect Leads action](./actions/collect-leads) ## Collected data This section shows the submissions collected by your [Collect Data actions](./actions/collect-data), along with their submission date and an Action column showing which action collected them. Each field configured on a Collect Data action gets its own column. You can filter submissions by date, export them as CSV or PDF, and delete the ones you select. # Analytics Source: https://chatbase.co/docs/user-guides/chatbot/analytics ## Chats **Analytics** aggregates the activity of your AI agent across conversations. It has four pages: **Chats**, **Topics**, **Sentiment**, and **Helpdesk**. By default, it shows the activity for all AI Agents under your workspace for the last week. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> It shows the total number of chats, total number of messages, the messages that had thumbs up from the users and the messages that had thumbs down, daily active users, weekly active users and stickiness. Below the totals, a line chart plots chats over the selected period against the **Previous period** (the dotted line), so you can see whether volume is rising or falling. Hover any point to compare the two dates directly. **Chats by country** shades a world map by volume and lists the top countries beside it, with **View all** for the full ranking. Countries are detected from the IP of the users having conversations with the AI agent. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> **Chats by channel** breaks the same total down by where the conversations came from, such as Widget/Iframe, Playground, or Slack. **Action calls** ranks how often each of your actions ran over the period, with **View all** for the complete list. It is a quick way to see which actions your agent actually uses. You can always filter the data by date. There are pre-defined date filters such as last 7 days, last 30 days, last 3 months and last year. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ## Topics This section shows the topics that were included in the conversations and mentioned by the users. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> Topics Actions: * Search topics * Add topic * Edit topic * Delete topic * Freeze topics: Stopping the AI Agent to detect any topics automatically. The topics are detected automatically by the AI Agent. However, you can add topics manually in the View All button in the the right of the page: <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ## Sentiment This section shows how the AI Agent detects the sentiment and emotion of the users during the conversations. The sentiment analysis is detected automatically by the AI Agent. <Frame> <img alt="Chatbase Embed Code Example" /> </Frame> ## Helpdesk Track ticket volume over time to monitor your support workload and resolution trends. Every metric on this page shows its change against the previous period, and each chart plots the **Selected period** as a solid line against the **Previous period** as a dotted one. ### Ticket volume * **Created tickets** — tickets opened during the period. * **Solved tickets** — tickets marked solved during the period. * **Unsolved tickets** — the outstanding backlog, plotted on its own chart so you can see whether it is growing or shrinking. ### Response times * **Median first response time** — how long a customer waits for the first human reply. * **Median response time** — the median across all replies, not just the first. * **Median time to close** — how long a ticket stays open before it is solved. Medians are used rather than averages so a handful of long-running tickets don't skew the figure. A chart below the three tiles plots response time across the period. ### Tickets by channel Breaks ticket volume down by where the tickets arrived from, such as **Email**, **Widget/Iframe**, or **API**. ### Filtering Use the date range picker to set the period. The filter button beside it narrows the whole page by **Assignee**, **Channel**, **Type**, or **Last message by** — pick a field, choose an operator such as **is any of**, then select the values and click **Apply**. **Discard** clears the filter you were editing. ## Notes Analytics data is updated with a 1-day delay, reflecting the previous day's information. Data is recorded once the user subscribes to a specific plan. Topics and sentiment data will only be available after the upgrade; any data from before the upgrade will not be included. **Activity** shows data per chat for users, while **Analytics** aggregates the information, including topics, sentiment, and thumbs down. Each panel uses the visualization that suits it: a line chart for chats over time, a shaded world map for **Chats by country**, and horizontal bars for **Chats by channel** and **Action calls**. The analytics page displays the total number of messages, including all conversation messages. However, credits are only calculated for AI-generated responses, excluding the initial messages. # Backstage Source: https://chatbase.co/docs/user-guides/chatbot/backstage Backstage is an AI-powered operations center that lets users manage their AI agent through natural language conversation, instead of navigating multiple settings pages manually. Think of it as a copilot for AI agent management — users describe what they want in plain English, and Backstage handles the rest. ## What Can Users Do With It? ### Analytics & Insights * Ask questions like "What are my top customer topics this month?" or "Show me conversation trends for the last 3 months" * View interactive charts (bar, line, area, pie) generated in real time * Check credit usage breakdowns * Identify knowledge gaps — questions the agent couldn't answer ### Training & Knowledge Base * Add, update, or delete knowledge base sources (text, Q\&A pairs, URLs) * Upload files (PDFs, Word docs, spreadsheets, archives) to extract training data from * Trigger retraining after making changes * Toggle auto-retrain on or off ### Agent Configuration * Update the agent's system instructions or channel-specific instructions * Change the AI model or temperature * Modify the chat bubble appearance (colors, header, button styles, themes) ### Helpdesk (Read-Only) * Query tickets by status, assignee, channel, or date * Search tickets using text or semantic search * View agent performance metrics, resolution analytics, and workload distribution * Review helpdesk settings and saved views ### Actions & Integrations * Create, update, enable/disable, or delete actions (Slack notifications, webhooks, ticket creation, etc.) * Check integration status and trigger OAuth connections for new integrations ### Deployment * Check which channels are active (chat bubble, WhatsApp, Slack, etc.) * Enable or disable channels ### Built-in Skills (Multi-Step Workflows) Users don't need to invoke these explicitly — the AI uses them automatically when relevant: * Weekly insights report * Tone/instruction updates with safe diff preview * Drafting Q\&A from knowledge gaps * New AI agent onboarding walkthrough * File/archive processing into training data * Helpdesk triage, issue review, performance review, and settings audit *** ## How Does Approval Work? Backstage **never makes changes silently**. Any mutative action (updating instructions, adding sources, deleting an action, etc.) triggers a confirmation UI where the user can review each change and approve or reject it individually before anything is applied. Text changes show a side-by-side diff; settings changes show a before/after table. *** ## Plan Access & Daily Message Limits Backstage is accessible to all plans — there is no plan-level gate blocking access. The only throttle is the daily message limit, which varies by plan: | Plan | Daily Messages | | ----------------- | -------------- | | Free (or no plan) | 2 | | Hobby | 5 | | Standard | 10 | | Pro | 100 | | Enterprise | 100 | | Agency | 100 | There is also a **rate limit of 10 requests per 60 seconds** per user to prevent abuse. *** ## Backstage on Slack & iMessage You can now talk to your agent's Backstage directly from Slack or iMessage, no need to open the dashboard. Ask questions, review analytics, manage your agent, and approve changes from the apps you already use. ### What you can do from a DM or a text <CardGroup> <Card title="Analyze your agent" icon="chart-column"> Ask questions like **"How did my agent do this week?"** or **"What did users ask about most?"** Charts and reports are delivered directly in the conversation. </Card> <Card title="Update your agent" icon="sliders"> Change models, instructions, chat interface, branding, and other settings using natural language. Every change requires your approval before it's applied. </Card> <Card title="Manage sources & actions" icon="database"> Inspect, update, and retrain knowledge sources, and manage actions without opening the dashboard. </Card> <Card title="Approve safely" icon="shield-check"> Review exactly what's changing before approving. Nothing is applied without your explicit confirmation. </Card> <Card title="Analyze files (Slack)" icon="paperclip"> Upload a CSV or other supported file and ask questions about its contents directly from Slack. </Card> <Card title="Continue anywhere" icon="repeat"> Start on Slack or iMessage and continue the same Backstage session on the web with full history, richer approvals, and interactive charts. </Card> </CardGroup> ### Approving changes Every change proposed by Backstage requires your explicit approval. <Tabs> <Tab title="Slack"> Review the proposed changes and approve or reject them directly from Slack. Each proposal includes: <ul> <li>A detailed diff of what will change</li> <li><strong>Approve</strong> and <strong>Reject</strong> controls for every change</li> </ul> </Tab> <Tab title="iMessage"> React with: <ul> <li>👍 to approve</li> <li>👎 to reject</li> </ul> </Tab> </Tabs> You can also reply with messages like **"yes"**, **"approve"**, **"no"**, or **"reject"**, or equivalent phrases in any language. <Note> If you send another request while an approval is pending, the previous proposal is automatically superseded. You won't accidentally approve an outdated change. </Note> ### Connect Slack 1. Open your **Dashboard**. 2. Select your agent. 3. Open **Backstage**. 4. Click **Controllers** in the top-right corner. 5. Expand **Slack**. 6. Click **Add to Slack**. You only need to do this once per workspace. 7. Copy the generated link message. 8. Send it as a DM to the **Backstage** Slack app. 9. Once you receive **Connected ✓**, you're ready to chat. <Info> Each Slack thread is its own Backstage session. If your Slack account has access to multiple agents, starting a new thread will ask which agent you'd like to use. </Info> ### Connect iMessage 1. Open **Controllers** from the Backstage page. 2. Expand **iMessage**. 3. Text the generated link message to the displayed phone number, or scan the QR code to open Messages with the number and message pre-filled. 4. Once you receive **Connected ✓**, you can start chatting. <Info> Your phone maintains one active conversation. To switch agents, send another agent's generated link message. This starts a new Backstage session for that agent. </Info> ## Good to know <AccordionGroup> <Accordion title="Link messages"> Link messages are **single-use** and expire after **10 minutes**. </Accordion> <Accordion title="Permissions"> Connections are personal. They inherit your Chatbase permissions and can be revoked at any time from the **Controllers** dialog. </Accordion> <Accordion title="Attachments"> Slack supports uploading files for analysis. iMessage does not support attachments, if you send one, it'll tell you your caption. </Accordion> <Accordion title="Web experience"> Large analyses, interactive charts, and long approval flows include a link back to the corresponding Backstage session in the dashboard. </Accordion> </AccordionGroup> <Warning> Nothing is ever changed without your explicit approval. </Warning> *** ## Limitations * **Message length**: 10,000 characters max per message * **File uploads**: Max 50 MB per file, up to 5 files per message * **Analytics range**: Queries can cover a maximum of 6 months * **Knowledge base source size**: Max 1 MB per text source or Q\&A entry * **Helpdesk is read-only**: Backstage can surface helpdesk analytics and tickets, but it **cannot** modify ticket status, assign tickets, or send messages to customers * **File tools are agent-focused**: Backstage will only process uploaded files for agent-related tasks (improving knowledge base, instructions, analytics). It won't do general-purpose tasks like summarizing a random document or solving homework * **Permission-based**: Users only see tools they have permission to use based on their RBAC role. If a user lacks write permissions, mutative tools will return an "insufficient permissions" error # Build Source: https://chatbase.co/docs/user-guides/chatbot/build Configure everything your agent needs to operate, including its instructions, knowledge, actions, widgets, and channel-specific behavior. ## Instructions Instructions define your agent's behavior, role, and response guidelines. Use them to provide context, set expectations, and control how your agent responds to users. Go to **Build > Instructions**. The instructions editor fills the left of the page, and the **Model configuration** panel on the right holds the **Model** dropdown and the **Temperature** slider. Use **Compare** in the header to test changes side by side, and **Save changes** to apply them. ### General The **General** section contains your agent's primary instructions. Use this section to define: * Your business or product context * The agent's role and responsibilities * Response style and tone * Goals and expected behavior * Any additional guidance the agent should follow These instructions serve as the foundation for your agent's responses. ### Guardrails Use **Guardrails** to define rules your agent should always follow. Examples include: * Restricting topics the agent can discuss * Preventing the disclosure of sensitive information * Defining safety or compliance requirements * Controlling fallback behavior * Limiting the agent's role or capabilities Guardrails are intended for non-negotiable rules that should apply to every conversation. <Tip> Start with a simple, clear description of your agent's purpose, then gradually add specific instructions based on user feedback and common queries. </Tip> ### AI Model The AI model refers to the specific machine learning model used to generate responses for your AI agent. Each model has different capabilities, performance characteristics and message credits cost, allowing you to choose the one that best fits your needs. <AccordionGroup> <Accordion title="GPT"> * **GPT-5.2**: 2 message credits * **GPT-5 Mini**: 1 message credit * **GPT-5 Nano**: 1 message credit * **GPT-5.5**: 4 message credits * **GPT-OSS-120B**: 1 message credit * **GPT-OSS-20B**: 1 message credit * **GPT-4o Mini**: 1 message credit * **GPT-5.6 Luna**: 1 message credit * **GPT-5.6 Terra**: 2 message credits </Accordion> <Accordion title="Claude"> * **Claude 4.6 Opus**: 5 message credits * **Claude 4.6 Sonnet**: 3 message credits * **Claude 4.5 Haiku**: 1 message credit * **Claude 4.5 Sonnet**: 3 message credits * **Claude 4.5 Opus**: 5 message credits * **Claude 4.7 Opus**: 6 message credits * **Claude 4.8 Opus**: 6 message credits </Accordion> <Accordion title="Gemini"> * **Gemini 3.1 Pro**: 2 message credits * **Gemini 3.1 Flash Lite**: 1 message credit * **Gemini 3 Flash**: 1 message credit * **Gemini 3.5 Flash**: 2 message credits * **Gemini 3.5 Flash Lite**: 1 message credit * **Gemini 3.6 Flash**: 2 message credits * **Gemini 2.5 Pro**: 2 message credits </Accordion> <Accordion title="Llama"> * **Llama 4 Scout**: 1 message credit * **Llama 4 Maverick**: 1 message credit </Accordion> <Accordion title="DeepSeek"> * **DeepSeek-V3**: 1 message credit * **DeepSeek-R1**: 1 message credit * **DeepSeek-V4-Flash**: 1 message credit </Accordion> <Accordion title="Grok"> * **Grok 4**: 4 message credits * **Grok 3**: 3 message credits * **Grok 3 mini**: 1 message credit </Accordion> <Accordion title="Mistral"> * **Mistral Medium 3.5**: 2 message credits * **Mistral Small 4**: 1 message credit </Accordion> <Accordion title="Kimi"> * **KimiK2**: 1 message credit </Accordion> <Accordion title="GLM"> * **GLM 5.2**: 2 message credits </Accordion> </AccordionGroup> ### Temperature Temperature controls how creative and varied your AI agent's responses will be. This setting ranges from 0 to 1 and directly affects response predictability: * **Lower temperature (close to 0)**: Produces focused, consistent responses by selecting the most probable outputs * **Higher temperature (closer to 1)**: Generates more creative and varied responses with less predictability Drag the slider between **Reserved** and **Creative** to set the value. <Note> The default temperature is set to 0. You can adjust this value to experiment with different response styles and find what works best for your use case. </Note> ## Compare Area Click **Compare** in the **Build > Instructions** header to open the compare view. <Frame> <img alt="Instructions Compare view" /> </Frame> The "Compare" area allows you to add different AI agents next to each other and assign different settings to each to make testing and figuring out the settings that best suit your needs easier! The same message will be sent to all chats so that you can test the AI agent's response to the same message under different settings. You can also configure the below settings (buttons explained from left to right): 1. You can untick the 'Sync' button if you don't want the message sent to this AI agent to reflect on the rest of chats. 2. Adjust the settings for this specific AI agent (AI model, temperature, prompt). 3. Save the settings you've assigned to the AI agent to the main AI agent's settings. 4. From the three dots, you can move the position of the agent either to the left or right, reset the chat, or to delete the chat box completely. <Frame> <img alt="Instructions Compare view actions" /> </Frame> You can also use any of the following options: * Clear all chats. * Reset the settings of the AI agent to the main settings. * Add a new AI agent to test with. 5. To change which AI models you are testing, click the filter icon and select a new model from the dropdown. > **Note:** If you see the error "***This agent is currently unavailable. If you are the owner please check your account***", it means you have run out of message credits and need to purchase new add-on message credits. You can read all about our add-ons [here](https://www.chatbase.co/docs/user-guides/workspace/settings#add-ons) # Channels Source: https://chatbase.co/docs/user-guides/chatbot/channels Build your Chatbase agent across web, messaging, phone, and productivity channels. The **Channels** tab lets you make your agent available to users across multiple channels, including your website, a standalone help page, and third-party platforms like Slack, Email, Meta Apps (Whatsapp, FB Messenger, Instagram), and Phone. You can enable one or multiple deployment channels depending on how you want users to interact with your agent. *** ## All Channels Overview The Channels page shows all available channels for your agent. Each channel can be enabled, configured, and managed independently. Available channels include: * **Chat bubble** — A floating chat bubble embedded on your website * **Help page** — A standalone help page hosted by Chatbase * **Center Stage** — A full-focus chat experience that opens centered over your website * **Email** — Let your agent respond to emails * **Phone** — Let your agent handle inbound phone calls, via Twilio or your own SIP trunk * **Slack** — Use your agent inside Slack * **Zapier** — Connect your agent to thousands of apps * **WordPress** — Official WordPress plugin * **WhatsApp** — Respond to WhatsApp messages * **Messenger** — Connect your agent to Facebook Messenger * **Instagram** — Let your agent respond to Instagram messages * **Zendesk** — Respond to Zendesk support tickets * **Salesforce** — Connect your agent to Salesforce to assist with CRM workflows * **Shopify** — Connect your agent to your Shopify store Use the **Manage** button on each channel card to configure it — cards for channels you haven’t set up yet show **Setup** instead. *** ## Chat Bubble The **Chat bubble** allows you to embed a floating chat window on your website so visitors can interact with your agent directly. ### Enable the Chat Bubble 1. Go to **Channels** and click **Manage** on the **Chat bubble** card. 2. Click **Deploy** and choose **Website widget**. 3. Click **Enable chat bubble**. *** ### Chat bubble settings The chat bubble settings are split into four tabs: * **Overview**: The model, data sources, actions, instructions, and visibility for this channel. * **Display**: What users see when the chat starts, including content, capabilities, colors, typography, floating bubble, and localization. * **Voice**: Voice calling for this channel. * **Actions**: The actions your agent can perform in this channel. *** ### Overview The **Overview** tab shows your agent's **Model** and **Data sources**, which apply to the whole agent, alongside the **Actions**, **Instructions**, and **Visibility** for this channel. #### Model The AI model your agent uses globally across all channels. #### Data sources A read-only summary of what the agent is trained on: its training status, total size, and counts of Links, Texts, and Q\&A's. #### Actions View the actions enabled for this channel. #### Instructions Customize the instructions used by this channel. #### Sync with global instructions By default, your agent uses **global instructions**, which define its core behavior across all channels. When **Sync with global instructions** is enabled, the chat bubble uses the same global instructions as the rest of your agent. When this setting is disabled, you can define **channel-specific instructions** that apply only to the chat bubble and override the global instructions for this channel. #### Visibility Control whether this channel is active. When disabled, the channel is hidden and messages from this channel won't be routed to your agent. ### Chat bubble display Under the **Display** tab, you can control what users see when the chat starts. <Frame> <img alt="Chatbase Content Settings" /> </Frame> #### Content * Agent picture: Picture of the AI agent when providing answers. * Display name: The name shown at the top of the chat bubble. * Initial message: The message shown before the user opens the chat bubble, designed to grab attention and encourage interaction, also shown once the user opens the bubble. Enter each message on a new line to send several. You can customize the initial message per user by following [this guide](/docs/developer-guides/custom-initial-messages). * Use different message for mobile: Toggle this on if you want to show a different initial message when users open your website on a mobile device (usually a shorter message). * Auto show initial messages pop-ups after set duration: Set a timer to control when the initial messages pop up. * Show auto pop-up on mobile: Toggle this off if you want to disable the pop up when users open your website on a mobile device. * Use different duration for mobile: Toggle this on if you want to set a different timer for the pop-up when users open your website on a mobile device. * Message placeholder: The text shown in the field where the users write their questions. * Dismissable notice: A message shown above the text input area that disappears after the user sends a message. Supports rich text, up to 200 characters. * Footer: A message shown below the text input area, for a disclaimer or a link to your privacy policy. Supports rich text, up to 200 characters. * Suggested messages: Predefined prompts shown when users open the chat to help them start the conversation quickly. These should reflect your most common questions or actions. Click **+ Add message** to add one, and use the type dropdown beside it (default **Basic**) to group related prompts under a main message, so users pick a category first and then a more specific follow-up. Enable **Keep showing suggested messages** to keep them visible after the first reply. These are fixed wordings. To have the agent adapt its suggestions as the conversation develops, use the [Suggested Messages action](/docs/user-guides/chatbot/actions/suggested-messages) instead. <Info> If you include links in the footer or a dismissible notice, they must be full URLs starting with `http://` or `https://` \ \ (e.g., `https://www.example.com`), not just `www.example.com` or `example.com` </Info> #### Capabilities * Enable attachments: Enable or disable sending attachments, allowing your agent to process attachments and respond based on their content. * Enable voice to text: When enabled, a dictation button (microphone) appears in the text input area. Users can speak their message, which is converted to text for them to review and edit before sending. * Copy messages: When enabled, a copy button on agent messages is displayed to allow users to copy the response. * Collect user feedback: When enabled, it allows the user to provide a feedback by displaying a thumbs up or down button on AI agent messages. * Delete conversations: Allow users to delete their own conversations from the recent chats screen. #### Style * **Theme:** Choose between **Light** or **Dark** mode. * **Tinted grayscale:** Add a subtle hue to neutral elements such as the chat background, borders, and agent message bubbles. Leave this disabled to use the default grayscale colors. * **Hue:** Set the base hue of the tint from `0` to `360` on the color wheel. For example, `0` is red, `120` is green, and `220` is blue. * **Tint:** Control the intensity of the tint from `0` to `9`. Higher values make the selected hue more noticeable. * **Shade:** Adjust the lightness or darkness of tinted surfaces from `-4` to `4`. Negative values make them lighter, positive values make them darker, and `0` keeps the default shade. * **Accent color:** Apply a custom color to highlighted elements, such as user message bubbles. When disabled, the default accent color is used. * **Color:** Enter the hex value of your accent color, or use the reset button to restore the default. * **Use accent color for header:** Apply the accent color to the chat header. * **Use accent color for send icon:** Apply the accent color to the send button in the text input area. * **Radius:** Set the corner radius of the chat widget to control how rounded its edges appear. <Tip> Tinted grayscale and the accent color are independent. The accent color controls the highlighted elements, while tinted grayscale controls the surfaces around them. Set both to hues that work together for a consistent look. </Tip> #### Typography * Font family: Choose the font used throughout the chat bubble. * Font size: Set the base font size for text displayed in the bubble. #### Floating bubble * Position: Align the bubble to the **Left** or **Right**. * Chat bubble icon style: You can select from the built-in icon styles or upload your own custom icon to better match your brand. * Chat bubble button color: Set the color of the floating chat button displayed on your website. * Show text in the chat bubble: Display a short label next to the chat bubble icon to make the chat bubble more noticeable and encourage visitors to start a conversation. #### Localization The Chat bubble supports localization, allowing you to translate action buttons and interface text into multiple languages. **Language source** Choose how the chat bubble detects which language to display: * Visitor's browser: Uses the language configured in the visitor's browser. This is the default option. * Website language: Uses the language specified in the page's **html lang** attribute. This is recommended for multilingual websites with their own language switcher, as it allows the chat bubble's language to match the language of the page the visitor is viewing. <Frame> <img alt="Chatbase Content Settings" /> </Frame> You can add multiple languages by clicking **Add language** and selecting from the available list, including right-to-left (RTL) languages. <Frame> <img alt="Chatbase Content Settings" /> </Frame> One language must be set as the **default**. Once a language is enabled, action buttons and menu items in the chat bubble are automatically translated, such as starting a new conversation, ending a conversation, and viewing previous conversations. <Frame> <img alt="Chatbase Content Settings" /> </Frame> <Info> The chat bubble only displays languages you've added under **Localization**. If the detected language hasn't been added, the chat bubble falls back to your default language. </Info> <Info> **Localize dynamic chat bubble content**: You can also use setOptions to localize these fields (Display name of the AI agent, Initial message, Message placeholder, Footer and Dismissable notice and Suggested messages) as [mentioned here](https://www.chatbase.co/docs/developer-guides/control-widget#runtime-options) to provide the appropriate translated content. </Info> *** ### Attachments Chatbase allows your end-users to upload attachments during conversations. The AI agent can analyze supported files and generate responses based on their content. **Supported Attachment Formats** * Images: .png, .jpg, .jpeg * Documents: .pdf <Info> Some platforms (such as Instagram, Messenger, and WhatsApp) may allow users to upload additional file types (e.g., GIF). These formats are not supported. Any unsupported file types will be automatically discarded and not processed. </Info> **Attachment Limits** To maintain performance and reliability, the following limits apply (any ): * Maximum attachments per message: 5 files * Maximum file size: 5 MB per file * Maximum PDF length: 5 pages per file * Maximum characters per PDF page: 2,000 token (\~8,000 characters) Any attachments that exceed these limits will be **ignored and not processed.** **Billing** When a message contains attachments, the total credits consumed include **both the text response and the attachments processed**. Each AI model has separate pricing for: * Text requests * Image analysis * PDF file analysis (per page) So for every reply the agent generates: * Credits are consumed for the **text response** * Additional credits are consumed for **each attachment** * **Images:** charged per image * **PDFs:** charged per page **Example (Model cost = 1 credit)** | Message | Credit Calculation | Total | | --------------------------------- | --------------------------------------------- | ----- | | `Hi` | 1 (text) | **1** | | `Hi + 1 image` | 1 (text) + 1 × 1 (image) | **2** | | `Hi + 2 images` | 1 (text) + 2 × 1 (image) | **3** | | `Hi + 1 PDF (3 pages)` | 1 (text) + 3 × 1 (PDF pages) | **4** | | `Hi + 2 images + 1 PDF (3 pages)` | 1 (text) + 2 × 1 (images) + 3 × 1 (PDF pages) | **6** | **Actions + Attachments** If the message triggers an **action** (for example booking a meeting), the attachments are processed more than once. They are charged once when the action is executed, and again when the agent generates a response. **Example (Model cost = 1 credit)** | Message | Credit Calculation | Total | | --------------------------------- | -------------------------------------------- | ----- | | `Hi + 1 image` (action triggered) | 1 (text) + 1 × 1 (image) (processing action) | **2** | | `Agent response` (after action) | 1 (text) + 1 × 1 (image) (generating reply) | **2** | | `Total for this message` | 2 + 2 | **4** | In this case, the image is billed twice: once when processing the action, and again when generating the agent’s response. **Other Supported Channels** * Help Page * Center stage * E-mail * Instagram * Messenger * WhatsApp *** ### Voice Configure channel-specific voice settings that override your agent's default voice configuration. Learn more about voice settings in the [Voice settings documentation](https://www.chatbase.co/docs/user-guides/chatbot/settings#voice). *** ### Deploy button The **Deploy** button provides the code needed to add the chat bubble to your website. It opens a dropdown with **Website widget**, **Website iframe**, **Shopify**, and **WordPress**. #### Allowed Domains You can restrict where your agent is allowed to load by specifying approved domains. When enabled, the agent will only work on the domains listed here. #### Website widget (Recommended) Embed a floating chat bubble on your website. * Supports all advanced features of the agent * Fully customizable from the **Display** and **Overview** tabs * Best option for most use cases #### Website iframe Embed the chat interface directly using an iframe. * Simple to integrate * **Advanced features are not supported** * Recommended only if iframe embedding is required by your setup You can copy the embed script and paste it into your site’s HTML, typically before the closing `<body>` tag. *** ## Help Page The **Help page** is a standalone page hosted by Chatbase.\ It’s ideal for help centers, documentation portals, or internal tools. ### Enable the Help Page 1. Go to **Channels → Help page** 2. Click **Deploy**, then **Enable help page** <Frame> <img alt="Chatbase Help Page" /> </Frame> *** ### Help page display #### General * Page title: The title shown in the browser tab. * Favicon: Upload a custom favicon for the help page. Supports JPG, PNG, and SVG files up to 1MB. #### Content * Welcome message: The text shown at the center of the Help page, greeting your users. * Message placeholder: The text shown in the field where the users write their questions. * Suggested Messages #### Assets * Scheme: Upload differents assets for dark and light modes. * Logos: Upload a logo for light mode. * Heros: Upload a hero for light mode. #### Capabilites * Enable voice to text: When enabled, a microphone button is shown in the text input area that converts speech into text for users to review before sending. * Enable attachments: Enable or disable sending attachments, allowing your agent to process attachments and respond based on their content. #### Colors * Theme settings: Enable or disable theme switching. Set a default theme for all users. Customize light and dark primary colors. #### Buttons * Add Primary and Secondary buttons to the left sidebar for if you have links that you'd like to refer your users to. * Add link buttons at the bottom of the help page ### Deploy Button The **Deploy** button shows the default URL Chatbase generated for your help page, and lets you host it on your own website. You can: * Use the default **Chatbase domain**. Your help page is served at `www.chatbase.co/{id}/help`, where `{id}` is a unique identifier generated automatically by Chatbase. * Deploy on your **own domain** (for example, `yourcompany.com/help`). Check out the [Help Page Proxy](/docs/developer-guides/help-page-proxy) for detailed steps on how to do it. *** ## Center Stage Center Stage opens your agent in a focused chat interface centered over your website. It’s ideal for giving visitors more space to interact with your agent while keeping them on the page they’re currently viewing. ### Enable Center Stage 1. Go to Channels → Center Stage 2. Click **Deploy**, then **Enable center stage** <Info> Center Stage offers the same settings and configuration options as the Chat bubble. </Info> *** ## Third-Party Channels ### Email Connect your agent to an email address and let it respond automatically to incoming messages. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/email). Use this for customer support or inbound inquiries. *** ### Slack Connect your agent to Slack so it can respond to messages when mentioned or messaged directly. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/slack). Ideal for internal knowledge bases and team support. *** ### Phone Let your AI agent handle inbound phone calls. Callers are connected directly to your agent, which responds using its configured voice settings and knowledge base. There are two ways to connect a number: * **Twilio**: import a number from your connected Twilio account. Detailed steps are in the [Twilio guide](/docs/user-guides/integrations/twilio). * **SIP trunk**: bring an existing number from your own PBX, SIP provider, or GSM gateway. Detailed steps are in the [SIP trunk guide](/docs/user-guides/integrations/sip-trunk). *** ### Zapier Use Zapier to connect your agent with thousands of apps and automate workflows. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/zapier). *** ### WordPress Use the official Chatbase WordPress plugin to add the chat bubble to your WordPress site without writing code. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/wordpress). *** ### WhatsApp Connect your agent to a WhatsApp number and let it respond to WhatsApp messages. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/whatsapp). *** ### Messenger Connect your agent to a Facebook Page and let it respond to Messenger conversations. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/messenger). *** ### Instagram Connect your agent to an Instagram account and let it respond to messages from your customers. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/instagram). *** ### Zendesk Connect your agent to Zendesk to create and respond to support tickets from your customers. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/zendesk). *** ### Salesforce Connect your agent to Salesforce and use it to assist with CRM workflows, such as answering questions about records, supporting agents, or automating responses inside your Salesforce environment. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/salesforce). *** ### Shopify Use the official Chatbase Shopify app to add the chat bubble to your Shopify store without writing code. Detailed integration steps can be found on [this guide](/docs/user-guides/integrations/shopify). *** ## Best Practices * Start with one channel and expand as needed * Customize prompts and suggested messages per channel * Test each deployment before sharing it with users * Use the Help page for structured support and the chat bubble for quick assistance # Contacts Overview Source: https://chatbase.co/docs/user-guides/chatbot/contacts/contacts-overview Learn how to use contacts to enable personalized, secure interactions between your users and AI agents. Contacts allow you to store and manage user data that your AI agent can access during conversations, enabling personalized interactions while maintaining security and privacy. ## How Contacts Work Contacts bridge the gap between anonymous visitors and identified users in your system. When users interact with your agent, you can link their session to stored contact data to provide personalized experiences. <Info> Unlike anonymous visitors, contacts represent users who are authenticated and identified within your business system. </Info> ### The Identification Process <Steps> <Step title="Create contacts"> Upload user data to Chatbase using the [Contacts API](/docs/api-reference/contacts/create-contacts-for-a-chatbot) or manage them through the dashboard. <Note> **Recommended:** Use [JWT identity verification](/docs/developer-guides/identity-verification##method-1-jwt-recommended) to automatically create and update contacts when users interact with your agent. This eliminates the need for separate API calls. </Note> </Step> <Step title="Verify user identity"> When users interact with your agent, use [identity verification](/docs/developer-guides/identity-verification) to securely link them to their contact data. <Note> The `user_id` from your verification must match the `external_id` of a contact for the data to be accessible. </Note> </Step> <Step title="Enable personalized interactions"> Once linked, your agent can access contact data to provide personalized responses and perform actions on behalf of the user. </Step> </Steps> ## Key Benefits <CardGroup> <Card title="Secure data storage" icon="shield-check"> User data is encrypted and access-controlled, ensuring privacy and compliance. </Card> <Card title="Personalized conversations" icon="user"> Agents can reference user-specific information to provide tailored responses. </Card> <Card title="Actions integration" icon="bolt"> Contact data powers actions, enabling agents to perform user-specific operations such as [Stripe actions](/docs/user-guides/chatbot/actions/stripe-action). </Card> <Card title="Data synchronization" icon="arrows-rotate"> Keep Chatbase contacts in sync with your external systems and databases. </Card> </CardGroup> ## Next Steps <CardGroup> <Card title="Getting Started" icon="rocket" href="/docs/user-guides/chatbot/contacts/getting-started"> Learn how to get started with contacts. </Card> <Card title="Identity Verification" icon="key" href="/docs/developer-guides/identity-verification"> Implement secure user identification to link sessions with contact data. </Card> </CardGroup> # Uploading Contacts Source: https://chatbase.co/docs/user-guides/chatbot/contacts/uploading-contacts Bulk contact import lets you upload multiple contacts at once through a guided import flow in your agent’s **Contacts** page. You can use this to: * Quickly add new contacts * Update existing contacts by External ID * Import custom attributes in bulk *** ## Import contacts The import flow consists of four steps. ### Upload file Upload a `.csv` or `.xlsx` file by dragging it into the upload area or clicking to select a file. > **Limits** > > * Maximum file size: **5 MB** > * Maximum rows per upload: **1,000** You can also download a CSV template with the correct headers. The template includes: * Standard contact fields * Any custom attributes defined for the AI agent *** ### Map columns After uploading your file, Chatbase automatically matches your file headers to contact fields. Supported fields include: * External ID * Name * Email * Phone * Custom attributes You can manually adjust mappings using the dropdown menus. > **Important** > > External ID is required. You must map a column to **External ID** before continuing. #### Mapping rules * Each CSV header can only be mapped to one field * Custom attributes appear automatically during mapping * Unmapped columns are ignored during import *** ### Review and confirm Before importing, Chatbase displays a paginated preview table with all mapped rows. Each row is validated against existing contacts and duplicate values. #### Duplicate handling | Condition | Result | | ------------------------------------------------ | ---------------------------------------------------------- | | Duplicate External ID in the file | Row is blocked | | Duplicate email or phone in the file | Row is blocked | | Email or phone already exists in another contact | Row is blocked | | External ID already exists | Row is marked as **Update** to update the existing contact | | Missing External ID | Row is automatically excluded | Rows marked as **Update** will update the existing contact with the same External ID. You can hover over warning icons or the **Update** badge to see more details, including which fields will change. > **Note** > > Phone numbers are normalized to E.164 format before duplicate checks are performed. #### Row selection You can: * Select individual rows * Deselect rows you do not want to import * Use the **Select all** checkbox *** ### Completing the Import After the import completes, Chatbase displays the import results. This includes: * Number of successful imports * Number of failed rows * Detailed error messages for failed rows Example error: ```text theme={null} A contact with this email already exists ``` You can retry failed rows or close the dialog. *** ## Add a single contact Contacts can also be added individually. Go to: ```text theme={null} Dashboard → AI Agent → Contacts → Add Contact ``` The form includes: * External ID * Name * Email * Phone * Any Custom attributes > **Important** > > External ID is required when creating a contact manually. *** ## Custom attributes Custom attributes allow you to store additional information about contacts. Manage them from: ```text theme={null} Contacts → Manage Attributes ``` ### Supported attribute types * Text * Number * Boolean * Date ### Behavior * Custom attributes appear during import mapping * Custom attributes appear in the contacts table * Archived attributes are hidden from forms * Archived attribute data is preserved # Data sources Source: https://chatbase.co/docs/user-guides/chatbot/data-sources **Build > Data sources** is where you manage all the content that powers your AI agent. Use the buttons across the top — **Add Files**, **Add website**, **Add Text**, **Add Q\&A's**, **Add Notion Pages**, and **Add Tickets** — to add content. Tickets requires an active Salesforce or Zendesk integration via OAuth. Everything you add appears in a single list below, tagged with its type (**URL**, **Text**, **Q/A**). Use **Search** and the **All sources** filter to narrow the list, **Bulk select** to act on several at once, and **Sources per page** to page through them. The counter on the right tracks usage against your plan's total size limit (in MB). The header shows when the agent was last trained, alongside the **Auto-retrain** dropdown and the **Retrain AI Agent** button. <Tip> **Standard** and **Pro** plans include [Auto Retrain](#auto-retrain), which automatically updates your agent's knowledge base weekly. </Tip> ## Files Click **Add Files** to upload and manage documents that train your AI agent. ### Supported File Types Chatbase supports the following file formats: * .pdf (PDF Documents) * .txt (Plain Text Files) * .doc / .docx (Microsoft Word Documents) ### Uploading Files 1. Click **Add Files** at the top of the Data sources page. 2. Select one or multiple documents from your device. 3. The files will enter a queue and be uploaded one by one. Each file remains in the queue until it has been successfully processed. You can monitor the status of each upload in real time. <Frame> <img alt="Uploading Files" /> </Frame> ### Preview and Metadata After upload: * Click on any document to preview its contents directly within the dashboard. * You can view timestamps indicating exactly when each file was added and last updated. This allows you to easily track and verify your training sources over time. ### File Deletion * Delete files individually by pressing on the three dots then clicking ‘delete’. * To delete all files at once, first select the "Bulk select" button to select all documents. Once selected, a Delete button will appear—click this to remove all selected files in one action. ### Exporting Files * Uploaded files are exported as text (.txt) files. * The export contains the text extracted from the uploaded file, not the original document. * If you export multiple files, they are bundled into a .zip file. ## Text Snippets Click **Add Text** to add and manage text snippets, a flexible way to organize custom content for your AI agent's training. This feature is ideal for maintaining smaller, structured pieces of information separate from document uploads. ### Adding Text Snippets You can create and store multiple text snippets, each with a unique title to help you easily identify the content at a glance. This is particularly useful for segmenting information by topic, department, or use case. Text Editing Features Each snippet can be fully customized using rich text formatting: * Add headings for clarity * Format with bold, italic, or strikethrough * Create ordered or bullet lists * Insert hyperlinks to external sources * Include emojis to enhance tone and readability <Frame> <img alt="Edit Text" /> </Frame> ### Preview and Metadata After creating a snippet: * Click on it to preview or edit the content at any time. * View precise timestamps showing when the snippet was added and last updated. ### Snippet Deletion * Delete snippets individually by pressing on the three dots then clicking ‘delete’. * To delete several at once, click **Bulk select**, tick the snippets you want (or **Select all**), then click **Delete** in the bar at the bottom. ### Exporting Snippets * Text snippets are exported as Markdown (.md) files. * If you export multiple text snippets, they are bundled into a .zip file. ## Website Crawling Click **Add website** to train your AI agent using content directly from websites. Whether you're working with a full site, a sitemap, or individual URLs, this tool gives you flexible control over what gets included in your agent's knowledge base. <Info> If you're using Shopify, it’s recommended to add your sitemap (/sitemap.xml) instead of crawling the entire website. This reduces total MB usage and avoids duplicate product and collection pages, since Shopify’s sitemap already provides a clean, structured source of your content. </Info> ### Crawling Options You have three ways to fetch content from the web: 1. Crawl a full website – Provide the homepage URL and let Chatbase discover all public pages. 2. Submit a sitemap – Point to an XML sitemap to fetch a structured list of URLs. 3. Add individual links – Manually input specific URLs you want to include. For website crawling and sitemap submission, you can refine your crawl using: * Include Paths – Only URLs matching these paths will be fetched. * Exclude Paths – URLs matching these paths will be skipped. You can specify multiple paths in both fields, make sure to press the space bar after each one. Multiple websites or links can be crawled in parallel for efficiency. <Frame> <img alt="Crawl Website" /> </Frame> ### Grouping and Link Management After crawling a website, Chatbase displays all discovered links so you can review exactly what content your agent will be trained on. Links are automatically grouped into three categories: **Trained** These are pages that were successfully crawled and contain valuable content that can be used to train your AI agent — such as product pages, blog posts, and documentation pages. **Not Found** These are links that could not be accessed during crawling, usually because the page does not exist or returned an error — such as broken links, deleted pages, and redirect issues. **Excluded** Excluded links are pages that are intentionally skipped because they do not contain useful training content for your AI agent — such as login pages, signup pages, and duplicate pages. <img alt="Edit Website" /> ### Editing and Excluding Links After crawling: * You can exclude specific links from a group if you don't want them used in training. - You can edit include/exclude paths anytime through 'Advanced options', recrawl the website, and update your AI agent accordingly. <img alt="Edit Website" /> ### Link and Group Deletion You have full control over link cleanup: * Delete individual links from a group by excluding it. * Deleting an entire group of links (i.e., all pages fetched from a domain). * Deleting all the groups at once by selecting the three dots next to the website. <Info> Website sources cannot currently be exported. </Info> ## Custom Q\&A Training The Q\&A feature in Chatbase lets you train your AI agent with custom question-and-answer pairs, enabling it to respond precisely to frequently asked or business-specific queries. ### Creating Q\&As * Each Q\&A entry begins with a title, this helps you quickly locate and organize questions. * You can associate multiple variations of a question with a single answer, improving recognition and response accuracy. * You can bulk upload Q\&As up to 100 rows per file in .xlsx format, with a maximum file size of 1MB. ### Editing Answers Answers are fully customizable with rich text formatting tools. You can: * Add headings for clarity * Format with bold, italic, or strikethrough * Create ordered or bullet lists * Insert hyperlinks to external sources * Include emojis to enhance tone and readability <Frame> <img alt="Adding Q&A" /> </Frame> ### Usage Insights Click on any Q\&A to open its detail view, where you'll find real-time usage metrics: * number of times the question has been asked by users (updated instantly) * Last time the question was asked * Date the Q\&A was added * A visual chart showing the frequency of the question over time These insights help you identify which topics matter most to your users and prioritize updates accordingly. ### Management & Deletion * Delete any Q\&A individually. * To delete several at once, click **Bulk select**, tick the entries you want (or **Select all**), then click **Delete** in the bar at the bottom. ### Exporting Q\&As * Q\&A sources are exported as a single Excel (.xlsx) file. * The exported Excel file can be re-imported using Bulk upload excel, allowing you to export, bulk edit, and re-import your Q\&As. * When the Q\&A filter is active, Export all exports every Q\&A matching your current search, not just the Q\&As visible on the current page. * Export all supports up to 5,000 Q\&As. ## Notion This integration enables your AI agent to access and utilize information stored in your Notion databases. Click **Add Notion Pages** to connect your workspace and choose which pages to import. <Info> Notion sources cannot currently be exported. </Info> ## Auto Retrain Auto Retrain automatically keeps your AI agent up-to-date by pulling the latest content from your data sources every week. This ensures your agent always has access to the most current information without requiring manual intervention. To turn it on, click the **Auto-retrain** dropdown in the **Data sources** header (next to “Last trained”) and flip the toggle. <Info> Auto Retrain is available on **Standard** and **Pro** plans only. Hobby plan users will need to manually retrain their agent after updating sources. </Info> ### Supported data sources Auto Retrain works with the following source types: * **Website** - Discovers newly added links and updates existing page content * **Notion** - Syncs changes from your connected Notion workspace * **Remote storage** - Google Drive, Dropbox, and other remote sources (when available) ### How It Works * Your agent automatically fetches new content from all connected data sources once weekly * Newly added pages or links on your website are automatically discovered and included * No manual action is required—updates happen in the background ## Tickets Click **Add Tickets** to train your AI agent using support tickets from integrated platforms. This requires an active Salesforce or Zendesk integration to be set up first. If no integrations are configured, you'll be prompted to set one up via OAuth. ### Integration Selection You can import tickets from Salesforce or Zendesk. Select the platform to train on tickets from—you can switch between integrations as needed, but training occurs from only one at a time. * **Import from Salesforce**: Requires Salesforce integration. Link to [/user-guides/integrations/salesforce](/docs/user-guides/integrations/salesforce) for OAuth setup details. * **Import from Zendesk**: Requires Zendesk integration. Link to [/user-guides/integrations/zendesk](/docs/user-guides/integrations/zendesk) for OAuth setup details. After selecting the integration, click "Save" to confirm. Multiple integrations cannot be active for training simultaneously. Switch integrations by updating your selection and re-importing tickets. <Frame> <img alt="Integration Prompt for Zendesk/Salesforce" /> </Frame> ### Importing Tickets 1. Ensure the desired integration is selected. 2. Ensure training on tickets is enabled. 3. Click the save button. 4. Click **Retrain AI Agent**. Now the next training will fetch your tickets from the selected integration and train on them. ### Limitations Currently, tickets cannot be filtered (e.g., by status or date), and ticket sources cannot be previewed, edited, or deleted individually. All eligible tickets from the active integration are imported. Ensure your integration has the necessary permissions to access ticket data. Press the **Retrain AI Agent** button (top-right of the Data sources page) after enabling or disabling training on tickets. ## General Notes * When uploading files, make sure they contain selectable text. * All data should be in plain text, using mark-down language is preferred. * When integrating with a Notion account that's on a paid plan, make sure you have admin access to provide all necessary permissions for the integration to be successful. * Make sure to press the **Retrain AI Agent** button after you’re done adding, deleting, or updating your sources. * For selected sources, you can export up to 50 items at a time, since items can only be selected from a single page. The maximum export size is 200 MB. # Email settings Source: https://chatbase.co/docs/user-guides/chatbot/email-settings Use your AI agent over email with agent emails, forwarding rules, and authenticated domains. ## Overview The **Email settings** feature lets you use your AI agent as an email support channel.\ You get a unique **agent email** in the format `agent@subdomain.chatbase-mail.com` that you can: * **Send** emails and automatically **receive** AI-crafted replies. * **Connect to your own domains and mailboxes**, so customers see messages coming from your email addresses instead of the default `chatbase-mail.com` domain. <Info> You can add up to **3 custom domains**, and up to **20 email addresses per domain**. </Info> <Info> Attachments are supported, allowing your agent to process them and respond based on their content. For more information, please refer to [this section](/docs/user-guides/chatbot/channels#attachments). </Info> ## How it works * **Agent email**: When you create an AI agent, we generate an email like `agent@subdomain.chatbase-mail.com`. * **Inbound messages**: Customers send an email to: * Your **agent email**, or * One of your own addresses (for example, `support@yourdomain.com`) that automatically forwards to the agent email. * **AI response**: Your agent processes the email and generates a reply. * **From address**: * If you **don’t** connect a domain, replies are sent from your `agent@subdomain.chatbase-mail.com`. * If you **do** connect and authenticate a domain, we can send email **on your behalf** (for example, `support@yourdomain.com`), once DNS is correctly configured. <Note> To send emails from your own domain, you must (1) configure automatic forwarding from at least one mailbox on that domain to your agent email, and (2) add the DNS records we provide to your DNS provider. </Note> ## Prerequisites * Access to the **Chatbase dashboard** and the AI agent whose email settings you want to configure. * Admin access to your **email provider** to set up forwarding rules. * Admin access to your **DNS provider** (domain registrar or DNS host) to add TXT, MX, and/or CNAME records. ## Accessing Email settings <Steps> <Step title="Open your AI agent settings"> Open your agent and go to **Settings → Email**. If you haven't used email before, you'll need to enable the email channel first. <Frame> <img alt="Email settings section in the AI agent settings" /> </Frame> </Step> <Step title="Locate your agent email"> You'll see your automatically generated **agent email**, for example: `agent@subdomain.chatbase-mail.com` <Frame> <img alt="Agent email address displayed in Email settings" /> </Frame> You can use this email address to send and receive emails from your AI agent. </Step> </Steps> ## Using the agent email directly You can start using the feature immediately by sending an email to your **agent email**: 1. Send an email from any mailbox to `agent@subdomain.chatbase-mail.com`. 2. The AI agent processes the email content. 3. You receive a reply from the same `agent@subdomain.chatbase-mail.com` address. <Note> To enable AI agent replies, you must first enable the email channel. Learn more about [enabling the email channel](/docs/user-guides/integrations/email). </Note> <Check> If you receive a reply from your agent email, your basic email channel is working correctly. </Check> To use **your own domain and addresses** (for example, `support@yourdomain.com` or `billing@yourdomain.com`), continue with the next sections. ## Step 1 – Add an email address To configure a custom email address for your AI agent, start by adding the email address you want to use. <Steps> <Step title="Click New email address"> In **Email settings**, click the **New email address** button to start the setup process. <Frame> <img alt="New email address button in Email settings" /> </Frame> </Step> <Step title="Enter your email address"> Enter the email address you want to use (for example, `support@yourdomain.com`). <Note> The domain will be automatically extracted from the email address. You can add up to **3 domains** per workspace and up to **20 email addresses per domain**. </Note> <Frame> <img alt="Enter email address dialog" /> </Frame> </Step> <Step title="Continue to forwarding setup"> Click **Continue** to proceed to the email forwarding configuration step. </Step> </Steps> ## Step 2 – Configure email forwarding Next, configure automatic forwarding in your email provider so that emails sent to your support addresses are delivered to your agent email. ### Forwarding flow 1. A customer emails `support@yourdomain.com`. 2. Your email provider forwards that message automatically to `agent@subdomain.chatbase-mail.com`. 3. The AI agent processes the email and generates a reply. 4. The response is sent back via email from your authenticated domain. <Warning> You must configure automatic forwarding for at least **one email address on the domain** before you can complete DNS authentication and send from that domain. </Warning> ### Set up forwarding in your email provider The exact steps depend on your provider, but the general pattern is: 1. Sign in to your email provider's admin or mailbox settings. 2. Open the **Forwarding**, **Rules**, or **Filters** section. 3. Create a rule that forwards incoming messages from the mailbox (for example, `support@yourdomain.com`) to your **agent email** (`agent@subdomain.chatbase-mail.com`). 4. If your email provider requires verification before allowing the forwarding rule: * The provider will send a verification email to your **agent email**. * You can find and approve the verification email in your agent's chatlogs. 5. Click **Verify automatic forwarding** in the Email settings drawer. * If everything is set up correctly, you'll be taken to the **authenticate domain** step (Step 3). ## Provider-specific forwarding guides For detailed instructions on setting up email forwarding, refer to your email provider's documentation. Here are links to official guides for popular email providers: ### Google Workspace and Gmail <Tip> **Recommended:** Configure forwarding with **Default routing** in the Google Workspace Admin Console — it **doesn’t have rate limits** and **doesn’t require creating a mailbox** for the address you’re forwarding. </Tip> #### Configure email forwarding in Google Workspace (Admin Console) — Recommended <Info> You need **Google Workspace administrator access** to complete these steps. </Info> <Steps> <Step title="Open the Google Workspace Admin Console"> Sign in to the [Admin Console](https://admin.google.com/) using an admin account. </Step> <Step title="Go to Gmail routing settings"> Navigate to **Apps** → **Google Workspace** → **Gmail**. Find **Default routing**, then click **Configure** or **add another rule** to create a new routing rule. </Step> <Step title="Create a routing rule for your support address"> When adding the setting: * Set **Envelope Recipient** to the email address you want customers to use (for example, `support@yourdomain.com`). * Under **Envelope Recipient**, select **Change Envelope Recipient**. * In **Replace Recipient**, enter your **Chatbase agent email** (for example, `agent@subdomain.chatbase-mail.com`). <Frame> <img alt="Google Workspace Email Settings" /> </Frame> </Step> <Step title="Save the rule and enable it for recognized + unrecognized addresses"> Before saving, confirm the option is set to: **Perform this action on non-recognized and recognized addresses** <Frame> <img alt="Google Workspace default routing applied to recognized and unrecognized addresses" /> </Frame> Then save your changes. </Step> <Step title="Verify forwarding in Chatbase"> Return to **Email settings** in Chatbase and click **Verify automatic forwarding**. </Step> </Steps> <Note> Changes can take up to **24 hours** to propagate, although they often take effect sooner. </Note> #### Forward from a personal Gmail inbox * **Gmail (personal inbox forwarding)**: [Set up email forwarding in Gmail](https://support.google.com/mail/answer/10957) ### Microsoft * **Outlook (all versions)**: [Turn on automatic forwarding in Outlook](https://support.microsoft.com/en-us/office/turn-on-automatic-forwarding-in-outlook-7f2670a1-7fff-4475-8a3c-5822d63b0c8e) — follow this guide to set up forwarding to your Chatbase agent email. This works for Outlook.com, New Outlook, Classic Outlook, and Outlook on the web. #### Allow external forwarding in Microsoft 365 (required for work accounts) After setting up forwarding in Outlook, Microsoft 365 will **block the forwarded emails from leaving your organization** by default. Your Microsoft 365 administrator must allow external forwarding for the emails to reach Chatbase. Without this step, forwarding appears configured in Outlook but emails are silently blocked and Chatbase verification will fail. For more details, see [Microsoft's documentation on external email forwarding](https://learn.microsoft.com/en-us/defender-office-365/outbound-spam-policies-external-email-forwarding). <Info> You need **Microsoft 365 administrator access** to complete these steps. If you are not the admin, share these instructions with your IT team. </Info> <Steps> <Step title="Allow external forwarding in the outbound spam policy"> Sign in to the [Microsoft Defender portal](https://security.microsoft.com). Navigate to **Email & Collaboration** → **Policies & Rules** → **Threat policies** → **Anti-spam** (under Policies). Select the **outbound spam filter policy** (the default policy or a custom policy that applies to your users). Click **Edit protection settings**. Find the **Automatic forwarding rules** setting and change it from **"Automatic - System-controlled"** (or **"Off - Forwarding is disabled"**) to **"On - Forwarding is enabled"**. Save your changes. <Info> If you don't want to enable forwarding for the entire organization, you can create a custom outbound spam policy that only applies to specific users or groups, and enable forwarding only in that policy. Alternatively, you can use **Remote domains** in the Exchange admin center to allow forwarding only to the Chatbase mail domain. </Info> </Step> <Step title="Verify forwarding in Chatbase"> Return to **Email settings** in Chatbase and click **Verify automatic forwarding**. </Step> </Steps> ### Other email providers * **Yahoo Mail**: [Automatically forward emails in Yahoo Mail](https://help.yahoo.com/kb/SLN22028.html) * **ProtonMail**: [Set up email forwarding in ProtonMail](https://proton.me/support/email-forwarding) ## Step 3 – Authenticate your domain with DNS Once we detect automatic forwarding from at least one email address on the domain, you'll be able to proceed to DNS authentication. This step allows Chatbase to send emails on your behalf from your custom domain. ### View your DNS records After forwarding is verified, you'll see the DNS records you need to add. In the **Email settings** drawer, you'll see: * **Record type** (CNAME or TXT) * **Name** (the DNS record name) * **Value** (the DNS record value) Each record will show its authentication status. Copy each record exactly as shown. <Frame> <img alt="DNS records displayed in Email settings" /> </Frame> ### Add records at your DNS provider Sign in to the DNS provider that manages your domain (this might be your registrar or a DNS host like Cloudflare), then add the records we provided. <Note> The DNS records you need to add include: * **CNAME record** for DKIM authentication (e.g., `chatbase._domainkey`) * **CNAME record** for SPF authentication (e.g., `outbound.chatbase`) * **TXT record** for DMARC policy (e.g., `_dmarc`) Copy each record exactly as shown on the **Email** tab, including the name and value. </Note> ### Provider-specific DNS guides For detailed instructions on DNS authentication, here are links to official guides for popular DNS and domain providers: #### Domain registrars * **GoDaddy**: [Add a TXT or CNAME record](https://www.godaddy.com/en/help/add-a-cname-record-19236) * **Namecheap**: [How to manage DNS records](https://www.namecheap.com/support/knowledgebase/article.aspx/9646/2237/how-to-create-a-cname-record-for-your-domain/) #### DNS hosting providers * **Cloudflare**: [Manage DNS records](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/) * **Amazon Route 53**: [Working with DNS records](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-creating.html) * **Google Cloud DNS**: [Managing DNS records](https://cloud.google.com/dns/docs/records) * **Azure DNS**: [Manage DNS records](https://learn.microsoft.com/en-us/azure/dns/dns-operations-recordsets-portal) ### Verify your domain After you add the DNS records at your DNS provider: 1. Return to the **Email settings** drawer in Chatbase. 2. Click **Validate** to check if the DNS records are correctly configured. The system will verify each DNS record: * **DKIM**: Shows as "authenticated" when the CNAME record is found * **SPF**: Shows as "authenticated" when the CNAME record is found * **DMARC**: Shows as "authenticated" when the TXT record is found <Warning> DNS changes can take up to **24–48 hours** to fully propagate. If verification fails immediately after adding records, wait a few hours and try again. </Warning> <Check> Once all DNS records are verified, this email can be configured to be used by the AI agent to respond to emails. Replies will be sent **from your domain addresses** (for example, `support@yourdomain.com`) instead of the default `agent@subdomain.chatbase-mail.com` address. Learn more about [configuring the email channel](/docs/user-guides/integrations/email). </Check> ## Adding and managing email addresses After you've added your first email address and completed the setup process, you can add additional email addresses to the same domain or add emails from different domains. ### Adding more email addresses To add additional email addresses: 1. Click **+ New email address** in the **Email configuration** card on the **Email** tab. 2. Enter the new email address (for example, `sales@yourdomain.com`). 3. Follow the same 3-step process: * Enter the email address * Configure email forwarding * Authenticate the domain (if not already done) <Info> You can add up to **20 email addresses per domain**. If you're adding an email from a domain that's already authenticated, you'll only need to complete steps 1 and 2 (email address and forwarding). </Info> ## Testing your setup Once forwarding and DNS are configured: 1. Send an email from an external address (for example, your personal Gmail) to one of your connected addresses (for example, `support@yourdomain.com`). 2. Confirm that: * The conversation appears under your AI agent’s conversations. * The reply is sent back to your external address. * The **From** address matches your expectations: * If the domain is not verified: it will come from `agent@subdomain.chatbase-mail.com`. * If the domain is verified: it will come from your configured address on that domain. If everything looks correct, your email support channel is fully configured. ## Troubleshooting ### Email forwarding issues **I don't see emails in my agent conversations** * Confirm that forwarding is enabled and points to the correct **agent email** (`agent@subdomain.chatbase-mail.com`). * Check for filters or rules that might be archiving or deleting messages before they are forwarded. * Verify that your email provider has sent and you've approved any required verification emails. * Check your agent email's conversation history for any verification emails that need approval. ### DNS authentication issues **Domain verification fails** * Ensure there are no typos in the CNAME or TXT record values—copy them exactly as shown. * Verify that you added records on the correct DNS zone: * For `yourdomain.com`, add records at the root level * For `subdomain.yourdomain.com`, add records for the subdomain * Wait for DNS propagation—some providers can take up to 48 hours to update DNS records globally. **Some DNS records verify but others don't** * Each record is verified independently. Check each one: * DKIM (CNAME): Verify the name includes `chatbase._domainkey` * SPF (CNAME): Verify the name includes `outbound.chatbase` * DMARC (TXT): Verify the name includes `_dmarc` * Ensure the record values match exactly what's shown in Email settings. ### Microsoft 365 forwarding blocked **Verification keeps failing and no emails reach Chatbase** * Microsoft 365 blocks automatic external forwarding by default. Your admin must enable it in the outbound spam filter policy. See [Allow external forwarding in Microsoft 365](#allow-external-forwarding-in-microsoft-365-required-for-work-accounts) above. * Check if the sender is receiving a non-delivery report (NDR) with the error: `5.7.520 Access denied, Your organization does not allow external forwarding`. This confirms external forwarding is blocked. * If using a custom outbound spam policy, ensure the policy applies to the correct users or groups. ### General issues **I can't add more domains** * You can add up to **3 domains** per workspace. Remove an existing domain if you need to add a new one. **I can't add more email addresses** * You can add up to **20 email addresses per domain**. Consider using a different domain if you need more addresses. **Emails are being marked as spam** * Ensure all DNS records (DKIM, SPF, DMARC) are properly configured and verified. * Check your domain's reputation using tools like [MXToolbox](https://mxtoolbox.com/). # AI Draft Replies Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/ai-draft-replies Generate AI-powered draft responses for Helpdesk tickets and review them before sending. AI Draft Replies help your support team respond faster by allowing human agents to generate suggested responses directly within the Chatbase Helpdesk. The draft is generated using the conversation context and your AI agent’s connected data sources. Human agents can then review, edit, and approve the response before sending it to the customer. This allows your team to benefit from the AI agent’s knowledge while maintaining full control over every response. <Frame> <img alt="AI compose dropdown menu with formatting, tone, and translation options" /> </Frame> ## How AI Draft Replies work When a human agent is handling a ticket, they can click the AI Draft Reply button in the message composer. Chatbase will generate a suggested response based on: * The customer’s conversation history * The latest message in the ticket * The AI agent’s instructions * The AI agent’s connected data sources The human agent can then: * Review the generated response * Edit or personalize the content * Add any missing information * Send the response when ready <Note> Each generated draft uses message credits, just like a reply generated directly by the AI agent. </Note> ## Enable AI Draft Replies To enable AI Draft Replies: 1. Log in to your Chatbase dashboard. 2. Open your agent. 3. Go to **Settings**. 4. Select **Helpdesk**. 5. Open **AI draft replies**. 6. Enable the AI Draft Replies toggle. 7. Click **Save**. Once enabled, the AI draft button will appear in the Helpdesk message composer for your human agents. ## Generate a draft reply To generate a response: 1. Open a ticket in the Chatbase Helpdesk. 2. Click the AI draft button in the message composer. 3. Wait for the AI agent to generate a suggested response. 4. Review and edit the draft as needed. 5. Click **Send** when the response is ready. <Info> AI-generated drafts are never sent automatically. A human agent must review and send the response. </Info> ## Disable AI Draft Replies To remove the AI draft button from the composer: 1. Go to **Settings** → **Helpdesk** → **AI draft replies**. 2. Disable the toggle. 3. Click **Save**. Disabling this setting hides the draft button from the message composer but does not affect the AI agent’s other Helpdesk functionality. # Ticket Assignment Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/assignment-algorithm Automatically assign incoming tickets to the most available teammate, or let your team manually pick up work. As your support volume grows, you need an efficient way to route tickets to the right people. Chatbase offers three assignment methods so you can match your workflow, whether you prefer full control, even distribution, or simple rotation. Assignment is configured **per team**. Each [team](/docs/user-guides/chatbot/help-desk/teams) has its own assignment strategy, max tickets per agent, and next-shift behavior, all set on **Settings → Helpdesk → Teams & assignment**: pick the team's chip, then edit its **Team settings** card. Once [routing](/docs/user-guides/chatbot/help-desk/team-routing) sends a ticket to a team, that team's strategy decides which agent receives it. Agent availability is managed separately on the **Members** page. <Note>There is no separate AI agent-wide ticket assignment page. Every assignment setting belongs to a team, and the default team is selected for you when the page opens.</Note> ## Assignment methods at a glance <Columns> <Card title="Manual" icon="hand"> Tickets remain unassigned until a teammate claims one or a manager assigns it. </Card> <Card title="Balanced" icon="scale-balanced"> Each new ticket goes to the available agent with the **fewest open tickets**. </Card> <Card title="Round Robin" icon="arrows-rotate"> Each new ticket goes to the available agent who has gone **longest without receiving one**. </Card> </Columns> *** ## Manual assignment With manual assignment, new tickets land in the shared inbox and wait for a teammate to pick them up or for a manager to assign them directly. This is the default strategy for new teams. **Best for:** * Small teams where agents self-select work * Specialized tickets that require specific expertise * Low-volume inboxes that don't need automation *** ## Balanced assignment Balanced assignment automatically routes each incoming ticket to the available agent with the **lowest number of open tickets**. This keeps workloads even across your team, so no single agent gets overwhelmed while others sit idle. ### How it works 1. A new ticket arrives in the helpdesk. 2. The system finds all agents whose status is **Available**. 3. If a max ticket limit is configured, agents who have reached that limit are excluded. 4. The ticket is assigned to the agent with the **fewest open tickets** (non-closed, non-cancelled). 5. If multiple agents are tied, the one who was **least recently assigned** a ticket receives it. *** ## Round robin assignment Round robin distributes tickets sequentially by assigning each new ticket to the available agent who was **least recently assigned**, regardless of how many tickets they currently have open. It's a good fit for **sales and lead distribution** where equal opportunity matters more than current workload. ### How it works 1. A new ticket arrives in the helpdesk. 2. The system finds all agents whose status is **Available**. 3. If a max ticket limit is configured, agents who have reached that limit are excluded. 4. The ticket is assigned to the agent with the **oldest last-assignment timestamp**, the teammate who has waited longest for a new ticket. Unlike balanced assignment, round robin does **not** factor in how many tickets an agent currently has open. It purely rotates based on assignment order. *** ## Comparison | Feature | Manual | Balanced | Round Robin | | :-------------------------------------------------------------------- | :----- | :---------------------- | :---------------------- | | Auto-assigns tickets | No | Yes | Yes | | Selection criteria | - | Fewest open tickets | Least recently assigned | | Considers current workload | - | Yes | No | | Respects max ticket limit | - | Yes | Yes | | Only assigns to available agents (unless next-shift assignment is on) | - | Yes | Yes | | Tie-breaking rule | - | Least recently assigned | - | | Supports next-shift fallback | - | Yes | Yes | *** ## Unassigned tickets When no agents are available or all agents have reached their ticket limit at the moment a ticket is created, the ticket stays in the shared inbox as **unassigned**. Auto-assignment runs at ticket creation, and nothing sweeps the backlog to retry it later on its own. The one exception is a team with **Unassign on reply** turned on, where a customer reply gives the ticket another chance at assignment. Otherwise, the ticket remains unassigned until a teammate picks it up or a manager assigns it. Unassigned tickets are not automatically backfilled later when an agent comes online. To work through the queue, agents can open the **Unassigned** view and claim tickets, or a manager can assign them directly. ### Unassign on reply Turn this on in the [team's settings](/docs/user-guides/chatbot/help-desk/teams). A customer reply then gives the ticket another chance at assignment: * If the ticket is already unassigned, assignment runs again. * If the ticket is assigned and that agent is still available, nothing changes. * If the ticket is assigned and that agent is no longer available, the agent is unassigned and assignment runs again. * On a **Manual** team, the agent is only unassigned. There is no auto-assignment to run, so the ticket goes back into the team's pool for someone to claim. * The ticket keeps its existing team, so routing rules do not run again. * The same max tickets per agent limit and **Assign to next available shift** setting apply, just as they do when the ticket is first created. * **Closed** and **Cancelled** tickets are skipped. *** ## When all agents are unavailable If every agent is set to **Away**, **Busy**, or **Paused** at the moment a ticket is created, the auto-assignment algorithms (balanced and round robin) cannot find an eligible agent. Here's what happens: * Incoming tickets stay **unassigned** in the shared inbox with a **New** status. * Tickets remain in the **Unassigned** view until a teammate manually picks one up or a manager assigns it. * An agent toggling back to **Available** does not automatically receive queued tickets. <Tip>To avoid a growing backlog, ensure at least one agent is set to **Available** during business hours, and review the **Unassigned** view regularly.</Tip> *** ## Assign to next available shift When every agent is unavailable and you use **Balanced** or **Round Robin** assignment, you can enable **Assign to next available shift** so that incoming tickets are automatically routed to an agent whose shift starts soonest, instead of staying unassigned. ### How it works 1. A new ticket arrives and the system finds no available agents (all are `Off shift`, `Away`, `Busy`, or `Paused`). 2. The system looks at all **scheduled** agents and calculates when each agent's next shift begins, skipping any agents who are on time off. 3. The ticket is assigned to the agent (or agents, if tied) whose shift starts the **earliest**. 4. The chosen agent is selected using the same algorithm you configured. **Balanced** picks the one with the fewest open tickets, **Round Robin** picks the one least recently assigned. <Info>This feature only applies to **scheduled** agents (those assigned to a shift). Manual agents are not considered because their next available time cannot be predicted.</Info> ### Enabling the toggle <Steps> <Step title="Open the team"> Navigate to **Settings → Helpdesk → Teams & assignment** and select the chip of the team you want to configure. </Step> <Step title="Choose an auto-assignment method"> Set the team's **Assignment strategy** to **Balanced** or **Round Robin**. The toggle is not available for **Manual** assignment. </Step> <Step title="Enable the toggle"> Turn on **Assign to next available shift** and save. When enabled, tickets that would otherwise stay unassigned are routed to the next agent coming on shift. </Step> </Steps> ### Things to know * **Max ticket limits still apply.** If you have a max tickets per agent configured, the next-shift agent must also be under that limit to receive the ticket. * **Time off is respected.** Agents on time off are skipped even if their shift is the soonest. * **Multiple agents on the same shift.** When several agents share the same next shift start time, the configured assignment algorithm (Balanced or Round Robin) breaks the tie. * **No scheduled agents?** If your team has no scheduled agents, this toggle has no effect since there are no shift start times to predict. *** ## Max tickets per agent For both automated methods (balanced and round robin), each team can optionally set a **maximum number of open tickets per agent**. When an agent reaches this limit, they stop receiving new assignments until they close or resolve existing tickets. * **Default:** No limit * **Scope:** Set per team, alongside the assignment strategy <Steps> <Step title="Open the team"> Navigate to **Settings → Helpdesk → Teams & assignment** and select the team's chip. Set its **Assignment strategy** to **Balanced** or **Round Robin** (the limit does not apply to Manual). </Step> <Step title="Set the cap"> Enter a value in **Max tickets per agent**. Leave it empty for no limit. A good starting point is **10** for most support teams. Adjust based on your ticket complexity and team size, then save. </Step> </Steps> <Warning>When all available agents are at capacity at the moment a ticket is created, the ticket remains unassigned in the shared inbox and is **not** automatically picked up later. A teammate must claim it or a manager must assign it. Monitor your team's workload to avoid bottlenecks.</Warning> *** ## Agent availability Only agents with an **Available** status are eligible for automatic assignment. For agents who aren't on a [shift schedule](/docs/user-guides/chatbot/help-desk/scheduling), you set this status yourself from the **Members** page (**Settings → Helpdesk → Members**), where every agent is listed with their teams and availability. A scheduled agent's status comes from their shift instead, so the Members page shows it as read-only. | Status | Receives auto-assigned tickets? | When to use | | :------------ | :------------------------------ | :---------------------------------------------------------------------------------------- | | **Available** | Yes | Agent is online and ready to handle tickets | | **Away** | No | Agent is temporarily unavailable (lunch, meeting) | | **Busy** | No | Agent is focused on existing work and should not receive new tickets | | **Paused** | No | Agent is offline or on extended leave | | **On shift** | Yes | Set automatically while a scheduled agent is inside their shift hours and not on time off | | **Off shift** | No | Set automatically outside a scheduled agent's shift hours | Agents can update their own status from the sidebar when an admin has enabled **Allow teammates to be able to change their availability status** on the Members page. *** ## Setting up assignment <Steps> <Step title="Open the team"> Navigate to **Settings → Helpdesk → Teams & assignment** and select the chip of the team you want to configure. </Step> <Step title="Choose an assignment method"> Set the team's **Assignment strategy** to **Manual**, **Balanced**, or **Round Robin** based on the team's workflow. </Step> <Step title="Configure ticket limits (optional)"> If using balanced or round robin, set **Max tickets per agent** to prevent agent overload, then save. </Step> <Step title="Set agent availability"> Open **Settings → Helpdesk → Members** and make sure agents who are ready to receive tickets are set to **Available**. </Step> </Steps> *** ## Good to know * **New agents default to Away.** When an agent is first added to an AI agent, their status is set to **Away**. They will not receive auto-assigned tickets until an admin or the agent themselves switches to **Available**. * **Ticket limits only apply to auto-assignment.** The max tickets per agent setting does not restrict manual assignment. An admin can still assign tickets to an agent who has exceeded the configured limit. * **Reassignment does not change ticket status.** When a ticket is reassigned from one agent to another, the ticket's status remains unchanged. It does not reset to **New** or **On You** automatically. * **The Away toggle only switches between Away and Available.** Paused agents and agents on a shift schedule do not get this toggle in the sidebar. An admin can change a paused agent's status from the **Settings → Helpdesk → Members** page. A scheduled agent's status follows their shift instead. # Email Settings Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/email-settings Configure email addresses, display names, signatures, and previews for your Helpdesk. ## Email Configuration The Email Configuration card allows you to choose which email addresses will be used as your help desk inboxes and who should be notified about deliverability issues. ### Selecting help desk emails You can configure one or more email addresses to receive support tickets. <Steps> <Step title="Add an email row"> Click **Add email** to add a new email row. Each row presents a dropdown of your available email addresses. </Step> <Step title="Select an email address"> Choose an email address from the dropdown. Emails from every domain are listed; ones with DNS problems appear disabled with an issue indicator. Once you pick an email in one row, that option becomes disabled in the other rows' dropdowns. </Step> <Step title="Review email status"> Each selected email is checked for three things: * **Forwarding** - Whether email forwarding is enabled * **DKIM** - Whether DKIM authentication is configured on the domain * **SPF** - Whether SPF records are configured on the domain All three must pass for the email to function correctly. An email that fails any of them shows a warning badge with the number of issues. </Step> <Step title="Save"> Click **Save** to apply your email configuration. </Step> </Steps> <Warning> Emails missing any of the three requirements (Forwarding, DKIM, SPF) display a badge showing the number of issues. Hover over it to see which checks are failing. Resolve these in your domain's DNS settings before using the email for help desk support. </Warning> ### Removing an email Click the trash icon next to any email row to remove it, including the last one. If no email is configured, outgoing replies fall back to the auto-generated agent address. ### Deliverability alert contact Configure which team member receives notifications when outgoing help desk emails fail to deliver. 1. Open the **Deliverability alert contact** dropdown. 2. Select a team member from your account's member list. 3. Click **Save**. The selected contact will receive alerts when emails bounce or encounter delivery issues. <Info> The deliverability alert contact is optional. If not set, no notifications will be sent for failed deliveries. </Info> ### Validation rules | Rule | Description | | -------------------- | ------------------------------------------------------------------------------------------- | | Non-empty email rows | Every added email row must have an email selected | | No duplicates | The same email address cannot be selected in multiple rows | | DNS requirements | Warnings are shown for emails missing Forwarding, DKIM, or SPF, but saving is still allowed | *** ## Display Name The Display Name setting controls what recipients see in the **From** field of emails sent from your help desk. This helps establish trust and brand recognition with your customers. ### Auto mode **Auto** uses the name of the support associate who responds to the ticket. Each outgoing email will show the actual agent's name, creating a more personal support experience. For example, if agent "Sarah Johnson" responds to a ticket, the email appears as: ```text theme={null} From: Sarah Johnson <support@yourdomain.com> ``` <Info> Auto mode is the default and recommended for teams that want a personal touch in customer communications. </Info> ### Custom mode **Custom** uses a fixed name you specify for all outgoing emails, regardless of which agent responds. This is useful for maintaining a consistent brand identity across all support communications. For example, if you set the custom name to "Acme Support": ```text theme={null} From: Acme Support <support@yourdomain.com> ``` When selecting custom mode, a text input appears where you enter the desired display name. The name cannot be empty. ### Changing the display name 1. Select either **Auto** or **Custom** using the radio buttons. 2. If **Custom** is selected, enter the desired display name in the text field. 3. Click **Save** to apply. <Note> Changes to the display name take effect on all future outgoing emails. Previously sent emails are not affected. </Note> *** ## Email Signature The Signature card lets you create a rich-text signature that is automatically appended to the bottom of every outgoing help desk email, including those sent by the AI agent. ### Creating a signature 1. Open the **Signature** card on the email settings page. 2. Use the rich-text editor to compose your signature. The editor supports bold, italic, underlined text, links, and line breaks. 3. Click **Save** to apply. ### Signature behavior | Scenario | Signature applied? | | -------------------------- | ----------------------------- | | AI agent auto-replies | Yes | | Manual agent replies | Yes | | No signature content saved | No signature section rendered | ### Editing or removing a signature * **Edit:** Modify the content in the rich-text editor and click **Save**. * **Remove:** Clear all content from the editor and click **Save**. An empty signature produces no signature block at send time. <Info> Keep signatures concise. Long signatures can push the actual email content out of the visible area on mobile devices. </Info> *** ### Fallback behavior | Condition | Fallback | | ------------------ | ---------------------------------------------------------------------- | | No emails selected | Uses the auto-generated agent email: `agent@{subdomain}.{mail-domain}` | <Note> The preview on the settings page uses placeholders when configuration is incomplete: `chatbase@mail.com` for a missing subdomain, and "Support Associate" for Auto display name. Real emails always use your subdomain and the responding agent's name. </Note> # Filters Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/filters The full set of fields, operators, and values you can use to filter the help desk inbox. Filters narrow the help desk inbox to a specific slice of tickets. They are used in two places: * The **Filter** button above the ticket list, for quick ad-hoc filtering of the current view. * The **Filters** tab when creating or editing a [saved view](/docs/user-guides/chatbot/help-desk/saved-views), where the same filters are persisted alongside a sort order and column layout. A filter is made of three parts: a **field**, an **operator**, and a **value**. Tickets must match every active condition to appear. You can stack up to 20 conditions at once. *** ## Available fields | Field | What it filters on | | ------------------- | -------------------------------------------------------------------------------- | | **Status category** | The ticket's current lifecycle state | | **Status** | A specific configured status, including any custom statuses your workspace added | | **Channel** | Where the ticket originated | | **Assignee** | The agent the ticket is assigned to | | **Team** | The team the ticket is assigned to | | **Mentions me** | Tickets where you are @mentioned in an internal note | | **Created** | When the ticket was first created | | **Last message** | When the most recent message was sent | | **Last message by** | Who sent the most recent message | | **Type** | Whether the ticket is a regular ticket or a live chat | *** ## Operators by field The available operators depend on the field. | Field | Operators | | --------------- | ------------------------------------------- | | Status category | `is any of`, `is none of` | | Status | `is any of`, `is none of` | | Channel | `is any of`, `is none of` | | Assignee | `is any of`, `is none of` | | Team | `is any of`, `is none of` | | Mentions me | (none) | | Created | `in the last`, `before`, `after`, `between` | | Last message | `in the last`, `before`, `after`, `between` | | Last message by | `is` | | Type | `is` | What each operator means: * **is any of** / **is none of**: pick one or more values; the ticket must match (or not match) any of them. * **is**: single fixed value (boolean or single-select). * **in the last**: relative window such as *the last 7 days*, *the last 2 weeks*, or *the last 3 months*. Maximum 365 days. * **before** / **after**: absolute date threshold. * **between**: absolute date range with a start and end date. *** ## Values by field ### Status category One or more of the six built-in status categories: * **New**: freshly created, not yet picked up * **On You**: assigned, awaiting agent action * **On Customer**: agent replied, awaiting customer response * **On Hold**: paused on an external dependency * **Closed**: resolved * **Cancelled**: spam, duplicate, or opened in error Any custom status your workspace adds falls under one of these categories. See [ticket statuses](/docs/user-guides/chatbot/help-desk/help-desk-overview#ticket-statuses) for how the categories work. ### Status One or more of the statuses configured in your workspace, including any custom statuses you've added under **Settings → Helpdesk → Ticket statuses**. Unlike Status category, this matches one specific configured status rather than its lifecycle group. ### Channel One or more of: * **Chat bubble**: embedded AI agent on your website * **Email**: email forwarding * **WhatsApp** * **API**: created programmatically * **Messenger** * **Instagram** * **Center stage**: full-focus chat experience centered over your website * **Phone**: inbound phone call handled by your AI agent ### Assignee One or more of: * **Me**: the currently signed-in agent * **Unassigned**: no agent assigned * Any specific agent in the workspace ### Team One or more of: * **My teams**: teams you belong to * **No team**: tickets with no team assigned * Any specific team in the workspace ### Mentions me This filter has no operator or value to configure. It is either present in your filter list or it isn't. When present, the inbox is restricted to tickets where you are @mentioned in an internal note. To turn it off, remove the filter row. ### Created / Last message Date values, used with one of the date operators above. Relative windows accept a positive integer up to 365 paired with a unit (`days`, `weeks`, or `months`). ### Last message by One of: * **Customer**: most recent message came from the customer * **Agent**: most recent message came from a teammate ### Type One of: * **Ticket**: standard support ticket * **Live chat**: active live chat session *** ## Combining filters Conditions are combined with **AND**: every condition must match. Stack different fields to slice the inbox precisely. For example: * *Channel is any of WhatsApp* + *Status category is any of New, On You* + *Created in the last 1 day* → fresh, unresolved WhatsApp tickets from the past day. * *Assignee is any of Unassigned* + *Last message by is Customer* → tickets waiting for someone to pick them up where the customer spoke last. To save a combination for reuse, build it as a [saved view](/docs/user-guides/chatbot/help-desk/saved-views) instead of re-applying it each time. # Helpdesk Overview Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/help-desk-overview Manage customer support tickets from a centralized dashboard. ## Introduction The Helpdesk is a centralized support dashboard where your team can manage customer tickets across every channel - bubble, email, WhatsApp, and API - in one place. Agents can triage, assign, and resolve tickets without switching between tools, keeping response times low and customer satisfaction high. <Frame> <img alt="Helpdesk dashboard overview showing sidebar, ticket list, and details panel" /> </Frame> ### Sidebar The sidebar is your primary navigation. It can be collapsed into icon-only mode for more screen space. * **My inbox** - tickets assigned to you * **Mentions** - tickets where you have been @mentioned in an internal note. The badge count shows how many unread mentions you have. * **All** - every ticket across agents that is not Closed or Cancelled * **Unassigned** - tickets with no agent assigned * **Solved** - tickets that are Closed or Cancelled * **Conversations** - all AI agent conversations, including those that have not been escalated to tickets Each view displays a badge count when there are items requiring attention. Below the built-in views, your saved views appear in two groups, **Shared views** and **My views**. Each group shows the first 5 views, with a **Show more** control to expand the rest. A search box filters views by name, and a **New view** button creates one. See [Saved views](/docs/user-guides/chatbot/help-desk/saved-views) for details. ### User Profile Click your avatar at the bottom of the sidebar to open the profile menu: * **Away mode** - toggle to mark yourself as unavailable for auto-assignment. This only appears if an admin has turned on "Allow teammates to be able to change their availability status" on the Members page. Agents on a shift schedule don't see it, since their shift sets their availability * **Sound notifications** - toggle notification sounds on or off * **Dashboard** - navigate to the main Chatbase dashboard * **Account settings** - manage your account * **Logout** - sign out of the helpdesk <Frame> <img alt="User profile menu showing away mode, sound notifications, dashboard, account settings, and logout options" /> </Frame> ### Notifications New activity on any ticket assigned to you triggers two notifications, wherever you are in the helpdesk: * **Sound** - a notification sound plays (if sound notifications are enabled in your profile menu) * **Tab badge** - the browser tab title updates to show the unread count, e.g. `(2) Helpdesk` This works even when the tab is not in focus. ### Search Click the search button to open a search modal with two tabs: **Tickets** and **Customers**. Results update in real time as you type, and you can click through to the full search results page. <Frame> <img alt="Search modal with Tickets and Customers tabs" /> </Frame> ## Tickets Inbox ### Table Columns The ticket list displays the following columns: | Column | Description | | -------------- | --------------------------------------------------------------- | | Status | Color-coded badge indicating the ticket's current state | | Ticket ID | Unique identifier, formatted as `#123` | | Requester | The customer who submitted the ticket (name or email) | | Assignee | The agent responsible for the ticket, or `-` if unassigned | | Team | The team the ticket is assigned to, or `-` if none | | Ticket Details | Subject line and a preview of the last message | | Created At | When the ticket was created (relative time, e.g. "2 hours ago") | | Last Updated | When the most recent message was sent (relative time) | Click any row to open the ticket. ### Filters Click the **Filter** button in the top right, above the ticket list, to narrow the results within the current view without changing it. Add one or more conditions, each made of a field, an operator, and a value. A badge next to the button shows how many conditions are active; **Clear all** resets them and **Apply** confirms your selection. Filters here are temporary, scoped to your session, and do not modify the underlying view. To make a filter combination permanent, save it as a [saved view](/docs/user-guides/chatbot/help-desk/saved-views), which persists conditions alongside a sort order, columns, and visibility. The full list of fields, operators, and values is documented in the [Filters reference](/docs/user-guides/chatbot/help-desk/filters). ## Ticket Statuses Every ticket has a status that reflects where it is in the support lifecycle. Statuses are grouped into **active** (New, On You, On Customer, On Hold) and **closed** (Closed, Cancelled). You can also configure your own custom status by clicking **Add status** on the **Settings → Helpdesk → Ticket statuses** page. <AccordionGroup> <Accordion title="New"> A freshly created ticket that hasn't been picked up by any agent yet. New tickets appear in the **Unassigned** view until an agent claims them. </Accordion> <Accordion title="On You"> The ticket requires action from the assigned agent. This is the default status when an agent picks up a ticket or when a customer replies. </Accordion> <Accordion title="On Customer"> The agent has replied and is waiting for the customer to respond. Use this status after sending a reply so your team knows no agent action is needed right now. </Accordion> <Accordion title="On Hold"> The ticket is paused because of an external dependency - for example, waiting on a third-party service or an internal escalation. Use this sparingly and add a note explaining the reason. </Accordion> <Accordion title="Closed"> The issue has been resolved. Closed tickets move out of the active queue. </Accordion> <Accordion title="Cancelled"> The ticket was spam, a duplicate, or opened in error. Cancelled tickets are removed from the active queue. </Accordion> </AccordionGroup> ## Requester and Assignee * **Requester** - the end user who submitted the ticket. Their profile can include a name, email, external ID, and phone number. * **Assignee** - the agent responsible for handling the ticket. Tickets can be assigned manually or through auto-assignment. <Tip> Configure auto-assignment rules for each team on the **Settings → Helpdesk → Teams & assignment** page. See [Assignment algorithm](/docs/user-guides/chatbot/help-desk/assignment-algorithm) for how tickets get routed to available agents. </Tip> ## Viewing a Ticket When you open a ticket, the view splits into a **conversation thread** on the left and a **details panel** on the right. ### Conversation Thread The conversation thread displays three types of entries: * **Replies** - customer-visible messages from either the customer or an agent * **Notes** - internal-only messages visible to your team (shown with an amber background) * **Events** - system-generated entries for status changes and assignment updates <Frame> <img alt="Conversation thread with customer replies, internal notes, and system events" /> </Frame> ### Ticket Details Panel The right sidebar contains the following collapsible sections: 1. **Assignee** - view or change the assigned agent. Click the edit icon to reassign to another agent or unassign the ticket entirely. 2. **Author** - the requester's information: name, email, external ID, and phone number. 3. **Ticket Details** - ticket ID, status badge, submission date, subject, and a **View conversation** button that links to the original AI agent conversation that created the ticket. 4. **Customer History** - a list of other tickets from the same customer, showing subject, ticket ID, time, and status badge. This gives agents quick context on the customer's support history. 5. **Notes** - a list of internal notes attached to the ticket, including any @mentions. Connected integrations can add their own panels, such as the **Shopify Orders** panel when a Shopify store is connected. See [Shopify integration](/docs/user-guides/chatbot/help-desk/integrations/shopify) for details. <Frame> <img alt="Ticket details panel showing assignee, author info, ticket details, previous tickets, and notes sections" /> </Frame> ## Replying to Tickets ### Reply vs Note The message composer at the bottom of the conversation thread has two tabs: * **Reply** - sends a public message to the customer through the same channel they used to contact you. * **Note** - saves an internal-only message (shown with an amber background) that only your team can see. <Warning> Always double-check which tab is selected before sending. Notes are internal-only, but replies go directly to the customer. </Warning> ### @Mentions Type `@` in the note composer to mention a team member. A dropdown appears listing available agents along with a colored dot indicating their current availability status. Select an agent to insert the mention into your note. <Frame> <img alt="Agent mention dropdown showing team members with availability status indicators" /> </Frame> When you @mention someone: * The mentioned agent receives a notification * The ticket appears in their **Mentions** sidebar view * The mention is rendered as a clickable link in the note Use @mentions to loop in colleagues, escalate to another agent, or flag a ticket for someone's attention without reassigning it. <Frame> <img alt="Ticket view showing an @mention in an internal note and the Mentions count in the sidebar" /> </Frame> <Warning> @mentions are only available in **Notes** (internal messages). They are not supported in customer-facing replies. </Warning> ### Attachments Click the **paperclip** icon to attach files to a reply or note. Any file type works, and you can remove an attachment before sending. ### AI Compose Click the **magic wand** icon in the composer toolbar to open the AI writing assistant. It offers the following options: | Option | Description | | ---------------------- | ----------------------------------------------------------------- | | Format text | Cleans up formatting and structure | | More friendly | Adjusts the tone to be warmer and more approachable | | More formal | Adjusts the tone to be more professional | | Rephrase | Rewords the text while keeping the same meaning | | Expand | Adds more detail and length | | Fix grammar & spelling | Corrects grammar and spelling errors | | Translate | Translates the text to another language (opens a language picker) | You need to have text in the editor for AI Compose to be available. <Frame> <img alt="AI compose dropdown menu with formatting, tone, and translation options" /> </Frame> ## Recommended Ticket Workflow A typical ticket lifecycle follows these steps: 1. A customer submits a request → ticket is created as **New** 2. An agent picks up the ticket → status changes to **On You** 3. The agent sends a reply → agent sets status to **On Customer** 4. The customer responds → status returns to **On You** 5. An external blocker is identified → agent sets status to **On Hold** 6. The issue is resolved → agent sets status to **Closed** 7. The ticket is spam or a duplicate → agent sets status to **Cancelled** <Tip> **Best practices:** * Set the status to **On Customer** after every reply so your team knows you're waiting for a response. * Use **On Hold** sparingly - add a Note explaining what you're waiting on. * Add **Notes** to document your investigation steps, so other agents can pick up where you left off. </Tip> ## Ticket Channels Tickets can arrive from multiple channels. The channel is shown on each ticket so agents know where the conversation originated: * **Email** - received via email forwarding * **Help desk** - created manually by an agent directly in the help desk * Using "Escalations" Action: * **Chat bubble** - submitted through the AI agent on your website * **WhatsApp** - from a WhatsApp conversation * **API** - created programmatically through the API * **Messenger** - from Facebook Messenger direct message. * **Instagram** - from Instagram direct message. * **Center stage** - submitted through the full-focus chat experience centered over your website * **Phone** - from an inbound phone call handled by your AI agent <Tip> When you reply to a ticket created from the chat bubble, the customer receives your reply in two places: their email **and** the chat bubble itself. To see it in the chat bubble, the customer opens the three-dot menu (•••) and selects **View tickets**. </Tip> # Shopify Orders Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/integrations/shopify See a customer's Shopify order history right inside the ticket. ## Introduction When your agent is connected to a Shopify store, the **Shopify Orders** panel appears in the ticket sidebar. It shows the order history of the person you are talking to—without leaving the Helpdesk or opening Shopify in another tab. Use it to check what a customer bought, confirm a shipping address, look up tracking, or jump straight to the order in Shopify admin while you reply. <Note> The panel only shows up when a **Shopify integration** is connected to this agent. If you don't see it, connect your store first—see the [Shopify integration guide](/docs/user-guides/integrations/shopify). </Note> ## How orders are matched The panel looks up orders using the ticket contact's details, in this order: 1. **Email** — the contact's email address is tried first. 2. **Phone** — if no orders are found by email (or there's no email on file), it falls back to the contact's phone number. ### Looking up a different customer Sometimes the ticket contact isn't the same person who placed the order (for example, they wrote in from a different email). Use the **lookup field** at the top of the panel to search by a different email or phone number. * Edit the field and confirm to run a new search. * Reset it to go back to the ticket contact's original details. ## The order list Each order shows a summary card with: * **Order number** (e.g. `#1024`) and the date it was placed * **Total price** * **Status badge** for fulfillment (unfulfilled, partially fulfilled, fulfilled) The panel heading shows how many orders the customer has, e.g. `Shopify Orders (12)`. When Shopify can't give an exact number, you'll see an estimate instead, like `Shopify Orders (12+)`. ### Load more Only the most recent orders load at first. Click **Load more** at the bottom of the list to fetch the next batch. This continues from where the list left off, so you won't see duplicates. ## Order details Click any order card to open its full details. From here you can see everything needed to help with the order: * **Line items** — each product with its image, quantity, and price * **Pricing breakdown** — subtotal, shipping, tax, discounts, and the final total * **Shipping address** — name, full address, and phone * **Status badges** for fulfillment and payment (paid, pending, refunded, and so on) * **Fulfillments & tracking** — fulfillment status plus tracking number, carrier, and a link to track the shipment * **Quick links** — open the order in **Shopify admin**, or view the customer-facing **order status page** Use **Back** to return to the order list. ## Related <Card icon="bag-shopping" href="/docs/user-guides/integrations/shopify" title="Shopify Integration"> Connect your Shopify store to Chatbase to enable the orders panel and Shopify actions. </Card> # Saved Views Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/saved-views Save reusable inbox configurations so each agent sees the tickets that matter to them. A **view** is a saved inbox configuration that controls which tickets show up and how the list looks. Each view bundles together: * A set of **conditions** built from the [available filters](/docs/user-guides/chatbot/help-desk/filters) (field + operator + value), combined with AND. Up to 20 per view. * A **sort order** that determines how matching tickets are ordered. * A list of visible **columns** and their order. * A **visibility** setting (Personal or Shared) that decides who can see the view. Five system views are built in for everyone. On top of those, each agent can save up to 10 personal views, and the workspace can hold up to 30 shared views. *** ## System views Five views are built in. They cannot be edited or deleted. | View | Shows | | -------------- | -------------------------------------------------------- | | **My inbox** | Tickets assigned to you that are not Closed or Cancelled | | **Mentions** | Tickets where you are mentioned | | **All** | All tickets that are not Closed or Cancelled | | **Unassigned** | Open tickets with no assignee | | **Solved** | Closed and Cancelled tickets | If you need a variant of a system view, build a new view with the same conditions and tweak from there. *** ## Create a view <Steps> <Step title="Open the New view dialog"> In the help desk sidebar, click **New view**. </Step> <Step title="Name the view"> Enter a short, descriptive name (up to 100 characters). Examples: *High priority*, *VIP customers*, *Email backlog*. </Step> <Step title="Choose visibility"> Pick **Personal** to keep the view to yourself, or **Shared** to make it available to every agent in the workspace. The visibility selector only appears if you have permission to create both kinds; otherwise the view defaults to whichever kind you can create. </Step> <Step title="Add filters"> On the **Filters** tab, click **Add filter** to add a rule. Each condition is a field, an operator, and a value (for example, *Channel is any of WhatsApp*). See [Filters](/docs/user-guides/chatbot/help-desk/filters) for the full list of fields, operators, and values. You can stack up to 20 conditions per view; tickets must match every condition to appear. </Step> <Step title="Pick a sort order"> Use the **Sort by** dropdown to choose how matching tickets are ordered. Defaults to *Last activity (newest)*. </Step> <Step title="Choose columns"> Switch to the **Columns** tab. Toggle the checkbox next to a column to show or hide it, and drag the handle to reorder. At least one column must stay visible. </Step> <Step title="Save"> Click **Create view**. The view appears in the sidebar under **My views** (Personal) or **Shared views** (Shared). </Step> </Steps> *** ## Available columns A view can show any of these columns, in any order: * **Status** * **Ticket ID** * **Requester** * **Assignee** * **Team** * **Ticket details** * **Created at** * **Last updated** Hide columns you do not need to keep the inbox compact. Column visibility and order are saved with the view, so different agents can see the same inbox differently without affecting each other. *** ## Sort options The **Sort by** dropdown offers: * Last activity (newest) * Last activity (oldest) * Ticket # (high to low) * Ticket # (low to high) * Status (A to Z) * Status (Z to A) * Created (newest) * Created (oldest) *** ## Edit, favorite, or delete a view * **Edit**: hover the view in the sidebar and pick **Edit** from the menu. You can change the name, visibility, conditions, sort order, and columns at any time. * **Favorite**: click the bookmark icon next to a view to favorite it. Favorited views pin to the top of the sidebar. * **Delete**: open the same menu and pick **Delete**. Confirm in the dialog. <Note> You can edit or delete personal views you created yourself. Shared views can be edited or deleted by anyone with the *Manage shared views* permission. If you don't see the edit or delete options on a view, you don't have permission to change it. </Note> <Warning> Deleting a view is permanent. Shared views are removed for everyone, not just you. </Warning> ### Sidebar layout Each section (Shared views, My views) shows the first 5 views by default; click **Show more** to expand. Within each section, views are ordered by: 1. Favorited views first 2. Then most recently used 3. Then alphabetical Use the search box at the top of the sidebar to filter views by name when the list grows long. *** ## Personal vs Shared <Note> **Personal** views appear only in your sidebar under **My views**. **Shared** views appear in every agent's sidebar under **Shared views**. Switch a view's visibility at any time by editing it. </Note> Use Personal views for your own triage workflow. Use Shared views to standardize how the team works through the queue (for example, a shared *Unanswered for 24h* view that everyone reviews each morning). *** ## Tips <CardGroup> <Card title="Build narrow views for triage" icon="filter"> Stack conditions to surface the exact slice of work you care about. *Example:* `Channel is WhatsApp` + `Assignee is Unassigned` + `Created in the last 1 day`. </Card> <Card title="Pair conditions with a sort" icon="arrow-down-wide-short"> Sort matching tickets so the most urgent ones come first. *Example:* `Status is any of New, On You` sorted by `Created (oldest)` puts the oldest open tickets at the top. </Card> <Card title="Keep shared views generic" icon="users"> Shared views are seen by every agent. Use them for workflows that apply to the whole team. </Card> <Card title="Use personal views for yourself" icon="user"> Personal views are perfect for your own triage workflow or experiments that don't belong in everyone's sidebar. </Card> </CardGroup> # Scheduling Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/scheduling Define shifts and time off so agent availability and ticket auto-assignment run on their own. The Scheduling feature lets you define recurring **Shifts**, assign agents to them, and add **Time off** entries. When an agent is on a shift, their availability is computed automatically from the shift's working hours and any time off, and that availability decides who is eligible for ticket auto-assignment. You manage scheduling from the agent’s **Settings → Helpdesk → Scheduling** page. It has three cards: **Shifts**, **Agent schedules**, and **Time off**. *** ## How availability is determined Each agent is in one of two modes: * **Scheduled**: the agent has a shift assigned. Their status (`On shift` / `Off shift`) is computed in real time from the shift's working hours plus any time off. They cannot change it manually. * **Manual**: the agent has no shift. Their status (`Available`, `Away`, `Busy`, `Paused`) is set by an admin, or by the agent themselves if you allow it on the **Members** page (**Settings → Helpdesk → Members**). Only agents who are currently `Available` (manual) or `On shift` (scheduled, with no active time off) are eligible for new ticket assignment. *** ## Create a shift A shift is a named, recurring weekly schedule with a timezone. <Steps> <Step title="Open the Shifts card"> Go to **Settings → Helpdesk → Scheduling** and click **Add shift** in the **Shifts** card. </Step> <Step title="Name the shift"> Enter a name like *Weekday Standard* or *EU Mornings*. Names help you tell shifts apart when you assign them. </Step> <Step title="Choose a timezone"> Pick the timezone the working hours should be evaluated in. The selector defaults to your browser's timezone. </Step> <Step title="Set working days and hours"> Toggle each day you want the shift to be active. For each enabled day, pick a **Start time** and **End time**. Times are in 15-minute increments and default to **09:00 to 17:00**. Use the **12h / 24h** toggle in the Shifts card header to switch the time format. If the End time is the same as or earlier than the Start time, the shift is treated as overnight and continues into the next day. The dialog shows a **(next day)** label so you can confirm. </Step> <Step title="Save"> Click **Save** to create the shift. It now appears in the Shifts card and becomes available in the Agent schedules dropdown. </Step> </Steps> You can edit or delete shifts at any time. Deleting a shift moves every agent assigned to it back to manual mode. *** ## Assign agents to shifts The **Agent schedules** card lists every help desk agent with a per-agent shift dropdown. * Pick a shift name from the dropdown to put the agent on that schedule. * Pick **No shift (manual)** to remove the schedule and manage their status manually. The badge at the top of the card shows how many of your agents currently have a shift, in the form **2/5 scheduled**. <Warning> Removing a shift from an agent who has scheduled time off will make those time off entries inert, since time off only applies to scheduled agents. The dashboard will warn you before this happens. </Warning> *** ## Add time off Use **Time off** to block dates for scheduled agents (vacation, holidays, sick leave, or anything else that should make them unavailable during their normal shift hours). <Steps> <Step title="Open the Time off card"> In **Scheduling**, click **Add time off** in the **Time off** card. </Step> <Step title="Pick agents"> Select one or more agents from the **Agents** field. Only agents who currently have a shift assigned can be picked, since time off has no effect on manual agents. </Step> <Step title="Pick a date range"> Choose a start and end date in the **Dates** picker. You cannot pick dates in the past. </Step> <Step title="Add a reason (optional)"> Optionally enter a short reason like *Annual leave* or *Public holiday*. </Step> <Step title="Save"> Click **Save**. During the selected dates, every chosen agent is treated as `Off shift` and is not eligible for new ticket assignment, even if their shift covers those days. </Step> </Steps> Past time off entries are hidden once their end date passes. *** ## Status indicators | Indicator | Meaning | | --------------------- | ------------------------------------------------------------------------ | | **On shift** (green) | Scheduled agent, currently inside their shift hours and not on time off. | | **Off shift** (amber) | Scheduled agent, outside shift hours, or on time off. | | **Available** (green) | Manual agent, set as available and eligible for assignment. | | **Away** (amber) | Manual agent, not eligible for assignment. | | **Busy** (red) | Manual agent, not eligible for assignment. | | **Paused** (grey) | Manual agent, not eligible for assignment. | On the **Members** page, scheduled agents show a tooltip *"Status is managed by the schedule"* followed by the shift name. Their status is read-only because the schedule is in charge. *** ## How scheduling affects auto-assignment Scheduling acts as the eligibility gate for ticket auto-assignment: * **Manual agents** are eligible when their stored status is `Available`. * **Scheduled agents** are eligible when the current time is inside their shift (in the shift's timezone) and they have no active time off. The assignment algorithm (Balanced or Round robin) then picks one agent from that pool. See [Ticket Assignment](/docs/user-guides/chatbot/help-desk/assignment-algorithm) for how each algorithm chooses. If nobody is eligible, the ticket stays unassigned until an agent is back on shift or set to `Available`. You can change this by enabling **Assign to next available shift**, which routes tickets to the agent whose shift starts soonest. See [Assign to next available shift](/docs/user-guides/chatbot/help-desk/assignment-algorithm#assign-to-next-available-shift) for details. *** ## Tips and edge cases * **Overnight shifts** wrap past midnight automatically. Pick an end time that is the same as or earlier than the start time, and the shift continues into the following day. * **Deleting a shift** moves every assigned agent back to manual mode. It does not reset their status. Picking **No shift (manual)** in the per-agent dropdown is what sets an agent to `Away`. * **New agents** start as `Away` until you assign them a shift or change their status manually. * **Time off only applies to scheduled agents.** If you want a manual agent to be unavailable, change their status directly. # Takeover Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/takeover Take over AI conversations and escalate them to help desk tickets for human support. ## Introduction Takeover lets a support associate step into an ongoing AI conversation and convert it into a help desk ticket. Once taken over, the AI stops responding and the support associate handles the rest of the conversation directly. This is useful when a customer's issue is too complex for the AI, requires a personal touch, or needs escalation. Takeover is available on the Chat bubble, Email, WhatsApp, Messenger, and Instagram channels. ## How It Works When a support associate takes over a conversation, the system: 1. Stops the AI from responding to the customer 2. Generates an AI-powered summary of the conversation 3. Creates a help desk ticket linked to the conversation 4. Assigns the ticket to the support associate who initiated the takeover ## Taking Over a Conversation <Steps> <Step title="Open the conversation"> Open the **Conversations** tab in the help desk sidebar and select an ongoing conversation. </Step> <Step title="Click Takeover"> Click the **Takeover** button in the conversation header. The button is only available for conversations that are currently ongoing. <Frame> <img alt="Takeover button in the conversation header" /> </Frame> </Step> <Step title="View the ticket"> After takeover, the newly created help desk ticket opens in a new browser tab. The ticket includes: * An AI-generated subject line and summary based on the conversation * Customer details (name, email, or other identifiers) <Frame> <img alt="Helpdesk ticket created from a taken-over conversation" /> </Frame> </Step> </Steps> ## Conversation States Every conversation has an activity state that determines whether takeover is available: <AccordionGroup> <Accordion title="Ongoing"> The conversation is active and the AI is responding. Takeover **is available**. </Accordion> <Accordion title="Taken Over"> A support associate has already taken over the conversation. The **Takeover** button is replaced with a **View Ticket** button that links to the associated help desk ticket. </Accordion> <Accordion title="Ended"> The conversation has ended. Takeover **is not available**. </Accordion> </AccordionGroup> ## AI-Generated Summary When a conversation is taken over, the system uses AI to generate a summary so the support associate can quickly understand the context without reading the entire conversation. The summary includes: * A **subject line** for the ticket * A **brief summary** of the customer's issue The summary is generated in the same language the customer used in the conversation. ## What the Customer Sees On chat channels (such as the widget), the customer receives real-time feedback when a takeover happens: 1. The AI stops responding immediately 2. A loading spinner appears with the message **"Waiting for support agent to join"** 3. Once the support associate sends their first message, the spinner disappears and the conversation continues as a live chat <Frame> <img alt="Waiting for support agent to join spinner shown to the customer" /> </Frame> <Info> The waiting message is automatically displayed in the customer's language. See [Localization](/docs/user-guides/chatbot/channels#localization) for more details. </Info> ## Allow AI Replies After taking over a conversation, you can re-enable the AI at any time by clicking **Allow AI replies**. This hands the conversation back to the AI so it can continue responding to the customer. <Steps> <Step title="Open the ticket"> Open the taken-over ticket from the help desk. </Step> <Step title="Click the menu"> Click the **three-dot menu** (⋯) in the ticket header. </Step> <Step title="Select Allow AI replies"> Click **Allow AI replies**. The AI resumes responding to the customer and the ticket is automatically closed. </Step> </Steps> ## Multiple Takeovers A single conversation can go through multiple takeover and AI resume cycles. Each time, the conversation is clearly divided into sections so both the support associate and the customer can follow the flow: * A **"Live chat"** separator marks where a support associate took over * An **"AI Resumed"** separator marks where the AI was re-enabled For example, a conversation might flow like this: 1. Customer chats with the AI 2. Support associate takes over → **Live chat** separator appears 3. Support associate resolves part of the issue and clicks **Allow AI replies** → **AI Resumed** separator appears 4. Customer continues chatting with the AI 5. A new issue arises and another support associate takes over → another **Live chat** separator appears Each cycle creates a new ticket, and the conversation timeline preserves the full history across all transitions. <Frame> <img alt="Conversation timeline showing Live chat and AI Resumed separators across multiple takeover cycles" /> </Frame> ## Concurrency Only one support associate can take over a conversation. If two support associates click **Takeover** at the same time, the first one to complete the action wins and gets the ticket. The second support associate sees a generic error message. They can refresh the conversation to see that it has already been taken over and use the **View Ticket** button to open it. <Tip> **Best practices:** * Review the conversation history before taking over so you have full context. * After taking over, set the ticket status to **On You** and begin responding to the customer promptly. * Use internal **Notes** to document any steps you've taken so other support associates can pick up if needed. </Tip> # Team Routing Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/team-routing Automatically send incoming tickets to the right team using ordered, first-match rules. <Warning> **Team Routing has been replaced by [Triggers](/docs/user-guides/chatbot/help-desk/triggers)**, which do everything routing did and much more. The rest of this page is kept for reference only. </Warning> Team Routing is an ordered list of rules that decide which [team](/docs/user-guides/chatbot/help-desk/teams) a new ticket is assigned to. When a ticket is created, the rules are checked from top to bottom and the ticket is routed to the team of the **first rule that matches**. If no rule matches, the ticket goes to your **default team**. Once a ticket reaches a team, that team's [assignment strategy](/docs/user-guides/chatbot/help-desk/assignment-algorithm) decides which agent picks it up. ## How routing works 1. A new ticket is created from any channel. 2. The system evaluates your rules in order, from top to bottom. 3. The ticket is routed to the team of the **first** rule whose conditions all pass. 4. If no rule matches, the ticket falls through to the **default team**. When you have no rules yet, every ticket goes straight to the default team. <Info>If a rule points to a team that has since been deleted, that rule is skipped and the ticket falls through to the next matching rule or the default team.</Info> *** ## Rule structure Each rule combines a set of conditions with a target team. A condition is made of a **field**, an **operator**, and one or more **values**. Conditions are organized into two groups: * **Match all of these** - every condition in this group must be true (AND logic). * **Match at least one of these** - at least one condition in this group must be true (OR logic). This group is optional. When both groups are used, a ticket matches only if it satisfies **all** conditions in the first group **and at least one** condition in the second. The rule editor shows a live plain-English summary as you build the rule, for example: "Route to Billing Support when a ticket matches **all** of the first group **and at least one** of the second." *** ## Fields and operators | Field | Operator | Value format | | :------------------ | :--------------- | :------------------------------------------------------------------------------------- | | **Subject** | contains any of | Free-text keywords. Matches if any keyword appears anywhere in the subject. | | **Body** | contains any of | Free-text keywords. Matches if any keyword appears anywhere in the message body. | | **Sender email** | is any of | Full email addresses, for example `name@company.com`. | | **Sender email** | domain is any of | Bare domains, for example `company.com` (no `@`). | | **Inbox email** | is any of | One of your verified inbound email addresses. | | **Inbox email** | domain is any of | A domain from your verified inbound addresses. | | **Inbox email** | contains any of | Free-text substring matched against the recipient address. | | **WhatsApp number** | is any of | The number the message was sent to, matched after phone-number normalization. | | **Channel** | is any of | One or more of: Email, WhatsApp, Instagram, Messenger, Chat bubble, Center stage, API. | <Note>All text matching (Subject, Body, Sender email, Inbox email) is **case-insensitive**.</Note> *** ## Managing rules <Steps> <Step title="Open the Team Routing page"> Navigate to your AI agent's **Settings → Helpdesk → Team routing**. </Step> <Step title="Add a rule"> Click **Add rule** to open the rule editor. Build your conditions in the two groups, then choose a target team from the **Route to team** dropdown (the default team is marked). </Step> <Step title="Save the rule"> Click **Add rule** in the editor. The rule appears in the list. </Step> </Steps> **Edit a rule** with the edit action on its row. The editor opens pre-filled with the rule's conditions and team. Click **Save rule** to apply your changes. **Delete a rule** with the delete action on its row, then confirm. Tickets that the rule used to match will fall through to the next matching rule or the default team. **Reorder rules** by dragging them up or down. Order is saved immediately and determines priority: because the first match wins, place more specific rules above broader ones. ### The Else row Below all of your rules, a fixed **Else** row shows the default team. This row always receives tickets that none of your rules matched. It cannot be removed, which guarantees that every ticket is routed somewhere. *** ## Limits | Limit | Value | | :------------------- | :------- | | Rules per AI agent | 50 | | Conditions per group | 10 | | Values per condition | 10 | | Characters per value | 1 to 500 | When you reach the rule limit, the **Add rule** button is disabled until you delete a rule. <Note>Routing rules use version tracking to protect against conflicting edits. If you and a teammate edit the rules at the same time, the second save is rejected with a version conflict so no changes are silently overwritten. Refresh the page to load the latest rules, then reapply your change.</Note> # Teams Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/teams Group your agents into teams so tickets can be routed and assigned to the right people. A team is a named group of support agents within an AI agent. Tickets are first routed to a team and then assigned to an individual agent inside that team. Teams let you split your support organization by function, product, or language, so the right group always handles the right tickets. Every AI agent has exactly one **default team**. When you first enable the Helpdesk, a team called **General** is created as the default and every account member is added to it. The default team catches all tickets that no [routing rule](/docs/user-guides/chatbot/help-desk/team-routing) matches. Teams and their assignment settings live on a single page: **Settings → Helpdesk → Teams & assignment**. ## Team properties | Property | Description | | :--------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Name** | A display name for the team, 1 to 100 characters (for example, "Billing Support"). | | **Assignment strategy** | How tickets are distributed to agents within the team: **Manual**, **Balanced**, or **Round Robin**. See [Ticket Assignment](/docs/user-guides/chatbot/help-desk/assignment-algorithm) for how each method works. | | **Max tickets per agent** | An optional cap on open tickets per agent. Only applies when the strategy is **Balanced** or **Round Robin**. Leave empty for no limit. | | **Assign to next available shift** | A toggle that routes tickets to the next agent coming on shift when no one is currently available. Only shown for **Balanced** and **Round Robin**. | | **Unassign on reply** | When a customer replies to a ticket whose assigned agent is currently unavailable, that agent is unassigned and the team's auto-assignment runs again. Off by default. | | **Default team** | Exactly one team per AI agent is the default. It receives every ticket that no routing rule matched. | <Note>The assignment strategy controls how tickets are shared **between agents inside a team**. Routing decides **which team** a ticket goes to. The two settings work together: routing picks the team, then the team's strategy picks the agent.</Note> *** ## The Teams & assignment page **Settings → Helpdesk → Teams & assignment** shows every team and the selected team's configuration on one screen. * **Team chips.** Each team appears as a chip at the top of the page with its **member count**, its number of **open tickets**, and a **Default** badge on the default team. * **Search.** Filter the chips by team name with the search box. * **Create team.** The **Create team** button sits next to the search box. A newly created team is selected automatically. * **Selected team.** Clicking a chip loads that team's **Team settings** and **Members** cards below the chips, with no page change. The default team is selected when you open the page, so auto-assignment settings are visible right away. * **Deep links.** The selected team is reflected in the URL as `?team=<team-id>`, so you can bookmark or share a specific team. *** ## Creating a team <Steps> <Step title="Open the Teams & assignment page"> Navigate to your AI agent's **Settings → Helpdesk → Teams & assignment**. </Step> <Step title="Start a new team"> Click **Create team**. A slide-over panel opens. </Step> <Step title="Name the team"> Enter a name, such as "Billing Support" or "Tier 2". </Step> <Step title="Add members (optional)"> Select agents from the member picker. You can search by name or email and use **Select all**. Members can also be added later. </Step> <Step title="Choose an assignment strategy"> Pick **Manual**, **Balanced**, or **Round Robin**. If you choose Balanced or Round Robin, you can optionally set **Max tickets per agent** and enable **Assign to next available shift**. </Step> <Step title="Save"> Click **Create team**. The team appears as a new chip and is selected immediately so you can keep configuring it. </Step> </Steps> *** ## Editing a team Select a team's chip to load its configuration below the chips. It has two main cards. ### Team settings Edit **the team’s name**, **assignment strategy**, **max tickets per agent**, **Assign to next available shift**, and **Unassign on reply** settings. A Save button appears once you make a change. This card also shows the team's default status: * If the team **is** the default, an info box explains that it receives all unmatched tickets. * If the team **is not** the default, a **Make default** button lets you promote it. ### Members The Members card lists the team's current agents in a searchable table showing each agent's availability status, current shift, and number of open tickets. * **Add a member** with the **Add member** control, which lists any account agent not already on the team. * **Remove a member** with the per-row **Remove** action. A confirmation dialog appears before the member is removed. *** ## The default team There is always exactly one default team per AI agent. * It is created automatically (named **General**) when the Helpdesk is first enabled, with all account members added. * Any team can become the default using **Make default** in its **Team settings** card. * The default team **cannot be deleted**. <Tip>Keep your default team staffed with agents who can handle general or uncategorized tickets, since it is the fallback for anything your routing rules do not match.</Tip> *** ## Deleting a team Only non-default teams can be deleted. Select the team, click **Delete team** at the bottom of its **Team settings** card, then confirm in the dialog. <Warning>If the team has open tickets, those tickets are **detached from the team** (they keep their assigned agent, if any, but are no longer tied to a team). The default team can never be deleted, so reassign the default first if you need to remove that team.</Warning> # Translation Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/translation Automatically detect and translate customer messages so your team can support anyone, in any language. ## Introduction Translation lets your support team communicate with customers regardless of the language they write in. When enabled, the helpdesk automatically detects the language of incoming customer messages and offers one-click translation into your team's preferred language. Only **customer messages** are translated. Agent replies remain in the language the agent writes them in. ## Enable Translation <Steps> <Step title="Open translation settings"> Navigate to **Settings** > **Helpdesk** > **Translation**. </Step> <Step title="Enable AI translation"> <Frame> <img alt="Translation settings page showing the Enable button and how-it-works overview" /> </Frame> </Step> <Step title="Choose your preferred language"> Select your team's **Preferred language** from the dropdown - this is the language that customer messages will be translated into. <Frame> <img alt="Translation settings with AI translation toggle enabled and preferred language set to English" /> </Frame> </Step> <Step title="Save"> Click **Save** to apply your settings. Translation is now active for all tickets. </Step> </Steps> To disable translation at any time, toggle **AI translation** off and click **Save**. ## How Translation Works in Tickets When you open a ticket from a customer who wrote in a different language, the helpdesk automatically detects the language and shows a **translation detection banner** at the top of the ticket. ### Before Translation The banner displays the detected language (e.g., "German detected") along with a **Translate** button. Customer messages appear in their original language. <Frame> <img alt="Ticket view showing a detected language banner with Arabic messages and a Translate button" /> </Frame> ### After Translation Click **Translate** to translate all customer messages into your preferred language. The banner updates to show the translation direction (e.g., "Translating German → English") and a **Show original** button appears so you can switch back at any time. <Frame> <img alt="Ticket view showing translated messages in English with the Show original button" /> </Frame> <Info> If you are viewing a ticket with an active live chat, new incoming messages from the customer will be **translated automatically** as they arrive - no need to click Translate again. </Info> ### Toggle Between Original and Translated You can switch between the original and translated versions at any time using the buttons in the translation banner: * **Show original** - displays the customer's messages in their original language * **Translate** - switches back to the translated view ## What Gets Translated | Content | Translated? | | ------------------------------------------------ | ----------- | | Customer messages (email, widget, WhatsApp, API) | Yes | | Agent replies | No | | Internal notes | No | | System events (status changes, assignments) | No | <Warning> Only customer messages are translated. Your replies are sent to the customer exactly as you write them. If you need to reply in the customer's language, use the **AI Compose > Translate** option in the message composer. <Frame> <img alt="Ticket view showing translated messages in English with the Show original button" /> </Frame> <Frame> <img alt="Ticket view showing translated messages in English with the Show original button" /> </Frame> </Warning> ## Supported Languages Translation supports **44 languages**, including: <Columns> <div> * Arabic * Bengali * Bulgarian * Bosnian * Catalan * Chinese (Simplified) * Chinese (Traditional) * Croatian * Czech * Danish * Dutch * English * Estonian </div> <div> * Finnish * French * German * Greek * Hebrew * Hindi * Hungarian * Indonesian * Italian * Japanese * Korean * Latvian * Lithuanian </div> <div> * Malay * Mongolian * Norwegian * Persian * Polish * Portuguese * Portuguese (Brazil) * Romanian * Russian * Serbian * Slovenian * Spanish * Swahili </div> <div> * Swedish * Thai * Turkish * Ukrainian * Vietnamese </div> </Columns> Right-to-left (RTL) languages such as Arabic, Hebrew, and Persian are fully supported. # Triggers Source: https://chatbase.co/docs/user-guides/chatbot/help-desk/triggers Automate your help desk with ordered rules that run when tickets are created or updated, setting statuses, routing work, and adding notes for you. ## Introduction Triggers are automation rules for your help desk. Each trigger watches for tickets that are **created** or **updated**, checks them against the conditions you define, and runs the actions you choose - like setting a status, assigning a team or agent, or adding an internal note - without anyone lifting a finger. The mental model is simple: **WHEN** a ticket matches your conditions, **THEN** run these actions. Triggers run **in order, top to bottom**, and **every matching trigger fires**. This lets you stack rules - one to route billing questions, another to prioritize angry customers - and they all apply to the same ticket in the order you set. You configure triggers from **Help desk settings → Triggers**. <Frame> <img alt="Triggers settings page listing existing triggers" /> </Frame> <Info> Triggers require the Help Desk to be enabled for your agent. If you haven't set it up yet, see the [Help Desk overview](/docs/user-guides/chatbot/help-desk/help-desk-overview). </Info> ## How a Trigger Works Every trigger is made of four parts: <Columns> <Card title="Details" icon="pen"> A **name** and optional **description** so your team knows what the rule does and why. </Card> <Card title="Conditions (WHEN)" icon="filter"> The rules that decide whether a ticket matches - based on its status, channel, assignee, team, subject, and more. </Card> <Card title="Actions (THEN)" icon="bolt"> What happens when a ticket matches - set a status, assign work, or add a note. Actions run in order. </Card> <Card title="Status" icon="toggle-on"> Whether the trigger is **Active** or **Paused**. Only active triggers run. </Card> </Columns> ## How Triggers Run (Cycles) Triggers don't just run once from top to bottom - they run in **cycles**. This lets one trigger's action feed into another trigger's conditions, so your rules can build on each other. Here's what happens each time a ticket is created or updated: <Steps> <Step title="Scan from the top"> Chatbase checks every active trigger in order, top to bottom, against the ticket. </Step> <Step title="Matching triggers fire"> Each trigger whose conditions match runs its actions. </Step> <Step title="A change restarts the scan"> If any trigger changes the ticket (for example, it sets a new status or assigns a team), the scan **starts over from the top**. Triggers that hadn't matched before now get another chance, because they're re-checked against the ticket's updated state. </Step> <Step title="Repeat until nothing changes"> The cycle keeps restarting until a full pass makes no further change. At that point the ticket is done and the final result is saved. </Step> </Steps> <Tip> Ordering still matters. Put the trigger that sets the foundational value (like status or team) **above** the triggers that react to it, so the reaction gets picked up when the scan restarts. </Tip> ## Creating a Trigger <Steps> <Step title="Open Triggers"> Go to **Help desk settings → Triggers** and click **New trigger**. A panel opens from the right. </Step> <Step title="Name your trigger"> Give it a clear **Name** (for example, "Route billing tickets") and an optional **Description** explaining what it does. <Frame> <img alt="New trigger panel with name, conditions, and actions" /> </Frame> </Step> <Step title="Set the conditions (WHEN)"> Add the conditions that decide when the trigger should run. See [Conditions](#conditions) below for every available field and operator. </Step> <Step title="Add the actions (THEN)"> Add at least one action to perform when a ticket matches. See [Actions](#actions) below for the full list. </Step> <Step title="Activate and save"> Use the **Active / Paused** toggle to decide whether the trigger runs, then click **Create trigger**. New triggers are active by default. </Step> </Steps> ## Conditions Conditions decide which tickets a trigger applies to. They're organized into two groups: * **Match ALL of** - every condition in this group must match. * **Match ANY of** - at least one condition in this group must match. This group is optional and is combined with the ALL group using **AND**. <Tip> Use **Match ALL of** for the rules that must always be true (for example, "Status category is New") and **Match ANY of** for a set of alternatives (for example, subject contains "refund" **or** "chargeback"). </Tip> ### When does a trigger run? Add a **Ticket is Created** or **Ticket is Updated** condition to control when a trigger fires. If you don't add one, the trigger runs on **both** create and update. ### Ticket condition fields | Field | What it matches | Operators | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | **Ticket** | Whether the ticket was just **Created** or **Updated**. Use this to scope when the trigger runs. | `is` | | **Status category** | The ticket's category: **New**, **On you**, **On customer**, **On hold**, **Closed**, or **Cancelled**. | `is`, `is not`, `is any of`, `is none of`, `changed`, `not changed`, `changed to`, `not changed to`, `changed from`, `not changed from` | | **Status** | A specific ticket status you've configured (see [Ticket statuses](/docs/user-guides/chatbot/help-desk/ticket-statuses)). | `is`, `is not`, `is any of`, `is none of`, `changed`, `not changed`, `changed to`, `not changed to`, `changed from`, `not changed from` | | **Channel** | The channel the ticket came in on - **Help desk**, **Chat bubble**, **Email**, **WhatsApp**, **API**, **Messenger**, **Instagram**, **Center stage**, or **Phone**. Select several at once. | `is any of`, `is none of` | | **Assignee** | Who the ticket is assigned to, including **Unassigned**. | `is`, `is not`, `is any of`, `is none of`, `changed`, `not changed`, `changed to`, `not changed to`, `changed from`, `not changed from` | | **Team** | Which team the ticket belongs to, including **No team**. | `is`, `is not`, `is any of`, `is none of`, `changed`, `not changed`, `changed to`, `not changed to`, `changed from`, `not changed from` | | **Subject** | Keywords in the ticket subject. Add one or more keywords; matching is case-insensitive. | `contains any of` | | **Description** | Keywords in the ticket description. Add one or more keywords; matching is case-insensitive. | `contains any of` | ### Contact condition fields Match on the ticket **requester's** contact record. These look up the person who opened the ticket, so a ticket from an unidentified visitor (no contact record) matches nothing. Contact fields appear under the **Contact** group in the field picker. | Field | What it matches | Operators | | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | **Name / Email / Phone number / External ID** | A built-in field on the requester's contact. | `is`, `is not`, `is any of`, `is none of`, `contains any of`, `is set`, `is not set` (Email adds `domain is any of`) | | **Custom attributes** | Any [custom contact attribute](/docs/user-guides/chatbot/help-desk/teams) you've defined, matched against the requester's value. | `is`, `is not`, `is any of`, `is none of`, `contains any of`, `is set`, `is not set` | ### Routing condition fields These describe **how the ticket arrived** (its delivery "envelope") and are only meaningful **on ticket creation** - they're how you replace [Team Routing](/docs/user-guides/chatbot/help-desk/team-routing) with triggers. Pair them with a `Ticket is Created` condition and an **Assign team** action. | Field | What it matches | Operators | | --------------------- | -------------------------------------------------------------- | -------------------------------------------------- | | **Recipient address** | The support email address that received the ticket. | `is any of`, `domain is any of`, `contains any of` | | **Recipient phone** | The business phone / WhatsApp number that received the ticket. | `is any of` | ### About operators | Operator | What it does | | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `is` / `is not` | Compares the ticket's **current** value. For example, "Status category **is** New." | | `is any of` / `is none of` | Matches when the field is (or is not) one of several selected values. | | `contains any of` | Matches when the text contains any of the keywords you list (used for **Subject**, **Description**, and text contact fields). | | `domain is any of` | Matches the part **after the `@`** of an address - used for the contact **Email** field and the **Recipient address** field (for example, route everything from `acme.com`). | | `changed` / `not changed` | Matches when the field did (or did not) change at all during this update, regardless of the new value. Takes no value. | | `changed to` / `not changed to` | Matches (or excludes) a specific transition target - for example, "Assignee **changed to** Unassigned." | | `changed from` / `not changed from` | Matches (or excludes) a specific transition source - for example, "Status **changed from** Open." | | `is set` / `is not set` | Matches when a contact field has (or doesn't have) any value. Takes no value. | <Note> The `changed*` operators only make sense on **updates** - they compare the value before and after the change. On ticket **creation** there's no previous value, so a `changed` condition won't match. </Note> ## Actions Actions are what the trigger does when a ticket matches. Add at least one; they run **in order**, top to bottom. | Action | What it does | | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Set status** | Move the ticket to a specific ticket status you've configured. | | **Set status category** | Move the ticket to a category. This applies the category's **default status**. Tickets already in that category are left unchanged. | | **Assign team** | Assign the ticket to a team, or to **Default team** (which always follows your current default team, even if you change it later). Optionally check **Auto-assign an agent using the team's strategy** to also route it to an agent based on that team's [assignment method](/docs/user-guides/chatbot/help-desk/assignment-algorithm). | | **Assign agent** | Assign the ticket to a specific agent, or choose **Unassign** to clear the assignee. | | **Add internal note** | Add an internal note to the ticket. Notes are visible to your team only, never to the customer. | | **Send webhook** | Send an HTTP request to an external system. See [Send webhook](#send-webhook). | ### Send webhook The **Send webhook** action posts an HTTP request to an external endpoint - to notify another system, kick off an automation, or sync ticket data. The action itself is just a **selector**: you pick one of the webhooks you've configured under [**Settings → Webhooks**](/docs/user-guides/chatbot/settings#webhooks). The endpoint URL, headers, request body, and signing secret all live on the webhook connection, so several triggers can reuse the same one. <Frame> <img alt="Send webhook action selecting a saved webhook connection" /> </Frame> * Configure the endpoint, custom headers, and a request body template (with `{{ticket.*}}` placeholders) once under [**Settings → Webhooks**](/docs/user-guides/chatbot/settings#webhooks), then reference it from as many triggers as you like. * Each delivery is signed with the connection's secret via an `X-Chatbase-Signature` header so your endpoint can verify it came from Chatbase. * Webhooks are delivered **after** the ticket change is saved and are retried on transient failures, so your endpoint may receive the same event more than once - dedupe on the delivery id. Set up a connection on the [**Settings → Webhooks**](/docs/user-guides/chatbot/settings#webhooks) page: <Frame> <img alt="Webhooks configuration page with endpoint, headers, and request body" /> </Frame> ## Managing Triggers ### Ordering Triggers run in the order they appear in the list. Drag the handle on the left of any trigger to reorder it. Because **every matching trigger fires**, the order matters when two triggers touch the same field - the later one wins. <Frame> <img alt="Dragging to reorder triggers in the list" /> </Frame> ### Activate or pause Use the switch on each trigger row to turn it **Active** or **Paused**. Paused triggers stay in your list but don't run, so you can temporarily disable a rule without deleting it. ### Edit or delete Open a trigger to edit its name, conditions, or actions at any time. To remove a trigger, use the delete control and confirm - deleted triggers stop running on new and updated tickets, and this can't be undone. ### Needs attention If a trigger references something that no longer exists - a deleted team, an archived status, or a removed agent - it's flagged with a **Needs attention** badge. Open the trigger and update the affected condition or action to fix it. ## Good to Know * **Every matching trigger fires.** Triggers aren't exclusive - all rules whose conditions match will run, in order. Use ordering to control which action takes precedence. * **Triggers run after the ticket is saved.** They apply once a create or update is committed, so they never block or fail the underlying ticket change. Webhook actions are sent after the save, too. * **Only active triggers run.** Pause a trigger to disable it without losing its configuration. * **Triggers replace Team Routing.** Route tickets to teams with a `Ticket is Created` condition, a **Recipient address** / **Channel** condition, and an **Assign team** action. See the [Team Routing](/docs/user-guides/chatbot/help-desk/team-routing) page for the field-by-field mapping. ### Limits | Limit | Value | | -------------------- | ----- | | Triggers per agent | 1000 | | Conditions per group | 50 | | Actions per trigger | 50 | | Values per condition | 50 | | Characters per value | 1000 | # Models Comparison Source: https://chatbase.co/docs/user-guides/chatbot/models-comparison # AI Model Comparison Guide This guide compares the AI models available for your AI agent by message credit cost, helping you balance capability against price. Each model is assessed across the dimensions that matter most: technical capability, empathy and communication, speed, the ability to take actions (such as escalating to a human, booking meetings, or changing subscriptions), and handling multi-step or complex tasks. ## Recommended Models by Credit Cost Models are grouped below by how many message credits each consumes per message, listed from lowest to highest cost. ### Recommended 1 Credits / Message Models: GPT-5.6 Luna<br />GPT-5.6 Luna is the fastest and most cost-efficient tier of OpenAI's GPT-5.6 family—optimized for high-volume, low-latency tasks while retaining the core capabilities of the 5.6 series.<br /><br />Auto<br />Auto is engineered by Chatbase for peak performance, speed, and efficiency. It adapts to every conversation, giving instant answers for everyday questions and frontier grade intelligence for demanding ones, with multilingual and image understanding built in. One choice that handles every turn end to end, tools included.<br /><br />Gemini 3 Flash<br />Gemini 3 Flash is a fast and efficient model with advanced reasoning capabilities. It balances quality, latency, and cost. Ideal for demanding tasks requiring quick responses with sophisticated reasoning, coding, multi-step function execution, and complex instruction following. ### Recommended 2 Credits / Message Models: GPT-5.6 Terra<br />GPT-5.6 Terra is the balanced tier of OpenAI's GPT-5.6 family, pairing strong reasoning and context retention with everyday speed and cost efficiency—ideal for the majority of production AI workflows. Gemini 3.5 Flash<br />Gemini 3.5 Flash is a Google reasoning model that delivers fast, high-quality responses. It handles complex questions, multi-step instructions, and image understanding with ease, making it a strong fit for agents that need solid reasoning at low latency. ### Recommended 3 Credits / Message Models: Claude Sonnet 4.6<br />Claude Sonnet 4.6 is an Anthropic model in the Sonnet series that builds on 4.5 with stronger reasoning, improved instruction following, and better performance on complex multi-step tasks. It offers an excellent balance of intelligence and speed for everyday workflows. ### Recommended 4 Credits / Message Models: GPT-5.5<br />GPT-5.5 is one of OpenAI's most capable models, delivering notably stronger reasoning, improved context retention, and better performance across highly demanding tasks. It delivers high accuracy and efficiency for enterprise workflows. ### Recommended 5 Credits / Message Models: Claude Opus 4.6<br />Claude Opus 4.6 is a powerful model in the Opus series that builds on 4.5 with stronger reasoning, improved instruction following, and better performance on complex multi-step tasks. It excels at demanding coding challenges, agentic workflows, and sophisticated problem-solving while managing context efficiently. # Outbound Campaigns Source: https://chatbase.co/docs/user-guides/chatbot/outbound-campaigns Send targeted messages to your contacts at scale. Create campaigns, personalize content, and track delivery in real time. Outbound campaigns let you proactively reach out to your contacts at scale. Build targeted audiences, personalize message content using contact data, and track delivery in real time. To get started, open your agent and click **Outbound** in the sidebar. ## Supported Channels <CardGroup> <Card title="WhatsApp Campaigns" icon="whatsapp" href="/docs/user-guides/chatbot/outbound-whatsapp"> Send campaigns to your contacts using pre-approved WhatsApp message templates. Requires a connected WhatsApp integration and approved templates in Meta. </Card> </CardGroup> <Info> More channels are coming soon. WhatsApp is currently the only supported campaign channel. </Info> ## Key Features Every outbound campaign — regardless of channel — includes: * **Audience selection** — Choose recipients from your contact list. Search by name or phone number, and filter by custom attributes like subscription tier or region. * **Content personalization** — Use contact fields (name, email, custom attributes) to personalize each message per recipient, or set static values for fixed content. * **Reply behavior** — Choose how replies are handled: * **AI Replies** (default) — Your AI agent responds automatically. Best for support questions and automated follow-ups. * **Human Takeover** — Replies create helpdesk tickets tagged with the campaign name. Best for sales outreach and high-touch conversations. * **Delivery tracking** — Monitor campaign progress in real time with a delivery funnel (Queued → Sent → Delivered → Read → Replied), recipient-level status, and error details for failures. ## How It Works 1. **Pick a channel** — Select the channel you want to send on (e.g., WhatsApp). 2. **Configure content** — Compose your message and personalize it with contact data. 3. **Select your audience** — Pick which contacts should receive the campaign. 4. **Send** — Launch the campaign and monitor delivery from the campaign detail page. For a full step-by-step walkthrough, see the guide for your channel above. # WhatsApp Campaigns Source: https://chatbase.co/docs/user-guides/chatbot/outbound-whatsapp Send outbound WhatsApp campaigns to your contacts using pre-approved Meta message templates. Step-by-step guide for creating, sending, and tracking WhatsApp campaigns. WhatsApp campaigns let you send bulk messages to your contacts using pre-approved message templates from Meta. This is the primary way to proactively reach out to customers on WhatsApp outside the 24-hour conversation window. <Info> WhatsApp requires all outbound messages to use **pre-approved templates**. You cannot send free-form text as a campaign — templates must be created in Meta and approved before use. See the [WhatsApp Templates guide](/docs/user-guides/integrations/whatsapp-templates) for how to create and manage templates. </Info> ## Prerequisites * A connected WhatsApp integration ([setup guide](/docs/user-guides/integrations/whatsapp)) * At least one approved message template in Meta ([WhatsApp Templates guide](/docs/user-guides/integrations/whatsapp-templates)) * Contacts with phone numbers in your contact list ([Contacts guide](/docs/user-guides/chatbot/contacts/contacts-overview)) * A payment method configured in your [Meta billing settings](https://business.facebook.com/billing_hub) <Warning> Meta charges fees for each template message sent. Fees vary by country and template category. See [Meta's WhatsApp pricing](https://developers.facebook.com/docs/whatsapp/pricing) for current rates. </Warning> ## Creating a WhatsApp Campaign 1\. Click **Outbound** in the sidebar and click **+ New campaign**. <Frame> <img alt="Campaigns list page with New campaign button" /> </Frame> The new campaign page has two tabs: **Configuration** and **Audience**. ### Configuration <Frame> <img alt="New campaign configuration page showing Delivery, Replies, and Content sections with a message preview" /> </Frame> **Delivery** — Select **WhatsApp** as your channel and choose the phone number to send from. The selected number displays its verified business name. **Replies** — Choose how your team handles replies from campaign recipients: * **AI replies** (default) — Your AI agent responds to replies automatically. The conversation continues like any normal inbound chat. * **Human takeover** — When a recipient replies, a helpdesk ticket is created automatically. Your team picks up the conversation from there. **Content** — Enter a campaign name, then click **Select from template** to browse your approved templates from Meta. A preview of the message appears on the right as you configure it. All template categories are supported: **Marketing**, **Utility**, and **Authentication**. Templates with headers (image, video, or document) display a media preview. <Frame> <img alt="Completed campaign configuration with template selected and message preview" /> </Frame> If your template includes variables (e.g., `{{name}}`), map each one to a data source: * **Contact field** — Pulls from the recipient's contact data (name, email, phone number, or custom attributes). Each recipient gets a personalized value. * **Static value** — Enter fixed text that will be the same for all recipients. Click on a variable in the template body to open the mapping dropdown. <Frame> <img alt="Variable mapping dropdown showing contact fields (Name, Email, Phone), custom attributes (Tag, City), and free text option" /> </Frame> ### Audience Switch to the **Audience** tab to choose recipients. <Frame> <img alt="Audience tab showing the contact list with name, tag, and city columns" /> </Frame> Browse your contact list and select who should receive the campaign. You can: * **Search** contacts by name or phone number * **Filter** by custom attributes — click a column header like **Tag** or **City** to filter by specific values <Frame> <img alt="Tag filter dropdown showing Customer and VIP Customer options" /> </Frame> <Frame> <img alt="Contact list filtered by Customer tag showing matching contacts" /> </Frame> You can combine search and filters to narrow down your audience further. <Frame> <img alt="Audience filtered by city and searched by name, showing one matching contact" /> </Frame> The selected contact count appears at the top of the tab. At least one contact is required to send. <Info> Only contacts with a valid phone number can receive WhatsApp campaign messages. If a contact doesn't appear in the list, make sure their phone number is set in their [contact profile](/docs/user-guides/chatbot/contacts/contacts-overview). </Info> ## Sending Your Campaign Once you've configured delivery, content, and audience, click **Send now** in the top right. You'll be redirected to the campaign detail page where you can monitor delivery in real time. ## Monitoring Delivery After sending, the campaigns list shows the status and activity for each campaign at a glance. Hover over the activity bar to see a breakdown of delivery stages. <Frame> <img alt="Campaign activity bar with tooltip showing Sent, Delivered, and Replied counts" /> </Frame> Click a campaign to open the detail page with full delivery visibility: * **Status counters** — Queued, Sending, Sent, Delivered, Read, Replied, and Failed counts at the top. * **Overview** — Campaign name, channel, reply mode, send time, and recipient count. * **Content** — The template message that was sent. * **Delivery funnel** — A visual breakdown showing the percentage of recipients at each stage. Helps you see drop-off between Sent → Delivered → Read → Replied. * **Recipients table** — A searchable, filterable list of every recipient with their delivery status and timestamps. <Frame> <img alt="Campaign detail page showing overview, content, delivery funnel, and recipients table" /> </Frame> <Info> **Understanding messaging tiers:** Meta assigns a messaging tier to your WhatsApp Business Account based on quality and volume. Your tier determines how many unique contacts you can message per day. The current usage is shown as **Meta limits** in the top right of the campaigns page. </Info> ## Reply Handling When contacts reply to your campaign, the behavior depends on the mode you selected during creation: **AI Replies** — Your AI agent handles the reply automatically. The conversation continues like a normal inbound chat. This works well for product inquiries, support questions, and automated follow-ups. **Human Takeover** — The reply creates a helpdesk ticket tagged with the campaign name. Your team picks up the conversation and responds manually from the helpdesk inbox. <Frame> <img alt="Helpdesk ticket created from a campaign reply, showing the campaign name in the subject and the recipient's message" /> </Frame> ## Troubleshooting * **Campaign stuck in "Sending"?** Large campaigns are processed in batches and may take a few minutes. If there's no progress after 10 minutes, check that your [WhatsApp integration](/docs/user-guides/integrations/whatsapp) is still connected. * **Recipients showing "Failed"?** Common causes include an invalid phone number, Meta rate limits being reached, or a missing payment method in your [Meta billing settings](https://business.facebook.com/billing_hub). * **Template not appearing?** Make sure the template has been approved in Meta. Only approved templates appear in the campaign template picker. * **Replies not creating tickets?** Verify that reply behavior is set to **Human Takeover**. * **Hitting rate limits?** Your Meta messaging tier determines daily send limits. Check your tier on the campaigns page. To increase your tier, maintain high message quality and gradually increase volume. # Playground Source: https://chatbase.co/docs/user-guides/chatbot/playground Preview your agent across supported channels and customize its style and capabilities in real time. The **Playground** lets you preview and interact with your agent exactly as your end users would. When you open the Playground, it automatically loads the last channel you were working on from the **Channels** page. For example, if you last viewed the **Chat bubble** or **Help page**, the Playground will open that same channel so you can continue testing without switching views. Use the Playground to: * Preview your agent's behavior in real time. * Test conversations and responses. * Edit channel-specific settings, such as your agent's **style** and **capabilities**, and immediately see how those changes affect the experience. To preview a different channel, click the channel name at the top of the page and pick one from the list, or choose **View all channels** to go to the [Channels](/docs/user-guides/chatbot/channels) page. <Frame> <img alt="Playground image" /> </Frame> ## Tabs The tabs available depend on which channel you are previewing. A web channel such as **Chat bubble** shows: | Tab | What it controls | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Overview** | Your agent's **Model** and a read-only **Data sources** summary (training status, total size, and counts of Links, Texts, and Q\&A's), both of which apply to the whole agent. Below them, the **Actions** available in this channel and the **Instructions** it uses. | | **Display** | Appearance and behavior for this channel, grouped into **Content**, **Capabilities**, **Colors**, **Floating bubble**, and **Localization**. See [Chat bubble display settings](/docs/user-guides/chatbot/channels#chat-bubble-display). | | **Voice** | Your agent's voice conversation settings. See [Settings → Voice](/docs/user-guides/chatbot/settings#voice). | | **Actions** | The actions this channel can run. | Other channels expose a different set. **Messenger**, for example, replaces **Voice** with **Leads**, and the **Slack** channel uses **Overview**, **Connections**, **Actions**, and **Extra Settings**. ### Instructions and global instructions On the **Overview** tab, **Sync with global instructions** controls whether this channel uses your agent's global instructions or its own. Leave it on to keep every channel consistent; turn it off to write instructions that apply only to this channel. ## Preview Click **Preview** in the top-right to open your agent on a page of its own. The preview opens in a new tab and renders the agent on an otherwise empty page, so you can see and use it the way a visitor would instead of inside the Playground's editing layout. You can share the preview URL with anyone in your workspace, which makes it a convenient way to collect feedback on your agent before deploying it. A toolbar at the top of the preview page controls how the page around your agent looks: * **Light and dark** — switch the page background between light and dark to check your agent's colors against both. * **Upload background** — upload an image, such as a screenshot of your own website, to sit behind the agent. This shows how your agent will look in place on your site before you deploy it anywhere. Everything else behaves as it would once deployed, including initial messages, suggested questions, the floating bubble and its label, and the full conversation. ## Deploying Click **Deploy** in the top-right to get the code or connection details for the current channel. For the chat bubble, the dropdown offers: * **Website widget** — a floating chat bubble on any website. * **Website iframe** — the agent embedded as an inline element on any website. * **Shopify** — add the chat bubble to your Shopify storefront. * **WordPress** — add the chat bubble using the official Chatbase plugin. The Playground makes it easy to iterate on your agent's behavior and appearance before publishing your changes. # How Procedures Run Source: https://chatbase.co/docs/user-guides/chatbot/procedures/how-procedures-run How the AI agent decides which procedure to run, why a procedure may be skipped, and how procedure-only actions keep certain tools on rails. When a message comes in, the agent looks at your **active** procedures, decides whether one applies, and if so, follows its steps. This page explains the rules that govern that decision so your procedures behave predictably. ## Only one procedure runs per turn Within a single turn, the agent runs **at most one procedure**: the one whose **trigger** best matches what the customer is asking for *right now*. It never executes two procedures in the same reply. This is a per-turn limit, not a lock. The active procedure can change from one message to the next: if the customer is partway through procedure A and then sends a message that matches procedure B's trigger, the agent can switch to procedure B on that turn. <Info> A procedure stays in flight across turns while the customer is mid-flow (for example, replying "yes" or providing a value the agent asked for). It ends when the situation is handled, or when the customer clearly switches topics, at which point a different procedure can engage on the next turn. </Info> ## Procedures are dropped when an action isn't available A procedure can reference actions (with `@action_name`) in its steps. Before a procedure is even considered for a conversation, the agent checks that **every** action it references is available on the **current channel**. If even one referenced action is unavailable, the **whole procedure is skipped** for that conversation. An action counts as unavailable when it is: * Disabled or removed, * Disabled on the current channel, or * Not supported on the current channel/medium (for example, a widget-based action on a channel that can't render widgets). <Warning> The check is all-or-nothing and covers steps **inside conditional branches too**, even branches that might never run on a given conversation. If a deep branch references an action that's off on, say, WhatsApp, the entire procedure is dropped on WhatsApp. This is intentional: a half-runnable procedure is worse than none. </Warning> **What this means for you:** if a procedure works in one channel but seems to be ignored in another, check that *all* of its referenced actions are enabled on that channel. ## Procedure-only actions By default, the agent can call any enabled action on its own whenever the action's **When to use** matches. Sometimes you want the opposite: an action the agent should **never** reach for by itself, and only ever run as a deliberate step inside a procedure — for example, a "process refund" action you only want fired after the refund procedure's checks have passed. Turn on **Only use in procedures** in the action's settings to enforce that. The action stays enabled and fully functional, but: * The agent won't select it on its own judgment, so its **When to use** field is hidden (it no longer needs one). * It runs **only** when a procedure step references it with `@action_name`. This keeps sensitive tools on rails — they can't fire outside the flow you designed. See [Actions](/docs/user-guides/chatbot/actions/actions-overview#only-use-in-procedures) for where to find the setting. ## Waiting on the customer If a step calls an action that needs user input (an account picker, a form, a confirmation), the agent treats it as a **pause**, not a failure. It tells the customer it's waiting, then stops. It resumes the same step once the customer responds. It won't retry or jump to another action. ## Troubleshooting <AccordionGroup> <Accordion title="My procedure never triggers"> Confirm it's **Active**, and that its trigger describes the customer's intent clearly and distinctly from other procedures. Overlapping triggers can cause a different procedure to win. </Accordion> <Accordion title="It works on the website but not on WhatsApp/another channel"> A referenced action is likely unavailable on that channel, which drops the whole procedure there. Enable every referenced action on that channel. </Accordion> <Accordion title="Two things should happen at once"> Only one procedure runs per turn. Combine the flow into a single procedure (using branches) rather than expecting two procedures to run together. </Accordion> </AccordionGroup> # Overview Source: https://chatbase.co/docs/user-guides/chatbot/procedures/procedures-overview Give your AI agent a multi-step procedure (workflow) end to end to follow whenever a conversation matches a trigger you define. A **procedure** captures how your AI agent should handle a specific situation as a repeatable, standard operating procedure (SOP). Each one pairs a **trigger** (the situation that engages it) with an ordered list of **steps** the agent works through, including the [actions](/docs/user-guides/chatbot/actions/actions-overview) it calls along the way. Reach for procedures on high-stakes flows like refunds, escalations, and onboarding, where you don't want the agent improvising. <Frame> <img alt="Image" title="Image" /> </Frame> ## Anatomy of a procedure Every procedure has three parts: | Field | Purpose | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Name** | A human-readable label (e.g. "Refund Request"). Shown on the conversations and used in [analytics](#analytics). | | **Trigger** | A description of *when* this procedure should engage: the situation or intent that should route the conversation here. Labeled **When to use** in the editor. | | **Steps** | The ordered list the agent follows. Steps can reference actions and branch on conditions. | <Frame> <img alt="Image" title="Image" /> </Frame> ## Steps Steps run **in order**, top to bottom. There are two kinds: * **Instruction steps**: a plain instruction the agent follows ("Ask the customer for their order number"). * **Branch steps**: a decision point with one or more `if` / `else if` conditions and an optional `otherwise`. The agent evaluates the conditions top-to-bottom, runs the **first** matching branch, then continues after the branch. <Info> Limits: up to **15** instruction steps per procedure, up to **5** branches per decision point (`if` / `else if` / `else`), and a branch **can't** be nested inside another branch. </Info> ### Referencing actions with `@` Inside a step, type `@` to reference an [action](/docs/user-guides/chatbot/actions/actions-overview) the agent should run at that point (for example `@lookup_order`). When the agent reaches that step, it invokes the tool. <Frame> <img alt="Referencing an action in a step with @" /> </Frame> <Warning> If a step references an action that isn't available on the current channel, the **entire procedure is skipped** for that conversation. See [How procedures run](/docs/user-guides/chatbot/procedures/how-procedures-run#procedures-are-dropped-when-an-action-isn-t-available). </Warning> <Info> If a step references an action that doesn't exist or is disabled, the editor flags it and won't let you enable the procedure until you fix or remove the reference. </Info> ### Using variables with `{{ }}` You can personalize your steps and branch conditions with `{{token}}` variables that are resolved at runtime. Type `{{` in a step or condition to open the picker, which groups the available variables into: | Group | Variables | What it resolves to | | ---------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | | **Contact attributes** | `{{contact.name}}`, `{{contact.email}}`, `{{contact.phonenumber}}` | The matched contact's saved details. | | **Custom attributes** | `{{contact.custom_attributes.*}}` | Any custom contact attributes you've defined for this agent. | | **Session attributes** | `{{user.name}}`, `{{user.email}}` | Identity passed by the embedding site for the current session. | | **Helpdesk** | `{{agentAvailable}}` | `true` when at least one helpdesk agent is available right now (handy in branch conditions). | <Info> A variable resolves only when its value is available for the conversation. For example, `{{user.email}}` is empty unless the embedding site passes it, and `{{contact.*}}` requires a matched contact. Write steps so the agent can still proceed (or asks for the value) when a variable is missing. </Info> <Frame> <img alt="Inserting a variable token in a step" /> </Frame> ## Start from a template Don't want to build from scratch? Open the **Templates** tab to browse ready-made procedures for common flows like order returns, subscription cancellations, and billing disputes, all grouped by category. Pick one to create an editable copy, then tailor its trigger and steps to your business. ## Creating a procedure <Steps> <Step title="Open the Procedures tab"> Go to your agent and then click on **Build** from the side bar, then open **Procedures**, then click **Add procedure** (or start from a [template](#start-from-a-template)). </Step> <Step title="Name it and define the trigger"> Give it a clear name, then use the **When to use** field to describe the trigger: the situation that should route the conversation to this procedure. </Step> <Step title="Add steps"> Add instruction steps, reference actions with `@`, add variables with `{{ }}`, and add conditional branches where the flow forks. </Step> <Step title="Enable it"> Save and set the procedure to **Active**. Only active procedures are considered at runtime. </Step> </Steps> ## Analytics Open a procedure and switch to the **Analytics** tab to see how it's performing over a date range you choose: | Metric | Meaning | | ------------- | ------------------------------------------------------------------------ | | **Triggered** | How many times the agent engaged this procedure. | | **Pending** | Runs still in progress — the flow was triggered but hasn't finished yet. | | **Resolved** | Runs that reached their end. | A trend chart below the counters breaks the same numbers down by day, so you can spot patterns (for example, a spike in refund requests) at a glance. <Frame> <img alt="Procedure analytics tab" /> </Frame> ## Next steps <Card title="How procedures run" icon="route" href="/docs/user-guides/chatbot/procedures/how-procedures-run"> Understand triggering, one-procedure-per-turn, and how procedures interact with actions. </Card> # Settings Source: https://chatbase.co/docs/user-guides/chatbot/settings Open an agent and click **Settings** in the sidebar. The page has eight tabs: **General**, **Voice**, **Email**, **Helpdesk**, **Security**, **Custom domains**, **Webhooks**, and **Notifications**. ## General The **General** tab has three cards: **Agent details** (Agent ID, Size, Name), **Credits limit**, and **Danger zone** (Delete all conversations, Delete agent). <Frame> <img alt="Agent Details" /> </Frame> In the **Credits limit** card, enable **Set credits limit on agent** to cap how many of the workspace’s credits this agent can consume. <Frame> <img alt="Credits limit" /> </Frame> ***DANGER ZONE*** The actions done in the section aren’t reversible. If you deleted the AI agent or the conversations, you can’t retrieve them moving forward. <Frame> <img alt="DANGER ZONE" /> </Frame> ## Voice This section allows you to configure how your AI agent sounds and behaves during voice conversations. ### Credit Usage Voice sessions consume credits based on two components: * **Agent voice**: Every voice session consumes **6 message credits per minute**. This is a per-minute cost regardless of the actual messages exchanged. * **AI model**: Each response from the AI agent during a voice session consumes message credits based on the model used, just like in text conversations. See the [full list of models and their message credit costs](./build#ai-model). The total credit cost of a voice session is the sum of both components. <Frame> <img alt="Voice model settings" /> </Frame> <Accordion title="Pricing Example"> Suppose your voice agent uses **GPT-5.6 Luna** (1 message credit per request). If a user has a **10-minute voice call** with **15 AI requests**: | Component | Calculation | Message Credits | | ----------------------- | ------------------------------ | --------------- | | Agent voice | 10 min x 6 credits/min | 60 | | AI model (GPT-5.6 Luna) | 15 requests x 1 credit/request | 15 | | **Total** | | **75** | </Accordion> ### Voice Model Select the AI model used specifically for voice sessions. This model is separate from the one used for text-based conversations and only applies when users interact with your AI agent through voice. You can also adjust the **Temperature** to control how creative or reserved the AI agent's responses are during voice conversations. <Frame> <img alt="Voice model settings" /> </Frame> ### Transcriber Choose the model used to transcribe user speech during voice conversations. <Frame> <img alt="Voice transcriber settings" /> </Frame> * **Language**: The language used to transcribe user speech. Select **Multilingual (auto-detect)** to let the transcriber detect the language automatically, or pick a specific language to improve accuracy. * **Model**: The speech-to-text model that converts user audio into text. Each model supports a different range of languages. * **Silence Threshold**: Seconds of silence before the AI agent considers the user has finished speaking. Lower values switch turns faster but may cut off pauses mid-thought. * **Noise Sensitivity**: Controls how loud audio must be to count as speech. Lower values pick up quieter speech but are more sensitive to background noise. Higher values filter out noise but may miss soft-spoken users. <Info> **Multiple transcription languages:** When using the default **Soniox v5** model, you can select up to **8 languages**. Limiting the set of possible languages helps the transcriber focus on the selected languages, improving transcription accuracy. </Info> ### Agent Voice Choose a voice for your AI agent and fine-tune how it sounds during voice conversations. <Frame> <img alt="Voice agent voice settings" /> </Frame> Click on the voice selector to open the voice picker, then fine-tune how the selected voice sounds. The available controls depend on the voice you picked, some voices expose sliders such as speed, stability, and similarity, while others let you describe the desired delivery. A few examples: * **Speed**: Controls how fast or slow the AI agent speaks. Adjust the slider between slower and faster to match your preferred pace. * **Stability**: Determines how stable the voice is. Lower values introduce a broader emotional range, while higher values produce a more consistent, monotone delivery with limited emotion. * **Similarity**: Determines how closely the AI adheres to the original voice when replicating it. Higher values result in a closer match to the selected voice. * **Voice instructions**: For voices that support it, enter a short prompt describing the tone, style, or dialect you want the AI agent to use when speaking. Make sure to click **Save** on the voice card to apply your changes. #### Selecting a voice The voice picker has two tabs: **All voices** for browsing pre-recorded voices, and **Custom voice** for bringing a custom voice from a supported provider. <Frame> <img alt="Voice selection modal" /> </Frame> Under **All voices**, you can search by name and filter voices by language, accent, age, and gender. Each row shows the voice's supported languages and a **Preview language** dropdown, pick a language and click the play button to hear a sample of the voice speaking it. Select a voice and click **Confirm voice** to apply it to your agent. <Frame> <img alt="Custom voice selection modal" /> </Frame> Under **Custom voice**, you can add a custom public voice that isn't in the pre-recorded list by referencing it directly from your provider: * **Provider**: The voice provider that hosts the custom voice (for example, ElevenLabs). * **Voice ID**: The identifier of the voice in the provider's account. Paste it in and click **Add voice** to make it available for selection, then click **Confirm voice** to apply it to your agent. <Note> Custom voices only work with **publicly available shared voices** from your provider. Private voices in your provider account are not supported. </Note> #### Using Dialects and Regional Accents Some voices support custom dialects and accents through Voice Instructions. Look for voices marked with the ✨ sparkle icon. These voices can adapt their accent, dialect, pacing, and speaking style based on the instructions you provide. <Frame> <img alt="Voices Sparkle" /> </Frame> After selecting the desired voice, in the Instructions field, describe how you want the voice to sound. **Recommended Settings** * Transcriber: Soniox * Voice LLM: GPT-5.6 Luna or Gemini 3.5 Flash ### Messages Configure the initial greeting and error messages for your voice agent. <Frame> <img alt="Voice messages settings" /> </Frame> * **Initial message**: The first message the AI agent speaks when a voice session begins. If left empty, the voice agent will wait for the user to speak first. * **Error message**: The message played if the voice session encounters an error. If left empty, the default error message "The voice session encountered an error. Please try again." will be used. ### Session Configurations Control how the AI agent handles interruptions, silence, and text input during active voice calls. <Frame> <img alt="Voice session configurations settings" /> </Frame> * **Allow interruptions**: When enabled, users can speak over the AI agent to interject mid-response. Disable this if you'd prefer the agent to always finish speaking before listening for the user's next turn. Defaults to **enabled**. * **End conversation after silence**: The number of seconds of inactivity after which the call is automatically ended. Useful for closing out abandoned sessions and avoiding unnecessary credit usage. Defaults to **300 seconds**. * **Allow text input during voice calls**: When enabled, users can type messages mid-call alongside speaking. Helpful for entering details that are easier to type than to say, such as names, emails, or URLs. Defaults to **disabled**. ### Recordings Enable recording of voice sessions for quality review and training purposes. You can also toggle **Retain voice recordings forever** to keep recordings indefinitely, or set a custom retention period. <Frame> <img alt="Voice recordings settings" /> </Frame> ### Limits Control session volume and duration to manage costs and performance. <Frame> <img alt="Voice limits settings" /> </Frame> * **Max no. of concurrent voice sessions**: The maximum number of voice sessions that can run at the same time. If left empty, your plan's default limit will apply. * **Max call duration**: The maximum length of a single voice call in minutes. The default is 15 minutes. * **Allowed no. of daily calls**: The total number of voice calls allowed each day. If left empty, your plan's default limit will apply. <Note> Your subscription plan enforces account-level limits for daily sessions and concurrent sessions across all your AI agents. You can set agent-specific limits here to further restrict usage for individual agents. </Note> ## Email The **Email** tab holds your agent's dedicated **Agent email address** and the **Email configuration** card, where you add and verify the addresses used to send and receive mail. See [Email settings](/docs/user-guides/chatbot/email-settings). ## Helpdesk The **Helpdesk** tab has its own sub-navigation: **Email**, **Members**, **Teams**, **Scheduling**, **Team routing**, **Ticket statuses**, **Translation**, and **AI draft replies**. See [Helpdesk](/docs/user-guides/chatbot/help-desk/help-desk-overview). ## Security The **Security** tab holds a single **Rate limit** card. Use it to cap how many messages one device can send to your agent through the chat bubble and iframe over a chosen time period, which helps prevent abuse. Set **Limit to** *N* **messages every** *N* **seconds**, and write the **Message to show when limit is hit**. <Frame> <img alt="Rate limiting" /> </Frame> <Note> The rate limit applies to your agent on your own site, not to you when testing from chatbase.co. To restrict which domains your agent can load on, see [Allowed Domains](/docs/user-guides/chatbot/channels#allowed-domains) under Channels. </Note> ## Custom domains White label the embed script so it loads from a domain you own instead of a Chatbase URL. See [Custom domains](/docs/developer-guides/custom-domains). ## Webhooks The **Webhooks** tab sends ticket and event data to your own endpoints. Click **Create webhook** and pick one of two types: * **Help desk webhook** - a reusable connection used by the [Triggers](/docs/user-guides/chatbot/help-desk/triggers#send-webhook) **Send webhook** action. Set the endpoint URL, optional custom headers, and a request body template (insert ticket fields with `{{ticket.*}}` placeholders). When you create one, Chatbase shows a signing **secret** once - every delivery carries an `X-Chatbase-Signature` header your endpoint can verify with it. * **Events webhook** - subscribe an endpoint to agent events (for example, form submissions). Tick the events to listen for and the URL that receives them. Existing connections appear under **Help desk webhooks** and **Event webhooks**, where you can edit or delete them. <Frame> <img alt="Webhooks configuration" /> </Frame> Each webhook sends a POST request to your chosen endpoint, which you can use to automate workflows with third-party tools. <Note> Lead submission webhooks are configured on the action itself, not here. Open your **Collect Leads** action and use its **Webhooks** tab. See [Collect Leads](/docs/user-guides/chatbot/actions/collect-leads#webhooks). </Note> ## Notifications From this page, you can configure the notifications you get from the agent. You can either opt for getting one email per day that contains all the leads submitted for that day. You can also opt for another email that sends you a daily email with the conversations done on that day.  You can add multiple email addresses to receive these emails if needed. <Frame> <img alt="Notifications - Receive emails with your daily leads and conversations" /> </Frame> ## Webhooks  On this page, you can configure webhooks that are triggered when a Custom Form is submitted. When a user completes and submits a Custom Form in your agent, Chatbase automatically sends a POST request to your configured webhook endpoint containing the submitted form data. You can use this webhook to integrate with third-party services, automate workflows, store submissions in your own systems, or trigger custom business logic whenever a form is submitted. # Bubble Source: https://chatbase.co/docs/user-guides/integrations/bubble ## Step 1: Set Up Your Chatbase AI agent To integrate your Chatbase AI agent into your Bubble application, begin by logging into your Chatbase account. If you haven't already created an account, you can sign up for a free account. After signing in, you can configure you agent within the Chatbase platform by uploading relevant data sources, such as files, text snippets, websites, or question-and-answer pairs, which the agent can use to build its knowledge base. Here is a [step-by-step roadmap for successfully deploying your Chatbase agent](/docs/user-guides/quick-start/your-first-agent). ## Step 2: Generate and Copy Your Chatbase AI agent Embed Code 1\. Log into your Chatbase account and navigate to your [**dashboard**](https://www.chatbase.co/dashboard/). 2\. On the list of available agents, click on the one you want to integrate into your Bubble website. 3\. Click **Channels** in the left sidebar, then click **Manage** on the **Chat bubble** card (or **Setup**, if you haven't configured it yet). 4\. Click on **Deploy** and select the **Website widget** embed type. Scroll down and Click **Copy** to copy the provided script. <Frame> <img alt="Deploy" /> </Frame> ## Step 3: Embed Chatbase AI agent on Your Bubble App 1\. Once you've copied your Chatbase embed code, sign into your Bubble account and head to your account dashboard. 2\. On your dashboard, pick out the Bubble app or website you wish to embed the agent on and click the **Launch Editor** button next to it. <Frame> <img alt="image" /> </Frame> 3\. Once your Bubble Editor comes up, scroll down to the section of the page you want to add the embed code. 4\. On the left sidebar of the editor, locate the HTML component and drag it to the section of the page. <Frame> <img alt="image" /> </Frame> 5\. Double-click on the HTML component to reveal the code editor. 6\. Paste the embed code on the editor and you should automatically see a floating agent icon on the bottom left corner of the editing canvas. <Frame> <img alt="image" /> </Frame> 7\. You can now preview your Bubble app to test your agent. <Frame> <img alt="image" /> </Frame> **Congratulations, your Chatbase agent is now live on your Bubble app!** <Note> You can customize the appearance and colors of your agent on your Chatbase dashboard. To do this, go to your **dashboard**, choose an agent, click **Channels** in the left sidebar, click **Manage** on the **Chat bubble** card, then open the **Display** tab to edit Content, Capabilities, Colors, Floating bubble, and Localization. </Note> # Email Source: https://chatbase.co/docs/user-guides/integrations/email Enable AI-powered email responses with automated customer support through email ## Overview Chatbase's Email Integration enables your AI agent to automatically respond to customer emails, providing instant support and information directly through your company's email system. Set up takes just minutes and provides seamless AI-powered email automation across your organization. <Info> **Prerequisites Required**: Before configuring the Email channel, you must: 1. [Create a Chatbase account](https://www.chatbase.co/auth/signup) and build your AI agent 2. Configure your email domain ([Email settings](/docs/user-guides/chatbot/email-settings)) with proper authentication (DKIM, SPF, forwarding) 3. Have an active Chatbase agent ready for deployment </Info> ## How Email Integration Works The Email Integration allows your AI agent to automatically monitor and respond to incoming emails through your configured email addresses. Here's how it works: 1. **Email Reception**: Incoming emails are forwarded to your Chatbase agent 2. **AI Processing**: The agent analyzes the email content and determines the appropriate response 3. **Automated Reply**: AI generates and sends a contextually appropriate response 4. **Delivery Monitoring**: System tracks email delivery and alerts you of any issues <Warning> **Domain Configuration Required**: Email integration will not function until your email domain is properly configured with forwarding, DKIM, and SPF records. Complete domain setup in **Settings** → **Email** before deploying, you must also use a **company email**. </Warning> ## Setup Instructions <Steps> <Step title="Access Your Chatbase Dashboard"> Navigate to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent you want to integrate with email. <Tip> If you haven't created an agent yet, follow our [step-by-step guide to creating your first agent](/docs/user-guides/quick-start/your-first-agent) to get started. </Tip> </Step> <Step title="Configure Your Email Domain"> Navigate to **Settings** → **Email** and follow the domain configuration process. Refer to [Email settings](/docs/user-guides/chatbot/email-settings) for detailed instructions. <Check> Verify all configuration steps are complete before proceeding. Email addresses with configuration issues will display warnings. </Check> </Step> <Step title="Enable the Email Channel"> 1. Navigate to **Channels** → **Email** <Frame> <img alt="Email integration navigation" /> </Frame> 2. Click **Manage** to access email deployment settings <Frame> <img alt="Email manage button" /> </Frame> 3. Click **Deploy** and toggle the channel to **Enabled** <Frame> <img alt="Email deployment interface" /> </Frame> </Step> <Step title="Customize Email Settings"> Configure your AI agent's email behavior and appearance from **Channels → Email → Manage**. <Frame> <img alt="Email configuration options" /> </Frame> </Step> </Steps> ## Email Configuration Options Customize how your AI agent sends and formats emails to match your brand and communication standards. ### Reply Address Select which configured email address will appear as the reply-to address for AI-generated emails. <Card title="Configuration" icon="reply"> Choose from your verified email addresses. Addresses with configuration issues (forwarding, DKIM, or SPF not enabled) will display warnings, and you will not be able to select them. </Card> ### Deliverability Alert Contact Designate a team member to receive notifications about email delivery failures and issues. <Card title="Monitoring" icon="bell"> Select from your account members or choose "None" to disable delivery alerts. </Card> **Recommended**: Assign this to your technical or support team lead to ensure quick resolution of delivery issues. ### Blocked senders Add email addresses that should never receive an AI reply. Emails from blocked senders are still saved to your conversations. ### Email Display Name Set the sender name that appears in recipients' inboxes when they receive emails from your AI agent. <Card title="Branding" icon="signature"> This name appears in the "From" field and represents your brand identity in customer communications. </Card> **Examples**: * "CustomerSupport at \[Company Name]" * "\[Company Name] AI Assistant" * "Help Desk" ### Spam detection Enable **Spam detection** to use AI to identify suspected spam emails. Suspected spam is saved to your conversation logs but does not receive an automatic AI reply. You can still reply to these conversations manually. #### Whitelisted senders Add email addresses that should always receive an AI reply and bypass **Spam detection**. ### Reply Delay Hold each AI-generated reply for a set amount of time before it is sent. An instant response can feel automated. A short delay makes replies read like they came from a person, and gives your team a window to step in before an email goes out. <Card title="Pacing" icon="clock"> Enter a duration and choose **seconds** or **minutes**. The maximum delay is 1 hour. Set it to 0 (or leave it empty) to send replies immediately. </Card> <Frame> <img alt="Reply delay configuration" /> </Frame> **How it works**: * The AI composes its reply as soon as the customer's email arrives, but the send is held for the configured time. * While a reply is waiting, it appears in your conversation logs as a pending message with a countdown showing when it will be sent. * [Taking over](/docs/user-guides/chatbot/help-desk/takeover) the conversation cancels any waiting replies — you are warned first, and if you proceed the customer never receives them and the unsent drafts are removed from the conversation. <Frame> <img alt="Warning shown when taking over a conversation with a waiting delayed reply" /> </Frame> <Info> The delay applies only to automatic AI replies. Replies your team sends from the help desk, and spam conversations you release manually with **Reply anyway**, are always sent immediately. </Info> If a delayed reply fails to send, it is retried automatically. If it still cannot be delivered, your [Deliverability Alert Contact](#deliverability-alert-contact) is notified and the reply is discarded. ### AI Composition Disclaimer Add transparency by including a disclaimer that identifies AI-generated content. <Card title="Transparency" icon="info-circle"> When enabled, adds a customizable disclaimer at the end of emails (default: "This message is composed by AI.") </Card> **Use Cases**: * Regulatory compliance requirements * Company transparency policies * Building customer trust ### Email Signature Create a professional signature that appears at the bottom of all AI-generated emails. <Card title="Customization" icon="pen-fancy"> Supports rich text formatting including multiple lines, links, styling, and contact information. </Card> **Signature Elements**: * Company contact information * Social media links * Legal disclaimers * Unsubscribe options <Note> Remove "**Powered by Chatbase**" branding from your emails by purchasing the white-label addon. See [Pricing](https://www.chatbase.co/pricing) for details. </Note> ## Common Use Cases The Email Integration is ideal for: * **Customer Support Automation**: Handle common inquiries and FAQs automatically * **Employee Self-Service**: Answer HR, IT, or administrative questions instantly * **Lead Qualification**: Screen and respond to sales inquiries with relevant information * **Appointment Scheduling**: Assist with booking and calendar management * **Order Status Updates**: Provide shipping and order information on demand <Tip> **Getting Started**: Begin with a focused use case like FAQ responses or status inquiries, then expand your agent's capabilities as you refine its performance. </Tip> # Framer Source: https://chatbase.co/docs/user-guides/integrations/framer ## Step 1: Sign Into Your Chatbase Account and Copy Your Embed Code 1\. Log into your Chatbase account and navigate to your [**dashboard**](https://www.chatbase.co/dashboard/). 2\. On the list of available agents, click on the one you want to integrate into your Framer website. 3\. Click **Channels** in the left sidebar, then click **Manage** on the **Chat bubble** card (or **Setup**, if you haven't configured it yet). 4\. Click on **Deploy** and select the **Website widget** embed type. Scroll down and Click **Copy** to copy the provided script. <Frame> <img alt="Deploy" /> </Frame> ## Step 2: Sign Into Your Framer Website and Embed Your AI agent 1\. Sign in to your Framer website and head to your project dashboard 2\. Click on the website project you wish to embed your Chatbase agent <Frame> <img alt="image" /> </Frame> 3\. After clicking through to open the website project, locate the page you wish to embed your agent on the left side of the editor and click the three-dot icon next to the name of the page. <Frame> <img alt="image" /> </Frame> 4\. Click **Settings** to open the settings for that page. 5\. On the Settings page, scroll down to find the section labeled "**Custom Code**." 6\. Right under the Custom Code section, paste your Chatbase agent embed code in the first box labeled *"Start of \<head> tag"* and click **Save** on the top right corner of the panel. <Frame> <img alt="image" /> </Frame> 7\. If everything was done well, you should now see a floating Chatbase agent icon on the bottom left corner of your Framer website (on the page you added it to) <Frame> <img alt="image" /> </Frame> **Congratulations! Your Chatbase agent is now ready to use on your website.** <Note> You can customize the appearance and colors of your agent on your Chatbase dashboard. To do this, go to your **dashboard**, choose an agent, click **Channels** in the left sidebar, click **Manage** on the **Chat bubble** card, then open the **Display** tab to edit Content, Capabilities, Colors, Floating bubble, and Localization. </Note> # Freshdesk Source: https://chatbase.co/docs/user-guides/integrations/freshdesk Integrating Freshdesk with Chatbase allows your custom agent to automatically escalate complex customer issues to your human support team by creating a ticket directly in Freshdesk. The AI agent generates a Freshdesk ticket that includes a clear summary of the user’s issue along with the relevant conversation context. This ensures that when a case requires human attention, your support team receives all the necessary information upfront, eliminating the need for customers to repeat themselves. The AI handles routine inquiries instantly, and when escalation is needed, Freshdesk becomes the system where your human agents step in to resolve the issue. This guide will walk you through the steps required to connect your agent to Freshdesk and configure automated ticket creation for smooth handoffs to your support team. ## Setup Guide Here's how to integrate a Chatbase agent with your Freshdesk account ### Step 1: Connect to Freshdesk * Login to your Chatbase dashboard * Select your Agent * Choose **Integrations** * Click **Connect** under Freshdesk *** ### Step 2: Locate Your Freshdesk API Key & Subdomain To authorize the integration, you’ll need your Freshdesk subdomain and API key. Find your Freshdesk API Key: 1. Log in to your Freshdesk account. 2. Click your profile picture (top-right corner). 3. Select **Profile Settings**. 4. On the right-hand side, locate **Your API Key**. <Frame> <img alt="freshdesk" /> </Frame> *** ### Step 3: Create 'Escalations' action Now you're ready to configure your Escalations action to route tickets to Freshdesk. You can follow [this step-by-step guide](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human) to set up the action properly. *** That’s it! Your Freshdesk integration is now fully set up and ready to go. Whenever human intervention is required, your Chatbase agent will automatically create a ticket in Freshdesk with a summary of the user’s issue and relevant context, allowing your support team to step in and resolve the case seamlessly. # Gorgias Source: https://chatbase.co/docs/user-guides/integrations/gorgias Integrating Gorgias with Chatbase allows your custom agent to automatically escalate complex customer issues to your human support team by creating a ticket directly in Gorgias. The AI agent generates a Gorgias ticket that includes a clear summary of the user's issue along with the relevant conversation context. This ensures that when a case requires human attention, your support team receives all the necessary information upfront, eliminating the need for customers to repeat themselves. The AI handles routine inquiries instantly, and when escalation is needed, Gorgias becomes the system where your human agents step in to resolve the issue. This guide will walk you through the steps required to connect your agent to Gorgias and configure automated ticket creation for smooth handoffs to your support team. ## Setup Guide Here's how to integrate a Chatbase agent with your Gorgias account. ### Step 1: Connect to Gorgias * Login to your Chatbase dashboard * Select your Agent * Choose **Integrations** * Click **Connect** under Gorgias *** ### Step 2: Locate Your Gorgias Subdomain & API Key To authorize the integration, you'll need your Gorgias subdomain, account email, and API key. Find your Gorgias API Key: 1. Log in to your Gorgias account. 2. Go to Settings → REST API. 3. Create a new API key (or copy an existing one). 4. Copy the API key and paste it into the Chatbase integration form, along with your account email and subdomain. <Frame> <img alt="gorgias" /> </Frame> *** ### Step 3: Create 'Escalations' action Now you're ready to configure your Escalations action to route tickets to Gorgias. You can follow [this step-by-step guide](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human) to set up the action properly. *** That’s it! Your Gorgias integration is now fully set up and ready to go. Whenever human intervention is required, your Chatbase agent will automatically create a ticket in Gorgias with a summary of the user’s issue and relevant context, allowing your support team to step in and resolve the case seamlessly. # Help Scout Source: https://chatbase.co/docs/user-guides/integrations/helpscout Integrating Help Scout with Chatbase allows your custom agent to automatically escalate complex customer issues to your human support team by creating a ticket directly in Help Scout. The AI agent generates a Help Scout ticket that includes a clear summary of the user’s issue along with the relevant conversation context. This ensures that when a case requires human attention, your support team receives all the necessary information upfront, eliminating the need for customers to repeat themselves. The AI handles routine inquiries instantly, and when escalation is needed, Help Scout becomes the system where your human agents step in to resolve the issue. This guide will walk you through the steps required to connect your agent to Help Scout and configure automated ticket creation for smooth handoffs to your support team. ## Setup Guide Here's how to integrate a Chatbase agent with your Help Scout account ### Step 1: Connect to Help Scout * Login to your Chatbase dashboard * Select your Agent * Choose **Integrations** * Click **Connect** under Help Scout to enter your credentials and finish the integration *** ### Step 2: Create 'Escalations' action Now you're ready to configure your Escalations action to route tickets to Help Scout. You can follow [this step-by-step guide](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human) to set up the action properly. *** That’s it! Your Help Scout integration is now fully set up and ready to go. Whenever human intervention is required, your Chatbase agent will automatically create a ticket in Help Scout with a summary of the user’s issue and relevant context, allowing your support team to step in and resolve the case seamlessly. # HubSpot Source: https://chatbase.co/docs/user-guides/integrations/hubspot Connect HubSpot to Chatbase so your AI agent can create tickets. ## Setup Guide ### Before you start * A Chatbase account with an agent * A HubSpot account with permissions to install apps * A paid Chatbase plan with Integrations enabled <Steps> <Step title="Open your Chatbase agent"> Go to your Chatbase dashboard and select the agent you want to connect. </Step> <Step title="Connect HubSpot"> Go to the **Integrations** tab, find **HubSpot**, and click **Connect**. <Frame> <img alt="Integrations page with the HubSpot card" /> </Frame> </Step> <Step title="Approve the requested scopes"> You will be redirected to HubSpot. Review the requested permissions and click **Connect app**. <Frame> <img alt="HubSpot OAuth page" /> </Frame> </Step> <Step title="Confirm the connection"> After approval, you will return to Chatbase and see HubSpot marked as **Connected**. </Step> </Steps> ## Configure the ticket action Create a ticket action so your agent can open tickets in HubSpot. <Steps> <Step title="Create a ticket action"> Go to **Build → Actions → Create action → Escalations** </Step> <Step title="Select HubSpot"> Choose **HubSpot** as the ticket platform, then fill in the ticket fields. </Step> <Step title="Save and test"> Save the action and run a test conversation to verify a ticket is created in HubSpot. </Step> </Steps> ## Use the integration Once connected, your agent can create tickets in HubSpot when the action is triggered. You can check out [the action guide here](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human). ## Disconnect HubSpot To disconnect, go to the **Integrations** tab, find HubSpot, and click **Disconnect**. ## Uninstall the app To uninstall Chatbase from HubSpot, follow HubSpot's [uninstall guide](https://knowledge.hubspot.com/integrations/connect-apps-to-hubspot#uninstall-an-app). # Instagram Source: https://chatbase.co/docs/user-guides/integrations/instagram Integrating Instagram with Chatbase allows your custom agent to communicate directly with customers via your Instagram pages. This integration also enables you to take over the conversation whenever you want and communicate with users yourself through Instagram's direct messaging. It provides a seamless and efficient way to handle inquiries and automate responses, while giving you the freedom to interact with your customers whenever you choose. This guide will walk you through the necessary steps to connect your agent to Instagram, ensuring smooth and effective customer interactions. <Info> Attachments are supported, allowing your agent to process them and respond based on their content. For more information, please refer to [this section](/docs/user-guides/chatbot/channels#attachments). </Info> <Note> You can connect more than one Instagram page: select multiple pages during setup, or add more later from the **Manage** page. </Note> ## Prerequisites You will need the following: * An Instagram [Professional Account](https://www.facebook.com/help/instagram/138925576505882). * A Facebook Page connected to that account. ## Connecting Instagram 1\. First navigate to the instagram page settings for you Professional Account, then under '**How others can interact with you**', click on **Messages and story replies** > **Message controls** > **Allow Access to Messages** 2\. Navigate to your dashboard, and pick an agent. 3\. Navigate to **Channels**. 4\. Click on **Connect** then **I understand**. <Frame> <img alt="image" /> </Frame> 5\. Click on **Continue.** <Frame> <img alt="image" /> </Frame> 6\. Login on **Get Started**. This will allow you to login to instagram and turn your account to a Professional Account if it is not already. <Frame> <img alt="image" /> </Frame> 7\. Login to instagram. <Frame> <img alt="image" /> </Frame> 8\. Choose the businesses affiliated with you Instagram page. If you have no business select **Opt in all current future businesses.** <Frame> <img alt="image" /> </Frame> 9\. Choose the Facebook Page(s) linked to your Instagram. <Frame> <img alt="image" /> </Frame> 10\. Select the Instagram page(s) you want to integrate. <Frame> <img alt="image" /> </Frame> 11\. Click save. <Frame> <img alt="image" /> </Frame> 12\. Your page should be integrated successfully, to see the integrated page click on **Manage.** <Frame> <img alt="image" /> </Frame> 13\. You can add more pages or delete existing ones from the manage page. <Frame> <img alt="image" /> </Frame> ## The Human Takeover Feature The human takeover feature allows you to takeover the conversation whenever you would like so you can respond to your users directly. It works on a conversation level meaning you would be able to choose a specific conversation from the dashboard and stop the agent from answering. <Note> some conversations may not have the human takeover icon, that happens when you delete a page from instagram's integration, you would still have access to your conversations in the chat logs, but since the integration was deleted you will not have access to the takeover feature. This will also happen if you delete a page and add it again. </Note> #### Enable Human Takeover for a Specific Conversation 1\. Navigate to Activity > Conversations 2\. in the **Conversations section** make sure to show only Instagram chats. 3\. Click the human takeover icon. 4\. You can click the icon again to restore access to the agent. <Frame> <img alt="image" /> </Frame> ## Connecting different agents to different pages With the Chatbase Instagram integration, you can connect different agents to various pages. This capability allows multiple agents to manage different Instagram pages, providing specialized interactions for each page. here are the steps to adding different agents to different pages. 1\. After connecting the first page(s) you should now have access to the **manage Instagram pages** integrations page. navigate to the agent you want to connect then **Channels > Manage.** 2\. Click the **Manage** button to navigate to the dashboard. If you want to connect another agent to an already connected page, click, then delete the page. 3\. Navigate to the agent you want to integrate to the page deleted, then reinitialize the integrations steps. > **Note:** if you deleted an agent it will be selected in the integration steps, don't deselect any agent you want to stay connected to the instagram or facebook integrations on chatbase as deselecting the agent will result in disabling that agent for chatbase. ## Troubleshooting Authentication Issues If you're having trouble completing the Instagram authentication flow, check the following: <AccordionGroup> <Accordion title="Off-Meta activities tracking is disabled"> If your Facebook account has **Off-Meta activities** set to "Don't track", this can block the Instagram authentication. To check this setting, go to your Facebook account settings and look under privacy settings for Off-Meta activities tracking, then enable it temporarily during the connection process. </Accordion> <Accordion title="Network redirect blocking authentication"> Some networks redirect Facebook from `facebook.com` to `web.facebook.com` during login, which can block the authentication flow. When this happens, the Instagram login popup completes successfully and closes, but the first Meta window doesn't move to the next step. If you experience this, try switching to a different network (such as mobile data or a different WiFi connection) and attempt the connection again. </Accordion> </AccordionGroup> <Info> You can now enable or disable Instagram integration without disconnecting it. Disabling pauses messages while keeping your setup intact, and you can re-enable anytime to resume. New chats will still appear in your Chatbase dashboard chat logs. </Info> Now this brings an end to the Instagram integration guide, for any further questions please do not hesitate to [contact us](https://www.chatbase.co/help). # Intercom Source: https://chatbase.co/docs/user-guides/integrations/intercom Integrating Intercom with Chatbase allows your custom agent to automatically escalate complex customer issues to your human support team by creating a ticket directly in Intercom. The AI agents generates an Intercom ticket that includes a clear summary of the user’s issue along with the relevant conversation context. This ensures that when a case requires human attention, your support team receives all the necessary information upfront, eliminating the need for customers to repeat themselves. The AI handles routine inquiries instantly, and when escalation is needed, Intercom becomes the system where your human agents step in to resolve the issue. This guide will walk you through the steps required to connect your agent to Intercom and configure automated ticket creation for smooth handoffs to your support team. ## Setup Guide Here's how to integrate a Chatbase agent with your Intercom account ### Step 1: Connect to Intercom * Login to your Chatbase dashboard * Select your Agent * Choose **Integrations** * Connect your Intercom to authorize access <Frame> <img alt="intercom" /> </Frame> *** ### Step 2: Create 'Escalations' action Now you're ready to configure your Escalations action to route tickets to Intercom. You can follow [this step-by-step guide](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human) to set up the action properly. *** That’s it! Your Intercom integration is now fully set up and ready to go. Whenever human intervention is required, your Chatbase agent will automatically create a ticket in Intercom with a summary of the user’s issue and relevant context, allowing your support team to step in and resolve the case seamlessly. # Messenger Source: https://chatbase.co/docs/user-guides/integrations/messenger Integrating Messenger with Chatbase allows your custom agent to communicate directly with customers via your Facebook pages. It also allows you to takeover the conversation whenever you want and communicate with users yourself through messenger. This provides a seamless and efficient way to handle inquiries and automate responses, while giving you the freedom to talk to your customers whenever you want. This guide will walk you through the necessary steps to connect your agent to Messenger for your facebook pages, ensuring smooth and effective customer interactions. <Info> Attachments are supported, allowing your agent to process them and respond based on their content. For more information, please refer to [this section](/docs/user-guides/chatbot/channels#attachments). </Info> <Note> You can connect more than one Facebook page: select multiple pages during setup, or add more later using **Connect a new Facebook page** in the Messenger dashboard. </Note> ## Connecting to Messenger 1\. First navigate to your dashboard, and pick an agent. 2\. Navigate to **Channels**. 3\. Click on 'Setup' if it is the first time you use the integration or manage, if you already connected pages before. 4\. If this is the first time you will be asked for permission to allow chatbase to use your information. **Note:** if you integrated some pages and would like to modify your selection pick the **Edit Previous Settings** option. <Frame> <img alt="image" /> </Frame> 5\. Choose which pages you would like to integrate the agent with by selecting the **Opt into current pages only** option, if you want to integrate all pages on your account select the **Opt all current pages** option. <Frame> <img alt="image" /> </Frame> 6\. Review the permissions and click save. <Frame> <img alt="image" /> </Frame> 7\. click on **done** and wait for the integration to connect, this should take only a few seconds. <Frame> <img alt="image" /> </Frame> 8\. Once connected you can manage you pages through the Messenger dashboard. It allows you to add new pages by clicking the **Connect a new Facebook page** button or delete existing pages using the three dots next to the page. ## Human Takeover Feature The human takeover feature allows you to takeover the chat whenever you would like and chat with users yourself! It works on a conversation level meaning you would be able to choose a specific conversation from the dashboard and stop the agent from answering that conversation. > **Note:** some conversations may not have the human takeover icon, that happens when you delete a page from the integrations dashboard, you would still have access to your conversations in the chat logs, but since the integration was deleted you will not have access to the takeover feature since this page's integration was deleted. This will also happen if you delete a page and add it again, so be careful when deleting pages from the messenger dashboard. #### Enable human takeover for a specific conversation 1\. Navigate to **Activity > Conversations** in the left sidebar. 2\. in the **Conversations section** make sure to show only messenger chats. 3\. Click the human **takeover icon** to the right of source. 4\. Click the icon to enable human takeover. <Frame> <img alt="image" /> </Frame> 5\. You can click the icon again to restore access to the agent. ## Connecting Different Agents to Different Pages With the Chatbase Messenger integration, you can connect different agents to various pages. This capability allows multiple agents to manage different Facebook pages, providing specialized interactions for each page. here are the steps to adding different agents to different pages. 1\. After connecting the first page(s) you should now have access to the **manage Facebook pages** integrations page. navigate to the agent you want to connect then **Channels > Manage.** <Frame> <img alt="image" /> </Frame> 2\. As shown in the screenshot below, you will find all the pages connected to the same agent. To connect a new page to the same agent, click on **Connect a new Facebook Page.** <Frame> <img alt="image" /> </Frame> 3\. Click on **Edit previous settings.** <Frame> <img alt="image" /> </Frame> 4\. A list of pages connected will be displayed, if you deleted an agent in **step 2** it will be selected here, don't deselect any agent you want to stay connected to chatbase as deselecting the agent will result in disabling that agent for chatbase. <Frame> <img alt="image" /> </Frame> 5\. Select the page you want to add the new agent to, and click the next button. if the page was already selected click the next button. <Frame> <img alt="image" /> </Frame> 6\. Click the save button. <Frame> <img alt="image" /> </Frame> 7\. The new page was added to the dashboard, and is now integrated with the new agent. <Info> You can now enable or disable Messenger integration without disconnecting it. Disabling pauses messages while keeping your setup intact, and you can re-enable anytime to resume. New chats will still appear in your Chatbase dashboard chat logs. </Info> # Salesforce Source: https://chatbase.co/docs/user-guides/integrations/salesforce Chatbase provides a quick and easy way to add an intelligent AI-powered agent to your Salesforce organization. In just a few minutes, you can make a Chatbase agent available across your company's Salesforce organization. The agent will be able to respond to users' cases and help the workspace provide round-the-clock automated support. ## Setup Guide Here's how to integrate a Chatbase agent into your Salesforce organization: ### Step 1: Access and Configure Your Chatbase Agent These steps assume that you have already created a Chatbase account and that you have a Chatbase agent already available for use. If you haven't yet, [<u>create a Chatbase account</u>](https://www.chatbase.co/auth/signup) and build your first AI agent. For example, you can create a company FAQ agent to handle common employee questions or build a recruiting assistant to screen candidates and schedule interviews. Get your agent ready before moving to the integration. **Read More:** [<u>A step-by-step guide to creating a Chatbase agent in just a few minutes</u>](/docs/user-guides/quick-start/your-first-agent). ### Step 2: Connect the Salesforce Integration 1. Once you have a Chatbase account and an agent set up, head over to your [dashboard](https://www.chatbase.co/dashboard/). On your dashboard, you'll find a list of all the agents you have created. Locate and click on the agent you wish to integrate with Salesforce. 2. Click on the **Channels** tab from the sidebar. 3. Find the **Salesforce** integration and click on **Connect**. 4. A new tab will open. It will ask you to login to your Salesforce account to authorize the integration. ### Step 3: Configure the Salesforce Integration 1. Once you have authorized the integration, click **Manage** on the Salesforce integration card to configure the integration. 2. You should see the following: * Select the Salesforce user that the agent will reply as. * Choose to either sync the agent’s Salesforce instructions with the global instructions or write a different instructions prompt. This is useful if you want to instruct the agent to escalate the case to a human agent in certain cases (e.g. escalate to a human agent if the user asks for a refund ...etc) and then click on **Save**. ### Step 4: Enable the **Generate Draft Response** feature Don’t want the agent to respond directly? You can also enable the **Generate Draft Response** feature. This allows you to review and edit the AI-generated response before sending it to your users. Once you have configured the integration, you will have the option to enable the **Generate Draft Response** with a single click by following the below steps: 1. Navigate to any of your cases and click on the gear icon at the top right then select "Edit Page" <Frame> <img alt="zendesk" /> </Frame> 2. Select the section where you want the button to appear (for example, the Highlights Panel). Then click “Add Action”, search for “Chatbase AI Draft Response”, and add it to the layout. <Frame> <img alt="zendesk" /> </Frame> The “Generate Draft Response” button should be available across all cases, allowing agents to easily generate responses when needed. ## Human Escalation via Salesforce Ticket Creation ### Step 1: Connect to Salesforce * Choose **Integrations** * Connect your Salesforce to authorize access ### Step 2: Create 'Escalations' action Now you're ready to configure your Escalations action to route tickets to Salesforce. You can follow [this step-by-step guide](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human) to set up the action properly. # Shopify Source: https://chatbase.co/docs/user-guides/integrations/shopify Connect your Shopify store to Chatbase and turn your AI agent into a powerful e-commerce assistant. Your agent will be able to help customers browse products, manage their cart, place orders, track and exchange orders, and update their account details—all through natural conversation. <Warning> **You do not need to add any embed code manually.** Once you install the Chatbase Shopify app — whether from Chatbase or the Shopify App Store — the chat bubble is automatically added to your store. You do not need to copy or paste any embed script into your theme code. </Warning> ## Integration Methods You can connect your Shopify store to Chatbase in two ways: | Feature | Via Chatbase (Recommended) | Via Shopify Marketplace | | ----------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------- | | Billing | Through Chatbase | Through Shopify | | Available Add-ons | Auto recharge credits, Extra message credits, Extra AI agents, Custom Domains, Remove 'Powered By Chatbase' | Auto recharge credits only | | Number of Agents | Multiple Agents (only a single agent connected to the Shopify store though) | Single agent per account | | Setup Location | Chatbase Dashboard | Shopify App Store | <Note> We recommend connecting via Chatbase for full access to all features and add-ons. </Note> ## Method 1: Connect via Chatbase (Recommended) This method gives you access to all Chatbase features and add-ons. ### Step 1: Set Up Your Chatbase Agent Before connecting Shopify, you'll need a Chatbase account and an agent ready to use. If you haven't set this up yet, [create a free Chatbase account](https://www.chatbase.co/auth/signup) and build your first AI agent. Make sure to make your agent public. **Read More:** [Create your first Chatbase agent in minutes](/docs/user-guides/quick-start/your-first-agent). ### Step 2: Find the Shopify Integration 1. Go to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent you want to connect to Shopify. 2. Click **Channels** from the sidebar and make sure the **Chat bubble** toggle is switched on. 3. Find the Shopify card in the **Channels** tab and click **Setup**. ### Step 3: Connect Your Store 1. Enter your Shopify store name, this is the subdomain of your myshopify.com URL. For example, if your store is at `mystore.myshopify.com,`enter`mystore`. 2. Click **Submit** to start the authorization process. 3. Shopify will ask you to authorize Chatbase. Review the requested permissions and click **Install**. 4) Once authorized, you'll be redirected back to Chatbase with a confirmation message. ### Step 4: Manage your integration 1. On the Channels page, click **Manage** on the Shopify card <Frame> <img alt="image" /> </Frame> 2. Choose the theme you wish to embed your widget in and open your Shopify theme editor to configure the widget's display settings. <Frame> <img alt="image" /> </Frame> *** ## Method 2: Connect via Shopify Marketplace Choose this method if you prefer to manage billing through Shopify. Keep in mind that this option has limited add-ons and only allows a single AI agent. ### Step 1: Install the Chatbase App 1. Go to the **Chatbase** app listing on the **Shopify App Store:** [https://apps.shopify.com/chatbase](https://apps.shopify.com/chatbase) 2. Click **Install**. 3. Review the permissions Chatbase requires and click **Install** to approve. <Frame> <img alt="image" /> </Frame> ### Step 2: Complete Setup 1. After installation, you'll be redirected to Chatbase onboarding process to finish setting up your account. 2. Follow the prompts to configure your agent. 3. Open your Shopify theme editor to configure the widget's display settings. <Warning> Accounts created through the Shopify Marketplace are limited to a single agent. For multiple AI agents or additional add-ons, use Method 1 instead. </Warning> *** ## Next Steps Once your Shopify store is connected, you'll need to enable **actions** that allow your agent to assist customers with product searches, order lookups, cart management, and more. <Frame> <img alt="Shopify Actions" /> </Frame> <Card icon="bolt" href="/docs/user-guides/chatbot/actions/shopify-actions" title="Shopify Actions"> Learn how to configure and use Shopify actions to help customers browse products, manage their cart, place and exchange orders, track deliveries, and update their account information. </Card> <iframe title="YouTube video player" /> # SIP Trunk (Phone) Source: https://chatbase.co/docs/user-guides/integrations/sip-trunk The **SIP trunk** phone method lets you connect an existing phone number from your own PBX, SIP provider, or GSM gateway to your Chatbase agent. You give the number a name, Chatbase generates a SIP URI, and you point your carrier or telephony provider at that URI. Inbound calls to the number are then answered by your AI agent using its configured voice, personality, and data sources. Use this method when you already own numbers with a carrier or run your own telephony (PBX / SIP provider / GSM gateway) and want to route their inbound calls to Chatbase. <Info> Make sure the phone channel is supported on your plan. Check the [pricing page](https://www.chatbase.co/pricing) for details. </Info> ## Before you start * An existing phone number on a PBX, SIP provider, or GSM gateway. * The ability to configure that trunk's inbound call routing (origination) to point at an external SIP URI. Where this setting lives depends on your carrier or telephony provider. * Make sure your Chatbase agent is set up with the voice settings you want callers to hear. You can configure voice, language, and greeting under your agent's **Settings > Voice** tab. ## Step 1: Open the Phone channel 1\. Navigate to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent you want to enable phone calls for. 2\. Click **Channels** in the sidebar and open the **Phone** channel. 3\. Go to the **Connections** tab. This is where you assign phone numbers to the agent. ## Step 2: Choose the SIP trunk method 1\. Under **Assign phone numbers**, click **Assign a new number**. 2\. In the **Assign a new number** dialog, choose **SIP trunk**: *"Connect an existing number from your PBX, SIP provider or GSM gateway."* 3\. Click **Continue**. <Info> If you don't have a Twilio account connected, **SIP trunk** is already selected for you. The **Twilio number** option only becomes available once a Twilio account is connected to the agent. </Info> ## Step 3: Enter the number details In the **Connect SIP trunk** dialog: 1\. Enter a **Name**, a friendly label to help you identify this number later (for example, "Main office trunk"). 2\. Enter the **Phone number** in E.164 format, including the country code (for example, `+15550000000`). 3\. Click **Connect SIP trunk**. ## Step 4: Copy the SIP URI Once the number is connected, the **SIP trunk created** dialog shows the SIP URI Chatbase generated for it. 1\. Click the **copy** icon to copy the SIP URI. It looks like this: ``` sip:+15550000000@sip.chatbase.co:5061;transport=tls ``` 2\. Click **Done**. <Info> Copy the SIP URI **exactly** as shown in the dialog, including the port and transport (for example, `;transport=tls`). You can copy it again at any time from the number's menu (see [Managing phone numbers](#managing-phone-numbers)). </Info> ## Step 5: Point your carrier at the SIP URI In your carrier, PBX, SIP provider, or GSM gateway configuration, route inbound calls for this number to the SIP URI you copied. This is usually configured as the trunk's **origination**, **outbound routing**, or **SIP destination** for the number. The exact steps vary by provider, but in general you will: 1\. Open your provider's trunk or number settings. 2\. Set the inbound call destination (origination URI / SIP endpoint) to the copied Chatbase SIP URI. 3\. Save the configuration and place a test call to the number. Once your provider is routing calls to the SIP URI, the number is ready to receive calls. In the **Connections** tab, the number appears as a card showing the phone number, a green **Active** badge, its friendly name, and a **SIP trunk** provider badge. ## How calls work Once a SIP trunk number is connected and enabled for an agent: * **Inbound calls** to that number are routed through your carrier to Chatbase and answered by the assigned agent. * The agent uses its configured **voice settings** (voice provider, model, and language) to speak with the caller. * The agent greets the caller with the **first message** defined in its voice settings. * The conversation follows the agent's instructions, knowledge base, and actions, just like a chat conversation. * Each call creates a conversation entry visible in your agent's **Activity > Conversations** with the source marked as **Phone**. ## Managing phone numbers ### Copy the SIP URI again If you need the SIP URI after closing the created dialog: 1\. On the **Connections** tab, find the number's card and click the **menu** icon (**⋯**). 2\. Select **Copy SIP URI**. The SIP URI is copied to your clipboard. ### Enable or disable a number Use the toggle on the number's card to enable or disable it. A disabled number stops receiving calls but stays connected to the agent, so you can re-enable it at any time without reconfiguring your carrier. ### Delete a number 1\. On the number's card, click the **menu** icon (**⋯**) and select **Delete**. 2\. Confirm in the dialog. <Info> Deleting a number permanently removes it from this AI Agent and detaches it from your SIP trunk. This can't be undone. The number itself remains with your carrier, and you can connect it again later using the same SIP URI. </Info> # Slack Source: https://chatbase.co/docs/user-guides/integrations/slack Chatbase provides a quick and easy way to add an intelligent AI-powered agent to your Slack workspace. Integrating Chatbase into Slack enables your workspace to instantly leverage a wealth of AI capabilities right within your Slack workspace. In just a few minutes, you can make a Chatbase agent available across your company's Slack channels to improve communication, boost productivity, and enhance the employee experience. The agent will be able to understand natural language and respond to common queries, resolve issues, look up information, and supercharge your Slack with round-the-clock automated support <Info> Attachments are supported, allowing your agent to process them and respond based on their content. For more information, please refer to [this section](/docs/user-guides/chatbot/channels#attachments). </Info> Here's how to integrate a Chatbase agent into your Slack workspace: ## Step 1: Access and Configure Your Chatbase Agent These steps assume that you have already created a Chatbase account and that you have a Chatbase agent already available for use. If you haven't yet, [<u>create a Chatbase account</u>](https://www.chatbase.co/auth/signup), subscribe to a plan then build your first AI agent. For example, you can create a company FAQ agent to handle common employee questions or build a recruiting assistant to screen candidates and schedule interviews. Get your agent ready before moving to the integration. **Read More:** [<u>A step-by-step guide to creating a Chatbase agent in just a few minutes</u>](/docs/user-guides/quick-start/your-first-agent). ## Step 2: Locate the Slack Integration 1. Once you have a Chatbase account and an agent set up, head over to your [dashboard](https://www.chatbase.co/dashboard/). On your dashboard, you'll find a list of all the agents you have created. Locate and click on the agent you wish to integrate with Slack. 2. Click **Integrations** in the left sidebar to see the list of integration options. 3. Click on **Connect** under the Slack card 4. Up next, you'll be asked to authorize Chatbase to access your Slack account and workspace. <Frame> <img alt="image" /> </Frame> 5. Scroll down and click on **Allow**. <Frame> <img alt="image" /> </Frame> 5. If all goes well, you should get a message saying "**Chatbase has been successfully added to your workspace.**" <Frame> <img alt="image" /> </Frame> 6. Click on **Open Slack** to launch your Slack workspace. 7. You'll be prompted to sign into your Slack workspace or select from a list of Slack workspaces you are currently signed into. Click open beside the target workspace. <Frame> <img alt="image" /> </Frame> ## Step 3: Deploy Slack Agent Once you've launched the Slack workspace that hosts your Chatbase agent, you can start setting up the agent as a Slack agent. To do this: 1. Open any channel on your Slack workspace, and type **@chatbase** followed by any question related to the purpose of your agent. This should trigger a prompt by Slack asking you to invite the agent to the channel or take no action. <Frame> <img alt="image" /> </Frame> 2. Click on **Invite Them**. The agent will then be available in the channel to answer any questions you might have. ## Step 4: Start Chatting! That's it! Your Chatbase agent is now integrated and ready to elevate workspace communication in your Slack workspace. Anytime you or any member of your workspace needs a question answered, just type @chatbase followed by your question, and your agent will respond. <Frame> <img alt="image" /> </Frame> *** ## Message Appearance in Slack Replies sent by your agent in Slack use the agent name and avatar configured in your Chat bubble settings. **How it works** If a custom name and avatar are set in your Chat bubble settings, those will be reflected in Slack messages. If no custom values are provided, default values will be used: * **Name:** Chatbase * **Avatar:** Chatbase logo ### Customize your agent's response appearance To change how your agent appears in Slack, update the profile picture and display name that are inside the Widget's settings in your Chatbase dashboard. <Frame> <img alt="image" /> </Frame> <Info> If the agent is mentioned inside a thread, it will reply within that same thread (instead of the main channel). Each Slack thread is treated as a separate conversation, allowing the agent to maintain more accurate context within each discussion. </Info> ## Ignore bot messages Under **Channels → Slack → Manage → Extra Settings**, tick **Ignore bots** and click **Save**. When enabled, your Chatbase agent will ignore messages sent by other Slack bots and only respond to messages from human users. This is useful if your Slack workspace contains automation bots or AI agents that post messages, as it prevents your Chatbase agent from replying to them and avoids unintended bot-to-bot loops or infinite conversations. *** ## Backstage Slack is one of the ways you can interact with Backstage, Chatbase's AI assistant for managing your agent. You can refer to [it's documentation](/docs/user-guides/chatbot/backstage) to learn more. *** Team members can ask your AI agent questions in any channel where it's added. It responds right in the conversation, so your whole workspace can get answers without leaving Slack. Integrating Chatbase into Slack unlocks game-changing possibilities. Your employees gain a productivity-boosting agent that enriches the collaboration experience. So go ahead, and give your new AI-powered workspace member a try! Intelligent automation is just a chat away. <Info> Incase you need your Chatbase agent to notify you on slack when a specific topic is triggered, check out [Slack notification action](https://www.chatbase.co/docs/user-guides/chatbot/actions/slack) </Info> # Stripe Source: https://chatbase.co/docs/user-guides/integrations/stripe Integrating Stripe with Chatbase allows your custom agent to access and display key billing information directly to users, enhancing customer support and transparency. With this integration, your agent can securely retrieve and show users their subscriptions and invoice history, streamlining common billing inquiries. This setup provides a fast, automated way to manage subscription details, while giving users a clear view of their payment status and history—all within the chat experience. This guide will walk you through the steps to connect Stripe to your Chatbase agent, enabling smooth and secure access to subscription and invoice data. ## Step 1: Access and Configure Your Chatbase AI agent These steps assume that you have already created a Chatbase account and that you have a Chatbase agent already available for use. If you haven't yet, [<u>create a free Chatbase account</u>](https://www.chatbase.co/auth/signup) and build your first AI agent. For example, you can create a company FAQ agent to handle common employee questions or build a recruiting assistant to screen candidates and schedule interviews. Get your agent ready before moving to the integration. **Read More:** [<u>A step-by-step guide to creating a Chatbase agent in just a few minutes</u>](/docs/user-guides/quick-start/your-first-agent). ## Step 2: Locate the Stripe Integration 1\. Once you have a Chatbase account and an agent set up, head over to your [dashboard](https://www.chatbase.co/dashboard/). On your dashboard, you'll find a list of all the agents you have created. Locate and click on the agent you wish to integrate with Stripe. 2\. Click **Integrations** in the left sidebar to see the list of integration options. 3\. Click on **Connect** under the Stripe card <Frame> <img alt="Integrations - Connect Stripe" /> </Frame> 4\. Up next, you'll be asked to authorize Chatbase to access your Stripe account. <Frame> <img alt="image" /> </Frame> 5\. After clicking on **Continue** you will be asked to choose the account you want to connect to. <Frame> <img alt="image" /> </Frame> 5\. If all goes well, you should be redirected back to Chatbase with a message saying "**Stripe integration successful.**" 6\. Add Stripe accounts to your customers' contacts. For more information, see [Contacts](../chatbot/contacts/uploading-contacts). ## Step 3: Start Chatting! That's it! Your Chatbase agent is now integrated and ready to provide superb customer support. # Sunshine Source: https://chatbase.co/docs/user-guides/integrations/sunshine As part of Zendesk, Sunshine Conversations serves as a live chat solution. This integration centralizes communication, enabling support workspaces to efficiently track and resolve customer inquiries, ultimately improving response times and customer satisfaction. Chatbase offers an integration with Sunshine Conversations in order to give the agent the ability to connect the user to a live chat agent for fixing problems that require human interaction with the user. > **Note** This requires your Zendesk Account to have a minimum Suite plan of **Professional** or above ## Step 1: Sign Into Your Zendesk Account 1. Sign in to your Zendesk Account as an Admin and navigate to the **Admin Center** 2. Navigate to **Apps and integrations** > **APIs** > **Conversations API** 3. Click on **Create API Key**, enter **Chatbase** as the name and press **Next** 4. Copy the **App ID**, **Key ID** and **Secret key** displayed <Frame> <img alt="image" /> </Frame> ## Step 2: Set up the Sunshine Integration 1\. Navigate to your Chatbase [dashboard](https://www.chatbase.co/dashboard/). 2\. You should see a list of agents, click the agent you wish to enable live chat for. 3\. Navigate to **Integrations**. Make sure that **Zendesk** is connected before you attempt to connect **Sunshine**. 4\. Enter the copied **App ID**, **Key ID** and **Secret key**, and press **Submit**. ## Step 3: Enable Multi-Conversations Option in Zendesk We need to enable the multi-conversations option in Zendesk to allow for the same user to open multiple tickets, one per conversation, at the same time. Since the same user can have multiple conversations opened at the same time, then this option must be enabled for a smooth experience. 1\. Sign in to your Zendesk Account as an Admin and navigate to the **Admin Center** 2\. Click **Channels** in the sidebar, then select **Messaging and social** > **Messaging**. 3\. At the top of the page, click **Manage settings**. 4\. Under Web Widget and Mobile SDKs, expand **Multi-conversations**. 5\. Click **Set up multi-conversations**. 6\. Click **Turn on multi-conversations for your account**, then select the channels on which you want to offer multi-conversations, then click **Save**. For more information regarding multi-conversations for messaging, visit [Understanding multi-conversations for messaging](https://support.zendesk.com/hc/en-us/articles/8195486407706-Understanding-multi-conversations-for-messaging). ## Step 4: Enable End Messaging Sessions in Zendesk To allow agents to end conversations when issues are resolved, you'll need to enable the messaging session end feature in Zendesk. 1\. Sign in to your Zendesk Account as an Admin and navigate to the **Admin Center** 2\. Click **Channels** in the sidebar, then select **Messaging and social** > **Messaging**. 3\. At the top of the page, click **Manage settings**. 4\. Under Advanced, expand **Ending sessions**. 5\. Select **Agents can end messaging sessions at any time**. 6\. Click **Save settings**. For more information regarding ending messaging sessions, visit [About ending messaging sessions](https://support.zendesk.com/hc/en-us/articles/8009788438042-About-ending-messaging-sessions). ## Step 5: Add the User Identification To use the Sunshine integration, you must identify your user. You can find the guide [here](https://www.chatbase.co/docs/developer-guides/identity-verification). ## Step 6: Enable the Live Chat Action 1\. Navigate to your Chatbase [dashboard](https://www.chatbase.co/dashboard/). 2\. Choose the agent you have integrated with Sunshine Conversations. 3\. Navigate to **Build** > **Actions**. 4\. Click on **Create Action** then select the **Sunshine live chat** 5\. Customize the **When to use**, then save and enable the action. # Twilio (Phone) Source: https://chatbase.co/docs/user-guides/integrations/twilio Integrating Twilio with Chatbase allows your AI agent to handle inbound phone calls. Your AI agent will answer calls using its configured voice, personality, and data sources. In just a few minutes, you can connect your Twilio account, import your phone numbers, and assign them to your agent. <Info> Don't use Twilio? You can also connect an existing number from your own PBX, SIP provider, or GSM gateway using the [SIP trunk method](/docs/user-guides/integrations/sip-trunk). </Info> <Info> Make sure the phone channel is supported on your plan. Check the [pricing page](https://www.chatbase.co/pricing) for details. You will also need a [Twilio account](https://www.twilio.com/try-twilio) with at least one phone number to get started. </Info> ## Before you start * You need a Twilio account. If you don't have one, [sign up for Twilio](https://www.twilio.com/try-twilio). * You need at least one phone number purchased in your Twilio account. * Your Twilio **Account SID** and **Auth Token** are available on your [Twilio Console dashboard](https://console.twilio.com/). * Make sure your Chatbase agent is set up with the voice settings you want callers to hear. You can configure voice, language, and greeting under your agent's **Settings > Voice** tab. ## Step 1: Connect your Twilio account 1\. Navigate to your [Chatbase dashboard](https://www.chatbase.co/dashboard/) and select the agent you want to enable phone calls for. 2\. Go to the **Integrations** tab in the left sidebar. 3\. Find the **Twilio** card and click **Connect**. 4\. Enter your **Account SID** and **Auth Token** from the [Twilio Console](https://console.twilio.com/). * **Account SID** starts with `AC` followed by 32 characters (e.g., `ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`). * **Auth Token** is a 32-character string. 5\. Click **Connect Twilio**. Chatbase will validate your credentials against the Twilio API. Once connected, your Account SID will be displayed in a read-only field. <Info> Your Twilio credentials are encrypted before being stored. Chatbase never displays your Auth Token after the initial connection. Each agent has its own Twilio connection — you can use the same or different Twilio accounts for different agents. </Info> ## Step 2: Import phone numbers Once your Twilio account is connected to this agent, you can import your phone numbers. 1\. On the same Twilio integration page, click **Import from Twilio**. 2\. A dialog will show all available phone numbers from your Twilio account. 3\. Select the numbers you want to import. For each number, you can optionally set a **friendly name** to help you identify it later (e.g., "Sales line" or "Support US"). 4\. Click **Import selected**. Chatbase will automatically configure a SIP trunk on your Twilio account and register each number for call routing. Imported numbers will appear in the phone numbers table with their status shown as **Inactive** until you enable them from the Channels page. <Info> Each phone number can only be imported to one agent at a time. Numbers that are already imported will appear grayed out in the import dialog. </Info> ## Step 3: Enable a phone number After importing, you need to enable the number to start receiving calls. 1\. Navigate to your agent's **Channels** page. 2\. Find the **Phone** channel card and click **Setup** (or **Manage** if you have already enabled numbers). 3\. Click **Assign number**. 4\. Select one or more numbers from the list of imported numbers. 5\. Click **Assign selected**. The enabled numbers will appear as cards on the page showing the phone number, a green **Active** badge, and the friendly name if one was set. Your agent is now ready to receive calls on those numbers. ## How calls work Once a phone number is enabled for an agent: * **Inbound calls** to that number are automatically routed to the assigned agent. * The agent uses its configured **voice settings** (voice provider, model, and language) to speak with the caller. * The agent greets the caller with the **first message** defined in its voice settings. * The conversation follows the agent's instructions, knowledge base, and actions, just like a chat conversation. * Each call creates a conversation entry visible in your agent's **Activity > Conversations** with the source marked as **Phone**. ## Managing phone numbers ### Disable a number 1\. Go to your agent's **Channels** page and click **Manage** on the Phone channel card. 2\. Click the menu icon on the number card and select **Unassign**. The number will stop receiving calls but remains imported to this agent. You can re-enable it at any time from the same page. ### Remove a number from the agent 1\. Go to your agent's **Integrations** tab and click **Manage** on the Twilio card. 2\. In the phone numbers table, click the menu icon next to the number and select **Remove**. The number will be removed from this agent but will remain in your Twilio account. You can import it again at any time. ### Disconnect Twilio 1\. Go to your agent's **Integrations** tab and click **Manage** on the Twilio card. 2\. Click **Disconnect** in the danger zone at the bottom. <Info> Disconnecting Twilio from an agent will remove all imported phone numbers and delete the SIP trunk from your Twilio account. This action cannot be undone. Your phone numbers will remain in your Twilio account, but you will need to reconnect and re-import them if you want to use them again with this agent. </Info> # Vercel Source: https://chatbase.co/docs/user-guides/integrations/vercel Install Chatbase AI Agent directly from the Vercel Marketplace with one-click integration The Chatbase Vercel integration allows you to add an AI-powered agent to your Vercel-hosted applications directly from the Vercel Marketplace. No code required—just a few clicks to get started. ## Overview The Chatbase native integration for Vercel provides a seamless way to add conversational AI to your web applications. With this integration, you can: * Install Chatbase directly from the Vercel Marketplace * Create and configure your AI agent without leaving Vercel * Automatically inject environment variables into your project * Deploy AI-powered chat experiences instantly * Scale automatically with Vercel's global edge network <Info> The Chatbase integration works seamlessly with all frameworks supported by Vercel, including Next.js, React, Vue.js, SvelteKit, and static HTML sites. </Info> ## Prerequisites Before you begin, ensure you have: * A Vercel account ([Sign up for free](https://vercel.com/signup)) * An existing Vercel project or [use our template here](https://github.com/Chatbase-co/nextjs-marketplace-template) ## Installation Guide Follow these steps to install and configure Chatbase from the Vercel Marketplace: ### Step 1: Install Chatbase from Vercel Marketplace <Steps> <Step title="Navigate to Vercel Marketplace"> 1. Log into your [Vercel Dashboard](https://vercel.com/dashboard) 2. Click on the **Marketplace** tab in the top navigation 3. In the search bar, type **"Chatbase"** 4. Click on the Chatbase integration from the search results <Tip> You can also access the Chatbase integration directly at [vercel.com/integrations/chatbase](https://vercel.com/integrations/chatbase) </Tip> </Step> <Step title="Click Install"> On the Chatbase integration page, click the **Install** button to begin the installation process. <Check> You'll be redirected to the Chatbase configuration wizard. </Check> </Step> </Steps> ### Step 2: Configure Your Agent <Steps> <Step title="Choose Agent Preset"> Select the preset that best matches your use case: * **AI Agent** - A general-purpose intelligent assistant * **Customer Support Agent** - Optimized for answering customer questions and providing support * **Sales Agent** - Helps guide customers through product selection and purchase decisions <Info> You can customize any preset later. This just provides a starting point for your agent's behavior. </Info> </Step> <Step title="Choose Agent Preset"> Select the preset that best matches your use case: * **AI Agent** - A general-purpose intelligent assistant * **Customer Support Agent** - Optimized for answering customer questions and providing support * **Sales Agent** - Helps guide customers through product selection and purchase decisions <Info> You can customize any preset later. This just provides a starting point for your agent's behavior. </Info> </Step> <Step title="Select AI Model"> * If you're on a paid plan, you can select an AI model. * If you're on a free plan, it will use the default model which you can change from your Chatbase dashboard. <Tip> You can change both the personality, AI model, and styles anytime from your Chatbase dashboard. </Tip> </Step> </Steps> ### Step 3: Choose Your Subscription Plan <Steps> <Step title="Select a Plan"> Choose the plan that fits your needs: * **Free** - Perfect for testing and small projects (limited messages/month) * **Hobby** - For personal projects and small websites * **Standard** - For growing businesses * **Pro** - For high-traffic applications Review the features and message limits for each plan before selecting. </Step> <Step title="Select a Plan"> Choose the plan that fits your needs: * **Free** - Perfect for testing and small projects (limited messages/month) * **Hobby** - For personal projects and small websites * **Standard** - For growing businesses * **Pro** - For high-traffic applications Review the features and message limits for each plan before selecting. </Step> <Step title="Complete Billing"> After selecting your plan: 1. An invoice will be sent to your registered email address 2. Follow the payment link in the invoice to complete your subscription 3. Your plan will become active once the invoice is paid <Warning> Your selected plan will only take effect after the invoice is paid. Until then, you'll have access to the free tier features. </Warning> <Info> Billing is handled securely through Vercel's payment system. You can manage your subscription from the Vercel dashboard. </Info> </Step> </Steps> ### Step 4: Name Your Agent <Steps> <Step title="Enter Agent Name"> Provide a descriptive name for your agent. This name will: * Appear in your Chatbase dashboard * Help you identify the agent if you create multiple agents * Be visible in your Vercel integration settings **Examples:** * "Website Support Agent" * "Product Assistant" * "Sales Lead Qualifier" * "Documentation Helper" <Tip> Choose a name that clearly describes the agent's purpose, especially if you plan to create multiple agents for different projects. </Tip> </Step> </Steps> ### Step 5: Customize in Chatbase Dashboard <Steps> <Step title="Access Your Chatbase Dashboard"> After creating your agent, you'll be provided with a link to access your Chatbase dashboard. Alternatively, visit [chatbase.co/dashboard](https://www.chatbase.co/dashboard) and log in with your account. </Step> <Step title="Customize Appearance (Optional)"> Customize Appearance from [here](/docs/user-guides/chatbot/channels#chat-bubble-display) </Step> <Step title="Add Training Data Sources (Optional)"> Follow the steps [here](https://www.chatbase.co/docs/user-guides/chatbot/data-sources) <Info> The more relevant training data you provide, the better your agent will respond to user queries. </Info> </Step> <Step title="Configure Actions (Optional)"> Add interactive capabilities to your agent: * **Lead Collection** - Capture visitor information * **Calendar Booking** - Integrate with Calendly or Cal.com * **Stripe Payments** - Accept payments directly in chat * **Custom Actions** - Create custom workflows and API calls * **Web Search** - Allow the agent to search the internet for current information [Learn more about Actions →](/docs/user-guides/chatbot/actions/actions-overview) </Step> <Step title="Set Up Integrations (Optional)"> Connect your agent with other tools: * **Slack** - Send notifications to Slack channels * **Zapier** - Connect with 5,000+ apps * **Webhooks** - Send data to your own endpoints * **CRM systems** - Sync contacts with your CRM [Explore all integrations →](/docs/user-guides/integrations/zapier) </Step> </Steps> ### Step 6: Connect to Your Vercel Project <Steps> <Step title="Return to Vercel"> Go back to your Vercel dashboard where you initiated the Chatbase installation. </Step> <Step title="Click Connect Project"> 1. In the Chatbase integration settings, click **Connect Project** 2. A dialog will appear showing all your Vercel projects 3. Select the project(s) where you want to add the Chatbase agent <Info> You can connect the same agent to multiple projects if needed. </Info> </Step> <Step title="Confirm Connection"> Click **Connect** to finalize the connection. Vercel will automatically inject the environment variables into your selected project(s). <Check> Your environment variables are now configured and ready to use! </Check> </Step> </Steps> ### Step 7: Redeploy Your Project <Steps> <Step title="Trigger a New Deployment"> For the environment variables to take effect, you need to redeploy your project: 1. Go to your project in the Vercel dashboard 2. Click on the **Deployments** tab 3. Click the three-dot menu (⋯) on your latest deployment 4. Select **Redeploy** <Info> Environment variables are injected at **build time**, not runtime. This is why a redeployment is necessary. </Info> </Step> </Steps> ### Step 8: Verify Installation <Steps> <Step title="Visit Your Deployed Project"> Once the deployment is complete: 1. Click the **Visit** button in your Vercel dashboard 2. Or navigate directly to your project's URL Your Chatbase chat bubble should now appear on your website, typically in the bottom-right corner. </Step> <Step title="Test the Chat bubble"> Verify that your agent is working correctly: 1. **Look for the chat bubble** - Should be visible in the corner of your page 2. **Click to open** - The chat interface should expand 3. **Send a test message** - Try asking a question related to your training data 4. **Verify response** - The AI should respond based on the sources you configured <Check> If the agent responds appropriately to your test questions, your integration is successful! </Check> </Step> </Steps> ## Managing Your Integration ### Updating Your Agent Changes made in your Chatbase dashboard apply instantly without requiring redeployment: * **Appearance customization** - Colors, position, styling * **Training data updates** - Add or remove sources * **Response behavior** - Adjust personality and model * **Actions and integrations** - Enable or disable features <Tip> Only environment variable changes require redeployment. All agents configuration changes are live immediately. </Tip> ## Advanced Features ### Multiple Projects You can connect the same Chatbase agent to multiple Vercel projects: 1. Go to your Vercel dashboard 2. Navigate to **Integrations** → **Chatbase** 3. Click **Manage** on your Chatbase integration 4. Click **Add Project** to connect additional projects <Tip> This is useful if you have multiple frontends (web app, marketing site, documentation) that should use the same agent. </Tip> ### Different Agents for Different Environments To use different agents for production, preview, and development environments: 1. Create separate agents in Chatbase for each environment 2. In Vercel, manually override environment variables: * Go to **Settings** → **Environment Variables** * Set different `NEXT_PUBLIC_CHATBOT_ID` values for Production, Preview, and Development This allows you to: * Test changes without affecting production conversations * Maintain separate training data per environment * Monitor environment-specific analytics separately ### Managing Your Subscription Plan To change your Chatbase subscription: 1. Go to your Vercel dashboard 2. Navigate to **Integrations** → **Chatbase** → **Settings** 3. Click **Change Plan** 4. Select your desired plan option #### Upgrading Your Plan Choose a higher-tier plan and complete the invoice payment. <Check> Plan upgrades take effect **immediately** once the invoice is paid. You'll have instant access to all the features and increased limits of your new plan. </Check> **What happens when you upgrade:** * Your new plan features activate right away * Increased message limits are available immediately * Any prorated charges are calculated automatically * Your billing cycle continues with the new plan pricing #### Downgrading Your Plan Choose a lower-tier plan to switch to. <Info> Plan downgrades take effect at the **end of your current billing period**. This ensures you don't lose access to features you've already paid for. </Info> **What happens when you downgrade:** * You continue to enjoy your current plan features until period end * The new plan activates automatically when your billing cycle renews * You'll receive a confirmation email with the effective date <Tip> Downgrading at period end means you get full value for what you've paid. Use the remaining time to adjust to the new plan's limits or export any data if needed. </Tip> #### Canceling Your Subscription Select the **Free** plan and confirm your cancellation. <Warning> Subscription cancellations also take effect at the **end of your current billing period**. Your agent will continue working until then, ensuring you receive full value for your payment. </Warning> **What happens when you cancel:** * Your agent remains active until the end of your billing period * You retain access to all current plan features until period end * No future charges will be processed * You can resubscribe at any time if you change your mind * After cancellation takes effect, your plan reverts to the Free tier <Info> You can undo a cancellation before the period end by selecting a paid plan again from the same settings page. </Info> ## Uninstalling the Integration If you need to remove the Chatbase integration: 1. Go to your Vercel dashboard 2. Navigate to **Integrations** → **Chatbase** 3. Click **Manage** → **Remove Integration** 4. Confirm removal <Warning> Removing the integration will immediately stop the agent from appearing on your Vercel deployments. Make sure to redeploy after removing environment variables. </Warning> ## Troubleshooting <AccordionGroup> <Accordion title="Chat bubble not appearing after installation"> **Common solutions:** 1. **Redeploy your project** * Environment variables are injected at build time * Go to **Deployments** → Select latest → **Redeploy** 2. **Verify environment variables** * Check **Settings** → **Environment Variables** * Ensure `NEXT_PUBLIC_CHATBOT_ID` is present * Verify they're enabled for all environments 3. **Check browser console** * Open DevTools (F12) * Look for any JavaScript errors related to Chatbase * Verify the embed script is loading successfully 4. **Clear browser cache** * Hard refresh: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac) * Try in an incognito/private window </Accordion> <Accordion title="Integration installation failed"> **Solution steps:** 1. **Remove and reinstall** * Go to Vercel → **Integrations** → **Chatbase** * Click **Manage** → **Remove Integration** * Reinstall from the Vercel Marketplace 2. **Check permissions** * Ensure you have admin access to the Vercel team/project * Verify your Vercel account is properly authenticated 3. **Contact support** * If issues persist, contact [Chatbase Support](https://chatbase.co/help) * Provide your Vercel project ID and integration details </Accordion> <Accordion title="Environment variables not taking effect"> **Solution:** Environment variables require redeployment to take effect: 1. Make your environment variable changes 2. Trigger a new deployment: * Option A: Push a commit to your Git repository * Option B: Manual redeploy from Vercel dashboard 3. Clear browser cache and test </Accordion> <Accordion title="Plan billing issues"> **Common scenarios:** 1. **Invoice not received** * Check your email spam/junk folder * Verify email address in Vercel account settings * Contact Vercel support for invoice resend 2. **Plan not activating after payment** * Allow up to 10 minutes for payment processing * Check payment status in Vercel billing dashboard * Contact Vercel support if payment is confirmed but plan isn't active 3. **Subscription changes** * Upgrades activate immediately after payment * Downgrades and cancellations take effect at the end of current billing period * You retain current plan features until period end for downgrades/cancellations </Accordion> </AccordionGroup> ## Optimizing Response Quality For the best agent performance: 1. **Add comprehensive training data** - More sources = better responses 2. **Test regularly** - Use the Chatbase playground to verify quality 3. **Monitor conversations** - Review chat logs in Chatbase dashboard 4. **Iterate on sources** - Remove irrelevant content, add missing information 5. **Use custom actions** - Add interactive features for complex workflows [Learn more about Response Quality →](/docs/user-guides/quick-start/response-quality) ## Next Steps Now that your Chatbase agent is live on Vercel, explore these features to enhance your implementation: <CardGroup> <Card title="Add Training Data Sources" icon="book" href="/docs/user-guides/chatbot/data-sources"> Upload documents, connect websites, and add Q\&A pairs </Card> <Card title="Customize Appearance" icon="palette" href="/docs/user-guides/chatbot/settings"> Match your brand colors and style </Card> <Card title="Enable Actions" icon="bolt" href="/docs/user-guides/chatbot/actions/actions-overview"> Add lead collection, bookings, and custom workflows </Card> <Card title="Monitor Analytics" icon="chart-line" href="/docs/user-guides/chatbot/analytics"> Track conversations and measure performance </Card> <Card title="Connect More Apps" icon="plug" href="/docs/user-guides/integrations/zapier"> Integrate with Slack, CRMs, and 5,000+ apps </Card> <Card title="Developer Features" icon="code" href="/docs/developer-guides/overview"> Explore API, webhooks, and advanced integrations </Card> </CardGroup> ## Additional Resources <AccordionGroup> <Accordion title="Vercel Documentation"> * [Vercel Integrations Overview](https://vercel.com/docs/integrations) * [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) * [Vercel Deployments](https://vercel.com/docs/concepts/deployments/overview) * [Vercel Analytics](https://vercel.com/docs/analytics) </Accordion> <Accordion title="Chatbase Documentation"> * [Getting Started Guide](/docs/user-guides/quick-start/introduction) * [Your First Agent](/docs/user-guides/quick-start/your-first-agent) * [Best Practices](/docs/user-guides/quick-start/best-practices) * [Response Quality Tips](/docs/user-guides/quick-start/response-quality) * [JavaScript Embed Options](/docs/developer-guides/javascript-embed) </Accordion> <Accordion title="Support & Community"> Need help? We're here for you: * **Chatbase Help Center:** [chatbase.co/help](https://chatbase.co/help) * **Vercel Support:** [vercel.com/support](https://vercel.com/support) * **Email Support:** Contact us through your dashboard * **Documentation:** Browse our comprehensive guides <Tip> When contacting support, include your Vercel project ID and Chatbase agent ID for faster assistance. </Tip> </Accordion> </AccordionGroup> # ViaSocket Source: https://chatbase.co/docs/user-guides/integrations/viasocket Integrating Chatbase with viaSocket opens up endless opportunities to connect your Agent with your favorite apps and tools—no coding required. Simply drag and drop to automate tasks across your apps. ## Key Automation Ideas * **Lead Generation:** Automatically capture leads through form submissions and add them to your CRM (e.g., HubSpot, Salesforce) for follow-up. * **Customer Support:** Set up an automation to trigger support tickets in systems like Zendesk or Freshdesk when your Agent receives a customer inquiry. * **Email Campaigns:** Automatically add contacts from Agent to your email marketing platforms like Mailchimp or ActiveCampaign, then send personalized follow-up emails. * **Multi-Platform Support:** Deploy AI agents across various platforms, including websites, mobile apps, and messaging services, to reach users wherever they are. * **Social Media Management:** Trigger social media updates or create posts based on user interactions with your Agent. * **E-commerce Notifications:** Automate stock updates, order confirmations, or promotional notifications to customers based on their interactions with your Agent. ## Integrate your Agent with viaSocket Learn how to receive leads from your Agent, process them, and automatically add them to a Google Docs document using viaSocket. ### Step 1: Set Up a Trigger in viaSocket 1. Sign in to your viaSocket account. 2. Click on **Create New Flow** on the top left corner of the viaSocket app homepage. <Frame> <img alt="image" /> </Frame> 3. In the Flow editor, click on **Select Trigger**. <Frame> <img alt="image" /> </Frame> 4. Select **Webhook** as the trigger then copy the generated Webhook URL. <Frame> <img alt="image" /> </Frame> ### Step 2: Configure the Trigger in Chatbase 1. Navigate to your Chatbase [dashboard](https://www.chatbase.co/dashboard/). 2. You should see a list of Agents, click the Agent you wish to integrate with viaSocket. 3. Click **Settings** and select **Webhooks**. 4. Select the events you want to trigger, then paste the copied Webhook URL into the **Endpoint** field, then **Create Webhook**. <Frame> <img alt="image" /> </Frame> ### Step 3: Set Up an Action to Automate Tasks 1. Go back to the viaSocket Flow Builder and click on **Select Action**. <Frame> <img alt="image" /> </Frame> 2. Choose the **Google Docs** action: *Append Text to Document*. <Frame> <img alt="image" /> </Frame> 3. Establish a connection and configure your action with the required details. <Frame> <img alt="image" /> </Frame> ### Step 4: Test and Publish the Flow <Frame> <img alt="image" /> </Frame> With this setup, every time a lead is captured by your Agent on your website, it will be automatically added to your designated Google Docs file. # Webflow Source: https://chatbase.co/docs/user-guides/integrations/webflow ## Step 1: Sign Into Your Chatbase Account and Set Up Your AI Agent 1. Sign up for a free Chatbase account if you don't already have one. 2. Log into your Chatbase account and navigate to the agent creation page. 3. Provide training data for your new agent by uploading sources like text snippets, documents, website content, or Q\&A pairs. 4. Train and test your agent in Chatbase until it responds accurately to queries. <Info> New to Chatbase? Check out [Your First Agent](/docs/user-guides/quick-start/your-first-agent) to get started with the embed script first. </Info> ## Step 2: Copy Your AI Agent Embed Code Once you've set up and tested your Chatbase agent, you'll need the embed code to display the agent widget on your website. To do this: 1\. Go to the [dashboard](https://www.chatbase.co/dashboard/) of your Chatbase account. 2\. You should see a list of agents, click the agent you wish to integrate into your Webflow website. 3\. Click **Channels** in the left sidebar, then click **Manage** on the **Chat bubble** card (or **Setup**, if you haven't configured it yet). 4\. Click on **Deploy** and select the **Website iFrame** embed type. Click **Copy** to copy the provided HTML code. <Frame> <img alt="Copy Iframe" /> </Frame> <Frame> <img alt="Copy Iframe" /> </Frame> ## Step 3: Set Up a Container to Display Your Chatbase Agent Widget  Before adding the embed code to your Webflow site, you will need to create a container to display the widget. This will ensure that the widget is displayed in the correct place on your website and doesn't extend the entire width of the page. 1\. To create a container, on Webflow, log into your Webflow account and go to your dashboard. 2\. On your Webflow dashboard, you'll find a list of all your website projects, hover on the website you want to add the agent to and click on **Open Designer**. <Frame> <img alt="image" /> </Frame> 3\. On the designer page, click on the file icon (**Pages**) on the top left corner of the webflow site designer and select the page you want to embed the agent. <Frame> <img alt="image" /> </Frame> 4\. Once you've selected the page, click the Plus button (**Add elements**) on the top left corner of the designer screen, and a list of available elements should come up. 5\. Drag the **Section** element to the portion of the page you want to embed your agent. 6\. Drag a **Container** element unto the **Section.** 7\. Drag a **Div** element unto the Container element and set the size of the Div element to ensure that the agent will be contained within the Div and does not span the entire width of the page. <Frame> <img alt="image" /> </Frame> 8\. Now, scroll down down the list of elements and drag the **Embed** element unto the Div you added on the Webflow canvas. <Frame> <img alt="image" /> </Frame> 9\. Select and double-click the Embed element to reveal the HTML Embed code editor. 10\. Paste the Chatbase agent embed code from Step 2 above and click **Save & Close**. <Frame> <img alt="image" /> </Frame> If all goes well, you should see a preview of the agent on the live preview of your Webflow website right inside the designer. <Frame> <img alt="image" /> </Frame> After completing these steps, your agent should be ready to serve your website visitors! If you are having difficulties with managing the dimension of your Embed and agent element, it is a common problem. Webflow components take a bit of getting used to. You can follow this [official Webflow documentation on the Embed element](https://university.webflow.com/lesson/custom-code-embed?topics=elements) to learn more about embedding a third-party tool like Chatbase agent on a Webflow website. <Note> You can customize the appearance and colors of your agent on your Chatbase dashboard. To do this, go to your **dashboard**, choose an agent, click **Channels** in the left sidebar, click **Manage** on the **Chat bubble** card, then open the **Display** tab to edit Content, Capabilities, Colors, Floating bubble, and Localization. </Note> # Weebly Source: https://chatbase.co/docs/user-guides/integrations/weebly ## Step 1: Sign Into Your Chatbase Account and Set up your agent To embed your Chatbase agent into your Weebly website, first sign in to your Chatbase account. If you don't have an account yet, you can create one for free. Once signed in, you can set up your agent in Chatbase by uploading data sources like files, text snippets, websites, or Q\&A pairs that the agent can learn from. Here is a [<u>step-by-step guide for setting up your Chatbase agent</u>](/docs/user-guides/quick-start/your-first-agent). ## Step 2: Generate and Copy the agent's Embed Code 1\. After configuring your agent, navigate to your [**dashboard**](https://www.chatbase.co/dashboard/) page and select the specific agent you wish to embed. 2\. Click **Channels** in the left sidebar, then click **Manage** on the **Chat bubble** card (or **Setup**, if you haven't configured it yet). 3\. Click on **Deploy** and select the **iFrame** embed type. Scroll down and Click **Copy** to copy the provided HTML code. <Frame> <img alt="Deploy" /> </Frame> <Frame> <img alt="Copy Iframe" /> </Frame> ## Step 3: Add Embed Code to Your Weebly Website To add a Chatbase agent to your Weebly website: 1\. Sign in to your Weebly account and head to the **Edit site** page. 2\. Select the page to edit. 3\. From the Basic toolbar on the left side of the editing page, locate the widget that says **Embed Code**. <Frame> <img alt="image" /> </Frame> 4\. Drag the **Embed Code** element to wherever you want your agent to appear on the page. <Frame> <img alt="image" /> </Frame> 5\. You should then see a text element that says **Click to set custom HTML** where the Embed code widget was placed. Click on the text, and then click on **Edit Custom HTML.** 6\. Paste your Chatbase embed code into the custom HTML box. <Frame> <img alt="image" /> </Frame> 7\. Click outside the element and your agent should appear on the page. <Frame> <img alt="image" /> </Frame> Congratulations, your agent is now live on your Weebly website! <Note> You can customize the appearance and colors of your agent on your Chatbase dashboard. To do this, go to your **dashboard**, choose an agent, click **Channels** in the left sidebar, click **Manage** on the **Chat bubble** card, then open the **Display** tab to edit Content, Capabilities, Colors, Floating bubble, and Localization. </Note> # WhatsApp Source: https://chatbase.co/docs/user-guides/integrations/whatsapp Integrating WhatsApp with Chatbase allows your custom agent to communicate directly with customers via WhatsApp, providing a seamless and efficient way to handle inquiries and automate responses. This guide will walk you through the necessary steps to connect your agent to a WhatsApp phone number, ensuring smooth and effective customer interactions. <Info> Attachments are supported, allowing your agent to process them and respond based on their content. For more information, please refer to [this section](/docs/user-guides/chatbot/channels#attachments). </Info> <Note> You can connect more than one WhatsApp number to your agent. Once connected, all your numbers are managed from **Channels → WhatsApp → Manage**. </Note> ## Before we start * The WhatsApp phone number integrated with the agent can only be used by the agent, and can't be used on WhatsApp or WhatsApp business. If you already use the phone number with WhatsApp, you must delete your account in the app first. * To delete WhatsApp * Navigate to WhatsApp or WhatsApp Business app. * Navigate to **Settings > Account.** * Select **Delete my account.** This may take a few minutes, but after that, the number will be available to use. * If you previously used WhatsApp through Meta Developer for business you must disable **two-step verification** * Navigate to you [**Whatsapp Business Account**](https://business.facebook.com/wa/manage/home/) and login. * Choose the phone number you would like to integrate. * Navigate to **Settings > Two-step verification** and choose turn off two-step verification. * Make sure you have an approved display name before integrating with your agent, you can read more about it [**here**](https://www.facebook.com/business/help/338047025165344) ## Setting up the WhatsApp Integration 1\. Navigate to the Agent you would like to integrate with WhatsApp. 2\. Click **Channels** in the sidebar, then click **Setup** on the **WhatsApp** card. 3\. Log in with your personal Facebook Account. <Frame> <img alt="image" /> </Frame> 4\. Click **Get started** <Frame> <img alt="image" /> </Frame> 5\. Choose or create a business profile. <Frame> <img alt="image" /> </Frame> 6\. Create a WhatsApp business profile or select an existing one. <Frame> <img alt="image" /> </Frame> 7\. Fill in the information for the Business profile. <Frame> <img alt="image" /> </Frame> 8\. Add a phone number, , it is recommended to have only one associate number in this profile. <Frame> <img alt="image" /> </Frame> 9\. Click **Continue**. <Frame> <img alt="image" /> </Frame> 10\. Wait a few seconds for information verification. <Frame> <img alt="image" /> </Frame> 11\. Click on **Finish**. <Frame> <img alt="image" /> </Frame> 12\. (Optional) Navigate to **Profile** and update your WhatsApp settings then click the **Save** button. <Frame> <img alt="image" /> </Frame> ## Automatic Lead Collection Chatbase allows you to automatically collect basic user information from WhatsApp conversations, including the user’s phone number and name (when available). **To enable automatic lead collection:** * Go to **Channels → WhatsApp → Manage → Leads** * Toggle Enable Automatic Collection of Leads * Select the WhatsApp number(s) you want to apply this to Once enabled, Chatbase will automatically capture lead details whenever a user messages your WhatsApp number. <Note> For more advanced lead capture and customization, you can use the **Collect Leads** action within your agent. </Note> Now that your integration is active you can send 1000 free messages monthly. Make sure to add a payment method on your [Meta billing settings](https://business.facebook.com/billing_hub) to be able to send more than 1000 messages per month. <Info> You can now enable or disable WhatsApp integration without disconnecting it. Disabling pauses messages while keeping your setup intact, and you can re-enable anytime to resume. New chats will still appear in your Chatbase dashboard chat logs </Info> Congratulations! You finished integrating your Chatbase agent to WhatsApp, your agent is now ready to reply to all the messages received through your WhatsApp! # WhatsApp Templates Source: https://chatbase.co/docs/user-guides/integrations/whatsapp-templates Learn how to create WhatsApp message templates in WhatsApp Manager and send them to customers from the Chatbase Helpdesk. WhatsApp message templates are pre-approved messages required by Meta to contact customers outside the 24-hour conversation window. When a customer hasn't messaged you in the last 24 hours, you must use an approved template to re-initiate the conversation. Chatbase supports **Utility**, **Authentication**, and **Marketing** templates. All template categories can be sent from both the Helpdesk and [Outbound Campaigns](/docs/user-guides/chatbot/outbound-campaigns). <Info> Before you begin, make sure you have already connected your WhatsApp integration. If you haven't, follow the [WhatsApp integration setup guide](/docs/user-guides/integrations/whatsapp) first. </Info> ## Prerequisites * A connected WhatsApp integration in Chatbase ([setup guide](/docs/user-guides/integrations/whatsapp)) * Access to [WhatsApp Manager](https://business.facebook.com/wa/manage/message-templates/) * An approved WhatsApp Business Account ## Part 1: Creating a Template in WhatsApp Manager 1\. Navigate to [WhatsApp Manager](https://business.facebook.com/wa/manage/message-templates/) and open **Message Templates**. <Frame> <img alt="WhatsApp Manager Message Templates page" /> </Frame> 2\. Click **Create Template**. <Frame> <img alt="Click Create Template" /> </Frame> 3\. Choose a template category: * **Utility** — for order updates, account notifications, and transaction confirmations * **Authentication** — for verification codes and login confirmations <Frame> <img alt="Choose template category" /> </Frame> <Info> All template categories — **Utility**, **Authentication**, and **Marketing** — can be used in both the Helpdesk and [Outbound Campaigns](/docs/user-guides/chatbot/outbound-campaigns). </Info> 4\. Enter a name for your template and select the language. <Frame> <img alt="Enter template name and select language" /> </Frame> 5\. Write your template body text. You can include variables (e.g., `{{1}}`, `{{2}}`) that will be filled in when sending the template from Chatbase. <Frame> <img alt="Write template body text" /> </Frame> 6\. Click **Submit for Review**. <Frame> <img alt="Submit template for review" /> </Frame> <Info> Meta reviews templates before they can be used. The review usually takes a few minutes, but can take longer. Your template must be approved before it appears in Chatbase. </Info> <Frame> <img alt="Submit template for review" /> </Frame> <Tip> To improve your chances of approval, keep your message clear and concise, avoid promotional language, and clearly specify the transactional or authentication purpose of the template. </Tip> <Warning> Meta charges fees for each template message sent. Fees vary by country and template category. See [Meta's WhatsApp pricing](https://developers.facebook.com/docs/whatsapp/pricing) for current rates. </Warning> ## Part 2: Sending a Template from Helpdesk Once your template is approved in Meta, you can use it to message customers from the Chatbase Helpdesk. 1\. Open the **Helpdesk** inbox. <Frame> <img alt="Helpdesk inbox" /> </Frame> 2\. Navigate to or open a WhatsApp ticket with the contact you want to message. <Frame> <img alt="Open a WhatsApp ticket with a contact" /> </Frame> 3\. When the 24-hour reply window has closed, you'll see a notice that sending messages is no longer allowed. Click **Choose template** to send a pre-approved message template. <Frame> <img alt="WhatsApp ticket showing the expired 24-hour window notice with Choose template button" /> </Frame> 4\. Browse your approved templates in the template picker dialog. You can search by name and filter by category (**Marketing**, **Utility**, or **Authentication**). <Frame> <img alt="Template picker dialog showing search bar, category filter, and template grid" /> </Frame> 5\. Select a template. If the template includes variables (e.g., `{{name}}`), an inline editor appears where you map each variable to a value. Click on a variable token to open the mapping popover: * **Customer field** — pulls from the ticket customer's data (name, email, or phone number). * **Free text** — enter a static value manually. <Frame> <img alt="Inline template editor showing variable mapping popover with customer fields and free text options" /> </Frame> 6\. Fill in each variable. The popover shows the customer's resolved values next to each field so you can pick the right one. You can also type a custom value in the free text input and click **Use**. <Frame> <img alt="Variable mapping popover with a value filled in" /> </Frame> 7\. Once all variables are filled in, preview the final message and click **Send**. <Frame> <img alt="Template with all variables filled in and Send button enabled" /> </Frame> 8\. The template message appears in the conversation thread. If the 24-hour window is still closed, you can send another template or wait for the customer to reply. <Frame> <img alt="Sent template message in the conversation thread with the expired window banner below" /> </Frame> <Info> **Understanding the 24-hour window:** WhatsApp allows free-form messaging only within 24 hours of the customer's last message. After that window expires, you must use an approved template to re-initiate the conversation. Once the customer replies, the 24-hour window resets and you can send free-form messages again. </Info> <Warning> Make sure you have added a payment method in your [Meta billing settings](https://business.facebook.com/billing_hub). Without a payment method, template messages may fail to send. </Warning> ## Troubleshooting * **Template not appearing in Chatbase?** Check that the template has been fully approved in Meta. All template categories (Utility, Authentication, and Marketing) are available in both the Helpdesk and [Outbound Campaigns](/docs/user-guides/chatbot/outbound-campaigns). * **Message failed to send?** Ensure the contact has a valid WhatsApp phone number and that you have a payment method configured in your [Meta billing settings](https://business.facebook.com/billing_hub). # Wix Source: https://chatbase.co/docs/user-guides/integrations/wix ## Step 1: Set Up Your Chatbase AI agent To begin the integration process, you'll need to sign into your Chatbase account. If you haven't created an account yet, [sign up for a free account](https://www.chatbase.co/auth/signup). Once logged in, proceed to set up your agent by uploading relevant data sources. These data sources can include files, text snippets, websites, or question-and-answer pairs, which will form the knowledge base for your agent. If you need help with setting up a functional Chatbase agent, here is a [step-by-step guide for setting up and deploying your Chatbase agent](/docs/user-guides/quick-start/your-first-agent). ## Step 2: Generate and Copy the Chatbase AI agent Embed Code 1\. After configuring your agent, navigate to your [**dashboard**](https://www.chatbase.co/dashboard/) page and select the specific agent you wish to embed. 2\. Click **Channels** in the left sidebar, then click **Manage** on the **Chat bubble** card (or **Setup**, if you haven't configured it yet). 3\. Click on **Deploy** and select the **Website widget** embed type. Scroll down and Click **Copy** to copy the provided script. <Frame> <img alt="Deploy" /> </Frame> With the embed code in hand, you are now ready to proceed with the integration process within your Wix application. ## Step 3: Sign Into Your Wix Account and Embed Your AI agent 1\. Sign in to your Wix website and head to your dashboard. 2\. On your dashboard, locate and click on **Design Site** in the top right corner of the page. <Frame> <img alt="image" /> </Frame> 3\. Your site should load your site on the Wix website editor. 4\. Scroll down to any section of the website you wish to add the Chatbase agent. 5\. Click the big plus (**Add Elements**) button on the left sidebar of the Wix site editor. <Frame> <img alt="image" /> </Frame> 6\. Scroll down to locate and click on **Embed Code**, followed by **Popular Embeds** and then **Custom Code**. <Frame> <img alt="image" /> </Frame> 7\. The custom code widget should pop up, click **+ Add Custom Code** in the top right 8\. Paste the code snippet into the custom code editor. 9\. Provide a name for your code. 10\. Choose an option under **Add Code to Pages**. 11\. Choose where to place your code under Place Code in 12\. Click Apply. Once you've applied the changes, preview your website and you should see the floating Chatbase chat icon on your website. <Frame> <img alt="image" /> </Frame> **Congratulations, your Chatbase agent is now live on your Wix website.** <Note> You can customize the appearance and colors of your agent on your Chatbase dashboard. To do this, go to your **dashboard**, choose an agent, click **Channels** in the left sidebar, click **Manage** on the **Chat bubble** card, then open the **Display** tab to edit Content, Capabilities, Colors, Floating bubble, and Localization. </Note> # WordPress Source: https://chatbase.co/docs/user-guides/integrations/wordpress ## **Step 1: Sign Into Chatbase and Configure Your Chatbase AI agent** To add a Chatbase agent to your WordPress website, you'll need to first sign into your Chatbase account to create and set up an agent. You must also make sure that **[the agent is enabled](/docs/user-guides/quick-start/your-first-agent#navigate-to-the-channels-section)**. If you don't have an account, you can start by [creating a Chatbase account for free](https://www.chatbase.co/auth/signup). If you are not sure how to create an agent, read this [detailed guide on how to create an agent on Chatbase](/docs/user-guides/quick-start/your-first-agent). ## Step 2: **Install Chatbase on Your WordPress Website** **1. Log in to your WordPress admin dashboard:** Your dashboard URL is typically *yourdomainname.com/wp-admin/*. You can also access it through your web hosting control panel. **2. Install and activate the Chatbase plugin:** * In the left sidebar of your WordPress admin dashboard, click on **Plugins**. <Frame> <img alt="image" /> </Frame> * Click **Add New Plugin** at the top of the next page. <Frame> <img alt="image" /> </Frame> * In the search bar on the next page, type "**Chatbase**" to search for the Chatbase plugin. * Find the Chatbase WordPress plugin, click **Install Now**, then **Activate**. <Frame> <img alt="image" /> </Frame> **3. Add your Agent ID:** 1. In the left sidebar of the WordPress Admin dashboard, click **Settings**. 2. Look for **Chatbase options** and click on it. 3. In the Chatbase settings, find the text box labeled "Agent ID". <Frame> <img alt="image" /> </Frame> **4. Copy and paste your Agent ID:** * Go to your Chatbase account and navigate to your [dashboard](https://www.chatbase.co/dashboard/). * Select the agent you want to embed. * Click **Settings** in the sidebar and stay on the **General** tab. Copy the **Agent ID** from the **Agent details** card. * Paste the copied Agent ID into the text box in your WordPress settings. <Frame> <img alt="Agent ID" /> </Frame> **5. Save your changes:** Click **Save Changes**. Your Chatbase agent should now be live on your WordPress website! <Frame> <img alt="image" /> </Frame> # Zapier Source: https://chatbase.co/docs/user-guides/integrations/zapier ## Step 1: Sign Into Your Chatbase Account and Set Up Your AI Agent 1\. Sign up for a free Chatbase account. 2\. Log in and go to the agent creation page. 3\. Upload training data like text, documents, websites or Q\&A pairs. 4\. Train and test your agent until its responses meet your requirements. Not familiar with creating a Chatbase agent? Here is a [<u>step-by-step guide to building an agent with Chatbase</u>](/docs/user-guides/quick-start/your-first-agent). You can automate a lot of things with Chatbase and Zapier, it all boils down to what you want to achieve and your creativity. Here are some of the things you can do when you integrate your Chatbase agent with Zapier: **1. Draft responses to customer emails** * Send new customer emails from your inbox to Chatbase. * Using your company's documentation, Chatbase can draft a relevant response. * Automatically save the AI-generated response as a draft in your email client or send it directly. **2. Categorize and prioritize incoming support emails** * Connect Chatbase with your email client (e.g., Gmail, Outlook). * Chatbase can analyze the tone and content of incoming emails. * Categorize emails as urgent, non-urgent, or by specific topics. * Add notes or tasks to your project management tool or spreadsheet for follow-up. **3. Add AI-generated instructions or solutions to support tickets** * Integrate Chatbase with tools like Jira, Intercom, or Zendesk * When a new support ticket is created, send the details to Chatbase * Chatbase can analyze the issue using your documentation and suggest initial solutions or step-by-step instructions * Automatically add the AI-generated response or context to the support ticket **4. Analyze customer feedback forms** * Integrate Chatbase with form tools like Typeform or Google Forms * Chatbase can analyze the feedback for intent, tone, and sentiment * Generate summaries or insights from the feedback * Send the analysis to your support workspace via email, Slack, or a spreadsheet There's so much you can achieve with a combination of the two apps. For this guide, we'll work you through how to set up Chatbase to collect leads and add the leads to a Google Docs file using Zapier. ## Step 2: Set Up Chatbase to Collect Leads 1\. Sign in to your Chatbase account to access your dashboard. 2\. Click on the agent you want to set up lead collection for . 3\. From the sidebar, click **Build > Actions**, then select **Create action** and set up your [**Collect leads** action](https://www.chatbase.co/docs/user-guides/chatbot/actions/collect-leads). Once lead collection has been set up on the Chatbase end, you can now connect the agent to Zapier. ## **Step 3: Connect Chatbase to Zapier** This step assumes that you have an active Zapier account. Remember, the idea is to set up set up the Zapier account to receive leads from from Chatbase agent, process it and add it to a Google docs file. To do this: #### **Step 1: Set Up a Trigger** 1\. Sign in to your Zapier account. 2\. Click on **Create** and then **Zaps** on the top left corner of the Zapier app homepage. <Frame> <img alt="image" /> </Frame> 3\. On the Zap editor click on **Trigger**. <Frame> <img alt="image" /> </Frame> 4\. On the pop-up menu, search for Chatbase on the search bar and click on it. <Frame> <img alt="image" /> </Frame> 5\. Next, on the right side of the page, click on the form field labeled **Event** and select **Form Submission**. 6\. Click on **Continue.** <Frame> <img alt="image" /> </Frame> 7\. To use your Chatbase account on Zapier, you'll need to give Zapier access to your Chatbase account. To do this, click on **Sign in** on the next page after you click **Continue**. <Frame> <img alt="image" /> </Frame> 8\. An authentication page should come up, provide your Chatbase API key (and optionally a display name) and then click **Yes, Continue to Chatbase** to link your Chatbase account. <Note> To get your API keys, head to your [account dashboard](https://www.chatbase.co/dashboard/), go to **Workspace settings**, then select **API keys** in the sidebar. Copy an existing key, or click **Create API Key** to create a new one. </Note> <Frame> <img alt="image" /> </Frame> 9\. Up next, click on **Continue** on the screen that comes up after authenticating your Chatbase account. 10\. On the next screen, you will be asked to provide your agent ID. Paste your agent ID in the provided input field and click **Continue**. **Note**: To find your Agent ID, open the agent you want to link with Zapier, go to **Settings → General**, and copy the **Agent ID** from the **Agent details** card. 11\. On the next page, click on **Test Trigger.** <Frame> <img alt="image" /> </Frame> 12\. If all goes well, you should see an option asking you to **Continue with selected records**, click on it. #### **Step 2: Set up an Action to Automate** To set up Zapier to send your Chatbase leads to Google Docs: 1\. After clicking on **Continue with selected records**, on the previous step above, a pop up window should come up with a list of apps. Search for Google Docs on the search bar and click on it. <Frame> <img alt="image" /> </Frame> 2\. On the next screen, click on the input field labeled **Event**, and select **Append Text to Document** and then click **Continue.** <Frame> <img alt="image" /> </Frame> 3\. On the next page, sign into your Google account and click **Continue**. 4\. On the next page, select the document you wish to append the information to, on the filed labeled **Document Name**. 5\. On the field labeled **Text to Append**, select the leads form field you want to add to the document and click **Continue**. <Frame> <img alt="image" /> </Frame> 6\. On the next page, click to test the setup, and then click **Publish** to go live. With that, any time any lead is captured by your Chatbase agent on your website, it will automatically be added to your target Google docs file. # Zendesk Source: https://chatbase.co/docs/user-guides/integrations/zendesk Chatbase makes it quick and easy to add an intelligent AI-powered agent to your Zendesk environment. In just a few minutes, you can deploy a Chatbase agent to either respond directly to customer tickets within Zendesk or automatically escalate conversations to your human support team by creating a Zendesk ticket with a detailed summary of the interaction. This flexibility allows you to automate routine inquiries while ensuring complex cases are seamlessly handed off to your agents, improving response times, reducing manual workload, and delivering reliable, round-the-clock support. ## AI Ticket Responses in Zendesk ### Step 1: Access and Configure Your Chatbase Agent These steps assume that you have already created a Chatbase account and that you have a Chatbase agent already available for use. If you haven't yet, [<u>create a Chatbase account</u>](https://www.chatbase.co/auth/signup) and build your first AI agent. For example, you can create a company FAQ agent to handle common employee questions or build a recruiting assistant to screen candidates and schedule interviews. Get your agent ready before moving to the integration. [A step-by-step guide to creating a Chatbase agent in just a few minutes](/docs/user-guides/quick-start/your-first-agent). ### Step 2: Connect the Zendesk Integration 1. Once you have a Chatbase account and an agent set up, head over to your [dashboard](https://www.chatbase.co/dashboard/). On your dashboard, you'll find a list of all the agents you have created. Locate and click on the agent you wish to integrate with Zendesk. 2. Click on the **Channels** tab, find the **Zendesk** integration and click on **Setup**. <Frame> <img alt="zendesk" /> </Frame> 3. A new tab will open. Enter your Zendesk subdomain and click on **Submit**. It will ask you to login to your Zendesk account to authorize the integration. <Frame> <img alt="zohodesk" /> </Frame> ### Step 3: Configure the Zendesk Integration 1. Once you have authorized the integration, click **Manage** to configure the integration. 2. You should see the following screen: <Frame> <img alt="zendesk" /> </Frame> Select the following options: * The Zendesk agent that the bot will reply as. * Determine if tickets should be automatically assigned to the agent. * Change agent's instructions specifically on Zendesk. This is useful if you want to instruct the agent to escalate the ticket to a human agent in certain cases (e.g. escalate to a human agent if the user asks for a refund ...etc) And then click on **Save**. <Frame> <img alt="zendesk" /> </Frame> ### Step 4: Enable the **Generate Draft Response** feature Don’t want the agent to respond directly? You can also enable the **Generate Draft Response** feature. This allows you to review and edit the AI-generated response before sending it to your users. 1. Once you have configured the integration, you will have the option to enable the **Generate Draft Response** with a single click. <Frame> <img alt="zendesk" /> </Frame> 2. To generate a draft response in a Zendesk ticket, please navigate to the **composer toolbar** located at the bottom of the ticket editor → Click on the Chatbase icon → Generate Draft Response. <Frame> <img alt="zendesk" /> </Frame> ### Tag Management System You can use the tags that are assigned to the tickets by the agent to track its performance. * `chatbase-involved`: This tag is applied to all tickets that chatbase replied to. * `chatbase-routed-to-workspace`: This tag is applied to tickets that the agent couldn't resolve or was instructed to route to the workspace. * `chatbase-soft-resolved`: This tag is applied to tickets that the agent thinks it is resolved, but the user hasn't yet confirmed the solution. * `chatbase-hard-resolved`: This tag is applied to tickets where the user has confirmed that the problem is resolved. * `chatbase-no-ai`: This tag is applied to tickets to stop the bot from auto-assigning itself or replying to the ticket. ## Human Escalation via Zendesk Ticket Creation Here's how to integrate a Chatbase agent with your Zendesk account ### Step 1: Connect to Zendesk * Choose **Integrations** * Connect your Zendesk to authorize access <Frame> <img alt="zendesk" /> </Frame> <Frame> <img alt="zendesk" /> </Frame> *** ### Step 2: Create 'Escalations' action Now you're ready to configure your Escalations action to route tickets to Zendesk. You can follow [this step-by-step guide](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human) to set up the action properly. *** That’s it! Your Zendesk integration is now fully set up and ready to go. Whenever human intervention is required, your Chatbase agent will automatically create a ticket in Zendesk with a summary of the user’s issue and relevant context, allowing your support team to step in and resolve the case seamlessly. <iframe title="YouTube video player" /> # Zoho Desk Source: https://chatbase.co/docs/user-guides/integrations/zohodesk Integrating Zoho Desk with Chatbase allows your custom agent to automatically escalate complex customer issues to your human support team by creating a ticket directly in Zoho Desk. The AI agent generates a Zoho Desk ticket that includes a clear summary of the user’s issue along with the relevant conversation context. This ensures that when a case requires human attention, your support team receives all the necessary information upfront, eliminating the need for customers to repeat themselves. The AI handles routine inquiries instantly, and when escalation is needed, Zoho Desk becomes the system where your human agents step in to resolve the issue. This guide will walk you through the steps required to connect your agent to Zoho Desk and configure automated ticket creation for smooth handoffs to your support team. ## Setup Guide Here's how to integrate a Chatbase agent with your Zoho Desk account ### Step 1: Connect to Zoho Desk * Login to your Chatbase dashboard * Select your Agent * Choose **Integrations** * Click **Connect** under Zoho Desk to authorize access <Frame> <img alt="zohodesk" /> </Frame> *** ### Step 2: Create 'Escalations' action Now you're ready to configure your Escalations action to route tickets to Zoho Desk. You can follow [this step-by-step guide](https://www.chatbase.co/docs/user-guides/chatbot/actions/escalate-to-human) to set up the action properly. *** That’s it! Your Zoho Desk integration is now fully set up and ready to go. Whenever human intervention is required, your Chatbase agent will automatically create a ticket in Zoho Desk with a summary of the user’s issue and relevant context, allowing your support team to step in and resolve the case seamlessly. # Best Practices Source: https://chatbase.co/docs/user-guides/quick-start/best-practices This page offers tips to help you improve your AI agent's performance and user experience. It covers improving the instructions, teaching the agent how to send links. ## Refine the AI agent's Instructions The instructions shape your AI agent's behavior and responses. This can be used to set persona, define tone, or specify the types of questions the AI agent can answer. Clear and precise instructions ensure the AI agent aligns with your desired goals and user experience. Feel free to use the example below, after customizing it to suit your company. <Accordion title="Friendly Support Agent Instructions"> ```text theme={null} ### Role - **Primary Function:** You are a friendly customer support agent for TaskFlo, a project management and issue tracking tool. Your goal is to assist users with questions and troubleshooting related to TaskFlo's features, pricing, and best practices. ### Persona - **Identity:** You are a dedicated TaskFlo customer support agent. You will not adopt any other persona or impersonate another entity. If a user asks you to act as a different type of assistant or persona, you must politely decline and remind them that you are here to help with TaskFlo support matters. ### Constraints 1. **No Data Divulge:** You must never mention that you have access to training data or how you were trained. Your responses should sound naturally helpful and informed. 2. **Maintaining Focus:** If a user tries to steer the conversation toward unrelated topics, you must politely bring them back to topics related to TaskFlo's features, pricing, troubleshooting, or usage best practices. 3. **Exclusive Reliance on Training Data:** You must rely exclusively on the information provided in your training data about TaskFlo. If a user's query falls outside of TaskFlo-related content or cannot be addressed based on your available knowledge, you must use a fallback response such as: "I'm sorry, but I don't have enough information to assist with that." 4. **Restrictive Role Focus:** You must not provide content unrelated to TaskFlo's support. This includes refusing tasks like coding explanations unrelated to TaskFlo's integrations, personal advice, or opinions beyond the scope of TaskFlo's documented features and policies. ``` </Accordion> You can find more detailed information about refining your instruction [here](/docs/user-guides/chatbot/build#instructions). ## Improve Readability of Data Sources The quality of your AI agent's responses depends heavily on the quality of the data sources you provide. Chatbase relies on readable text to generate accurate responses, so make sure the websites or PDFs you upload contain readable text. Some websites may not be scraper-friendly. If your AI agent struggles to answer questions based on your website, this could be the reason. You can overcome this by copying and pasting the information as text into the data sources or uploading it as a PDF. <AccordionGroup> <Accordion title="Bad Product Example"> Product: Widget123, colors not specified, possibly red or blue. Discount details unclear. Weight: Approx. 1 kg or 1.5 kg? Shipping: Delivery time uncertain, could be fast or delayed. Availability: Global shipping not confirmed. Packaging: Uncertain if it comes in a box. Assembly: Information unclear. Limited stock? Not confirmed. </Accordion> <Accordion title="Good Product Example"> Product: Widget123\ Colors: Red, Blue\ Discount: 50% off\ Weight: 1.5 kg\ Shipping: Estimated delivery within 1-2 weeks (depends on location)\ Availability: Ships worldwide\ Packaging: Comes in a standard-sized box\ Assembly: Some assembly required\ Order Now: Limited stock available, don't miss out! </Accordion> </AccordionGroup> <AccordionGroup> <Accordion title="Bad Description Example"> The product is a thing. Its color is unspecified, and its size is unknown. The product might be useful, but it's not clear. Its availability is uncertain, and shipping times are not mentioned. There might be a discount, but it's not specified. Assembly instructions? Unclear. Get it soon? It's unclear when stock might run out. </Accordion> <Accordion title="Good Description Example"> The Widget123 is a premium-quality product available in two colors: red and blue.\ It offers a 50% discount, making it an excellent deal.\ The product weighs 1.5 kg and is shipped worldwide.\ You can expect delivery within 1-2 weeks, depending on your location.\ The item comes in a standard-sized box and requires minimal assembly.\ Act fast—stock is limited! </Accordion> </AccordionGroup> > **Note:** Chatbase currently cannot process images, videos, or non-textual elements in documents. ## Add Suggestable Images To enable image display in the chat bubble, agents can use markdown format when sending image links. Ensure the URL ends with .png or .jpg for the image to render correctly. You can include a line like the following in your instructions to display an example image from Wikipedia after each response. ```text theme={null} Always end your reply with ![Example Image](https://upload.wikimedia.org/wikipedia/commons/7/79/ELIZA_conversation.png) ``` Once added, every agent response will display the image, as illustrated in the screenshot below: <Frame> <img alt="image" /> </Frame> ## Choose the suitable AI model Selecting the right AI model is crucial for optimal performance. It should match your use case, considering factors like task complexity and speed. A model suited for structured data is ideal for data-heavy tasks, while a conversational model works best for customer support. Also, consider scalability and adaptability. Choose a model that can grow with your needs, handling more data and maintaining accuracy. Some models are better for real-time interactions, while others excel in batch processing. Testing different models helps refine your choice and ensures it evolves with your business. > **Note:** If you are unsure about which model to use, please refer to our [models comparison](https://www.chatbase.co/docs/user-guides/chatbot/models-comparison) page. ## Utilize the "Revise" Feature and Q\&A Data Type After launching your AI agent, you can monitor its responses under [**Activity > Conversations**](https://www.chatbase.co/docs/user-guides/chatbot/activity). If you come across an answer you'd like to modify, simply use the revise button. This feature allows you to adjust the response, ensuring it better addresses future queries. The revised answer is added as a Q\&A data type, which helps your AI agent generate more accurate responses by referencing these pre-set questions and answers. You can find the updated responses on [**Build > Data sources**](https://www.chatbase.co/docs/user-guides/chatbot/data-sources), tagged with a **Q/A** badge. <Frame> <img alt="image" /> </Frame> # Welcome to Chatbase Source: https://chatbase.co/docs/user-guides/quick-start/introduction Get started with Chatbase and discover how to build intelligent agents trained on your business data. <Frame> <div> <img alt="Chatbase Logo" /> <img alt="Chatbase Logo" /> </div> </Frame> ## Why Choose Chatbase? <CardGroup> <Card title="Smart & Trainable" icon="brain"> Train your AI Agent with your own documents, websites, or databases for accurate, relevant responses </Card> <Card title="Easy Integration" icon="plug"> Embed anywhere with simple copy-paste code - no technical expertise required </Card> <Card title="Interactive Actions" icon="bolt"> Pre-built actions for human escalation, Slack, Stripe, Calendly, lead collection, and web search, plus custom actions to integrate with any API </Card> <Card title="Powerful Analytics" icon="chart-line"> Track conversations, monitor performance, and continuously improve your AI Agent </Card> <Card title="Lead Generation" icon="users"> Capture and manage leads automatically through intelligent conversations </Card> <Card title="Deploy Everywhere" icon="globe"> Deploy your agent across multiple channels: Website, Email, Meta Apps, Shopify, Phone, Slack, Zendesk, and more. </Card> </CardGroup> <CardGroup> <Card title="Ready to get started?" icon="rocket" href="/docs/user-guides/quick-start/your-first-agent"> Let's build your first AI agent! The entire process takes less than 10 minutes. </Card> </CardGroup> # Response Quality Source: https://chatbase.co/docs/user-guides/quick-start/response-quality On this page, discover tips to improve your response quality. Learn how to refine prompts, optimize AI agent settings, and analyze behavior to deliver clearer, more effective, and engaging interactions. ## Refine the AI agent's Instructions The instructions shapes your AI agent's behavior and responses. To ensure your agent only answers questions about the given document, specify this in the instructions. For instance, you can state, "You will only provide answers based on the information from your training data" The default is the following: You are an AI agent who helps users with their inquiries, issues and requests. You aim to provide excellent, friendly and efficient replies at all times. Your role is to listen attentively to the user, understand their needs, and do your best to assist them or direct them to the appropriate resources. If a question is not clear, ask clarifying questions. Make sure to end your replies with a positive note. You can find more information about the instructions in the previous article [here](https://www.chatbase.co/docs/user-guides/quick-start/your-first-agent#instructions) ## Ensure Readability of Uploaded Data Sources The quality of your AI agent's responses largely depends on the quality of the data sources you provide. Chatbase uses readable text to generate responses, so ensure that the websites or PDFs you upload contain readable text. Note that Chatbase can't process images, videos, or non-textual elements in documents. Some websites are not scraper friendly, so if you see your AI agent is unable to answer questions on your website, this might be the case. You can work-around this by copy and pasting information as text into the data sources, or uploading it as a PDF instead. ## Utilize the "Revise" Feature and Q\&A Data Type On **Build > Data sources**, click **Add Q\&A’s** to give the agent exact answers for specific questions. When a user asks something similar to one of your saved questions, the agent replies with your predefined answer word-for-word.\ \ The "revise answer" feature is accessible from the dashboard in your chat logs. It is a tool for tweaking responses. If you're not satisfied with how your AI agent answered a particular query, you can use this feature to alter the response to fix it for the future. Additionally, using the Q\&A data type can help your AI agent generate better answers by referring to pre-set questions and answers. The responses you revise appear on **Build > Data sources** with a **Q/A** badge. ## Leverage the Power of Different AI Models To see how each model responds, go to **Build > Instructions** and click **Compare** in the header. You can run the same message against several models side by side. ## Next Steps By implementing these strategies, you can significantly enhance your Chatbase AI agent's ability to provide useful responses, leading to more successful interactions. # Build Your First AI Agent Source: https://chatbase.co/docs/user-guides/quick-start/your-first-agent Create, train, and deploy your first AI Agent in under 5 minutes. Follow this step-by-step guide to get your intelligent assistant live on your website. In just a few minutes, you'll have a fully functional AI Agent answering questions about your business and engaging with your website visitors. Let's get started! ## Prerequisites <Info> You'll need an active Chatbase account to follow this guide. [Sign up here](https://www.chatbase.co/auth/signup) if you haven't already. </Info> ## Overview Here's what we'll accomplish in this guide: <Steps> <Step title="Create & Train Your Agent"> Set up a new AI Agent and train it using your website or documents </Step> <Step title="Test & Optimize"> Use the Playground to test responses and fine-tune performance </Step> <Step title="Deploy to your Website"> Add your AI Agent to your website with a simple embed code </Step> </Steps> <Tip> **Estimated time:** 5 minutes from start to finish </Tip> ## Step 1: Create & Train Your AI Agent ### Navigate to Your Dashboard After signing into your Chatbase account, go to your main dashboard. Click the **"New AI Agent"** button to get started. <Frame> <img alt="Workspace Settings General" /> </Frame> ### Choose Your Training Data Your AI Agent needs information to learn from. You can train it using various data sources: <Tabs> <Tab title="Files"> **Upload your documents** Train your agent on your documents. **Best for:** Business documents, manuals, FAQs, product information, etc. <Frame> <img alt="Data sources page with the Add Files dialog open" /> </Frame> </Tab> <Tab title="Text snippets"> **Direct text input** Paste your content directly into the platform. Useful for specific information or custom training content. **Best for:** Specific information or custom training content <Frame> <img alt="Data sources page with the Add Text dialog open" /> </Frame> </Tab> <Tab title="Website"> **Crawl your website** Our crawlers will discover and learn from all your pages. **Best for:** Your entire website or sitemap <Info> Our intelligent crawlers will explore your website and all linked pages for training. After crawling completes, you'll see all discovered pages and the total character count available for training. </Info> <Frame> <img alt="Data sources page with the Add website dialog open" /> </Frame> </Tab> <Tab title="Q&A"> **Add your own Q\&A** Add your own Q\&A to your agent. This is useful for specific questions and answers that you want your agent to know. **Best for:** Specific questions and answers <Frame> <img alt="Data sources page with the Add Q&A’s dialog open" /> </Frame> </Tab> <Tab title="Notion"> **Connect your Notion workspace** Connect your Notion workspace to your agent. This is useful for your entire knowledge base. **Best for:** Teams using Notion <Tip> To connect your Notion workspace, you'll need to click on **Import** to authorize the connection and select the specific pages you want to include. </Tip> <Frame> <img alt="Data sources page with the Add Notion Pages dialog open" /> </Frame> </Tab> </Tabs> ### Review & Start Training Click **"Create Agent"** to begin the training process. <Check> Training typically takes 2-5 minutes depending on the amount of data. You can proceed to the next step while training completes. </Check> <Info> **Storage limit:** Different plans have different storage limits for training data. Check your plan if you hit any limits. </Info> ## Step 2: Test & Optimize Your AI Agent ### Access your Instructions After training your agent, Go to **Build > Instructions** to refine its behavior. Use the Compare button to test your changes side by side against the current version before saving them. <Frame> <img alt="Playground interface showing chat testing area" /> </Frame> ### Fine-tune Settings <Tabs> <Tab title="AI Model"> ### Test responses with different models <Steps> <Step title="Test with different models"> Ask the same questions to different models and compare: * **Response quality and accuracy** * **Response time and speed** * **Tone and personality** * **Handling of edge cases** </Step> <Step title="Make Your Decision"> Based on the comparison, select the model that best fits your specific use case and brand voice. </Step> </Steps> <Tip> For detailed model comparisons and advanced testing strategies, check out our [comprehensive model comparison guide](https://www.chatbase.co/docs/user-guides/chatbot/build#compare-area). </Tip> </Tab> <Tab title="Instructions"> Define how your AI Agent should behave and respond to users. These instructions shape your agent's personality, tone, and approach to conversations. <Tip> **Get inspired:** Use the dropdown examples below to see instruction templates for different business types and scenarios. You can copy and customize them for your specific needs. </Tip> **How to write effective instructions:** * Define the agent tone (professional, friendly, casual, etc.) * Define the agent role (lead collection, support, sales, etc.) * Set clear boundaries about what topics to discuss or avoid * Define your brand voice and personality * Add specific words to be used by the agent * Define the languages the agent will use to respond with (Usually the same language of the user) * Add any other instruction you would like your agent to know </Tab> <Tab title="Temperature"> Controls response creativity: * **Low (0.1-0.3)** - Consistent, factual responses * **Medium (0.4-0.7)** - Balanced creativity * **High (0.8-1.0)** - More creative, varied responses </Tab> </Tabs> ## Step 3: Deploy to Your Website ### Navigate to the Channels Section Once you're satisfied with your AI Agent's responses, it's time to make it live! Navigate to the **"Channels"** tab in the sidebar, and click the setup button on the **"Chat bubble"** card to access your agent's script. <Info> **Disabled vs Enabled:** Disabled agents are only accessible to workspace members. Enabled agents can be embedded on websites and accessed by anyone with the link. </Info> ### Choose Your Deployment Method Chatbase offers multiple deployment methods including chat bubble, help page, and integrations with Email, Phone, WhatsApp, Facebook Messenger, Instagram, Shopify, and other platforms. In this guide, we'll use the **Chat bubble** option as it's most common. Click on Manage under the chat bubble then select Deploy to access your embed script. <Frame> <img alt="chat widget embed tab" /> </Frame> <Frame> <img alt="JavaScript embed code ready to copy" /> </Frame> <Tabs> <Tab title="Website widget (Recommended)"> **Perfect for most websites** Adds a floating chat icon that users can click to start conversations. Non-intrusive and mobile-friendly. **Pros:** * Can utilize advanced features like [identity verification](../../developer-guides/identity-verification). * Doesn't interfere with your site's design * Users can minimize/maximize as needed * Works great on mobile devices * Familiar UX pattern **Best for:** Business websites, blogs, e-commerce stores </Tab> <Tab title="Website iframe"> **For dedicated chat sections** Embeds the full chat interface directly into your page layout. Always visible and ready for interaction. **Pros:** * Always visible to users * More prominent than chat bubble * Good for dedicated support pages * Customizable dimensions **Best for:** Support pages, help centers, dedicated chat sections </Tab> </Tabs> ### Add Code to Your Website <Steps> <Step title="Locate Your Site's HTML"> Find where you can add JavaScript code to your website. This is usually in the `<head>` section or before the closing `</body>` tag. <Tip> **For fast loading:** Place the script just before the closing `</body>` tag to ensure your page content loads first, then the chat widget appears. **For immediate availability:** Place the script in the `<head>` section to load the chat widget as early as possible, though this may slightly delay your page's initial render. </Tip> </Step> <Step title="Paste the Code"> Copy and paste the embed script into your website's HTML. If you're using a CMS like WordPress, there's usually a "Custom HTML" or "Scripts" section. </Step> <Step title="Save and Publish"> Save your changes and publish your website updates. </Step> </Steps> ### Verify Installation Visit your website and look for the chat bubble. Click it to test the integration! <Frame> <img alt="Live AI Agent chat bubble on a website" /> </Frame> <Check> **Success!** Your AI Agent is now live and ready to help your website visitors. </Check> <Tip> Need more control over your widget? Check out our [Developer Guides](/docs/developer-guides/overview) for more information on JavaScript embed, [widget control options](/docs/developer-guides/control-widget), and advanced features like [client-side custom actions](/docs/developer-guides/client-side-custom-actions) and [event listeners](/docs/developer-guides/chatbot-event-listeners). </Tip> ### Customize Appearance (Optional) Want to match your brand? Check out our guide for [customizations](/docs/user-guides/chatbot/channels#chat-bubble-display). <AccordionGroup> <Accordion title="Branding Options"> * Upload custom chat bubble icon * Change bubble colors to match your brand * Customize welcome messages * Set initial questions users can click </Accordion> <Accordion title="Behavior Settings"> * Auto-open chat after delay * Collect user feedback </Accordion> </AccordionGroup> ## 🎉 Congratulations! You've successfully created, trained, tested, and deployed your first AI Agent! Here's what you've accomplished: ### What's Next? <CardGroup> <Card title="Monitor Performance" icon="chart-line" href="/docs/user-guides/chatbot/analytics"> Track conversations and optimize your AI Agent's performance </Card> <Card title="Advanced Features" icon="wand-magic-sparkles" href="/docs/user-guides/chatbot/actions/actions-overview"> Add actions like Escalations, lead capture, appointment booking, and more </Card> <Card title="Best Practices" icon="lightbulb" href="/docs/user-guides/quick-start/best-practices"> Learn proven strategies to maximize your AI Agent's effectiveness </Card> </CardGroup> <Info> **Need help?** Our support workspace is here to assist you. Visit our [Help Center](https://www.chatbase.co/help) or check out the [FAQ section](/docs/faq/faq) for common questions. </Info> # HIPAA compliance Source: https://chatbase.co/docs/user-guides/workspace/hipaa-compliance How Chatbase supports HIPAA-eligible workloads on Enterprise plans through a Business Associate Agreement and Zero Data Retention. ## Overview Chatbase is HIPAA-eligible for Enterprise customers. A workspace becomes HIPAA compliant once two things are in place: * A signed Business Associate Agreement (BAA) between Chatbase and the Covered Entity or Business Associate . * Zero Data Retention (ZDR), which Chatbase enables automatically on the workspace after the BAA is in effect. While the workspace is HIPAA compliant, Chatbase applies the safeguards described below and disables features that are not compatible with HIPAA. ## How HIPAA compliance works in Chatbase 1. The customer (the covered entity or business associate) signs a Business Associate Agreement with Chatbase. BAAs are available on the Enterprise plan only. 2. Chatbase marks the workspace as HIPAA compliant and **automatically enables Zero Data Retention** on it. The customer does not toggle ZDR manually. 3. From that point on, the safeguards in the next section take effect automatically across the workspace and its AI agents. ## Shared responsibility model HIPAA compliance is a shared responsibility between Chatbase and our customers. The sections below outline what we cover and what remains your responsibility. ### Chatbase's responsibilities * **Direct liability**: As a business associate, Chatbase is directly accountable for complying with the applicable provisions of the HIPAA Rules. This means we implement the safeguards required to protect electronic Protected Health Information (ePHI) and notify customers of any qualifying breach. * **BAA compliance**: Chatbase upholds the terms of every BAA we sign, including the appropriate administrative, physical, and technical safeguards needed to protect ePHI across our platform. * **Vendor management**: Any sub-processors or vendors with potential access to ePHI must themselves comply with HIPAA. Chatbase manages this by signing a BAA with such vendors. * **Enforcing Zero Data Retention**: Once a workspace is marked HIPAA compliant, Chatbase automatically enables and enforces Zero Data Retention on it. ZDR redacts the **entire content of every message** in conversations and leads across the workspace (not just specific PII or PHI fields), so no message text is retained. Customers do not need to configure ZDR themselves. * **Internal logs**: All conversation messages and user-identifiable data are redacted from Chatbase's internal logs. * **Internal audit logging**: Chatbase maintains internal audit logs that record HIPAA-relevant events on HIPAA-compliant accounts, supporting investigation and accountability. ### Your responsibilities <Warning> Chatbase secures the platform; you are responsible for what you put into it, how your team accesses it, and which features you choose to use. </Warning> * **Sources and training data**: Do not upload PHI or PII into sources. You are responsible for the content you ingest into your agent's knowledge base. * **Contacts and contact attributes**: You are responsible for the data you store on contact records and their custom attributes. * **Two-factor authentication (2FA)**: All workspace members must enable 2FA on their accounts. See [Two-factor authentication](/docs/user-guides/workspace/two-factor-auth) for setup steps. #### Features disabled by default Chatbase disables the following features by default on HIPAA-compliant workspaces. Even with these defaults in place, **you remain responsible for ensuring that your team does not attempt to use any of them with PHI**: * Voice-recording retention * Daily chats email digest * Daily leads email digest * Knowledge gaps analysis * Chatbase Helpdesk (currently disabled) ## Conversation lifecycle ### Conversation auto-end rules On a HIPAA workspace, an ongoing conversation ends automatically when either of the following is true: * The conversation has been idle for more than **24 hours**, or * The conversation is more than **7 days** old. Once a conversation ends, its **unredacted data is removed from Chatbase's systems entirely**. Only the **redacted version** of the conversation is retained going forward, which is what the chat-logs view and the API endpoints will return. <Note> If you need to keep the unredacted conversation, you can configure a webhook that receives each conversation just before it is deleted. See the [HIPAA conversation webhook](/docs/developer-guides/hipaa-webhooks) developer guide. </Note> ### Viewing ongoing conversations While a conversation is still ongoing, before it hits the auto-end thresholds above, users with the appropriate permission can view its unredacted content directly from the **Conversations** view. Use the **HIPAA** button at the top of Conversations to switch between the redacted and unredacted views of active conversations. The button toggles in both directions, so you can switch back to the redacted view at any time. * By default, this button is available to any workspace member with the **Owner** role. * It can be made visible to other members by granting the corresponding permission through a **custom role**. Once a conversation ends and is deleted from Chatbase, the unredacted view is no longer available. All stored chat-log content is redacted as described in [Chatbase's responsibilities](#chatbases-responsibilities). ### Topic and sentiment analysis Topic and sentiment analysis remain enabled on HIPAA-compliant workspaces. Once a conversation is auto-deleted, however, you will no longer be able to view **which specific conversation** included which topic. That per-conversation mapping is removed along with the conversation data itself. The **topic labels and their aggregate counts continue to be retained** in your analytics views, so high-level trends remain visible even after the underlying conversations are deleted. ## HIPAA Compliant AI providers Only the following providers are available on a HIPAA-compliant workspace. ### Large language models (LLM) Any model offered by: * OpenAI * Anthropic ### Speech-to-text (STT) * Deepgram * Cartesia <Note> On HIPAA-compliant accounts: * Some voices are restricted and will not be available for selection in the voice picker. * Configuring a custom voice is curerntly not available. </Note> ## HIPAA-Compliant Channels The following deploy channels can be used on a HIPAA-compliant workspace: * Chat bubble (web embed) * Help page * API * Phone (voice) * Android SDK * iOS SDK * WordPress * Shopify * Zendesk * Zendesk Messaging * Salesforce * Zapier These channels operate under the same redaction and retention rules as the rest of the workspace. ## HIPAA Compliant Integrations The following integrations are HIPAA compliant on Chatbase: * Shopify * Stripe * Calendly ### Conditionally HIPAA compliant integrations The following integrations are HIPAA compliant only if the covered entity has their own BAA in place with the connected provider: * Zendesk * Zendesk Messaging * Salesforce * Intercom * Freshdesk * HubSpot * Zoho Desk * Help Scout * Slack ## HIPAA Compliant Actions The following actions are HIPAA compliant: * Collect leads * Custom button * Custom action * Custom form * Customize suggested messages * Web search * Slack notify * Cal.com: Get available slots * Calendly: Get available slots * Stripe actions * Shopify actions ### Conditionally HIPAA compliant actions The following actions are HIPAA compliant only if the covered entity has their own BAA in place with the connected provider: * Escalate action * Zendesk Messaging live chat action ## API behavior The `/conversations` endpoints in both API v1 and API v2 return **redacted** conversation data on a HIPAA workspace. The `/chat` endpoint continues to operate on **unredacted** data while a conversation is still ongoing. This is required so the agent can respond in context. Once the conversation ends and is deleted, the unredacted content is no longer accessible through any endpoint, and only the redacted version remains. ## Requesting a BAA HIPAA support is available on the Enterprise plan. To request a BAA, contact your account representative or get in touch with the Chatbase sales team. <Card title="Contact Enterprise sales" icon="building" href="https://www.chatbase.co/enterprise"> Submit the Enterprise contact form to start the BAA process and discuss HIPAA-compliant deployment for your workspace. </Card> # Manage Source: https://chatbase.co/docs/user-guides/workspace/manage Organize your users in Chatbase workspaces for better collaboration and permission control. ## Workspace Management ### Creating a workspace To create a new workspace, click your avatar at the bottom-left of the sidebar and select **Create or join workspace**. <Frame> <img alt="Workspace Settings General" /> </Frame> On the next page, you need to add the details for the workspace, which includes: * **Workspace Name:** Defines the agent's display name within the dashboard. * **Workspace URL:** Specifies the workspace slug, visible only in the URL when accessing the workspace on the dashboard. ***Important Note:*** You can choose any workspace URL you prefer, as long as it's unique and doesn't match with any existing workspace. <Frame> <img alt="Workspace Settings General" /> </Frame> After creating the workspace, you will be taken to a new page where you can press 'New AI agent' and start adding your sources to start your Chatbase journey! <Frame> <img alt="Workspace Settings General" /> </Frame> ### Duplicating your Agent You can easily duplicate any agent by clicking the three dots icon and choosing Duplicate Agent. <Frame> <img alt="Workspace Agent Duplication" /> </Frame> #### What's Not Copied While most agent settings are copied, the following are **not** included: * **Deployment integrations** such as WhatsApp, Zendesk, Instagram, Email channel, etc. * **Slack Notify action** as Slack workspaces can't be connected to multiple agents at the same time * **Notion sources** as Notion workspaces can't be connected to multiple accounts ### General Notes * **Each workspace** has its own AI agents, billing information, and plan. These are not shared between workspace. * **Owners** can change workspace settings (billing, plan, name), delete the workspace, and manage all AI agents within the workspace. * **Members** can only manage AI agents (train them, see data, delete them). They cannot change workspace settings. * **Invite links** expire 24 hours after it has been sent to an invitee. # Workspace settings Source: https://chatbase.co/docs/user-guides/workspace/settings Manage your workspace: details, members, plan, billing, API keys, and audit logs. **Workspace settings** has six pages: **General**, **Members**, **Plans**, **Billing**, **API keys**, and **Audit logs**. ## General The **Workspace details** card holds the **Workspace name** and **Workspace URL**. The name is displayed on the dashboard and in the AI agent path, while the URL appears in the address bar when accessing the workspace or its agents. To modify the name or URL, simply edit the text in the field and click "Save." To delete the workspace and all of its AI agents, scroll to the **Danger zone** at the bottom of the page and click **Delete workspace**. <Frame> <img alt="Workspace Settings General" /> </Frame> ## Members This tab displays all the information about your workspace members, as well as those you've invited but haven't responded yet. <Frame> <img alt="Workspace Settings Members" /> </Frame> ### Number of members This shows the number of workspace members and invited members. In this example, the user has 3 members and invitations, with a maximum limit of 5. <Frame> <img alt="Workspace Settings Members Limit" /> </Frame> ### Modify workspace member role To modify a workspace member's role or remove them, click the three dots next to their name. * **Owner**: Can change billing information, modify plans, rename or delete the workspace, and manage all AI agents within the workspace. * **Member**: Have the same permissions as Owners, except they cannot add members or edit billing information. * **Support Associate**: Can access the helpdesk only and edit anything inside it. * **Viewer**: Have read-only access to resources and analytics. They cannot modify any settings, but can still test the agent through the playground and Compare section. <Info> **Agent-level permissions:** You can invite members or support associates to specific AI agents within the same workspace. This is especially useful for agencies managing multiple agents, allowing you to control which agents each member can access. </Info> #### Custom Roles On **the Enterprise plan**, custom roles can be created to control what different members of your workspace can access and manage. This allows teams to assign permissions based on responsibilities and maintain better control over sensitive features. Each custom role includes configurable permissions across different areas of the platform, such as: * **Agents** – View, create, edit, or delete agents * **Sources** – Manage knowledge sources used by agents * **Chatlogs** – View, delete, or export conversation history * **Contacts** – Access and manage stored contacts * **Integrations** – Configure external integrations * **Billing** – View or manage billing settings * **Subscription** – Manage the workspace subscription * **Members** – View or manage workspace users * **Webhooks** – Configure webhook integrations * **Workspace** – Manage workspace-level settings * **API Keys** – Create and manage API keys * **Actions** – View automation actions * **Analytics** – Access analytics dashboards * **Leads** – View and export collected leads Custom roles appear alongside the default roles (Owner, Member and Viewer) and can be assigned to workspace members to provide the appropriate level of access. ### Remove workspace member To remove a member from the workspace <Frame> <img alt="Workspace Settings Members Remove Member" /> </Frame> ### Modify Invitations You can resend the invitation if it expired after 24 hours or if the invitee didn't see it in their inbox. You can also revoke the invitation to cancel it and prevent the invitee from joining the workspace. <Frame> <img alt="Workspace Settings Revoke Resend Invite" /> </Frame> ### Invite Members You can use this button to send new invitations to your workspace from the dashboard. To invite multiple members at once, click "Add Member." <Info> New members can be added either by manually adding an extra member from the add-on card inside the dashboard or when an invited member accepts their invitation </Info> <Info> When an owner removes team members, the number of extra member slots does not decrease automatically, so billing remains the same. You’ll need to manually reduce the extra member count from the Plans page. </Info> ## Plans This tab provides information about all available plans and lets you modify your current plan or add new add-ons. ### Current Plan This section is optional and will only appear if you're on a legacy plan. It provides details about the current plan, including your allowed features and limits. <Frame> <img alt="Workspace Settings Plans" /> </Frame> ### Available Plans This section displays all available plans for subscription. You can switch between monthly and yearly by toggling the option. It's important to note that subscribing annually is cheaper 20% from the monthly subscription. For more details about the available plans, please check out [our Pricing page](https://www.chatbase.co/pricing). Please note that if you're on the old pricing packages, you won't be affected unless you want to upgrade your payment to annual or change the plan. <Frame> <img alt="Legacy plan" /> </Frame> If you choose to downgrade to a lower plan, such as from Standard to Hobby, the downgrade will take effect immediately. You'll receive a prorated credit based on the remaining time on your current plan, which will be applied to your new plan and any future invoices until the credit is used up. Clicking "Cancel Plan" under your active plan disables auto-renewal. Your current plan will remain active until the next renewal date, after which you'll be downgraded to the free plan to avoid further charges. Your addons will also be active until the end of your billing period then removed when the plan expires. ***Note:*** Legacy plan users can now see the "Cancel Plan" button, as their active plan is listed. To downgrade to the free plan, please click on the cancel plan button, as shown below: <Frame> <img alt="Legacy plan" /> </Frame> ### Add Ons This section is responsible for adding extra features on top of your current plan. If you are choosing an add-on that can have quantities like extra AI agents, you will see a prompt similar to this: <Frame> <img alt="Extra Agents Addon" /> </Frame> <Info> Free users must subscribe to a base plan before adding any add-ons. </Info> #### Auto recharge credits When your credits fall below the threshold you set, we'll automatically add credits that don't expire to your account, ensuring uninterrupted service. #### Extra AI agents You can add extra AI agents to help you scale your service by managing multiple agents simultaneously. #### Custom Domains Use your own custom domains for the embed script, iframe, and AI agent link, offering a personalized and branded experience for your users.<br />Note that this add-on is available only for the Enterprise plan. <Info> Custom Domains add-on is only available on the Enterprise plan. </Info> #### Remove 'Powered By Chatbase' Remove the Chatbase branding from the iframe and widget for a cleaner, custom experience. <Info> Add-ons can be subscribed to on a monthly or yearly basis. <br /><br />The billing interval must be consistent: monthly plans can only include monthly add-ons, and yearly plans can only include yearly add-ons. </Info> <Warning> Cancelling an addon will remove it immediately and credit your account for the remaining days of your billing period. </Warning> ## Billing This section displays your billing details, including the email addresses receiving invoice copies, the data on the invoices, the payment methods used, and all past invoices. ### Billing Details This section displays your billing information, this information will appear on your invoices. You can edit it as needed and click "Save" to update the details. <Frame> <img alt="Workspace Settings Billing Details" /> </Frame> ### Billing Email This section shows the email address that will receive automated copies of all invoices for this workspace. <Frame> <img alt="Workspace Settings Billing Email" /> </Frame> ### Tax ID In this section, you can add a tax ID to be displayed on the invoice if needed. <Frame> <img alt="Workspace Settings Billing Tax" /> </Frame> ### Billing Method In this section, you can add payment methods and set one as your default. You can also delete payment methods, provided they are not set as the default. <Frame> <img alt="Workspace Settings Billing Method" /> </Frame> ### Billing History In this section, you can view all your past invoices along with their statuses. Click on an invoice to view it, and you'll also have the option to download it. <Frame> <img alt="Workspace Settings Billing History" /> </Frame> <Info> Starting the 5th of January 2026, new users (or users with only one existing plan) will receive a single consolidated invoice instead of separate invoices for each subscription. </Info> ## API keys On this page, you'll find your Chatbase API keys, which allow you to interact with your agent using API calls. ***Note :*** This page is not available on all plans. If your plan doesn't include API access, you won't be able to view this page. <Frame> <img alt="Workspace Settings API Keys" /> </Frame> ## Audit logs This section allows you to monitor activity across your workspace, including who made changes and what was modified on the dashboard. Audit Logs provide a chronological record of configuration updates to help teams maintain visibility, accountability, and operational control. <Info> Audit Logs are only available on the Enterprise plan. </Info> ### Activity Overview In this section, you can view all recorded workspace activity, including: * Agent updates * Source creation and deletion * Action creation and deletion * Integration creation and deletion Each log entry displays: * The event type (Created, Updated, Deleted) * The object type (Agent, Source, Action, etc.) * The object name or ID * The user who performed the action * The timestamp of the change <Frame> <img alt="Workspace Settings API Keys" /> </Frame> <Frame> <img alt="Workspace Settings API Keys" /> </Frame> ### Filters & Search You can filter audit logs to quickly find specific changes using: * Date range selector * Agent filter * Event type filter * Search by user name or object ID This makes it easier to investigate unexpected behavior or review activity within a specific timeframe. # Two-factor authentication (2FA) Source: https://chatbase.co/docs/user-guides/workspace/two-factor-auth Secure your Chatbase workspace with two-factor authentication and backup recovery codes. ## What two-factor authentication does Two-factor authentication (2FA) adds an extra step when you sign in or perform sensitive actions, so your account stays protected even if someone knows your password. With 2FA enabled in Chatbase, you: * Sign in with your email and password * Then confirm using: * A 6‑digit code from an authenticator app (TOTP), or * A one-time recovery code as backup <Tip> We strongly recommend enabling 2FA for all workspaces. </Tip> ## Enable 2FA for your account <Steps> <Step title="Open your account security settings"> 1. Sign in to the Chatbase dashboard. 2. Click your avatar at the bottom-left of the sidebar. 3. Select **Account settings** and open the **Two step verification** section. <Frame> <img alt="Account settings page showing the Two step verification section in Chatbase" /> </Frame> </Step> <Step title="Scan the QR code with your authenticator app"> 1. Select **Set up two-step verification**. 2. Open your authenticator app (for example, Google Authenticator, 1Password, or Authy). 3. Scan the QR code shown in Chatbase. <Warning> Anyone with access to this QR code or secret can generate valid 2FA codes for your account. Do not share it or store screenshots in insecure places. </Warning> <Frame> <img alt="Two-factor authentication setup dialog in Chatbase showing the QR code and secret key" /> </Frame> </Step> <Step title="Confirm with a 6‑digit code"> 1. In Chatbase, enter the 6‑digit code from your authenticator app. 2. Select **Confirm** to finish setup. <Check> After confirmation, you’ll be prompted for a 2FA code the next time you sign in. </Check> </Step> </Steps> ## Recovery codes Recovery codes let you sign in when you don’t have access to your authenticator app (for example, if you lost your phone). Key rules: * You see recovery codes **only once** when you generate them * Each code is **single-use** * Generating a new set of codes **invalidates all previous codes** <Warning> Treat recovery codes like physical keys. Store them in a secure password manager or print them and keep them in a safe place. </Warning> ### Generate and download recovery codes 1. In the Chatbase dashboard, go to **Account settings → Two step verification**. 2. Open **Manage recovery codes**. 3. Select **Generate codes**. 4. Copy or download the codes and store them securely. <Frame> <img alt="Manage recovery codes dialog in Chatbase showing a list of one-time backup codes with copy and download options" /> </Frame> If you close the recovery codes dialog without saving, you will need to generate a new set. Old codes are invalidated when you regenerate. ## Sign in with 2FA When 2FA is enabled, the sign-in flow looks like this: 1. Enter your email and password as usual. 2. If your account requires 2FA, Chatbase redirects you to a **Two-factor authentication** page. 3. On this page you can: * Enter a 6‑digit code from your authenticator app, or * Select **Use a recovery code** and enter one of your single‑use codes. If the code is valid, you’re redirected back to the page you were trying to access. <Frame> <img alt="Two-factor authentication challenge page in Chatbase with fields for authenticator code and a link to use a recovery code" /> </Frame> <Note> If you close or navigate away from the 2FA challenge page without completing it, Chatbase signs you out to protect your session. </Note> ## Change email or 2FA settings Some actions in Chatbase are protected by 2FA, including: * Changing your account email * Managing or regenerating recovery codes * Removing 2FA from your account When you try one of these actions, you’ll be asked to confirm with: * A 6‑digit authenticator code, or * A recovery code (for most actions) <Warning> If you remove 2FA, your account will fall back to password-only protection. Do this only if you have a strong, unique password and understand the risk. </Warning> # Usage Source: https://chatbase.co/docs/user-guides/workspace/usage This tab displays the usage details of all AI agents in the selected workspace. You can also filter usage data for a specific workspace. By default, it shows the usage for all agents under your workspace for the current month. <Frame> <img alt="Usage Overview" /> </Frame> ## Configuration ### AI agents You can view usage for all your agents, a specific agent, or deleted agents to check the credits used by removed agents. To switch between AI agents: <Frame> <img alt="Usage Agent Configuration" /> </Frame> ### Time Interval You can configure the time interval to view usage for a specific period, such as last week. The selected time interval is highlighted in blue, as shown below. To adjust the time interval: <Frame> <img alt="Usage Date Configuration" /> </Frame> ## Usage Summary This section shows a summary for credits used and the number of AI agents used within the time interval you specified. ### Credits Used The section displays the number of message credits used. <Frame> <img alt="Usage Credits Used" /> </Frame> ### AI agents Used This section shows the number of AI agents in use compared to the total allowed. For example, this workspace has 4 AI agents out of a maximum of 60. <Frame> <img alt="Usage Agents Used" /> </Frame> ### Usage History The usage history displays the number of message credits used per day for the selected time interval. Hover over a specific histogram to see the exact credits used on that day. <Frame> <img alt="Usage History" /> </Frame> ### Credits used per AI agent This section compares credit usage across AI agents for the selected time interval. Hover over any color in the pie chart to see the exact number of credits used by the AI agent assigned to that color. <Frame> <img alt="Usage Credits Piechart" /> </Frame>