Adding the Mobile SDK Channel (iOS & Android)
The Mobile SDK channel — shown in the Channels module under the Mobile apps group as Mobile - iOS and Mobile - Android — lets you embed a bot in a native mobile application. Your application links the SentiOne Automate SDK, and the SDK talks to the Automate backend directly over gRPC. There is no webhook to expose and no web page to host.
Unlike webhook-based channels, this channel does not authenticate against someone else's messaging platform. It authenticates your own application binary: on the first call the SDK proves which app it is, and Automate checks that against the identity you register here. Most of the configuration below exists for that reason.
One channel per platformA Mobile SDK channel is bound to a single platform. An iOS app and an Android app need two separate channels — each with its own App Key — even when they are the same product and serve the same project.
The platform cannot be changed after the channel is created. If you pick the wrong tile, create a new channel instead.
Prerequisites
- Permission to edit channels in the
Channelsmodule. - A project (bot) to assign the channel to. The channel stays inactive until it is assigned.
- The identity of the mobile application, obtained from whoever builds it — see Step 1.
- Only if you want to require signed-in users: an identity provider that issues JWTs and publishes a JWKS endpoint on a public HTTPS URL — see External JWT authentication.
- Only if the app should speak or listen: TTS and/or ASR providers enabled for your organisation.
Step 1: Collect the application identity
During the initial handshake the SDK sends the identity of the running application, and Automate compares it with the values registered on the channel. If they do not match, the handshake is rejected with UNAUTHORIZED_PLATFORM and the app cannot open a conversation.
This binds the App Key to one specific, signed build, so a leaked key cannot be used from a different or re-signed application. Ask your mobile developer for the values below — they are all properties of the app build, not something you create in Automate.
iOS
| Value | Where it comes from |
|---|---|
| Bundle ID | Xcode → select the app target → General → Bundle Identifier. Equivalently, CFBundleIdentifier in the target's Info.plist. |
| Apple Team ID | Apple Developer → Membership details → Team ID. Also visible in Xcode → Signing & Capabilities → Team, where it is the 10-character code shown next to the team name. |
Android
| Value | Where it comes from |
|---|---|
| Package Name | The applicationId in the app module's build.gradle.kts (or build.gradle). This is the application ID, which is not always the same as the Kotlin/Java package of the source code — take the applicationId. |
| SHA-256 certificate fingerprint | The fingerprint of the certificate that signs the build which will connect. Obtain it with ./gradlew signingReport (read the SHA-256 line for the relevant variant), or with keytool -list -v -keystore <keystore-file> -alias <alias>. |
Android: register the certificate that actually signs the delivered appWhen Google Play App Signing is enabled, Play re-signs your app with the app signing key, so the installed app carries a different certificate than your upload key. Register the app signing key fingerprint from Play Console → Test and release → Setup → App signing → SHA-256 certificate fingerprint.
Debug builds are signed with the local debug keystore and therefore have a different fingerprint than release builds. A channel registered for the release fingerprint will reject debug builds — create a separate channel for development if your team needs one.
If the app is signed by more than one signer, or its signing key has been rotated, the SDK reports only the first fingerprint the platform returns. That is the one to register here.
Step 2: Create the channel
- Go to the
Channelsmodule and click Create. - In the Mobile apps group, select the Mobile - iOS or Mobile - Android tile.
- Fill in the form. Only Name and the two platform fields are required; every field is described in Step 3.
- Click Save.
- Automate generates the App Key at this point and opens a summary screen with two things on it: a project selector, and the App Key with a copy button. Assign the project here, or later from the channels list.
Copy the App Key when you need it, not necessarily nowThe summary screen is not your only chance to read the key — reopening the channel for editing shows it again in the Authentication section. But it is not shown while creating a channel, because it does not exist yet.
Step 3: Field reference
The sections below follow the order of the form.
Authentication
Present only when you reopen an existing channel; on the summary screen straight after saving, the same value appears in its own panel.
| Field | Required | Format and rules | What it is |
|---|---|---|---|
| App Key | generated | Read-only, masked. mc- followed by 32 random letters and digits. Use the copy button to read it. | The credential the mobile app presents on every call. Automate generates it when the channel is saved — you never type it in. Give it to your mobile developer, who puts it in the SDK configuration. It identifies this channel, so it is bound to one platform, one app identity and one environment: a key issued on one Automate environment is rejected by another. |
The App Key is not a secret in the way an API secret isIt ships inside the application binary, so anyone with a copy of the app can read it. That is expected — it is the platform identity check from Step 1, and optionally external JWT authentication, that stop a stolen key from being useful. Still, treat the key as configuration to hand over deliberately, not something to publish.
Basic Information
| Field | Required | Format and rules | What it is |
|---|---|---|---|
| Name | yes | Non-empty, up to 256 characters; must be unique among your channels. | Your own label for the channel, shown in the channels list. It is never displayed to end users, so name it for the app and platform it serves, for example Retail app — Android (production). |
The remaining fields in this section depend on the platform tile you selected. Their values come from Step 1; what follows is what the form enforces.
Mobile - iOS
| Field | Required | Format and rules | What it is |
|---|---|---|---|
| Bundle ID | yes | Reverse-DNS: at least two dot-separated parts, each starting with a letter and continuing with letters, digits or underscores — for example com.example.app. | The bundle identifier of the app permitted to use this channel. |
| Apple Team ID | yes | Exactly 10 characters, uppercase letters and digits only — for example A1B2C3D4E5. | The Apple Developer Team that signs the app. Together with the Bundle ID it identifies the build allowed to connect. |
Hyphens in a Bundle IDApple permits hyphens in a bundle identifier, but the channel form currently rejects them. If your Bundle ID contains a hyphen, contact SentiOne support rather than altering the app's identifier.
Mobile - Android
| Field | Required | Format and rules | What it is |
|---|---|---|---|
| Package Name | yes | Reverse-DNS: at least two dot-separated parts, each starting with a letter and continuing with letters, digits or underscores — for example com.example.app. | The applicationId of the app permitted to use this channel. |
| SHA-256 certificate fingerprint | yes | 64 hexadecimal characters, either continuous (a1b2…) or as 32 colon-separated pairs (A1:B2:…). Letter case and colons are ignored, so paste whichever form your tool produced. | The fingerprint of the signing certificate of the app permitted to use this channel. |
TTS and ASR (default)
Both sections are optional, and only relevant if the app offers speech. Configure TTS to let the SDK play synthesized bot replies, and ASR (default) to let it stream the microphone in for transcription. Text conversations need neither.
| Field | Required | Format and rules | What it is |
|---|---|---|---|
| Provider | no | Selected from the providers enabled for your organisation. Mobile channels support Techmo, Google, Microsoft and ElevenLabs; other providers your organisation may have are not offered here. | Which speech engine serves this channel. Leave the section untouched to keep speech off. |
| Provider-specific fields | yes, once a provider is chosen | Depends on the provider: a language and voice for Google and Microsoft, a speech key and region for Microsoft, an API key and voice for ElevenLabs, and so on. | The specific voice or recognition model to use. These are the same provider settings as on the Voice Gateway channel — see Adding Voice channel (Google provider) and Adding Voice channel (Microsoft provider) for what each provider expects. |
| Raw Mode | no | Toggle in the section header, available once a provider is selected. Replaces the guided fields with a JSON editor (TTS Params / ASR Params); the JSON must be valid. | An escape hatch for provider options the guided form does not expose. Switching Raw Mode back off asks for confirmation and discards JSON that the guided form cannot represent, so prefer the guided fields unless you specifically need it. |
The app can tell whether voice is availableLeave a section empty and speech simply stays off for this channel: at handshake the SDK is told that speech-to-text and/or text-to-speech is unavailable, and a voice call made anyway fails with
SPEECH_TO_TEXT_NOT_AVAILABLEorTEXT_TO_SPEECH_NOT_AVAILABLE. Well-behaved apps hide their microphone and playback controls based on that signal, so configuring a provider here is what makes the feature appear in the app.
Handover to Agent
Optional. Determines what happens when the flow hands the conversation to a human. The default is Listen & React, SentiOne's own agent application, which needs no extra configuration. Other destinations, such as Genesys, require their own credentials, and which ones appear here depends on what is enabled on your installation — ask your system administrator if an option you expect is missing.
Once the conversation is owned by an agent, the agent's replies reach the app asynchronously and the bot stops answering until the thread is handed back. For what each option involves, see Conversation handover.
External JWT authentication
This section is optional. Leave Enforce external JWT off and the channel is anonymous: any installation of the registered app can start a conversation, and the SDK sends no user credential. Anonymous is the right choice for a public assistant that does not need to know who is asking.
Turn it on when the bot should serve signed-in users only, or when the flow needs to know who the user is. The app then has to attach a JWT issued by your own identity provider to every call, and Automate verifies it against the JWKS below before allowing the session. The three fields appear only once the switch is on.
| Field | Required | Format and rules | What it is and where to get it |
|---|---|---|---|
| Enforce external JWT | no | Toggle. Off by default. | Off — anonymous channel, no user credential. On — the SDK must present a JWT signed by your identity provider, validated against the JWKS URL below. |
| Audience (aud) | yes, when enforced | Non-empty, up to 256 characters. | The value Automate expects to find in the token's aud claim. A token is accepted only when its audience list contains this value; anything else is rejected as an audience mismatch. Take it from your identity provider's configuration — it is whatever identifier you registered for the Automate integration (an API identifier, a client ID, or a name you chose). |
| JWKS URL | yes, when enforced | Absolute HTTPS URL, up to 512 characters. The host must resolve to a public address — localhost, private and internal addresses are rejected. | The JSON Web Key Set endpoint Automate fetches to verify token signatures. Every mainstream identity provider publishes one; it is often listed as jwks_uri in the provider's OpenID configuration document (…/.well-known/openid-configuration). Automate must be able to reach it, which is why private hosts are refused. |
| User identifier claim | yes, when enforced | Non-empty, up to 128 characters. | The name of the claim whose value identifies the user — not the value itself. Commonly sub, but any claim your provider issues will do: a user ID, a username, a customer number, or an ID of the user's own session. Automate reads that claim to tie the conversation to a user, and a session started under one user's token cannot be continued with another's. |
| Pass external JWT to bot flow | no | Toggle. Off by default. | When on, every message reaching the bot carries the raw token and its decoded claims, available in the flow as external.externalToken.raw and external.externalToken.payload. Turn it on when the flow needs data from the token — an account number, an entitlement, a tier — and leave it off otherwise, so claims are not written into conversation data unnecessarily. |
What the token has to look likeAutomate accepts tokens signed with RS256, RS384, RS512, ES256, ES384 or ES512, verified against a key from your JWKS endpoint. The token must carry an
exp(expiry) claim, must not be expired, must include the configured audience, and must contain the configured user identifier claim with a non-empty value. Tokens are validated on every call, so a session lives no longer than the token backing it — your app is responsible for refreshing the credential, and the SDK picks the new value up.
On-premise installations and internal JWKS hostsRejecting private and internal JWKS hosts is a deliberate safeguard on SentiOne cloud. On an on-premise installation where the identity provider is only reachable inside your network, this check can be relaxed by an administrator through the
allow-private-jwks-hostssetting. Contact your system administrator.
Step 4: Assign the channel to a project
A Mobile SDK channel does nothing until it is assigned to a project — that assignment is what decides which bot answers. Until then the channel is marked Channel inactive, and the SDK cannot start a conversation.
Assign it on the summary screen right after saving, or later from the channels list. You can also change the assignment afterwards to point the same app at a different bot, which is a convenient way to move an app between a test bot and a production bot without rebuilding it.
Step 5: Hand the configuration to your mobile developer
The channel is only half of the integration; the other half lives in the app. Give your mobile developer the following:
| What to hand over | Why they need it |
|---|---|
| App Key | Goes into the SDK configuration as appKey. Identifies this channel. |
| Which Automate environment to connect to | App Keys are environment-bound. For an on-premise installation they will need the host name and port of your Automate deployment, which the SDK accepts as a custom environment. |
| Whether the channel is anonymous or enforces external JWT | Decides whether the app must supply a client access token at all. Sending a token to an anonymous channel is rejected, and so is omitting one where a token is required. |
| The audience, user identifier claim, and issuing provider — when external JWT is enforced | Their tokens must carry the audience and claim this channel expects; otherwise every call is rejected. |
| The exact identity you registered — Bundle ID and Team ID, or Package Name and fingerprint | So they can confirm the build they ship matches the registration, and know that a differently signed build needs its own channel. |
Minimal iOS configuration:
import SentiOneAutomate
let configuration = try SentiOneSDKConfiguration(
appKey: "mc-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
teamId: "A1B2C3D4E5"
)
let sdk = SentiOneSDK(configuration: configuration, delegate: self)Minimal Android configuration:
val sdk = SentiOneAutomate.create(
context = context,
config = Configuration(appKey = "mc-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
tokenProvider = null, // required only when the channel enforces external JWT
)Everything beyond this — installing the SDK, opening a session, streaming replies, handling voice and errors — is covered by the integration guide shipped with each SDK. Ask the SentiOne team for the current version.
Troubleshooting
The form will not save
| Message | What to do |
|---|---|
| Channel name cannot be empty | Enter a name. |
| Bundle ID / Package Name must be reverse-DNS, for example com.example.app | Use at least two dot-separated parts, each starting with a letter. |
| Apple Team ID must be 10 uppercase alphanumeric characters | Paste the Team ID only, without the surrounding parentheses that Xcode shows next to the team name. |
| SHA-256 fingerprint must be 64 hex characters, optionally separated into pairs by colons | You probably pasted a SHA-1 fingerprint (40 characters) — take the SHA-256 line instead. |
| Cannot change the platform of an existing MobileChat channel | Create a new channel for the other platform. |
| Audience (aud) cannot be empty / must be at most 256 characters | Fill in the audience your identity provider issues, or turn off enforcement. |
| JWKS URL must be a valid absolute https URL | Use a full https://… URL. Plain HTTP and relative paths are refused. |
| JWKS URL host must resolve to a public address | The endpoint is not reachable from Automate. See the note on on-premise installations above. |
| User identifier claim cannot be empty / must be at most 128 characters | Enter the claim name, for example sub. |
| Selected TTS / ASR provider is not supported for mobile channels | Choose Techmo, Google, Microsoft or ElevenLabs. |
The app cannot connect
The SDK surfaces the reasons below; each maps to something in this configuration.
| Reported reason | Cause |
|---|---|
INVALID_APP_KEY | The key does not exist — often a key from another Automate environment, or a typo. |
APP_KEY_REVOKED | The channel has been disabled. |
UNAUTHORIZED_PLATFORM | The app's identity does not match the registration: wrong Bundle ID or Team ID, wrong Package Name, or — most commonly on Android — a build signed with a different certificate than the fingerprint you registered. |
CLIENT_ACCESS_TOKEN_MISSING | The channel enforces external JWT but the app sent no token. |
CLIENT_ACCESS_TOKEN_NOT_SUPPORTED | The opposite: the app sent a token to an anonymous channel. |
CLIENT_ACCESS_TOKEN_EXPIRED | The token's exp has passed. The app must refresh it; long-lived streams end when the token backing them expires. |
CLIENT_ACCESS_TOKEN_SIGNATURE_INVALID | The signature did not verify against any key from the JWKS endpoint, or the signing algorithm is not one of the supported RSA/ECDSA algorithms. |
CLIENT_ACCESS_TOKEN_AUDIENCE_MISMATCH | The token's aud does not contain the Audience (aud) configured here. |
PRINCIPAL_CLAIM_MISSING | The token has no claim by the configured User identifier claim name, or its value is empty. |
PRINCIPAL_MISMATCH | An attempt to resume a session with a token belonging to a different user. |
AUTH_PROVIDER_UNAVAILABLE | Automate could not reach your JWKS endpoint. Check that it is up and publicly reachable, then retry. |
SDK_VERSION_UNSUPPORTED | The app embeds an SDK version below the supported minimum and must be updated. Nothing on the channel needs changing. |
Updated 1 day ago
