# Trigger Bot Application API V3

Sprinklr's **Conversational AI** is an automated, AI-powered virtual assistant that engages with customers. It interprets the intent behind a customer's query, identifies why they reached out, and takes the actions your brand configured. It also reads the sentiment of the message and replies appropriately.

The **Trigger Bot Application API** drives that assistant programmatically. You send it the bot application to run, the message text, and the conversation the message belongs to. It returns the bot's generated response together with the updated conversation context, letting you track where the conversation sits in the dialogue tree.

> **Prerequisite.** Conversational AI must be enabled in your environment. Contact your Success Manager to enable it before you call this API.


## Overview

| Operation | Method | Path |
|  --- | --- | --- |
| Trigger a conversational AI bot application | `POST` | `/api/v3/bot/trigger` |


### The three things that identify a bot turn

Every call is addressed by a triple:

| Concept | Field | What it identifies | Lifetime |
|  --- | --- | --- | --- |
| Bot application | `applicationId` | The configured bot application (dialogue tree) to execute | Static — configured in the Sprinklr platform |
| Conversation | `conversationId` | The dialogue thread this message belongs to | Caller-owned; you generate it and reuse it |
| Turn | `text` | The single user utterance being processed | One call |


**`conversationId` is caller-supplied.** Enter a random conversation ID to start a new conversation, or the exact existing conversation ID to continue one. Sprinklr does not issue conversation IDs — you generate one, store it, and send it back on every subsequent turn. If you lose it, the customer restarts the dialogue tree from the root.

> **`conversationId` and `conversationContext.id` are different values.** The server maintains its own context record, returned as `data.response.conversationContext.id`. Do not send that value back as your `conversationId`.
| Field | Owned by |
|  --- | --- |
| `conversationContext.conversationId` | You |
| `conversationContext.id` | Sprinklr |
| `conversationContext.applicationId` | You (echoed back) |
| `conversationContext.openAIConversationId` | Sprinklr |



### When to use this API

In the platform, bots are normally driven by a **Bot Rule** — the "Sprinklr Live Chat Bot (Conversational AI)" rule under the Customer/Queue rule type — which runs the bot, tags custom fields, and adds bot cases to assignment queues.

Use this API when an **external** system owns the channel: your own chat widget, an IVR front end, a test harness, a regression suite, or a third-party messaging integration where you need the bot's reply in the HTTP response.

## Base URL

```
https://api3.sprinklr.com/{env}/api/v3/bot/trigger
```

Replace `{env}` with your assigned environment identifier: `prod`, `prod0`, `prod2`, `prod3`, `prod4`, `prod5`, `prod6`, `prod8`, `prod11`, `prod12`, `prod15`, `prod16`, `prod17`, `prod18`, `prod19`, `prod21`, or `prod25`.

Make the base URL a single configuration value so that moving between environments is a configuration change rather than a code change.

## Authentication

