SDK API reference

With the Android SDK, you can customize the behavior of your AI Agent by configuring initial settings, either in XML or programmatically using the AdaMessagingView.Settings class.

1<!-- Example 1: XML -->
2<cx.ada.messaging.widget.AdaMessagingView
3 android:id="@+id/ada_view"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 app:ada_handle="my-handle"
7 app:ada_language="en"
8 app:ada_greeting="5c59aaabd8269e0339979014" />

Settings

The Ada Android SDK supports the following settings on AdaMessagingView.Settings.Builder. Settings that also have an XML attribute list it next to the builder method.

acceptThirdPartyCookies

app:ada_accept_third_party_cookies="true" or .acceptThirdPartyCookies(true)

Allows the WebView to accept third-party cookies. Defaults to false. Only set this if an Ada integration you use requires it.

appUrl

.appUrl("https://apps.example.com/ada-app/")

Overrides the app frame URL that the Messaging runtime mounts.

Your handle’s Allowed websites list controls custom apps. In your Ada dashboard, go to Channels > Chat and add your app’s origin. If the list does not allow the origin, the runtime drops the URL with a logged warning and mounts the default app.

The value must be an absolute https: URL. The runtime drops invalid values with a logged warning and mounts the default app instead. If the custom app fails to load or complete its handshake, the runtime falls back to the default app.

For local development against an emulator, expose your development server through an https: tunnel, and add the tunnel origin to Allowed websites. The dashboard accepts only https:// entries. On the production and pre-production environments, the WebView’s host page is an Ada asset origin, not a loopback page. The web SDK’s implicit loopback allowance therefore does not apply there. The emulator reaches the tunnel origin directly, so no port forwarding is needed.

The exception is the local asset-server environment (AdaEnvironment.Local), used for SDK development. Its WebView host page is https://localhost:4900, a loopback origin, so the implicit loopback allowance applies and a loopback appUrl needs no entry. The emulator’s 10.0.2.2 host alias is not a loopback host, so the runtime rejects it as an appUrl. A host page served from that alias also loses the implicit allowance, for the same reason. Instead, forward the port so the emulator reaches your development server at http://localhost:5173:

1adb reverse tcp:5173 tcp:5173

The SDK delivers the value to the web runtime through an injected configuration object, not through the WebView URL. Unlike identityToken, which is delivered once, the value is delivered again on every document load. See Custom apps. Ignored on the Legacy runtime.

cluster

app:ada_cluster="ca" or .cluster("ca")

Specifies the cluster your AI Agent runs on. Set this only if your Agent is hosted on a non-default cluster. If the Agent is on the default cluster, leave this unset.

Do not change this value unless instructed by your Ada team.

deviceToken

app:ada_device_token="fcm-device-token" or .deviceToken("fcm-device-token")

Registers the device’s push notification token at initialization. Use this so end users can receive push notifications for new messages while the app is closed. To change the token after initialization, use the setDeviceToken action.

domain

.domain("acme")

The Ada domain your AI Agent is served from. Applies to the Legacy runtime only. The Messaging runtime resolves its host from cluster and environment.

Do not set this value unless instructed by your Ada team.

embedVersion

.embedVersion("<build-sha>")

Pins the Legacy runtime to a specific embed build for pre-release validation. Leave blank for the stable rollout. Ignored on the Messaging runtime.

Only use this when the Ada team gives you a build to validate.

enableProgrammaticControl

.enableProgrammaticControl(true)

Opts your app into the Messaging runtime’s programmatic control surface. Defaults to false. When set to true, your app can:

While the flag is false, the runtime rejects sendMessage with a ProgrammaticControlNotEnabled error, and those events are not delivered to your callbacks.

Ignored on the Legacy runtime, which has no such gate.

Turning this on delivers full message bodies to your native code. The ada:message:sent and ada:message:received events carry the conversation transcript, including any PII your end users type. Have your product and security teams accept that exposure explicitly before you enable it.

