Before you start
1
Open the SDK channel
Open Channels in your agent’s sidebar. On the iOS SDK or
Android SDK card, choose Setup (Manage once the channel is
enabled). The channel opens on its Setup
tab, next to Overview and Actions.
2
Copy the agent ID
Under Agent ID, choose Copy. You pass this ID when you create the
client. The Quick start snippet on the same tab already contains it,
together with the base URL of your Centillion host, which ends in
/api/sdk.3
Turn on Visibility
Open Overview, switch on Visibility and save. Until you do, the
agent answers no messages from the app, and requests fail with
AGENT_NOT_FOUND. The card on Channels shows Enabled once the
platform is visible.iOS
The iOS SDK needs iOS 17 or later (macOS 14 or later), Swift 6 and Xcode 16 or later.Install the iOS package
In Xcode, choose File → Add Package Dependencies and paste the package URL:0.1.0 or later and add CentillionSDK to your app target.
For a Swift package, add the dependency to Package.swift instead:
Package.swift
Send a message from Swift
async
function or a Task. onTextDelta receives the reply as it streams;
onToolCall and onToolResult report the actions the agent runs.
To continue a conversation, pass its ID: send("Tell me more", conversationId: response.conversationId). A send without a conversationId starts a new
conversation. Cancel the calling Task to cancel the request.
On iOS
- The signed-in user’s token is kept in the Keychain, readable only on this
device. After the app restarts, the user is still signed in, but
currentUserIdstays empty until you callidentifyagain. - The SDK accepts plain HTTP only for
localhost,127.0.0.1and::1. In the simulator, usehttp://localhost:3000/api/sdkagainst a local server. Remote servers need HTTPS.
Android
The Android SDK needs Android 7.0 or later (API 24), JDK 17 or later, and an Android Studio version that supports Android Gradle plugin 8.13.2. The SDK builds with Kotlin 2.2.20 and Gradle 9.2.1, and adds theINTERNET permission
to your app.
Install the Android module
The SDK is installed from source. Clone it beside your project:centillion-sdk module and depend on it. Use the Google and
Maven Central repositories.
Send a message from Kotlin
suspend functions from a coroutine, such as
viewModelScope. Its callbacks (onStart, onTextDelta, onToolCall,
onToolResult, onFinish and onError) run on Dispatchers.Main.
The Android client continues its current conversation by default. Pass another
conversationId to switch, or call client.newConversation() to start a new
one. Cancel the coroutine to cancel the request.
Raw event streams
sendMessage runs your app’s actions for you. If you need every event
yourself, sendMessageStream and retryStream return a Flow<StreamEvent>
with Start, TextDelta, ToolRequested, ToolCompleted and Finish. These
flows do not run actions: for a ToolRequested event, call
submitToolResult(conversationId, requestId, callId, output) yourself, unless
the call’s execution is "server", which means Centillion already ran it.
On Android
- The signed-in user’s token is kept in memory only, never in preferences. Call
identifywith a fresh token from your backend each time the app starts. - The SDK accepts plain HTTP only for
localhost,127.0.0.1,10.0.2.2and::1. In the emulator, usehttp://10.0.2.2:3000/api/sdkagainst a local server. Remote servers need HTTPS.
Replies and retries
Every reply ends with a response that holdsmessage, conversationId,
userMessageId, finishReason and usage, which counts the credits,
inputTokens and outputTokens the reply used.
sendNonStreaming waits for the whole reply and returns the same response,
running your app’s actions along the way.
retry takes a conversation ID and the ID of one of the agent’s answers, and
asks the agent to answer again. The saved conversation changes only when the
new answer succeeds: the answer and every message after it are replaced. If the
retry fails, the conversation stays as it was.
When the stream ends before the reply finishes, the request fails with
INCOMPLETE_STREAM. A lost connection is a URLSession error on iOS and a
NetworkException on Android. The SDK never sends the message again by itself; show the
error and let the customer try again.
Conversation state
ConversationState keeps one conversation ready for your chat screen. On iOS
its properties are observable; on Android it publishes a StateFlow snapshot.
It holds messages, conversationId, isSending, isLoadingHistory,
hasMoreHistory, toolCalls, toolResults and error. Use sendMessage,
retry, loadHistory, loadMoreHistory, clearError and clear.
ConversationListState does the same for the list of conversations, with
conversations, isLoading, hasMore and error, and load, loadMore,
clearError and clear.
When the signed-in user changes, cancel any work still running and clear both.
History
listConversations and listMessages return a page with data, total,
hasMore and cursor. A page holds 20 items unless you ask for between 1 and
100. Conversations come most recently active first, each with a title taken
from the customer’s first message. The first page of messages holds the newest ones, in
the order they were written; each later page holds older messages to put in
front.
History only holds this agent’s iOS and Android conversations. Website
conversations are never included.
- Before sign-in, history belongs to the app installation. The SDK creates an installation ID the first time it runs and keeps it for that agent and base URL.
- A signed-in user has the same history on every device and on both platforms.
status is ongoing, taken_over or ended. An ended
conversation accepts no new messages or retries. While a teammate has the
conversation (taken_over), new messages go to them rather than to the agent,
and retries are refused. See Helpdesk for taking a conversation
over.
To rate an answer, call feedback with the conversation ID, the answer’s ID and
"up" or "down". Pass nil on iOS or null on Android to clear the rating.
Signed-in users
When someone is signed in to your app, your backend can vouch for them, so their conversations follow them across devices.1
Get the token secret
Open Settings → Identity and copy the Token secret. Keep it on your
backend. It must never ship inside the app.
2
Sign a token on your backend
After your backend has authenticated the user, sign a JWT with HS256 and the
token secret. It must name the user in
sub or user_id. If it has an
exp, it can be at most 24 hours ahead, plus 60 seconds for clock
differences. The token works exactly like the website widget’s; see
Identity verification for the
contact fields it can carry.3
Pass it to the SDK
Fetch the token from your backend and call
identify. Call logout when
the user signs out.INVALID_IDENTITY until you call identify with a new one.
Signed-in users need the Standard plan or above, and identity verification set
up for the agent. Without them, every token is refused. See
plans.
App actions
The agent can ask your app to do something, such as reading the app version or opening a screen, and use the result in its answer.1
Create the action
Create a custom action and choose Run client-side code in Action
type. Keep Wait for response on when the agent needs the result. See
Custom tools.
2
Enable it for the app
Turn the action on for iOS SDK, Android SDK or both. The SDK
channel’s Actions tab lists the actions for that platform.
3
Register a handler
Register a handler under the action’s exact name:
- The result must be JSON of at most 20,000 bytes.
- By default the SDK runs at most 10 app actions per reply. On iOS, change
this with
maxToolLoopStepswhen you create the client; on Android, setclient.maxToolLoopSteps. - With Wait for response on, your handler has 25 seconds. After that, the agent tells the customer the action could not be completed.
- With no handler under that name, or when the handler throws, the agent gets an error instead of a result.
onToolCall and onToolResult report them too, with execution set to
"server". Each platform uses its own action settings, even in a conversation
that started on the other one.
An action written as JavaScript for the website does not run in a native app.
Implement it in Swift or Kotlin instead.
Errors
On iOS, server errors areSDKError, and lost connections are URLSession
errors. On Android, server errors are ApiException, and lost connections are
NetworkException. Both server error types carry status, code and
message. A cancelled request stays a cancellation.
Example apps
Each example app is a working chat app built on its SDK, with streaming replies, history, retry and aget_app_version action. To try that action, create a
client action with that name, turn on Wait for response, enable it for the
platform and ask the agent for the app version.
- iOS. Clone ios-sdk-example-app,
open
CentillionSample.xcodeproj, choose an iPhone simulator and run. Runswift testin a clone of the SDK to test the library. - Android. Clone
android-sdk-example-app
with
git clone --recurse-submodules, open it in Android Studio and run theapptarget.