All calls are authenticated with OAuth 2.0. See [API Overview](https://dev.sprinklr.com/api-overview) and [API Key and Secret Generation](https://dev.sprinklr.com/api-key-and-secret-generation).

### Required headers

| Header | Value | Purpose | Required on |
|  --- | --- | --- | --- |
| `Authorization` | `Bearer {{accessToken}}` | Authenticates the user with the server | All requests |
| `Key` | `{{apiKey}}` | Authenticates the application with the server | All requests |
| `Content-Type` | `application/json` | Declares the request body media type | All requests |
| `Accept` | `application/json` | Declares the acceptable response type | All requests |


> **Credential hygiene.** Never commit an access token or API key to source control, never paste one into a ticket, chat, or screenshot, and never log the `Authorization` or `Key` header values. Every credential on this page is a placeholder.


## Trigger a bot application

```
POST https://api3.sprinklr.com/{env}/api/v3/bot/trigger
```

### Request body parameters

| Parameter | Required | Type | Description |
|  --- | --- | --- | --- |
| `applicationId` | Required | String | Unique identifier of the bot application to trigger |
| `text` | Required | String | The message text sent to the bot to trigger a response |
| `conversationId` | Required | String | Identifier of the conversation the message belongs to. Reusing an existing ID continues that conversation; a new ID starts a fresh one |
| `language` | Required | String | Language code for the message. Use `"en"` for English or `"all"` for all languages |
| `snId` | Optional | String | Social network ID. **New in V3** |
| `snType` | Optional | String | Social network type. Defaults to `DEFAULT` when blank. **New in V3** |
| `contextVariables` | Optional | Object | Additional context variables passed to the bot application. **New in V3** |


### Using `contextVariables`

`contextVariables` is an open map, so values are not restricted to strings. Use it to seed the bot with information your system already knows — order number, customer tier, cart value, the page the chat was launched from — so the dialogue tree does not have to ask for it.

Keys correspond to variables configured on your bot application. Coordinate key names with whoever built the application in the Sprinklr UI.

### Using `snId` and `snType`

These fields let a single bot application be driven on behalf of an identified social identity rather than an anonymous conversation. When neither is sent, `snType` defaults to `DEFAULT`, which is reflected as `botParameters.SN_TYPE` in the response.

### Example request

```bash
curl -X POST \
  'https://api3.sprinklr.com/{env}/api/v3/bot/trigger' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "applicationId": "0000000000000000000000a1",
    "text": "Where is my order?",
    "conversationId": "chat-7f3a91c2-0001",
    "language": "en"
  }'
```

Extended form using the V3-only fields:

```bash
curl -X POST \
  'https://api3.sprinklr.com/{env}/api/v3/bot/trigger' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "applicationId": "0000000000000000000000a1",
    "text": "Where is my order?",
    "conversationId": "chat-7f3a91c2-0001",
    "language": "en",
    "snType": "DEFAULT",
    "snId": "webchat-user-42",
    "contextVariables": {
      "orderId": "ORD-10045",
      "customerTier": "gold",
      "cartValue": 129.5
    }
  }'
```

*`contextVariables` keys are placeholders — use the variable names configured on your own bot application.*

## Response format

### The envelope

| Field | Type | Description |
|  --- | --- | --- |
| `data` | Object | The bot trigger result — `response` plus `botStatus` |
| `errors` | Array | Error objects. Empty when there are no transport or validation errors |
| `metadata` | Object | Response metadata |


Each error object has three fields:

| Field | Type | Description |
|  --- | --- | --- |
| `id` | String | Error identifier |
| `code` | Integer | Numeric error code |
| `message` | String | Error key, for example `account.not.found` |


### `data.response.responseDTOList[]` — the bot's turn

**The reply itself**

| Field | Type | Meaning |
|  --- | --- | --- |
| `responseDetails` | Array | **The bot's reply — this is what you render to the customer.** Each entry has the form `{"responseType": "TEXT", "detail": {"text": "…", "responseDelay": 0}}` |
| `accumulatedMessages` | Array | User messages accumulated for this turn: `assetCreatedTime` (epoch ms), `messageText`, `matchedThemes` |
| `botParameters` | Object | Bot execution variables — see below |


**Flow control — what your client should do next**

| Field | Type | Meaning |
|  --- | --- | --- |
| `endOfConversation` | Boolean | The conversation has ended |
| `endOfApplication` | Boolean | The bot application has finished |
| `routeToAgent` | Boolean | Hand the conversation to a human agent |
| `routedToIVR` | Boolean | The conversation was routed to IVR |
| `transition` | Boolean | A transition to another bot or node occurred |
| `reTrigger` | Boolean | The bot should be triggered again |
| `endAndReplayOngoingBot` | Boolean | End and replay the in-flight bot |
| `repeatParentReply` | Boolean | Repeat the parent node's reply |
| `waitForAsyncResponse` | Boolean | An asynchronous response is pending |
| `waitForAccumulation` / `accumulated` | Boolean | Message accumulation state |
| `accumulateAtNodeWaitTime` | Integer | Accumulation wait at the node, in milliseconds |
| `ignored` | Boolean | The message was ignored |


**Error, fallback, and guardrail state**

| Field | Type | Meaning |
|  --- | --- | --- |
| `error` | Boolean | This turn errored |
| `fallbackResponse` | Boolean | The reply is a fallback response |
| `retryOnFallback` | Boolean | Retry behaviour on fallback |
| `userReplyNotMatched` | Boolean | The user's reply matched no configured path |
| `stuck` | Boolean | The conversation is stuck |
| `publishingStopped` | Boolean | Publishing was stopped |
| `isGuardrailSuccess` | Boolean | Guardrail evaluation result |
| `rateLimitReached` | Boolean | A rate limit was reached at the bot layer |
| `triggerFilterMatched` | Boolean | The trigger filter matched |


**Position in the dialogue tree**

| Field | Type | Meaning |
|  --- | --- | --- |
| `currentBotActivityId` | String | Current node or activity ID |
| `currentBotActivityType` | String | Activity type, for example `DYNAMIC_CONVERSATION_ACTIVITY` |
| `processDefinitionId` | String | Process definition (bot) ID |
| `botsExecuted` | Array | Bot IDs executed on this turn |
| `pathToButton` | Object | Button path map |


**Voice and IVR**

| Field | Type | Meaning |
|  --- | --- | --- |
| `botGatherDTMF` | Boolean | The bot is gathering DTMF input |
| `bargeInParams.minPromptDurationMillisForBargeIn` | Integer | Minimum prompt duration before barge-in is allowed, in milliseconds |
| `bargeInParams.percentToTriggerBargeInAfter` | Number | Percentage of the prompt after which barge-in triggers |
| `bargeInParams.triggerBargeInAfterVadMillis` | Integer | Voice-activity-detection threshold before barge-in, in milliseconds |


**Other**

| Field | Type | Meaning |
|  --- | --- | --- |
| `openAIConversationId` | String | Generative-AI conversation ID |
| `addDummyResponseIfRequired` | Boolean | Whether a dummy response is inserted if required |
| `futureMessageCustomFields` | Object | Custom fields to apply to future messages |


### `data.response.conversationContext` — the durable state

| Field | Type | Meaning |
|  --- | --- | --- |
| `id` | String | Sprinklr-side context ID (**not** your `conversationId`) |
| `conversationId` | String | The conversation ID you supplied, echoed back |
| `applicationId` | String | The bot application ID, echoed back |
| `botConversationStatus` | String | Conversation status, for example `WAITING_FOR_RESPONSE` |
| `botVsConversationStatus` | Object | Per-bot status map, keyed by bot ID |
| `finished` | Boolean | Whether the conversation is finished |
| `freshContext` | Boolean | Whether this is a newly created context |
| `createdTime` / `modifiedTime` | Long | Epoch milliseconds |
| `expireAt` | String | Expiry as a formatted date string, for example `"Nov 18, 2026, 05:24:42 AM"`. **Note this is not epoch milliseconds like the sibling timestamps** |
| `detectedIssueTypes`, `pendingIssueTypes`, `completedIssueTypes`, `currentDetectedIssueTypes`, `newlyDetectedIssueTypes`, `currentPendingIssueTypes` | Array | Issue-type tracking across the conversation |
| `detectedIntents`, `currentDetectedIntents`, `intentsToDiscover` | Array | Intent tracking |
| `detectedSlots`, `detectedSlotEntities`, `entitiesToDiscover` | Object / Array | Slot and entity extraction state |
| `buttonsToDiscover`, `buttonLabelMap` | Array / Object | Button state |
| `userReplyPaths` | Array | Reply paths taken |
| `orders`, `currentOrders` | Array | Order context |
| `processVariablesToTransfer` | Object | Variables carried across a transition |
| `processedAssetIds` | Array | Assets already processed |
| `openAIConversationId` | String | Generative-AI conversation ID |
| `latestActivityType`, `latestActivityId`, `latestProcessDefinitionId` | String | Most recent execution pointers |
| `profileContext` | Boolean | Whether profile context is attached |
| `voiceBot` | Boolean | Whether this is a voice bot conversation |
| `replay`, `ignoreTransition`, `simpleContextSwitch`, `skipAlwaysRunBots`, `anyTriggerFilterMatched` | Boolean | Execution flags |
| `issueTypeVsTriggeredByIntents`, `botVsTriggeredByIssueType` | Object | Trigger provenance maps |


Sibling fields of `conversationContext` under `data.response`: `repeatedIssueTypeFallback`, `issueTypeDetectionSkipped`, `botsExecuted`, `issueTypeDetectionInfos`.

### `botParameters` — bot execution variables

| Parameter | Notes |
|  --- | --- |
| `BOT_APPLICATION_ID` | Echoes your `applicationId` |
| `BOT_CONTEXT_ID` | Matches `conversationContext.id` |
| `ROOT_BOT` | Root bot ID |
| `GLOBAL_CONTEXT_VARIABLES` | Global context variable reference |
| `TEXT` | Echoes your `text`. **V2 called this `USER_SAYS_TEXT`** |
| `Language` | Echoes your `language`. Note the mixed-case key |
| `SN_TYPE` | Corresponds to the `snType` request field |
| `TEST_MODE`, `FALLBACK_BOT`, `INLINE_PUBLISH`, `TYPING_INDICATOR_ENABLED`, `DISABLE_TRANSITION_ON_LOCAL_FALLBACK` | Boolean execution flags |
| `SUBSEQUENT_ISSUE_TYPE_CONTEXT` | **Returned as the string `"false"`, not a boolean** |
| `CURRENT_DETECTED_ISSUE_TYPE_DETECTED_AGAIN` | **Returned as the string `"false"`, not a boolean** |
| `NUM_DETECTED_ISSUE_TYPES`, `NUM_DETECTED_ISSUE_TYPES_ON_CURRENT_MESSAGE`, `NUM_PENDING_ISSUE_TYPES` | Integer counts |
| `DETECTED_ISSUE_TYPES`, `ALL_DETECTED_ISSUE_TYPES`, `DETECTED_INTENTS`, `UPDATED_FIELDS`, `ORDERS`, `CURRENT_ORDERS` | Arrays |
| `CURRENT_APPLICATION_DETECTED_SLOT`, `CURRENT_APPLICATION_DETECTED_SLOT_ENTITIES` | Objects |


> **Parse `botParameters` defensively.** Several boolean-looking values are returned as strings (`"false"` rather than `false`).


## Detecting the outcome of a turn

> ### A `200` response does not mean the bot succeeded
The API returns HTTP `200` with an empty top-level `errors` array even when the bot itself failed to produce a reply. **Always branch on the bot-level outcome fields, not on the HTTP status code alone.**


An errored turn looks like this — note that `errors` is empty and the status is `200`:

```json
{
  "data": {
    "response": {
      "responseDTOList": [
        {
          "responseDetails": [],
          "error": true,
          "routeToAgent": true,
          "endOfConversation": true,
          "endOfApplication": true
        }
      ],
      "conversationContext": {
        "botConversationStatus": "ERROR",
        "botVsConversationStatus": {
          "0000000000000000000000b1": "ERROR"
        }
      }
    },
    "botStatus": "ERROR"
  },
  "errors": []
}
```

*Abridged to the outcome fields.*

Check these five signals:

| Signal | Errored turn |
|  --- | --- |
| `data.botStatus` | `"ERROR"` |
| `data.response.conversationContext.botConversationStatus` | `"ERROR"` |
| `botVsConversationStatus[botId]` | `"ERROR"` |
| `responseDTOList[0].error` | `true` |
| `responseDTOList[0].responseDetails` | Empty — the bot produced no reply text |


A successful turn returns a populated `responseDetails` array and `error: false`.

```javascript
function turnFailed(res) {
  const dto = res.data?.response?.responseDTOList?.[0];
  return res.data?.botStatus === 'ERROR'
      || dto?.error === true
      || !dto?.responseDetails?.length;
}
```

### `botStatus`

`data.botStatus` carries the outcome of the turn. The platform's Bot Rule documentation describes five bot status scenarios:

| Scenario | Meaning |
|  --- | --- |
| Error State | The application encountered an error state |
| Routed to Agent | The conversation is routed to an agent |
| Fallback | The bot triggered a fallback |
| Conversation with Bot | The conversation is currently with the bot |
| Conversation Ended | The conversation has ended |


> **Always include a default branch when switching on `botStatus`.** New status values may be introduced, so treat any unrecognised value as a non-success outcome rather than falling through silently.


## Status codes

| HTTP Code | Description |
|  --- | --- |
| `200 OK` | Success |
| `400 Bad Request` | Bad request |
| `401 Unauthorized` | Missing or invalid authentication |
| `403 Forbidden` | Insufficient permissions |
| `404 Not Found` | Resource not found |


### Troubleshooting

From the platform-wide [REST API Errors and Status Codes](https://dev.sprinklr.com/rest-api-error-and-status-codes) guide:

| Code | Possible reasons | Recommended solution |
|  --- | --- | --- |
| `400 Bad Request` | Bad syntax; missing or wrong key; missing access token; wrong method type; invalid request or response | Recheck the documentation and update the request. If unchanged, contact the integration support team. |
| `401 Unauthorized` | The bearer token may be invalid, expired, or may lack the necessary permissions | Refresh the authorization token. The access token is valid for 30 days; refresh after that. |
| `401 Unauthorized` | Invalid consumer key | Check whether the key is associated with the right environment. Key information is under **MY ACCOUNT** on the developer portal. |
| `403 Developer Inactive` | Probable issue with the headers | Recheck `Key`, `Authorization` token, and `Content-Type`. If it persists, check whether you have access to the requested endpoint. |
| `403 Forbidden` | The call is correct but the user is not permitted the resource | Cross-check the endpoint URI, clear cookies, and request the required permissions. |
| `403 Developer Over Rate` | API calls per second or hour exceed the set call limit | Retry after some time. |
| `404 Resource Not Found` | The requested resource could not be found | Cross-check the endpoint URL; recheck headers, method type, and request body. |
| `411 Length Required` | A `POST` or `PUT` was made without a `Content-Length` header | Add `Content-Length`. If there is no request body, send `Content-Length: 0`. |
| `415 Unsupported Media Type` | Incorrect or unsupported payload format | Check `Content-Type` and `Accept`. |
| `421 Misdirected Request` | The API key and the environment do not match | Check the API key and the environment it is mapped against. A key issued for Prod2 will not work for Prod3. |
| `429 Too Many Requests` | Exceeding the set call rate limit | Wait for the rate limit to reset. |
| `500 Internal Server Error` | Server-side issue | Usually resolves on its own; contact integration support if it persists. |
| `503 Service Unavailable` | Server not ready; possibly scheduled maintenance | Retry after some time. |
| `504 Gateway Timeout` | The gateway could not fetch a timely response | Retry after some time. |


## Migrating from V2

### What changed at a glance

| Aspect | V2 | V3 |
|  --- | --- | --- |
| Endpoint | `POST /api/v2/triggerBotApplication` | `POST /api/v3/bot/trigger` |
| Path style | Single camelCase verb segment | Resource (`/bot`) plus action (`/trigger`) |
| Request fields | `applicationId`, `text`, `conversationId`, `language` | The same four, **plus** `snId`, `snType`, `contextVariables` |
| Response envelope | `{ data, errors }` | `{ data, errors, metadata }` |
| Headers | `Authorization`, `Key`, `Content-Type`, `Accept` | Unchanged |
| Authentication | OAuth 2.0 | Unchanged |


### The request body is unchanged

All four V2 fields keep their exact names, types, and meanings. A V2 payload is a valid V3 payload. For a parity migration, this is a URL change:

```diff
- https://api3.sprinklr.com/{env}/api/v2/triggerBotApplication
+ https://api3.sprinklr.com/{env}/api/v3/bot/trigger
```

| V2 field | V3 field | Change |
|  --- | --- | --- |
| `applicationId` | `applicationId` | None |
| `text` | `text` | None |
| `conversationId` | `conversationId` | None |
| `language` | `language` | None |
| — | `snId` | **New in V3** |
| — | `snType` | **New in V3**, defaults to `DEFAULT` when blank |
| — | `contextVariables` | **New in V3** |


### Identifier format change

> **This is the change most likely to break a V2 client, and it is easy to miss because no field was renamed.**


| Field | V2 format | V3 format |
|  --- | --- | --- |
| `currentBotActivityId` | Prefixed UUID, for example `node-d1052330-dd70-48c7-948d-1b12953a64c2` | 24-character hex ID |
| `processDefinitionId` | UUID | 24-character hex ID |
| `botParameters.ROOT_BOT` | UUID | 24-character hex ID |
| `botVsConversationStatus` keys | UUID | 24-character hex ID |


If you persist, index, log-correlate, regex-validate, or size a database column against these values, **the V2 format will not validate and the V3 format will not fit a UUID column**. Audit every place a bot activity or process definition ID is stored before cutover.

### Response field changes

**Renamed**

| V2 | V3 |
|  --- | --- |
| `botParameters.USER_SAYS_TEXT` | `botParameters.TEXT` |


**New in V3**

| Area | New fields |
|  --- | --- |
| Flow control | `endOfApplication`, `endAndReplayOngoingBot`, `repeatParentReply`, `accumulateAtNodeWaitTime`, `addDummyResponseIfRequired` |
| Error and guardrail | `stuck`, `publishingStopped`, `userReplyNotMatched`, `isGuardrailSuccess`, `rateLimitReached` |
| Dialogue position | `currentBotActivityType`, `botsExecuted`, `pathToButton` |
| Voice and IVR | `bargeInParams` |
| Generative AI | `openAIConversationId` on both `responseDTOList[]` and `conversationContext` |
| Context | `expireAt`, `detectedSlotEntities`, `newlyDetectedIssueTypes`, `buttonLabelMap`, `processVariablesToTransfer`, `botConversationStatus`, `profileContext`, `voiceBot`, `freshContext`, `orders`, `currentOrders`, `simpleContextSwitch`, `latestActivityType`, `latestActivityId`, `latestProcessDefinitionId`, `skipAlwaysRunBots` |
| Bot parameters | `TEST_MODE`, `SN_TYPE`, `CURRENT_DETECTED_ISSUE_TYPE_DETECTED_AGAIN`, `ALL_DETECTED_ISSUE_TYPES`, `DETECTED_ISSUE_TYPES`, `GLOBAL_CONTEXT_VARIABLES`, `ORDERS`, `CURRENT_ORDERS`, `CURRENT_APPLICATION_DETECTED_SLOT_ENTITIES` |
| Envelope | `metadata` |


## Common Use Cases

### Start a new conversation

Generate a fresh `conversationId` and send the first utterance. `conversationContext.freshContext` returns `true`.

```json
{
  "applicationId": "0000000000000000000000a1",
  "text": "Hi",
  "conversationId": "chat-7f3a91c2-0001",
  "language": "en"
}
```

Store `conversationId` against your session — you need it for every subsequent turn.

### Continue an existing conversation

Send the **same** `conversationId` with the next utterance. Do not send anything else back from the previous response; the server holds the state.

```json
{
  "applicationId": "0000000000000000000000a1",
  "text": "Order 10045",
  "conversationId": "chat-7f3a91c2-0001",
  "language": "en"
}
```

Do not send `conversationContext.id` as your `conversationId` — they are different fields.

### Seed the bot with known context

Pass what your system already knows so the dialogue tree does not have to ask:

```json
{
  "applicationId": "0000000000000000000000a1",
  "text": "Where is my order?",
  "conversationId": "chat-7f3a91c2-0001",
  "language": "en",
  "contextVariables": {
    "orderId": "ORD-10045",
    "customerTier": "gold"
  }
}
```

### Hand off to a human agent

When `responseDTOList[0].routeToAgent` is `true`, stop sending turns to the bot and transfer the conversation to your agent workflow. Render any content in `responseDetails` first — the bot may have a closing message.

### Drive a voice bot

For voice channels, read `bargeInParams` to configure interruption handling and `botGatherDTMF` to know when the bot expects keypad input. `conversationContext.voiceBot` confirms the conversation is running in voice mode.

## Best practices

- **Never treat `200` as success.** Inspect `data.botStatus` and `responseDTOList[].error` on every turn.
- **Always include a default branch** when switching on `botStatus`.
- **Store and reuse `conversationId`.** Losing it restarts the customer's dialogue from the root.
- **Never send `conversationContext.id` as your `conversationId`.**
- **Parse defensively** — some `botParameters` values are strings rather than booleans, and `expireAt` is a formatted date string rather than epoch milliseconds.
- **Handle rate limiting at two layers.** `403 Developer Over Rate` and `429 Too Many Requests` indicate HTTP-level rate limiting; `responseDTOList[].rateLimitReached` signals a limit at the bot layer. Implement retry with exponential backoff.
- **Never log or screenshot the `Authorization` or `Key` header values.**