environment

.environment(AdaEnvironment.Production)

Selects the Ada deployment environment. Defaults to production. See the AdaEnvironment type for the available values. Most apps never set this.

greeting

app:ada_greeting="5c59aaabd8269e0339979014" or .greeting("5c59aaabd8269e0339979014")

Customizes the greeting message that new end users see. The value is the ID of the Answer you want to use. You can find the ID in the URL of the corresponding Answer in the dashboard.

This setting only applies if you’re using a scripted AI Agent.

The plural forms .greetings(...) and app:ada_greetings are accepted as compatibility aliases. Use the singular greeting form in new code.

handle

app:ada_handle="my-handle" or AdaMessagingView.Settings.Builder("my-handle")

The handle for your AI Agent. This is a required field, passed as the Settings.Builder constructor argument.

headless

.headless(true)

Runs the Messaging runtime without its default UI. Defaults to false. The runtime still boots, connects, and emits events, and programmatic commands such as sendMessage still work. Only the rendered conversation surface is suppressed.

Use this when your app renders its own conversation UI, or when it only consumes conversation events. Pair it with the AdaMessagingView.headless factory to run the view without attaching it to a layout, and with enableProgrammaticControl when you need sendMessage.

Ignored on the Legacy runtime. See Headless mode.

Headless sessions run with no visual indicator to the end user. The conversation session is created the same way as a visible session. Treat enabling headless as a meaningful trust decision for your app.

identityToken

.identityToken(token)

Authenticates the end user with a one-shot identity token minted by your backend. The Messaging runtime exchanges the token for an authenticated session during startup.

The flow is:

  1. Your backend requests a short-lived, single-use JWT for the signed-in end user from Ada’s POST /v2/auth/tokens/ endpoint.
  2. Your app passes that token to .identityToken(...) when it builds the settings.
  3. The runtime performs the exchange before the conversation starts.
Kotlin
1val settings = AdaMessagingView.Settings.Builder("my-handle")
2 .webSdk(AdaWebSdk.Messaging)
3 .identityToken(tokenFromYourBackend)
4 .build()

Each token is single-use and expires quickly. Mint a fresh token from your backend for each initialization. Do not reuse tokens, and do not mint them on the device.

The SDK hands the token to the runtime through a secure native channel. The token never appears in a URL, and the SDK never persists it to disk.

Exchange failures surface as the ada:identity_token:error and ada:identity_token:expired events through addEventCallback.

Ignored on the Legacy runtime.

language

app:ada_language="en" or .language("en")

Takes a language code to programmatically set the AI Agent language. You must first turn languages on in your Ada dashboard. Go to Customization > Languages. See Support multiple languages in the same AI Agent for more information.

Language codes use the ISO 639-1 language format.

loadTimeoutMillis

app:ada_load_timeout="10000" or .loadTimeoutMillis(10000)

Sets the WebView load timeout in milliseconds. Defaults to 30000. When the timeout elapses before the conversation loads, the SDK invokes webViewLoadingErrorCallback.

metaFields

app:ada_metaFields="@raw/meta_fields" or .metaFields(builder)

Passes information about an end user to Ada. Use this to track information about your end users, and to personalize their experience. For example, you may wish to track the phone_number and name for conversation attribution.

Kotlin
1.metaFields(
2 AdaMessagingView.MetaFields.Builder()
3 .setField("name", "John")
4 .setField("age", 20)
5 .setField("authorized", true),
6)

To set metaFields in XML, create a JSON file in the res/raw directory, and reference it from the view declaration.

To change these values after initialization, use the setMetaFields action.

preprodDemoToken

.preprodDemoToken(token)

Time-bound access token for Ada’s pre-production environment. Leave blank for production. Only use this when the Ada team gives you a token for pre-release validation.

sensitiveMetaFields

app:ada_sensitiveMetaFields="@raw/sensitive_meta_fields" or .sensitiveMetaFields(builder)

