NewInstance Documentation
View as Markdown

Android

Native Kotlin chat SDK with a full Jetpack Compose UI: AI chatbot, live-agent handoff, attachments, typing indicators and unread counts.

Installlink

mavenCentral() must be present in dependencyResolutionManagement; consumer R8/ProGuard rules ship in the AAR. minSdk 24, JDK 17.

implementation("cloud.newinstance:liveandaichat:0.5.0")

Quick startlink

Your backend mints a customer token (see Session tokens (REST API)) and hands it to the app:

val chat = LiveAndAiChat.Builder(context)
    .config(LiveAndAiChatConfig(customerToken = tokenFromYourBackend))
    .build()

chat.openChat()

openChat() starts the bundled chat activity internally; Compose hosts can embed ChatScreen(sdk, onClose, onPickFile = {}, modifier) directly.

Auth modeslink

Configure exactly one credential. Both, neither, or a bare key ID make LiveAndAiChatConfig throw LiveAndAiChatError with code E_CONFIG. Its toString() redacts the secret and the token.

Customer token mode (recommended). LiveAndAiChatConfig(customerToken = ...). The SDK sends Authorization: Bearer <token> and the server derives the customer from the signed claims, so setUser fields are not sent. When a fresh token is due, call chat.setUserToken(freshTokenFromYourBackend): it swaps the credential for every later request and reconnects the realtime subscription without destroying the SDK. A token for the same customer keeps the conversation; the SDK compares the token's subject, not the token string.

Key mode (trusted internal apps only). This ships your secret inside the APK, so never use it in an app distributed to the public.

val chat = LiveAndAiChat.Builder(context)
    .config(LiveAndAiChatConfig(apiKey = "sk_live_abc123:YOUR_SECRET_KEY"))
    .build()
chat.setUser(ChatUser(customerName = "Ada", customerEmail = "ada@example.com", customerId = "usr_123"))

The SDK sends the full key in x-api-key. ChatUser requires a non-blank customerName (it throws otherwise); switching to a different customer in setUser clears the saved conversation and starts fresh. setUserToken throws E_CONFIG in key mode.

Errorslink

LiveAndAiChat.state exposes a ChatSdkError with a stable code, and listeners receive onError(LiveAndAiChatError) carrying the same code. Codes are shared with every other chat SDK; see Authentication and identity -> Diagnosing problems. An auth failure is reported as INVALID_IDENTITY_TOKEN in customer token mode and INVALID_PUBLIC_KEY in key mode, which is the difference between minting a fresh token and fixing the key. After an auth failure the SDK does not reconnect with the same credential; a later setUserToken restarts it.

Configurationlink

FieldDefaultNotes
customerTokennoneCustomer token minted by your backend. Selects customer token mode (recommended)
apiKeynoneThe full keyId:secret, sent whole. Selects key mode, trusted internal apps only. A bare key ID is rejected with E_CONFIG
baseUrlhttps://service.newinstance.cloudRelease builds throw on any override (debug-only escape hatch)
gqlPath / ssePath / wsPath/service / /graphql/stream / /graphql/wsTransport paths
transportinheritedsse or ws override
initialMessagenoneMessage sent automatically when the conversation opens
themedashboard themeChatThemeOverride(...) local theme, ranked below the dashboard theme and above the built-in one. See Theming
allowRemoteAttachmentUrlsfalseOpt-in: lets attach() download and upload http(s) sources

API surfacelink

initialize, openChat, closeChat, sendMessage, retryMessage, attachFile(bytes, name, mimeType, previewUri), attach(AttachmentRequest, previewUri?), removeAttachment (cancels an in-flight upload), clearAttachments, updateDraft, requestHandoff(reason), connectToAgent(reason), sendTypingStart / sendTypingStop, setUser, setUserToken, addListener / removeListener, destroy.

Observe state via StateFlows: lifecycle, connectionState, messages, conversation, assignment, agentTyping, unreadCount, orgConfig, agentsOnline, attachments, flowState, widgetOpen, draftText; or a listener with onMessageReceived, onMessageSent, onTyping, onConnectionChange, onUnreadCountChange, onError, onAttachmentUpdate, onChatClosed. Errors carry type (NETWORK, VALIDATION, AUTH, SYSTEM) and recoverable.

Programmatic attachmentslink

attach(AttachmentRequest(source, name, mimeType?, declaredSize?, metadata)) accepts any source: AttachmentSource.Base64Data, DataUri, FilePath, ContentUri, Bytes, or RemoteUrl (config-gated). AttachmentSource.detect(value) safely classifies strings. Validation runs before anything is queued: base64 must decode, URIs must be readable, files must be non-empty and at most 25 MB, MIME must be png/jpeg/webp/gif/pdf, a wrong declaredSize is rejected as corruption, and the extension must agree with the MIME type. Reads and uploads run off the main thread with real byte progress on the attachments flow and onAttachmentUpdate (statuses QUEUED, UPLOADING, UPLOADED, FAILED, CANCELLED). A message is never sent with an attachment that has not finished uploading, and attachment contents are never logged.

The chat close eventlink

onChatClosed fires exactly once per chat presentation, whichever way the screen goes away: the in-chat X (close_button), the system back button or gesture (back_navigation), closeChat() (programmatic; it now also finishes the chat activity), destroy() (session_ended), or host navigation (host_navigation). The event carries reason, initiator (user/host/sdk), timestamp, conversationId, assignmentId, channel, previousState, unreadCount, hasDraft, pendingAttachmentCount and SDK metadata; never message contents, credentials or attachment data.

Platform noteslink

  • The SDK manifest already declares INTERNET, ACCESS_NETWORK_STATE and legacy WRITE_EXTERNAL_STORAGE (maxSdkVersion 28) and merges the chat activity; add READ_MEDIA_IMAGES only if your own picker needs it.
  • Theming comes from the org configuration (the dashboard can force dark or light; otherwise the system theme applies); there is no local theme parameter.
  • All UI strings are Android string resources, so hosts can localise with values-xx overrides.
  • No push notifications: unread is in-app only via unreadCount.
  • destroy() cancels the SDK scope; any later call throws IllegalStateException, so build a new instance to start again.
  • Steps from your connected MCP servers (forms and secure pages) require 0.5.0; see MCP servers.