# Case API V3 — Developer Guide

- **Applies to:** Sprinklr Case API V3 (`/api/v3/case`)
- **V2 API reference:** [Case | Sprinklr Developer Portal](https://dev.sprinklr.com/case)


## 1. Overview

Sprinklr's **Case Management** bundles related inbound and outbound messages into a single Case so that agents see the whole conversation, meet SLA requirements, and resolve issues end to end. Bundling messages into cases also produces accurate reporting on the number of *issues* handled rather than the number of *messages* received and sent.

Case V3 consolidates the V2 case surface onto **one primary resource path** — `/api/v3/case` — differentiated by HTTP method, plus five sub-resources for actions that are not plain CRUD:

| Operation | Method | Path |
|  --- | --- | --- |
| Create case | `POST` | `/api/v3/case` |
| Fetch cases | `GET` | `/api/v3/case?id=` or `?caseNumber=` or `?channelCaseId=` |
| Update case (full replace) | `PUT` | `/api/v3/case?id=` or `?caseNumber=` |
| Update case (partial) | `PATCH` | `/api/v3/case?id=` or `?caseNumber=` |
| Delete cases (bulk) | `DELETE` | `/api/v3/case?id=` or `?caseNumber=` |
| Bulk create cases (async) | `POST` | `/api/v3/case/bulk` |
| Poll bulk job status | `GET` | `/api/v3/case/bulk/status?processId=` |
| Apply macro | `POST` | `/api/v3/case/applyMacro` |
| Merge cases | `POST` | `/api/v3/case/merge` |
| List associated message IDs | `GET` | `/api/v3/case/associatedMessages` |
| Get AI+ smart summary | `GET` | `/api/v3/case/smartSummary` |


This is the central design change from V2, which spread the same capabilities across `POST /api/v2/case`, `POST /api/v2/case/profile`, `POST /api/v2/case/create-with-messages`, `POST /api/v2/case/bulk/profile`, `PUT /api/v2/case`, `GET /api/v2/case/{caseId}`, `GET /api/v2/case/case-numbers`, `GET /api/v2/case/channel-case-numbers`, and `POST /api/v2/case/merge-cases`.

### 1.1 The case data model

Case data is modeled in four layers. Understanding this model is the fastest way to understand every endpoint in this guide.

| Layer | Object | What it holds | Scope |
|  --- | --- | --- | --- |
| Case core | top-level fields | `id`, `caseNumber`, `subject`, `description`, `version`, `status`, `priority`, `caseType`, `dueDate`, `summary`, `createdTime`, `modifiedTime` | One per case |
| Workflow | `workflow` | `assignment`, `customProperties`, `queues`, `spaceWorkflows`, `campaignId`, `modifiedTime` | Partner (global) level plus per-workspace level |
| Customer | `contact`, `contactInfo` | `id`, `name`, `channelType`, `channelId`, `fromSnUserId` (response) / `firstName`, `lastName`, `fullName`, `email`, `phoneNo`, `website` (request) | One profile per case |
| Conversation | `associatedMessages`, `firstMessageId`, `latestMessageId`, `conversationId` | Messages attached to the case | Many per case |


Two further objects hang off the case: `externalCase` / `externalCaseInfo` (third-party cases in Salesforce, Zendesk, RightNow, and similar) and `channelCustomProperties` (channel-specific properties, discriminated by `channelType`; the specification currently defines `SPRINKLR_LIVE_CHAT` and `KHOROS_LIVE_CHAT`).

### 1.2 Addressing a case

A case is addressed in four ways:

- **By Sprinklr case ID** — `id`, for example `6a3d07d66298dbf8951561a7`
- **By case number** — `caseNumber`, for example `120337901`
- **By channel case ID** — `channelCaseId`, the third-party system's case ID, for example `500gL000017MMF3QAO`
- **By channel case number** — `channelCaseNumber`, the third-party system's case number


`GET` accepts all four. `PUT`, `PATCH`, `DELETE`, `applyMacro`, and `associatedMessages` accept `id` or `caseNumber`. `merge` and `smartSummary` work on `caseNumber`.

## 2. Base URLs and environments

**All API calls are sent to the production endpoint:**

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

So the case resource in production is:

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

Replace `{env}` with your assigned environment identifier (`prod0`, `prod2`, `prod11`, and so on — see [APIs | Sprinklr Developer Portal](https://dev.sprinklr.com/apis) for the environment list).

## 3. Authentication and common headers

All Case API calls are authenticated with OAuth 2.0. See [Developer Tools in Sprinklr](https://www.sprinklr.com/help/articles/developer-tools/developer-tools-in-sprinklr/692e8b39f0afa271d18a5929) for API key and secret generation, and the Authorize flow.

| Header | Value | Purpose | Required on |
|  --- | --- | --- | --- |
| `Authorization` | `******` | Credential used by the API to authenticate a user with the server | All requests |
| `Key` | `{{apiKey}}` | API key that authenticates the application with the server | All requests |
| `Content-Type` | `application/json` | Declares the request body media type | `POST`, `PUT`, `PATCH` |
| `Accept` | `application/json` | Determines the acceptable response type from the server | All requests |


## 4. Write operations

### 4.1 Create a case

**`POST /api/v3/case`**

Creates a case. The single V3 `POST` covers both V2 creation styles: creating a case on top of an external profile (V2 `POST /api/v2/case/profile`) and creating a case with messages attached (V2 `POST /api/v2/case/create-with-messages`). Which one you get depends on whether you send `associatedMessages`.

The request body is the `ProfileCaseWithMessagesDTO` schema.

#### Request body — core fields

| Parameter | Sub-parameter | Required | Type | Description |
|  --- | --- | --- | --- | --- |
| `subject` |  | Optional | String | The subject of the case |
| `description` |  | Optional | String | The description of the case |
| `status` |  | Optional | String | The state of the case. Example: `New`, `Open`, `In Progress`, `Closed` |
| `priority` |  | Optional | String | The urgency with which the case should be addressed |
| `caseType` |  | Optional | String | The type of the case. Example: `Problem`, `Incident`, `Task` |
| `dueDate` |  | Optional | Long (epoch ms) | If the case must be resolved within a time limit, it has a due date |
| `summary` |  | Optional | String | Case summary |
| `workflow` |  | Optional | Object | The object containing the workflow details |
|  | `customProperties` | Optional | Object | Custom properties of the case, as a map of custom field name to a **list** of values |
|  | `queues` | Optional | Array | Partner queue details on the asset, if any. See the queue table below. |
|  | `spaceWorkflows` | Optional | List | List of client (workspace) level workflows on the entity, if any |
|  | `campaignId` | Optional | String | Campaign identifier to associate the entity to |
|  | `assignment` | Optional | Object | Case assignment details: `assigneeId`, `assigneeType`, `assignedById`, `assignmentTime` |
| `channelType` |  | Required | String | The channel type associated with the profile. **Case-sensitive, uppercase** — `SMS`, `EMAIL`, `SPRINKLR_VOICE`, and so on. |
| `channelId` |  | Optional* | String | *Required for all channels except `EMAIL` and `SMS`.* Unique identifier for the customer profile, configurable client-side. It is treated as the social native user ID and the primary key for the customer profile: passing the same `channelId` on a second call creates a new case and associates it with the **existing** customer profile. |
| `contactInfo` |  | Required | Object | Detailed contact information associated with the profile |
|  | `email` | Required for `EMAIL`, optional for `SMS` | String | Email ID of the profile |
|  | `firstName` | Optional | String | First name of the profile |
|  | `lastName` | Optional | String | Last name of the profile |
|  | `fullName` | Optional | String | Full name of the profile |
|  | `phoneNo` | Required for `SMS`, optional for `EMAIL` | String | Phone number associated with the profile |
|  | `website` | Optional | List[String] | List of websites for the profile |
| `commentDTO` |  | Optional | Object | Object containing the comment details, if any |
|  | `comment` | Optional | String | The text of the comment |
|  | `attachments` | Optional | Array | Attachment details. See the attachment table below. |
| `associatedMessages` |  | Optional | Array[Object] | Messages to attach to the case at creation time. See [§4.2](#42-create-a-case-with-associated-messages). |
| `externalCase` |  | Optional | Object | Details of a linked third-party case: `id`, `caseNumber`, `channelType`, `permalink`, `createdTime`, `modifiedTime`, `clientId`, `subDomain`, `additional` |
| `additional` |  | Optional | Object | Free-form additional attributes (map of string to string) |


#### Queue array definition

| Parameter | Required | Type | Description |
|  --- | --- | --- | --- |
| `queueId` | Optional — required to add the case to an existing queue | Integer | Unique identifier of the queue where the case is added for assignment. Resolve queue IDs through the Bootstrap Resources API. |
| `assignmentTime` | Optional | Long (epoch ms) | Assignment time of the queue to the case |


#### Attachment array definition

| Parameter | Required | Type | Description |
|  --- | --- | --- | --- |
| `type` | Required | String | Type of attachment. Supported types: `IMAGE`, `VIDEO`, `LINK`, `DOC`, `AUDIO` |
| `title` | Optional | String | Title of the attachment |
| `url` | Required | URL | URL of the attachment |
| `mimeType` | Optional | String | Attachment type and format. Example: `image/jpg` |


#### Request — create a case on an external profile

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
    "subject": "External Profile Case creation via profile 1906",
    "description": "Description of the case 1906",
    "workflow": {
        "customProperties": {
            "spr_uc_status": [
                "New"
            ],
            "spr_uc_priority": [
                "High"
            ],
            "spr_uc_type": [
                "Complaint"
            ],
            "_c_6901b9c50116ee58c854edc5": "Testing case tokenization CF11"
        },
        "queues": [
            {
                "queueId": 103197,
                "assignmentTime": 1681908874828
            }
        ]
    },
    "channelType": "SMS",
    "channelId": "+12024003935",
    "contactInfo": {
        "email": "mithtest-email@sprinklr.com",
        "firstName": "Mithilesh",
        "lastName": "Uniyal",
        "fullName": "mithilesh Uniyal",
        "phoneNo": "9123000000",
        "website": [
            "www.sprinklr.com",
            "www.facebook.com"
        ]
    },
    "commentDTO": {
        "attachments": [
            {
                "type": "IMAGE",
                "title": "Sample Image",
                "url": "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg",
                "mimeType": "images/jpg"
            }
        ],
        "comment": "Testing Comment Here via api 26.7"
    }
}'
```

**Response — `201 Created`** *(from the supplied collection)*

```json
{
    "data": {
        "id": "6a426c41413ac871af4288b3",
        "caseNumber": 120338341,
        "subject": "#120338341 Sms External Profile Case creation via profile 1906",
        "description": "Description of the case 1906",
        "version": 0,
        "status": "New",
        "priority": "High",
        "caseType": "Complaint",
        "externalCaseInfo": {
            "externalCases": []
        },
        "workflow": {
            "customProperties": {
                "spr_uc_type": ["Complaint"],
                "spr_uc_priority": ["High"],
                "spr_uc_status": ["New"],
                "spr_is_profile_case": ["true"],
                "_c_6901b9c50116ee58c854edc5": ["Testing case tokenization CF11"]
            },
            "queues": [
                {
                    "queueId": 103197,
                    "assignmentTime": 1782737984838
                }
            ]
        },
        "channelCustomProperties": [],
        "contact": {
            "id": "SMS_9123000000",
            "channelType": "SMS",
            "channelId": "9123000000",
            "fromSnUserId": "9123000000"
        },
        "createdTime": 1782737984838,
        "modifiedTime": 1782737985545,
        "latestMessageAssociatedTime": 1782737984838,
        "totalProcessingClockTime": 0,
        "allEngagedUsersList": [],
        "associatedFanMessageCount": 0,
        "associatedBrandMessageCount": 0,
        "associatedUserBrandMessageCount": 0,
        "deleted": false,
        "conversationIntentIds": []
    },
    "errors": []
}
```

### 4.2 Create a case with associated messages

**`POST /api/v3/case`** with an `associatedMessages` array.

Creates a case and simultaneously attaches messages — transcripts or conversation logs — to it. This supports integrations with third-party systems such as external bots, where customer interactions are captured in real time and must be contextualized within a case for downstream processing.

#### `associatedMessages[]` fields

| Parameter | Required | Type | Description |
|  --- | --- | --- | --- |
| `messageId` | Required | String | Unique message ID in the format `ACCOUNT_<sourceId>_<channelCreatedTime>_<CHANNEL>_<n>_<channelMessageId>` |
| `sourceType` | Required | String | Source of the message. Collection and V2 reference use the fixed value `ACCOUNT`. |
| `sourceId` | Required | Integer / String | Source (account) identifier |
| `content` | Required | Object | Transcript content. Example: `{ "text": "customer message" }` |
| `channelMessageId` | Required | String | Externally generated unique message ID (for example `c1`, `c2`). Must match the suffix in `messageId`. |
| `channelType` | Required | String | Channel type of the message |
| `accountType` | Required | String | Account type of the message |
| `senderProfile` | Required | Object | Metadata about the originator of the message. Attributes: `channelType`, `channelId`. For a customer message use the customer's identifier; for a brand message use the brand profile identifier. |
| `receiverProfile` | Required | Object | Metadata about the recipient of the message. Same attributes as `senderProfile`, reversed. |
| `channelCreatedTime` | Required | Long (epoch ms) | Timestamp of message creation on the external system |
| `createdTime` | Required | Long (epoch ms) | Timestamp when the message was created in Sprinklr |
| `modifiedTime` | Required | Long (epoch ms) | Timestamp when the message was last modified |
| `brandPost` | Required | Boolean | `true` if the message was posted by the brand or external bot |
| `autoResponse` | Required | Boolean | `true` if the message is an automatic response generated by the external bot |


#### Request

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
    "subject": "SM Case creation",
    "description": "Description of the case",
    "workflow": {
        "customProperties": {
            "ressortID": [
                "1234"
            ],
            "spr_uc_priority": [
                "High"
            ],
            "_c_66c466b44ee87b14829998ed": [
                "Billing"
            ],
            "_c_66c2ece58c7d8703b61b4d6a": [
                "INDIA"
            ],
            "_c_66c4bedfdb55fe51a39aa277": [
                "Yes"
            ],
            "_c_6901b9c50116ee58c854edc5": "Testing case tokenization CF22"
        }
    },
    "channelType": "SMS",
    "channelId": "+919172034633",
    "contactInfo": {
        "firstName": "Dheeraj",
        "lastName": "Y",
        "fullName": "Dheeraj Y",
        "phoneNo": "+919172034633"
    },
    "associatedMessages": [
        {
            "messageId": "ACCOUNT_66124761_1782736826000_SMS_218_SMf620a63f123ac8b9ddb91058e5b8173e",
            "sourceType": "ACCOUNT",
            "sourceId": 66124761,
            "content": {
                "text": "customer message"
            },
            "channelMessageId": "c1",
            "channelType": "SMS",
            "accountType": "SMS",
            "senderProfile": {
                "channelType": "SMS",
                "channelId": "+919172034633"
            },
            "receiverProfile": {
                "channelType": "SMS",
                "channelId": "663caccd472e572a74286325"
            },
            "channelCreatedTime": 1724333771000,
            "createdTime": 1724333771000,
            "modifiedTime": 1724333771000,
            "brandPost" : "true",
            "autoResponse" : "true"
        }
    ]
}'
```

This returns `201 Created` with the same envelope as [§4.1](#41-create-a-case). In the recorded response the case carried `"version": 0`, `"priority": "High"`, `spr_is_profile_case: ["true"]`, and `contact.id` of `SMS_+919172034633`.

> **Open item — `brandPost` and `autoResponse` typing.** The collection sends these as JSON **strings** (`"true"`), while the V2 reference describes them as `true`/`false` values. Confirm whether the V3 endpoint requires string or boolean. See [§11](#11-questions-for-the-api-owner).


### 4.3 Bulk create cases (asynchronous)

**`POST /api/v3/case/bulk`**

Creates cases along with audience profiles in bulk. Unlike V2, V3 bulk creation is **asynchronous**: the call returns a `processId` immediately, and you poll [§4.4](#44-poll-bulk-job-status) for the outcome.

#### Request body

| Parameter | Required | Type | Description |
|  --- | --- | --- | --- |
| `records` | Required | Array[Object] | List of case records. Each record uses the same shape as the single-create body in [§4.1](#41-create-a-case). |
| `callbackUrl` | Optional | String | URL Sprinklr calls when the bulk job finishes |
| `callbackUrlHeaders` | Optional | Object | Optional HTTP headers to send with the callback request (map of string to string) |
| `syncProcessing` | Optional | Boolean | When `true`, process records synchronously in-request and return per-record results immediately |


#### Request

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/bulk' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--data '{
    "records": [
        {
            "subject": "External Profile Case creation via profile 1906",
            "description": "Description of the case 1906",
            "workflow": {
                "customProperties": {
                    "spr_uc_status": ["New"],
                    "spr_uc_priority": ["High"],
                    "spr_uc_type": ["Complaint"],
                    "_c_6901b9c50116ee58c854edc5": "Testing case tokenization CF11"
                },
                "queues": [
                    {
                        "queueId": 103197,
                        "assignmentTime": 1681908874828
                    }
                ]
            },
            "channelType": "SMS",
            "channelId": "+12024003935",
            "contactInfo": {
                "email": "mithtest-email@sprinklr.com",
                "firstName": "Mithilesh",
                "lastName": "Uniyal",
                "fullName": "mithilesh Uniyal",
                "phoneNo": "9123000000",
                "website": ["www.sprinklr.com", "www.facebook.com"]
            },
            "commentDTO": {
                "attachments": [
                    {
                        "type": "IMAGE",
                        "title": "Sample Image",
                        "url": "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg",
                        "mimeType": "images/jpg"
                    }
                ],
                "comment": "Testing Comment Here via api 26.7"
            }
        },
        {
            "subject": "External Profile Case creation via profile 1906",
            "description": "Description of the case 1906",
            "workflow": {
                "customProperties": {
                    "spr_uc_status": ["New"],
                    "spr_uc_priority": ["High"],
                    "spr_uc_type": ["Complaint"],
                    "_c_6901b9c50116ee58c854edc5": "Testing case tokenization CF11"
                }
            },
            "channelType": "SMS",
            "channelId": "+12024003936",
            "contactInfo": {
                "email": "mithtest-email+qa6@sprinklr.com",
                "firstName": "Mithilesh",
                "lastName": "Uniyal test",
                "fullName": "mithilesh Uniyal test",
                "phoneNo": "9143000000",
                "website": ["www.sprinklr.com", "www.facebook.com"]
            },
            "commentDTO": {
                "attachments": [
                    {
                        "type": "IMAGE",
                        "title": "Sample Image",
                        "url": "https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg",
                        "mimeType": "images/jpg"
                    }
                ],
                "comment": "Testing Comment Here via api 26.7"
            }
        }
    ]
}'
```

**Response — `202 Accepted`**

```json
{
    "data": {
        "processId": "6a462fb3c64ff1c8058dfdb2"
    },
    "errors": []
}
```

Store `processId`. It is the only handle to the job.

> **Note on record limits.** V2 `POST /api/v2/case/bulk/profile` documented a maximum of **10 cases and associated profiles per call**. The V3 specification does not state a limit for `/api/v3/case/bulk`. Confirm the V3 limit before sizing batches — see [§11](#11-questions-for-the-api-owner).


### 4.4 Poll bulk job status

**`GET /api/v3/case/bulk/status?processId={processId}`**

Returns the status of a bulk case creation job.

| Parameter | Type | Required | Description | Example |
|  --- | --- | --- | --- | --- |
| `processId` | String | Required in practice — the endpoint cannot resolve a job without it | Bulk process ID returned by `POST /api/v3/case/bulk` | `6a462fb3c64ff1c8058dfdb2` |


```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/bulk/status?processId=6a462fb3c64ff1c8058dfdb2' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

> **Gap.** The supplied collection contains this request but **no saved response**, and the specification types the `200` payload only as `string`. The status values, the per-record result shape, and the terminal states are not documented in any supplied source. See [§11](#11-questions-for-the-api-owner).


### 4.5 Update a case — full update

**`PUT /api/v3/case?id={caseId}`** or **`PUT /api/v3/case?caseNumber={caseNumber}`**

Replaces the case document. The request body is the full `Case` schema. Use this when your system is the source of truth and you are sending the complete, authoritative state of the case.

#### Query parameters

| Parameter | Type | Required | Description | Example |
|  --- | --- | --- | --- | --- |
| `id` | String | Optional — one of `id` or `caseNumber` is needed to address the case | Case ID | `6a3d07d66298dbf8951561a7` |
| `caseNumber` | String | Optional — one of `id` or `caseNumber` is needed to address the case | Case number | `120337901` |


#### ⚠️ `PUT` replaces — it does not merge

Fields absent from the body are replaced or cleared, including `workflow.customProperties`, `workflow.queues`, and `channelCustomProperties`. Before issuing a `PUT`:

1. `GET` the current case.
2. Merge your changes into the retrieved document.
3. `PUT` the merged result back.


If you only intend to change a few fields, use `PATCH` ([§4.6](#46-update-a-case--partial-update)) instead. `PATCH` exists precisely so you do not have to do a read-modify-write cycle.

> **Gap.** The supplied Postman collection contains **no `PUT` example**. The signature above is taken from the V3 OpenAPI specification. Validate the payload shape against a test case before running it in production.


### 4.6 Update a case — partial update

**`PATCH /api/v3/case?id={caseId}`** or **`PATCH /api/v3/case?caseNumber={caseNumber}`**

Changes a subset of case fields without resending the whole document. This is the safe default for incremental syncs, CRM integrations, and any system that is not the sole source of truth for the case.

The request body is the `CasePatchRequestDTO` schema. **This is a different schema from `PUT`** — payloads are not interchangeable.

#### Query parameters

| Parameter | Type | Required | Description |
|  --- | --- | --- | --- |
| `id` | String | Optional — one of `id` or `caseNumber` addresses the case | Case ID |
| `caseNumber` | String | Optional — one of `id` or `caseNumber` addresses the case | Case number |


#### Request body

| Parameter | Sub-parameter | Type | Description |
|  --- | --- | --- | --- |
| `subject` |  | String | Subject for the case |
| `description` |  | String | Description for the case |
| `status` |  | String | The state of the case. Example: `Open`, `Pending`, `Closed` |
| `priority` |  | String | The urgency with which the case should be addressed |
| `caseType` |  | String | The type of the case. Example: `Problem`, `Incident`, `Task` |
| `dueDate` |  | Long (epoch ms) | Case due date |
| `summary` |  | String | Case summary |
| `smartSummary` |  | Object | Case AI+ summary: `summary`, `lastEditedByUser`, `modifiedTime` |
| `attachment` |  | Object | Attachment to the case |
| `contact` |  | Object | Contact details of the case |
| `addedNotifyUsers` |  | Array[Long] | Users to add for notifications on the case |
| `removedNotifyUsers` |  | Array[Long] | Users to be removed from notifications on the case |
| `syncedNotifyUsers` |  | Array[Long] | Users to be updated for notifications on the case. **Replaces** any users already added for notification. |
| `syncedSelectedChannelCustomProperties` |  | Array[Object] | Channel custom properties to be synced on the case |
| `disassociateCaseIds` |  | Array[String] | Case IDs to disassociate from this case |
| `addedExternalCases` |  | Array[Object] | External cases to associate with this case |
| `externalCase` |  | Object | Details of a linked third-party case |
| `updateCustomFieldsInCRM` |  | Boolean | Whether to update custom fields in the CRM |
| `installedAppId` |  | String | Installed app ID |
| `installedAppOrgId` |  | String | Installed app organization ID |
| `installedAppUserId` |  | String | Installed app user ID |
| `applicationUserId` |  | String | Application user ID |
| `channelOwnerId` |  | String | Channel owner ID |
| `permalink` |  | String | Permalink |
| `priorityRank` |  | Integer | Priority rank |
| `priorityIncreasePerMinute` |  | Integer | Priority increase per minute |
| `additionalInformation` |  | Object | Additional information |
| `workflow` |  | Object | Workflow patch operations. See the table below. |


#### `workflow` patch operations (`WorkflowPatchRequestDTO`)

| Parameter | Type | Description |
|  --- | --- | --- |
| `assignment` | Object | Assignment details: `assigneeId`, `assigneeType`, `assignedById`, `assignmentTime` |
| `addedCustomProperties` | Object | **Adds** custom property values to the case, retaining existing values |
| `removedCustomProperties` | Object | **Removes** the listed custom property values from the case |
| `syncedCustomProperties` | Object | Treats the supplied map as final. Custom fields not present in the payload are **overridden**. |
| `syncedSelectedCustomProperties` | Object | Updates only the custom fields present in the payload, retaining the others |
| `incrementCustomProperties` | Object | Increments numeric custom property values (map of field name to list of longs) |
| `addedQueues` | Array[Long] | Queues to be added to the case |
| `removedQueues` | Array[Long] | Queues to be removed from the case |
| `syncedQueues` | Array[Long] | Queues to associate with the case. Existing queue IDs not present in the payload are **overridden**. |


#### Choosing the right custom-property operation

| Intent | Operation |
|  --- | --- |
| Append a value while keeping existing values | `addedCustomProperties` |
| Update specific fields, leave all other fields untouched | `syncedSelectedCustomProperties` |
| Make the payload the complete, final set of custom properties | `syncedCustomProperties` |
| Delete specific values | `removedCustomProperties` |
| Increase a numeric counter field | `incrementCustomProperties` |


Using `syncedCustomProperties` where you meant `syncedSelectedCustomProperties` silently discards every custom property you did not send.

> **Gap.** The supplied Postman collection contains **no `PATCH` example**. The parameter tables above are derived from `CasePatchRequestDTO` and `WorkflowPatchRequestDTO` in the V3 OpenAPI specification.


### 4.7 Delete cases

**`DELETE /api/v3/case?id={caseIds}`** or **`DELETE /api/v3/case?caseNumber={caseNumbers}`**

Deletes one or more cases. Supports bulk delete through comma-separated identifiers.

| Parameter | Type | Required | Description |
|  --- | --- | --- | --- |
| `id` | String | Optional — mutually usable with `caseNumber` | Comma-separated list of case IDs |
| `caseNumber` | String | Optional — mutually usable with `id` | Comma-separated list of case numbers |


V3 folds V2's two separate endpoints (`Delete Case Using Case Id` and `Delete Case Using Case Number`) into this one operation. The collection contains no delete example.

### 4.8 Apply a macro

**`POST /api/v3/case/applyMacro`**

Applies a macro to a case and, optionally, overrides specific custom property values as part of the macro execution. Returns the updated `Case`.

#### Query parameters

| Parameter | Type | Required | Description | Example |
|  --- | --- | --- | --- | --- |
| `id` | String | Optional — one of `id` or `caseNumber` addresses the case | Case ID | `6a3d07d66298dbf8951561a7` |
| `caseNumber` | String | Optional — one of `id` or `caseNumber` addresses the case | Case number | `120337901` |
| `macroId` | String | Used in both recorded calls | Identifier of the macro to apply | `6a3d150b09694c3ba3787fa6` |
| `inline` | Boolean | Used in both recorded calls | Sent as `true` in the collection | `true` |


#### Request body (`ManualActionDTO`)

| Parameter | Sub-parameter | Required | Type | Description |
|  --- | --- | --- | --- | --- |
| `customPropertyUpdateViaMacroDTOS` |  | Optional | Array[Object] | Custom property update details applied through the macro |
|  | `customPropertyName` | Required | String | Name of the custom property to update |
|  | `actionType` | Required | String | Type of action to perform. The collection uses `set`. |
|  | `values` | Required | List[String] | The custom field values to apply through the macro |


#### Request — address by case ID

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/applyMacro?id=6a3d07d66298dbf8951561a7&macroId=6a3d150b09694c3ba3787fa6&inline=true' \
--header 'Authorization: ******' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
    "customPropertyUpdateViaMacroDTOS": [
        {
            "customPropertyName": "_c_661f8027906789598f923852",
            "actionType": "set",
            "values": [
                "check"
            ]
        }
    ]
}'
```

#### Request — address by case number

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/applyMacro?caseNumber=120337901&macroId=6a3d150b09694c3ba3787fa6&inline=true' \
--header 'Authorization: ******' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
    "customPropertyUpdateViaMacroDTOS": [
        {
            "customPropertyName": "_c_661f8027906789598f923852",
            "actionType": "set",
            "values": [
                "check number"
            ]
        }
    ]
}'
```

Both calls return `200 OK` with the full updated case in `data`. In the recorded pair, the `id`-addressed call returned `"version": 27` with `_c_661f8027906789598f923852: ["check"]`, and the subsequent `caseNumber`-addressed call returned `"version": 29` with `_c_661f8027906789598f923852: ["check number"]`. **The `version` counter increments on every macro application** — use it for optimistic-concurrency checks.

### 4.9 Merge cases

**`POST /api/v3/case/merge`**

Customers often raise multiple tickets for similar issues. Merging them lets one agent handle the issue end to end and resolve it faster. One case becomes the parent; the merged cases become children. The conversations of the child cases appear on the parent case as agent notes.

#### Request body (`MergeCaseRequestDTO`)

| Parameter | Required | Type | Description |
|  --- | --- | --- | --- |
| `parentCaseNumber` | Required | Long | Case number of the parent case — the case into which other cases are merged |
| `childCaseNumbers` | Required | List[Long] | Case numbers of the child cases to merge into the parent. You can merge one or more cases without any limitation. |


#### Request

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/merge' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
    "parentCaseNumber": 120337901,
    "childCaseNumbers": [
        120337896
    ]
}'
```

**Response — `204 No Content`**

An empty `204` means the cases merged successfully. Do not parse a body.

### 4.10 Method comparison — when to use which

|  | `POST` | `PUT` | `PATCH` | `DELETE` |
|  --- | --- | --- | --- | --- |
| Purpose | Create a new case | Replace the full case document | Change selected fields | Remove cases |
| Addressing | None — identity comes from the body | `?id=` or `?caseNumber=` | `?id=` or `?caseNumber=` | `?id=` or `?caseNumber=` (comma-separated) |
| Body schema | `ProfileCaseWithMessagesDTO` | `Case` | `CasePatchRequestDTO` | None |
| Unspecified fields | N/A | **Replaced/cleared** | **Preserved** | N/A |
| Custom-property semantics | Set at creation | Whole `customProperties` map replaced | Per-operation: add, remove, sync, sync-selected, increment | N/A |
| Safe for incremental sync | — | No, without read-modify-write | Yes | — |
| Bulk | `/case/bulk` (async) | No | No | Yes, comma-separated |


`PUT` and `PATCH` take **different body schemas**. You cannot reuse one payload for both methods.

## 5. Read operations

### 5.1 `GET /api/v3/case` — Fetch cases

This is a **multi-mode** endpoint. It replaces four separate V2 reads:

| V2 endpoint | V3 equivalent |
|  --- | --- |
| [Read Case by Case Id](https://dev.sprinklr.com/read-case-by-case-id) (`GET /api/v2/case/{caseId}`) | `GET /api/v3/case?id=` |
| [Read Case by Case Number](https://dev.sprinklr.com/read-case-by-case-number) (`GET /api/v2/case/case-numbers?case-number=`) | `GET /api/v3/case?caseNumber=` |
| Read Case by Channel Case Id | `GET /api/v3/case?channelCaseId=&pageNumber=&pageSize=` |
| [Read Case by Channel Case Number](https://dev.sprinklr.com/read-case-by-channel-case-number) (`GET /api/v2/case/channel-case-numbers`) | `GET /api/v3/case?channelCaseNumber=` |


#### Parameters

| Parameter | Type | Required | Description | Example |
|  --- | --- | --- | --- | --- |
| `id` | String | Optional | Comma-separated list of case IDs | `6a3d07d66298dbf8951561a7` |
| `caseNumber` | String | Optional | Comma-separated list of case numbers | `120337901` or `120337901,120337935,120337934` |
| `channelCaseId` | String | Optional | Single channel case ID (the third-party system's case ID) | `500gL000017MMF3QAO` |
| `channelCaseNumber` | String | Optional | Single channel case number | `00040607` |
| `pageNumber` | String | **Required for channel case fetch** | Page number, 0-based | `0` |
| `pageSize` | String | Optional | Page size. Default: `20`, maximum: `100`. | `20` |


#### Mode 1 — Direct fetch by Sprinklr identifier

```bash
# Single case number
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case?caseNumber=120337901' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

```bash
# Multiple case numbers in one call
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case?caseNumber=120337901,120337935,120337934' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

```bash
# By Sprinklr case ID
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case?id=6a3d07d66298dbf8951561a7' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

#### Mode 2 — Paginated fetch by channel case identifier

Use this mode when you hold the identifier from the third-party system rather than a Sprinklr identifier. `pageNumber` is required in this mode.

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case?channelCaseId=500gL000017MMF3QAO&pageNumber=0&pageSize=20' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

**Response — `201 OK`**

```json
{
    "data": [
        {
            "id": "6a314dbbe2e30aea511e4181",
            "caseNumber": 120331397,
            "subject": "#120331397 Instagram ",
            "version": 215,
            "status": "New",
            "priority": "Medium",
            "externalCase": {
                "id": "500gL000017MMF3QAO",
                "caseNumber": "00040607",
                "channelType": "SALESFORCE",
                "permalink": "https://deepti006-dev-ed.develop.my.salesforce.com/500gL000017MMF3QAO",
                "createdTime": 1781616058000,
                "modifiedTime": 1781616058000
            },
            "externalCaseInfo": {
                "externalCases": []
            },
            "workflow": {
                "customProperties": {
                    "spr_uc_priority": ["Medium"],
                    "spr_uc_status": ["New"],
                    "_c_66a9fa676118504ce06ae5b6": ["Raj1"],
                    "_c_66d079ea7ef21a04c7af9728": ["Raj1"]
                },
                "queues": []
            },
            "channelCustomProperties": [],
            "contact": {
                "id": "INSTAGRAM_54963396257",
                "name": "aptiwadi",
                "channelType": "INSTAGRAM",
                "channelId": "54963396257",
                "fromSnUserId": "54963396257"
            },
            "createdTime": 1781616058705,
            "modifiedTime": 1782326740589,
            "firstMessageId": "ACCOUNT_600037626_1779440700000_INSTAGRAM_37_18442753900191622",
            "latestProfileMessageAssociatedTime": 1779440700000,
            "conversationId": "3900635358364111659",
            "firstMessageAssociatedTime": 1779440700000,
            "latestMessageAssociatedTime": 1782297368000,
            "firstUserBrandResponseCreationTime": 1781616187000,
            "avgCaseResponseSLA": 2175487000,
            "totalProcessingClockTime": 6294577,
            "allEngagedUsersList": [],
            "associatedFanMessageCount": 1,
            "associatedBrandMessageCount": 3,
            "associatedUserBrandMessageCount": 3,
            "deleted": false,
            "latestMessageId": "ACCOUNT_600037626_1782297368000_INSTAGRAM_306_17884961964597246",
            "conversationIntentIds": []
        }
    ],
    "errors": [],
    "metadata": {
        "totalCount": 1
    }
}
```

Note that the channel-case fetch returns a populated `metadata.totalCount` (`1`), whereas the direct-fetch responses in the collection return no `metadata` block at all.

#### Case response fields

| Field | Type | Description |
|  --- | --- | --- |
| `id` | String | Case ID |
| `caseNumber` | Long | Case number |
| `subject` | String | The value of the subject field for this case |
| `description` | String | Description of the case |
| `version` | Integer | Version number. Increments on every modification. |
| `status` | String | The state of the case. Example: `Open`, `Pending`, `Closed` |
| `priority` | String | The urgency with which the case should be addressed |
| `caseType` | String | The type of the case. Example: `Problem`, `Incident`, `Task` |
| `externalCase` | Object | Details of the linked third-party case |
| `externalCaseInfo` | Object | List of details of all linked third-party cases (`externalCases[]`) |
| `workflow` | Object | Workflow details: custom properties, queues, assignment details |
| `channelCustomProperties` | Array[Object] | Channel custom properties of the case |
| `contact` | Object | Contact details of the case: `id`, `name`, `channelType`, `channelId`, `fromSnUserId` |
| `attachment` | Object | Attachment on the case |
| `dueDate` | Long (epoch ms) | Due date, if the case must be resolved within a time limit |
| `summary` | String | Case summary |
| `smartSummary` | Object | Case AI+ summary: `summary`, `lastEditedByUser`, `modifiedTime` |
| `createdTime` | Long (epoch ms) | Created time of the case |
| `modifiedTime` | Long (epoch ms) | Last modified time of the case |
| `firstMessageId` | String | Message key for the first message associated with the case |
| `latestMessageId` | String | Message key for the last message associated with the case |
| `sentiment` | Integer | Numeric value representing the sentiment of the case |
| `conversationId` | String | Conversation identifier for the first message associated with the case |
| `latestProfileMessageAssociatedTime` | Long (epoch ms) | Last time a message was associated with the profile |
| `firstMessageAssociatedTime` | Long (epoch ms) | First time a message was associated with the case |
| `latestMessageAssociatedTime` | Long (epoch ms) | Last time a message was associated with the case |
| `firstUserBrandResponseCreationTime` | Long (epoch ms) | First time an agent responded on the case |
| `avgCaseResponseSLA` | Long | Average case response SLA |
| `totalProcessingClockTime` | Long | Total processing clock time of all users on the case. The clock starts whenever an agent opens the case. |
| `allEngagedUsersList` | Array[String] | All user IDs engaged on the case |
| `associatedFanMessageCount` | Integer | Number of associated fan messages |
| `associatedBrandMessageCount` | Integer | Number of associated brand messages |
| `associatedUserBrandMessageCount` | Integer | Number of associated user-brand messages |
| `deleted` | Boolean | Whether the case has been deleted |
| `associatedMessageIds` | Array[String] | Associated message IDs |
| `conversationIntentIds` | Array[String] | Conversation intent IDs |
| `customPropertiesMetadata` | Array[Object] | Custom field details: `fieldName`, `type`, `label`, `clientCustomProperty`, `values` |


### 5.2 `GET /api/v3/case/associatedMessages` — List associated message IDs

Returns the IDs of messages associated with a case. The response is a flat array of message-key strings — not message content. Feed those IDs to the Message API to hydrate content.

| Parameter | Type | Required | Description | Example |
|  --- | --- | --- | --- | --- |
| `id` | String | Optional — one of `id` or `caseNumber` addresses the case | Case ID | `6a3d07d66298dbf8951561a7` |
| `caseNumber` | String | Optional — one of `id` or `caseNumber` addresses the case | Case number | `120337901` |
| `cursor` | String | Optional | Association-time-based cursor for paging through large associations | — |
| `sinceChannelCreatedTime` | String (epoch ms) | Optional | Return messages created on the channel at or after this time | `1689437654240` |
| `untilChannelCreatedTime` | String (epoch ms) | Optional | Return messages created on the channel at or before this time | — |


```bash
# By case ID
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/associatedMessages?id=6a3d07d66298dbf8951561a7' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

```bash
# By case number
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/associatedMessages?caseNumber=120337901' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

```bash
# Time-bounded
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/associatedMessages?caseNumber=120337901&sinceChannelCreatedTime=1689437654240' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json'
```

**Response — `200 OK`**

```json
{
    "data": [
        "ACCOUNT_66000405_1782384598973_SPRINKLR_LIVE_CHAT_313_6a3d07d66298dbf8951561a8",
        "ACCOUNT_66000405_1782384598974_SPRINKLR_LIVE_CHAT_313_6a3d07d66298dbf8951561a9",
        "ACCOUNT_66000405_1782384600175_SPRINKLR_LIVE_CHAT_313_6a3d07d86298dbf8951562c4",
        "ACCOUNT_66000405_1782384600441_SPRINKLR_LIVE_CHAT_313_6a3d07d83a33fac8356a762f",
        "ACCOUNT_66000405_1782384601096_SPRINKLR_LIVE_CHAT_313_6a3d07d96298dbf895156324",
        "ACCOUNT_66000405_1782384601363_SPRINKLR_LIVE_CHAT_313_6a3d07d96298dbf89515636a",
        "ACCOUNT_66000405_1782384601681_SPRINKLR_LIVE_CHAT_313_6a3d07d96298dbf8951563a4",
        "ACCOUNT_66000405_1782384602306_SPRINKLR_LIVE_CHAT_313_6a3d07da3a33fac8356a7689",
        "ACCOUNT_66000405_1782384603650_SPRINKLR_LIVE_CHAT_313_6a3d07db3a33fac8356a76d9",
        "ACCOUNT_66000405_1782384603955_SPRINKLR_LIVE_CHAT_313_6a3d07db3a33fac8356a770b",
        "ACCOUNT_66000405_1782384604700_SPRINKLR_LIVE_CHAT_313_6a3d07dc6298dbf895156480",
        "ACCOUNT_66000405_1782384605010_SPRINKLR_LIVE_CHAT_313_6a3d07dd6298dbf8951564b5"
    ],
    "errors": []
}
```

Addressing by `id` and by `caseNumber` returned **identical 12-item arrays** in the recorded pair — the two identifiers are interchangeable here.

Message IDs follow the pattern `ACCOUNT_{sourceId}_{channelCreatedTime}_{CHANNEL}_{n}_{channelMessageId}`. In the sample above, `sourceId` is `66000405` and the channel is `SPRINKLR_LIVE_CHAT`.

> **Gap.** No response in the collection exercises `cursor`, so the cursor token format and where it is returned are undocumented. See [§11](#11-questions-for-the-api-owner).


### 5.3 `GET /api/v3/case/smartSummary` — Get the AI+ case summary

Returns the Sprinklr AI+ generated summary of a case as an HTML string. This capability has **no V2 equivalent** in the published Case reference — it is new in V3.

| Parameter | Type | Required | Description | Example |
|  --- | --- | --- | --- | --- |
| `caseNumber` | String | Used in the recorded call | Case number | `120340117` |
| `persistInCase` | Boolean | Optional | Persist the generated summary on the case | `true` |
| `regenerate` | Boolean | Optional | Regenerate the summary rather than returning the stored one | `false` |


```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/case/smartSummary?caseNumber=120340117&persistInCase=true&regenerate=false' \
--header 'Authorization: ******' \
--header 'Key: {{apiKey}}' \
--header 'Accept: application/json'
```

**Response — `200 OK`**

```json
{
    "data": "<h4> Contact Driver </h4><p> No Contract Driver Found</p><h4> Actions taken by Brand </h4><p>No Brand Steps found</p><h4> Pending actions/next steps </h4><p> No Pending Actions</p>",
    "errors": []
}
```

`data` is a **single HTML string**, not an object. The recorded summary is structured into three `<h4>` sections: *Contact Driver*, *Actions taken by Brand*, and *Pending actions/next steps*. Sanitize this HTML before rendering it in a browser.

Set `regenerate=true` to force a fresh generation, and `persistInCase=true` to write the result back onto the case (it then appears in `Case.smartSummary`).

## 6. Response format and status codes

### 6.1 The V3 envelope

V3 case endpoints return a consistent envelope:

```json
{
  "data": [ ... ],
  "errors": [],
  "metadata": {
    "totalCount": 1
  }
}
```

| Field | Type | Description |
|  --- | --- | --- |
| `data` | Object or Array | The case object(s), the message-ID array, the smart-summary string, or the bulk `processId`, depending on the endpoint |
| `errors` | Array[Error] | Array of error objects. Empty if there were no errors. |
| `metadata` | Object | Response metadata. Present on the channel-case fetch with `totalCount`; absent on the direct fetches recorded in the collection. |


`data` shape by endpoint:

| Endpoint | `data` shape |
|  --- | --- |
| `GET /case` | Array of `Case` |
| `POST /case` | Single `Case` object |
| `POST /case/bulk` | `{ "processId": "<string>" }` |
| `GET /case/associatedMessages` | Array of message-key strings |
| `GET /case/smartSummary` | HTML string |
| `POST /case/applyMacro` | Single `Case` object |
| `POST /case/merge` | No body (`204`) |


### 6.2 Response codes

| HTTP code | Scenario | Description |
|  --- | --- | --- |
| `200 OK` | Success | Cases fetched, macro applied, associated messages or smart summary returned |
| `201 Created` | Success | Case created |
| `202 Accepted` | Accepted | Bulk case create job queued; `processId` returned |
| `204 No Content` | Success | Cases merged successfully; no response body |
| `400 Bad Request` | Invalid parameters | Missing required parameters or invalid parameter combinations |
| `401 Unauthorized` | Authentication failed | Invalid or missing `Authorization` token |
| `403 Forbidden` | Insufficient permissions | The caller lacks the required case permission |
| `404 Not Found` | No cases found | No cases match the supplied identifiers |


## 7. V2 → V3 migration

### 7.1 Endpoint mapping

| V2 | V3 |
|  --- | --- |
| `POST /api/v2/case` (create with `firstMessageId`) | `POST /api/v3/case` |
| `POST /api/v2/case/profile` (create via external profile) | `POST /api/v3/case` with `channelType` + `contactInfo` |
| `POST /api/v2/case/create-with-messages` | `POST /api/v3/case` with `associatedMessages[]` |
| `POST /api/v2/case/bulk/profile` (synchronous, max 10) | `POST /api/v3/case/bulk` (asynchronous, returns `processId`) |
| — | `GET /api/v3/case/bulk/status?processId=` *(new in V3)* |
| `PUT /api/v2/case` with `updateActions[]` | `PUT /api/v3/case` (full replace) **or** `PATCH /api/v3/case` (partial) |
| `GET /api/v2/case/{caseId}` | `GET /api/v3/case?id=` |
| `GET /api/v2/case/case-numbers?case-number=` | `GET /api/v3/case?caseNumber=` |
| `GET /api/v2/case/channel-case-numbers?channelCaseNumbers=` | `GET /api/v3/case?channelCaseNumber=` |
| Read Case by Channel Case Id | `GET /api/v3/case?channelCaseId=&pageNumber=` |
| Delete Case Using Case Id / Case Number | `DELETE /api/v3/case?id=` / `?caseNumber=` |
| `POST /api/v2/case/merge-cases` | `POST /api/v3/case/merge` |
| Case Associated Messages | `GET /api/v3/case/associatedMessages` |
| — | `POST /api/v3/case/applyMacro` *(macro application via API)* |
| — | `GET /api/v3/case/smartSummary` *(new in V3)* |


The single biggest structural change: **V2 overloaded one `PUT /api/v2/case` with an `updateActions[]` enum** (`SET_DUE_DATE`, `ASSIGN_TO_USER`, `ADD_PROPERTIES`, `SYNC_PROPERTIES`, `SYNC_SELECTED_PROPERTIES`, `REMOVE_PROPERTIES`, `ADD_QUEUES`, `SYNC_QUEUES`, `REMOVE_QUEUES`, `EDIT_SUBJECT`, `EDIT_DESCRIPTION`, `UPDATE_CHANNEL_DETAILS`, `UPDATE_CHANNEL_CASE_ID`, `SYNC_CHANNEL_CUSTOM_PROPERTIES`, `UPDATE_INSTALLED_APP_DETAILS`, `INCREMENT_PROPERTIES`) that selected which field of the payload was honored. **V3 removes the action enum entirely.** The operation is expressed by the HTTP method and by the field name in `CasePatchRequestDTO`.

### 7.2 Update-action mapping

| V2 `updateAction` | V2 update field | V3 `PATCH` field |
|  --- | --- | --- |
| `EDIT_SUBJECT` | `subject` | `subject` |
| `EDIT_DESCRIPTION` | `description` | `description` |
| `ASSIGN_TO_USER` | `assignedTo` | `workflow.assignment` |
| `SET_DUE_DATE` | `dueDate` | `dueDate` |
| `ADD_PROPERTIES` | `addedCustomProperties` | `workflow.addedCustomProperties` |
| `SYNC_SELECTED_PROPERTIES` | `syncedSelectedCustomProperties` | `workflow.syncedSelectedCustomProperties` |
| `SYNC_PROPERTIES` | `syncedCustomProperties` | `workflow.syncedCustomProperties` |
| `REMOVE_PROPERTIES` | `removedCustomProperties` | `workflow.removedCustomProperties` |
| `INCREMENT_PROPERTIES` | `incrementCustomProperties` | `workflow.incrementCustomProperties` |
| `ADD_QUEUES` | `addedQueues` | `workflow.addedQueues` |
| `REMOVE_QUEUES` | `removedQueues` | `workflow.removedQueues` |
| `SYNC_QUEUES` | `syncedQueues` | `workflow.syncedQueues` |
| `SYNC_CHANNEL_CUSTOM_PROPERTIES` | `syncedChannelCustomProperties` | `syncedSelectedChannelCustomProperties` |
| `UPDATE_INSTALLED_APP_DETAILS` | `installedAppUserId`, `installedAppId`, `installedAppOrgId` | `installedAppUserId`, `installedAppId`, `installedAppOrgId` |
| `SET_EXTERNAL_CASES` | `externalCases` | `addedExternalCases` |


The V2 semantics carry over exactly: `SYNC_PROPERTIES` overrides custom fields absent from the payload; `SYNC_SELECTED_PROPERTIES` retains them.

### 7.3 Structural and field changes

| Aspect | API V2 | API V3 | Impact |
|  --- | --- | --- | --- |
| Case addressing | Path parameter (`/case/{caseId}`) or bespoke query names (`case-number`, `channelCaseNumbers`) | Uniform query parameters `id`, `caseNumber`, `channelCaseId`, `channelCaseNumber` on one path | One code path for all reads |
| Multi-case addressing | `caseIds` / `caseNumbers` arrays in the request body | Comma-separated query values | Reads and deletes no longer need a body |
| Update model | `updateActions[]` enum + matching field | HTTP method + field name | Fewer round trips, no enum drift |
| Bulk create | Synchronous, max 10 records, returns the created cases | Asynchronous, returns `processId`, poll for status | Requires a polling or callback loop |
| Workflow property key | `customFields` (in some V2 read responses) | `customProperties` | Rename in response parsers |
| Merge path | `/api/v2/case/merge-cases` | `/api/v3/case/merge` | Path rename only; body is identical |
| Macros | Not exposed on the V2 Case API | `POST /api/v3/case/applyMacro` | New capability |
| AI+ summary | Not exposed on the V2 Case API | `GET /api/v3/case/smartSummary` and `Case.smartSummary` | New capability |


## 8. Supported channel types

`channelType` values seen across the supplied collection and the V2 references:

| Channel type | Where it appears |
|  --- | --- |
| `SMS` | Create case via profile, create case with messages, bulk create |
| `EMAIL` | V2 bulk create examples |
| `INSTAGRAM` | Fetch case response (`contact.channelType`) |
| `SPRINKLR_LIVE_CHAT` | Associated message IDs, `channelCustomProperties` discriminator |
| `KHOROS_LIVE_CHAT` | `channelCustomProperties` discriminator |
| `SPRINKLR_VOICE` | V2 create-with-messages and read-by-case-id examples |
| `SOURCE_AGNOSTIC` | V2 create-with-messages example (external bot transcripts) |
| `SALESFORCE` | `externalCase.channelType` (third-party case source) |


**`channelType` values are always uppercase and case-sensitive.** A lowercase value — for example `sms` instead of `SMS` — will not resolve. `channelId` is required for all channels **except** `EMAIL` and `SMS`, where the identity is derived from `contactInfo.email` and `contactInfo.phoneNo` respectively.

## 9. Use cases

### 9.1 Raise a case from an external system on a customer who is not yet in Sprinklr

**Scenario:** your IVR or web form captures a complaint from a phone number that has never contacted the brand.

Issue a single `POST /api/v3/case` with `channelType: "SMS"`, the customer's `contactInfo`, and the workflow custom properties that drive routing ([§4.1](#41-create-a-case)). Sprinklr creates the audience profile and the case in one call and stamps `spr_is_profile_case: ["true"]`. Capture the returned `id` and `caseNumber` and store both.

### 9.2 Land a bot transcript as a case

**Scenario:** an external bot handled a conversation and now needs a human agent.

Use `POST /api/v3/case` with `associatedMessages[]` ([§4.2](#42-create-a-case-with-associated-messages)). Set `senderProfile` / `receiverProfile` per message so the transcript renders with correct attribution, and mark bot turns with `brandPost` and `autoResponse` so they are not counted as agent responses in SLA reporting.

### 9.3 Backfill a batch of cases from a legacy ticketing system

**Scenario:** a migration needs to land several hundred historical tickets.

Do not loop `POST /api/v3/case`. Use `POST /api/v3/case/bulk` ([§4.3](#43-bulk-create-cases-asynchronous)), register a `callbackUrl` so you are notified on completion instead of polling, and reconcile against the job status. Confirm the per-call record limit first — V2 capped this at 10 records per call and V3's limit is not stated in the supplied sources.

### 9.4 Keep a CRM in sync without clobbering agent work

**Scenario:** your CRM pushes updated case fields hourly, but agents also edit custom properties in Sprinklr.

Use `PATCH` with `workflow.syncedSelectedCustomProperties` — it updates the fields you send and retains every field you do not. Using `syncedCustomProperties` here would erase the agents' edits. `PUT` would be worse: it also clears `queues` and `channelCustomProperties`.

### 9.5 Apply a disposition macro at the end of an interaction

**Scenario:** an integration closes a case and must apply the standard closure macro plus a disposition code.

`POST /api/v3/case/applyMacro?caseNumber=…&macroId=…&inline=true` with a `customPropertyUpdateViaMacroDTOS` entry that sets the disposition custom property ([§4.8](#48-apply-a-macro)). The full updated case comes back in `data`, so no follow-up `GET` is needed. Compare `version` before and after to confirm the write landed.

### 9.6 Deduplicate repeat contacts

**Scenario:** a customer opened three cases about the same billing issue across SMS and Instagram.

Pick the oldest or most-progressed case as the parent and `POST /api/v3/case/merge` with the other two in `childCaseNumbers` ([§4.9](#49-merge-cases)). The child conversations surface on the parent as agent notes, so one agent owns the resolution. Expect `204 No Content` — not a body.

### 9.7 Reconstruct a full conversation for an audit

**Scenario:** compliance asks for every message on a case within a date window.

1. `GET /api/v3/case/associatedMessages?caseNumber=120337901&sinceChannelCreatedTime=…&untilChannelCreatedTime=…`
2. Hydrate each returned message key through the Message API.
3. Page with `cursor` if the case is long-running.


### 9.8 Resolve a Salesforce case ID back to the Sprinklr case

**Scenario:** an agent working in Salesforce needs the Sprinklr case behind a Salesforce case record.

`GET /api/v3/case?channelCaseId=500gL000017MMF3QAO&pageNumber=0&pageSize=20`. Remember that `pageNumber` is **required** in this mode. Read `data[0].caseNumber` for the Sprinklr identifier, and `data[0].externalCase.permalink` to link back.

### 9.9 Surface an AI+ handover summary

**Scenario:** a case transfers between agents and the receiving agent needs context fast.

`GET /api/v3/case/smartSummary?caseNumber=…&persistInCase=true&regenerate=true` regenerates the summary and writes it onto the case, so it is available in `Case.smartSummary` on later reads without another AI call. Sanitize the returned HTML before rendering.

### 9.10 Poll a bulk job to completion

```javascript
const { data } = await post('/api/v3/case/bulk', { records });
const processId = data.processId;             // from the 202 response

while (true) {
  const status = await get(`/api/v3/case/bulk/status?processId=${processId}`);

  if (status.errors && status.errors.length) {
    handleErrors(status.errors);              // V3 returns structured errors
    break;
  }

  if (isTerminal(status.data)) break;         // confirm terminal states with the API owner
  await sleep(5000);                          // back off between polls
}
```

Prefer a `callbackUrl` over polling where your infrastructure can receive one.

## 10. Caveats and best practices

**Method selection**

- Default to `PATCH`. Reach for `PUT` only when you hold the complete authoritative document.
- `PUT` replaces. Any custom property, queue, or channel property absent from the body is at risk.
- `PUT` and `PATCH` take different body schemas. Payloads are not interchangeable.


**Custom properties**

- Send custom property values as **lists**, even for single-valued fields — `{"spr_uc_status": ["New"]}`.
- Custom fields are keyed by field name or generated ID (for example `_c_6901b9c50116ee58c854edc5`). Resolve IDs once and cache them.
- Platform-managed properties (`spr_uc_status`, `spr_uc_priority`, `spr_uc_type`, `spr_is_profile_case`) are written by Sprinklr. Do not assume you control them.
- `syncedCustomProperties` overrides everything you omit. `syncedSelectedCustomProperties` does not.


**Identifiers**

- `channelType` is uppercase and case-sensitive.
- `channelId` is the primary key for the customer profile: reusing it associates the new case with the existing profile rather than creating a duplicate.
- `channelId` is not required for `EMAIL` and `SMS`; identity comes from `contactInfo.email` / `contactInfo.phoneNo`.
- URL-encode `channelId` values containing reserved characters — `+` in phone numbers in particular.
- Prefer `id` where you have it; `caseNumber` is equally valid on every endpoint that accepts it.
- Sprinklr rewrites `subject` on create, prefixing the case number and channel. Never match on `subject`.


**Pagination**

- `pageNumber` is **required** for the channel-case fetch mode and is **0-based**.
- `pageSize` defaults to **20** and is capped at **100**.
- `metadata.totalCount` was returned on the channel-case fetch in the collection but was absent from the direct fetches. Do not assume it is always present.


**Concurrency**

- `version` increments on every modification, including macro application. Read it before a write and compare after to detect lost updates.


**Bulk processing**

- `POST /api/v3/case/bulk` is asynchronous. A `202` means *queued*, not *created*.
- Register a `callbackUrl` where possible; poll `/case/bulk/status` with backoff otherwise.
- Set `syncProcessing: true` only for small batches where you need immediate per-record results.


**Error handling**

- Always inspect the `errors` array even on a `200` response.
- Handle `204 No Content` explicitly on merge — parsing it as JSON will throw.
- `data` is an array on `GET /case` and an object on `POST /case`. Branch on the endpoint, not on runtime type.


*All JSON payloads in this guide are illustrative examples taken from the supplied Postman collection and published references. They are not real customer data and are not guaranteed production responses. All credentials are placeholders (`******`, `{{apiKey}}`) and must never be committed or logged.*