Passes sensitive information about an end user. This works like metaFields, but the values are not stored in the database, and are deleted after 24 hours. To change these values after initialization, use the setSensitiveMetaFields action.

styles

app:ada_styles="..." or .styles("...")

Passes style overrides to the conversation. The value’s meaning depends on the runtime:

  • Legacy runtime: a CSS style override string, forwarded to the conversation frame.
  • Messaging runtime: a JSON object string of theme style tokens, for example .styles("{\"tintColor\":\"#520497\"}"). The runtime honors tintColor only today, and ignores unsupported keys. A value that does not parse as a JSON object is dropped with a logged warning.

version

.version("<build-sha>")

Pins the Legacy runtime’s conversation UI to a specific build for pre-release validation. Leave blank for the stable rollout. Ignored on the Messaging runtime.

Only use this when the Ada team gives you a build to validate.

webSdk

app:ada_web_sdk="legacy|messaging" or .webSdk(AdaWebSdk.Messaging)

Selects the web runtime the SDK loads. Defaults to AdaWebSdk.Legacy, which preserves the behavior of Ada’s existing Chat SDK. Set AdaWebSdk.Messaging to use the next-generation Messaging runtime.

The enableProgrammaticControl, headless, and identityToken settings, and the sendMessage action’s programmatic gate, apply to the Messaging runtime only.

Callback properties

Set these properties directly on your AdaMessagingView instance.

filePickerCallback

Fires when an end user requests to attach a file. Launch your file picker, then invoke callback.onFileTaken(uri) with the chosen URI. Pass null to cancel the request. Return true to signal that your app handles the picker flow.

Kotlin
1adaView.filePickerCallback = { callback ->
2 callback.onFileTaken(someUri)
3 true
4}

AdaMessagingActivity and AdaMessagingDialog handle file selection for you.

webViewErrorCallback

Fires whenever webViewLoadingErrorCallback fires, with a typed AdaWebViewError that describes the reason. When both callbacks are set, both fire.

Kotlin
1adaView.webViewErrorCallback = { error ->
2 when (error) {
3 is AdaWebViewError.Timeout -> showRetry()
4 is AdaWebViewError.HttpError -> log(error.statusCode)
5 is AdaWebViewError.LoadFailed -> log(error.description)
6 is AdaWebViewError.BridgeError -> log(error.error)
7 }
8}

webViewLoadingErrorCallback

Fires when the conversation fails to load, including when loadTimeoutMillis elapses. To learn why the load failed, set webViewErrorCallback instead, or in addition.

Kotlin
1adaView.webViewLoadingErrorCallback = {
2 // Show your own error state or retry.
3}

zdChatterAuthAsyncCallback

Asynchronous variant of zdChatterAuthCallback, for JWT tokens your app fetches over the network. The SDK invokes your callback with a respond function. Call respond(token) from any thread when your request completes, or respond(null) to fail the handoff request.

Kotlin
1adaView.zdChatterAuthAsyncCallback = { respond ->
2 fetchTokenFromApi { token ->
3 respond(token)
4 }
5}

The SDK accepts one answer per request and drops late answers for a superseded request. When both callbacks are set, zdChatterAuthAsyncCallback takes precedence.

zdChatterAuthCallback

Requests a JWT token from your API and passes it to Ada. This creates shared trust between Ada and Zendesk, which allows for verifiable end-user identity.

Kotlin
1adaView.zdChatterAuthCallback = {
2 getToken() // this function returns String
3}

The SDK invokes this callback on the main thread, so it must return quickly. To fetch the token over the network, use zdChatterAuthAsyncCallback instead.

zdChatterAuthCallback applies to Zendesk Chat only, and on this SDK it is invoked on the Messaging runtime only. On the Legacy runtime a Zendesk Chat handoff proceeds unauthenticated.

Actions

Use the actions below in conjunction with settings to customize the behavior of your AI Agent in an Android app.

The following actions apply to AdaMessagingView. To call actions on AdaMessagingActivity or AdaMessagingDialog, see AdaMessagingActivity and AdaMessagingDialog.

Actions called before the runtime reports ready are queued, then run once the sdk.ready event fires.

addEventCallback

addEventCallback(eventName: String = "*", callback: (event: Event) -> Unit)

Subscribes to conversation events. Pass an exact event key to receive only that event, or omit the key to receive every forwarded event through the "*" catch-all.

Kotlin
1adaView.addEventCallback("ada:message:received") { event ->
2 // A message from the AI Agent arrived.
3}
4
5adaView.addEventCallback { event ->
6 Log.d("Ada", "event=${event.eventName}")
7}

Useful event keys include:

  • ada:identity_token:error and ada:identity_token:expired report identityToken exchange failures.
  • ada:message:received and ada:message:sent fire per message on the Messaging runtime, and require enableProgrammaticControl.
  • ada.bridge.error reports a native bridge error.
  • ada.webview.loaded, ada.webview.loadFailed, and ada.webview.subresourceLoadFailed report the WebView’s own lifecycle. See WebView lifecycle events.
  • sdk.ready fires when the runtime is ready for commands.

Remove subscriptions with removeEventCallback(callback) or removeEventCallbacks(eventName).

addSdkEventCallback

addSdkEventCallback(callback: (key: String, data: String?) -> Unit)

Subscribes to every event with its raw key and JSON payload. Use this instead of addEventCallback when you need the unparsed payload. Remove subscriptions with removeSdkEventCallback(callback).

clearPersistedState

adaView.clearPersistedState()

Removes the SDK’s natively cached startup state: an allowlisted snapshot of non-sensitive branding state that smooths the next launch. Call it when an end user signs out. The next session starts without rehydrated state. See Session persistence.

The call works before initialize. It does not touch the web runtime’s own storage. To clear the conversation itself, use deleteHistory or reset.

deleteHistory

adaView.deleteHistory()

Deletes the end user’s conversation history from storage. When the end user opens a new conversation, the SDK creates a new end-user record.

initialize

adaView.initialize(settings)

Initializes the view with an AdaMessagingView.Settings object and starts loading the conversation. Required when the view was created programmatically, or when the XML declaration has no ada_handle attribute.

reset

adaView.reset()

Creates a new end-user session and refreshes the conversation.

Reset can also take optional parameters to apply to the new session: language, greetings, metaFields, sensitiveMetaFields, and resetChatHistory:

Kotlin
1adaView.reset(
2 language = "en",
3 metaFields = AdaMessagingView.MetaFields.Builder()
4 .setField("plan", "pro"),
5 sensitiveMetaFields = AdaMessagingView.MetaFields.Builder()
6 .setField("authToken", "secure-session-token"),
7 resetChatHistory = true,
8)

sendMessage

adaView.sendMessage(message: String)

Sends a message into the conversation on the end user’s behalf, as if they had typed it. Calls queue until the runtime reports sdk.ready, so you can call it right after initialize.

Kotlin
1adaView.sendMessage("I need help with my order")

On the Messaging runtime, the send is rejected with a ProgrammaticControlNotEnabled error unless you set enableProgrammaticControl(true).

setDeviceToken

adaView.setDeviceToken(token: String)

Registers or updates the device’s push notification token. Use this so end users can receive push notifications for new messages while the app is closed.

setLanguage

adaView.setLanguage(language: String)

Changes the conversation language programmatically. Use this action, rather than the language setting, to change the language without clearing the conversation history. Language codes must use a lowercase, two-letter ISO 639-1 code.

Kotlin
1adaView.setLanguage("fr")

Before using setLanguage, you must turn languages on in your Ada dashboard. Calls made before the runtime reports sdk.ready are queued and dispatched when it becomes ready, so you can call it right after initialize.

setMetaFields

Changes your metaFields while the conversation is open:

Kotlin
1adaView.setMetaFields(
2 AdaMessagingView.MetaFields.Builder()
3 .setField("name", "John")
4 .setField("age", 20)
5 .setField("authorized", true),
6)

setSensitiveMetaFields

Changes your sensitiveMetaFields while the conversation is open:

Kotlin
1adaView.setSensitiveMetaFields(
2 AdaMessagingView.MetaFields.Builder()
3 .setField("authToken", "rotated-session-token"),
4)

Map<String, String> overloads for setMetaFields, setSensitiveMetaFields, and reset still exist for backward compatibility, but are deprecated. Use MetaFields.Builder for all new code.

WebView lifecycle events

The SDK synthesizes events for the WebView’s own lifecycle and delivers them through addEventCallback and addSdkEventCallback, alongside the runtime’s events:

KeyFires when
ada.webview.loadedThe WebView finishes loading its page. The payload includes the loaded url.
ada.webview.loadFailedThe initial load fails: a main-frame resource error, an HTTP status of 400 or higher, a load timeout, or a URL build failure. The payload includes url, code, statusCode, and error. webViewLoadingErrorCallback and webViewErrorCallback also fire.
ada.webview.subresourceLoadFailedA resource inside the page fails to load after the main document: a subresource error or an HTTP status of 400 or higher. Reported once per URL per page load. The payload includes url, code, statusCode, and error. The error callbacks do not fire, because the main frame is intact.

Headless mode

Headless mode runs the Messaging runtime without visible conversation UI. Your app receives conversation events and sends messages through native code. Use it to build native surfaces such as unread badges, notification banners, or a custom composer.

Two pieces combine into headless operation:

  1. The headless setting tells the runtime to suppress its default UI. The runtime still boots, connects, and emits events.
  2. The AdaMessagingView.headless(context, settings) factory constructs the view without a layout tree. The view starts loading immediately instead of waiting for window attachment.

You can also place a normal AdaMessagingView in your layout at zero size. The factory exists so you do not have to.

The headless factory

AdaMessagingView.headless(context: Context, settings: Settings): AdaMessagingView

Builds a view that runs without joining the layout tree. The factory forces headless = true on the settings it receives. It requires webSdk(AdaWebSdk.Messaging), and throws IllegalArgumentException when the settings target the Legacy runtime.

Example: drive a native unread badge

Kotlin
1val settings = AdaMessagingView.Settings.Builder("my-handle")
2 .webSdk(AdaWebSdk.Messaging)
3 .enableProgrammaticControl(true)
4 .identityToken(tokenFromYourBackend)
5 .build()
6
7val ada = AdaMessagingView.headless(context, settings)
8
9ada.addEventCallback("ada:message:received") { event ->
10 unreadBadge.increment()
11}
12ada.addEventCallback("ada:message:sent") { event ->
13 unreadBadge.clear()
14}
15
16ada.sendMessage("I need help with my order")

sendMessage calls queue until the runtime reports sdk.ready, so you can call it right after the factory returns.

Constraints

  • Messaging runtime only. The factory rejects AdaWebSdk.Legacy with an IllegalArgumentException.
  • sendMessage needs programmatic control. The runtime rejects the send with ProgrammaticControlNotEnabled unless you set enableProgrammaticControl(true).
  • No background execution. The WebView runs only while your process lives. It is not a push channel and not a background service. Use setDeviceToken and push notifications for delivery while your app is closed.
  • One conversation session per view. Do not create a headless view and a visible view for the same end user at the same time. Attach the headless view later if you need UI.

Lifecycle you still own

An unattached WebView does not receive lifecycle callbacks from the framework. Forward them yourself:

  • Call ada.onResume() when your owning screen or app comes to the foreground.
  • Call ada.onPause() when it leaves the foreground. This pauses timers and reduces battery use.
  • Call ada.destroy() when you are done with the view. Remove your event callbacks first.

Tie these calls to a LifecycleObserver on the owning activity, fragment, or process lifecycle.

Showing UI later

A headless view is a real AdaMessagingView. Add it to a layout with nonzero size to show the conversation:

Kotlin
1container.addView(ada, MATCH_PARENT, MATCH_PARENT)

The in-flight session continues, and the view does not reload on attachment. The runtime keeps its headless flag, so start a non-headless view when you need Ada’s own conversation UI.

AdaMessagingActivity and AdaMessagingDialog

To call actions on AdaMessagingActivity, call getAdaView() to obtain the AdaMessagingView instance. The method is public, so any code that holds the activity instance can call it. It is available from onCreate onward. For example, from a subclass:

Kotlin
1class MyCustomActivity : AdaMessagingActivity() {
2 override fun onResume() {
3 super.onResume()
4 val adaView = getAdaView()
5 adaView.setMetaFields(
6 AdaMessagingView.MetaFields.Builder()
7 .setField("name", "John"),
8 )
9 }
10}

AdaMessagingDialog forwards the common actions directly: clearPersistedState, deleteHistory, downloadTranscript, reset, sendMessage, setDeviceToken, setLanguage, setMetaFields, and setSensitiveMetaFields, plus the subscription methods addEventCallback, removeEventCallbacks, addSdkEventCallback, and removeSdkEventCallback. Obtain the dialog instance from the fragment manager:

Kotlin
1val adaDialog = supportFragmentManager
2 .findFragmentByTag(AdaMessagingDialog.TAG) as AdaMessagingDialog
3adaDialog.setMetaFields(
4 AdaMessagingView.MetaFields.Builder()
5 .setField("name", "John"),
6)
7adaDialog.reset()

You can register event callbacks on the dialog before it is shown. The dialog buffers them and attaches them when its view is created. Call the other forwarded actions only after the dialog is shown.

Session persistence

The Android SDK stores session state, including the end-user token and any active handoff context, in the WebView’s localStorage. The native side also caches a small allowlist of non-sensitive branding state, with a 10 minute expiry, to smooth the next launch. Remove that cache with clearPersistedState.

On Android, WebView localStorage is not guaranteed to survive a force-quit. If an end user force-closes the app during an active session or live agent handoff, their conversation state can be lost when they reopen the app.

If your app requires session continuity across app restarts, you need to implement your own native storage management. The SDK does not persist session state using platform-native storage such as SharedPreferences, and it never persists identity tokens to disk.

Types

AdaEnvironment

Sealed class that selects the Ada deployment environment. Pass it to environment.

ValueDescription
AdaEnvironment.ProductionAda’s production environment. The default.
AdaEnvironment.Preprod(branch)Ada’s pre-production environment, for validation the Ada team directs.
AdaEnvironment.Local(port, host)A local development server, for SDK development.

AdaWebSdk

Enum that selects the web runtime. Pass it to webSdk.

ValueDescription
AdaWebSdk.LegacyThe existing Chat runtime. The default.
AdaWebSdk.MessagingThe next-generation Messaging runtime.

AdaWebViewError

Sealed class delivered to webViewErrorCallback.

CaseDescription
BridgeError(error)The native bridge reported an error before the runtime became ready.
HttpError(url, statusCode)The main document responded with an HTTP error status.
LoadFailed(url, errorCode, description)The main document failed to load. url is null when the SDK could not build the WebView URL.
Timeout(timeoutMillis)The page did not finish loading within loadTimeoutMillis.

Event

Data class delivered to addEventCallback subscribers.

FieldTypeDescription
chatterTranscriptString?The conversation transcript, when the event carries one.
eventNameString?The event key, for example ada:message:received.
userDataJSONObject?Event-specific payload data.

MetaFields.Builder

Builder for metaFields and sensitiveMetaFields values. setField(key, value) accepts String, Boolean, Int, Long, Float, and Double values.

Kotlin
1AdaMessagingView.MetaFields.Builder()
2 .setField("name", "John")
3 .setField("age", 20)
4 .setField("authorized", true)