# Comment (Note) API V3 — Developer Guide

**Applies to:** Sprinklr Comment (Note) APIs V3 — `POST`, `GET`, `DELETE /api/v3/comment` and `PUT /api/v3/comment/{commentId}`
**V2 API reference:** [Comment (Note)](https://dev.sprinklr.com/comment)

## 1. Overview

A **Comment** — surfaced as a **Note** in the Sprinklr platform — is an internal annotation attached to a business object. Comments let agents collaborate on a record: an agent working in a third-party tool can add a note to a case programmatically so another agent has it for reference. Comments support attachments such as images, files, and video[doc:turn1doc1].

V3 consolidates six v1/v2 comment endpoints into **two paths** and replaces path-segment addressing with query-parameter addressing.

| Operation | Method and path | operationId |
|  --- | --- | --- |
| Create comment on an entity (with optional attachment) | `POST /api/v3/comment` | `CommentApiV3_createComment` |
| Fetch comment(s) by asset and comment id(s) | `GET /api/v3/comment` | `CommentApiV3_getCommentById` |
| Update a comment | `PUT /api/v3/comment/{commentId}` | `CommentApiV3_updateComment` |
| Delete comment(s) | `DELETE /api/v3/comment` | `CommentApiV3_deleteCommentById` |


All four operations carry the tag `Comment V3`.

For more details refer to the [Comment V3 API Reference](/apis/sprinklr-v3/comment).

### 1.1 What changed structurally in V3

Three design changes affect every caller:

1. **Addressing moved from path segments to query parameters.** V2 addressed a comment as `/api/v2/comment/{entityType}/{entityId}/{commentId}`[doc:turn1doc2][doc:turn1doc5]. V3 uses `/api/v3/comment?entityType=…&entityId=…&id=…`.
2. **The `/multiple-attachment` sub-path is removed.** V2 had a dedicated `POST /api/v2/comment/{entityType}/{entityId}/multiple-attachment` endpoint. In V3, multiple attachments are handled natively on the single create endpoint.
3. **Bulk read and delete.** The `id` query parameter accepts **one id or a comma-separated list of up to 50 ids**, all of which must share the same `entityType` and `entityId`.


### 1.2 Data model

```
CommentCreateRequestDTO  (POST body)
├── entityType            (EntityType)
├── entityId              (string)
├── text                  (string)
├── attachment            (Attachment)
├── externalComment       (ExternalComment)
├── inReplyToCommentId    (string)
├── isPrivate             (boolean)
└── … see §4.1 for the full property list

Comment  (GET response item)
├── id, text, attachment
├── commentingUser        (int64)
├── createdTime           (int64, epoch ms)
├── modifiedTime          (int64, epoch ms)
├── entityType, entityId, conversationId
├── externalComment       (ExternalComment)
├── isPrivate             (boolean)
└── inReplyToCommentId    (string)
```

The spec defines **no required properties** on `Comment`, `CommentCreateRequestDTO`, or `CommentUpdateRequestDTO`, and marks every query parameter `required: false`. The operation documents mark `entityType`, `entityId`, `text`, and `commentId` as Required. See §10.

### 1.3 Supported entity types

| Entity type | Identifier to send in `entityId` |
|  --- | --- |
| `CASE` | Case Number |
| `MESSAGE` | Message Id |
| `OUTBOUND_MESSAGE` | Outbound message (post) Id |
| `CAMPAIGN` | Campaign Id |
| `PROFILE` | Profile Id |


## 2. Base URLs and environments

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

`env` — default `prod`. Allowed values:

`prod`, `prod0`, `prod2`, `prod3`, `prod4`, `prod5`, `prod6`, `prod8`, `prod11`, `prod12`, `prod15`, `prod16`, `prod17`, `prod18`, `prod19`, `prod21`, `prod25`

## 3. Authentication and common headers

| Key | Value | Description |
|  --- | --- | --- |
| `Authorization` | `Bearer {{accessToken}}` | Authenticates the user with the server. To generate a token, see the **Authorize** section of the developer portal. |
| `Key` | `{{apiKey}}` | Authenticates the application with the server. To generate a key, see the **Getting Started** guide. |
| `Content-Type` | `application/json` | Media type of the request body. |
| `Accept` | `application/json` | Acceptable response type from the server. |


## 4. Write operations

All payloads below are **illustrative**. Credentials and identifiers are placeholders.

### 4.1 Create a comment — `POST /api/v3/comment`

Creates a comment on an entity, with an optional attachment. Request body is **required**, media type `application/json`, schema `CommentCreateRequestDTO`.

**Documented request parameters**

| Parameter | Sub-parameter | Required | Type | Description |
|  --- | --- | --- | --- | --- |
| `entityType` | — | Required | String | Entity type: `MESSAGE`, `OUTBOUND_MESSAGE`, `CASE`, `CAMPAIGN`, `PROFILE`. |
| `entityId` | — | Required | String | Entity id — e.g. Case Number for `CASE`, Message Id for `MESSAGE`. |
| `text` | — | Required | String | The comment text. In V2's multiple-attachment endpoint this field was named `comment`. |
| `attachments` | — | Required (for the attachment flow) | Array | Array of attachment objects. |
|  | `url` | Required | String | URL from the Media Upload API response. |
|  | `previewUrl` | Optional | String | Preview URL from the Media Upload API response. |
|  | `type` | Required | Enum | `IMAGE`, `VIDEO`, `DOC`. |


**Additional `CommentCreateRequestDTO` properties in the spec** (present in the schema, not covered by the operation documents):

| Property | Type | Description |
|  --- | --- | --- |
| `id` | string | Comment id. |
| `externalComment` | object (`ExternalComment`) | Third-party channel comment details when comments are synced with another system. |
| `inReplyToCommentId` | string | Parent comment's id, when this comment is a reply. |
| `contextId` | string | Context entity id when commenting in a nested context. |
| `contextClass` | `AssetClass` | Context asset class for nested context. |
| `clientId` | int64 | Client id override. |
| `commentingUser` | int64 | Sprinklr user id of the commenter. |
| `commentedOnDate` | int64 | Comment timestamp override (epoch ms). |
| `universalMessageKey` | object | Universal message key when the comment ties to a message. |
| `commentingCommunityUserId` | string | Community user id for community-sourced comments. |
| `collaborationChannelId` | string | Collaboration channel id. |
| `hasConversation` | boolean | Whether the comment has an associated conversation thread. |
| `restrictVisibility` | boolean | Restrict visibility of the comment. |
| `resolved` | boolean | Resolved flag for threaded / task comments. |
| `type` | string | Comment subtype, e.g. `BROADCAST` for `@here` collaboration comments. |
| `additionalInfo` | map<string, string[]> | Free-form additional information. |
| `isPrivate` | boolean | Private comment — internal only, not synced to third-party integrations. |


**Example — create a comment without an attachment**

```bash
curl --location 'https://api3.sprinklr.com/{env}/api/v3/comment' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'accept: application/json' \
--data '{
  "entityType": "CASE",
  "entityId": "116537343",
  "text": "comment test"
}'
```

Example response (as recorded in the source documents):

```json
{
  "data": {
    "id": "6a8825baa34ff204e0821a61",
    "text": "comment test",
    "commentingUser": 66015421,
    "createdTime": 1787307448962,
    "modifiedTime": 1787307448962,
    "entityType": "CASE",
    "entityId": "116537343",
    "conversationId": "7608262980542680350",
    "externalComment": {
      "channelType": "TIKTOK"
    }
  },
  "errors": []
}
```

**Creating a comment with attachments**

> **Dev Note.** Upload each attachment with the **Media Upload API** before calling this endpoint. The `/multiple-attachment` sub-path is removed in V3 — multiple attachments are handled natively.


1. Upload the file via the Media Upload API and keep the `url` and `previewUrl` from its response.
2. Reference those URLs on the create call, one entry per attachment, each with its `type`.


> **Caveat.** The "Create Comment with Multiple Attachments" example request in the source document is a copy of the plain-text example — it sends no attachments at all, and its response contains no attachment data. The parameter table above is therefore the only description of the attachment payload. A corrected worked example has been requested. See §10.


### 4.2 Update a comment — `PUT /api/v3/comment/{commentId}`

Updates a comment's text, media, external reply metadata, and/or channel sync fields.

**Parameters**

| Parameter | In | Required (spec) | Required (docs) | Type | Description |
|  --- | --- | --- | --- | --- | --- |
| `commentId` | path | **Yes** | Required | String | Id of the comment to update. |
| `entityType` | query | No | Required | String | Entity type (enum name, e.g. `CASE`). |
| `entityId` | query | No | Required | String | Id of the entity. |


**Request body** — required, schema `CommentUpdateRequestDTO`:

| Property | Type | Description |
|  --- | --- | --- |
| `entityType` | `EntityType` | Optional; **if set, must match the `entityType` query parameter.** |
| `entityId` | string | Id of the entity. |
| `text` | string | Text of the comment. |
| `attachment` | `Attachment` | Attachment of the comment. |
| `externalComment` | `ExternalComment` | Third-party channel comment details when comments are synced with another system. |
| `inReplyToCommentId` | string | Parent comment's id to which this is a reply. |
| `channelAssetId` | string | Channel-native asset id. |
| `channelCommentId` | string | Channel-native comment id. |
| `channelType` | string | Channel type. |
| `channelCreationTime` | int64 | Channel creation time (epoch ms). |
| `channelModificationTime` | int64 | Channel modification time (epoch ms). |


The last five properties absorb the work of V2's separate `PUT /api/v2/comment/{entityType}/{entityId}/{commentId}/channel-details` endpoint.

```bash
curl --location --request PUT \
'https://api3.sprinklr.com/{env}/api/v3/comment/{commentId}?entityType=CASE&entityId=116537343' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'accept: application/json' \
--data '{
  "text": "new comment updated",
  "entityType": "CASE",
  "entityId": "116537343"
}'
```

### 4.3 Delete comment(s) — `DELETE /api/v3/comment`

Deletes one or more comments.

| Parameter | In | Required (spec) | Required (docs) | Type | Description |
|  --- | --- | --- | --- | --- | --- |
| `entityType` | query | No | Required | String | Entity type (enum name, e.g. `CASE`). |
| `entityId` | query | No | Required | String | Id of the entity. |
| `id` | query | No | Required | String | Comment id(s): one id or a comma-separated list, **maximum 50**, all sharing the same `entityType` and `entityId`. |


```bash
curl --location --request DELETE \
'https://api3.sprinklr.com/{env}/api/v3/comment?entityType=CASE&entityId=116537343&id={commentId}' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'accept: application/json'
```

The source document records the response as `HTTP/1.1 204 (No Content)`. The spec declares `200` with an `APIResponse` body. See §10.

## 5. Read operations

### 5.1 Fetch comment(s) — `GET /api/v3/comment`

Fetches one or more comments for a given asset.

| Parameter | In | Required (spec) | Required (docs) | Type | Description |
|  --- | --- | --- | --- | --- | --- |
| `entityType` | query | No | Required | String | Entity type for which the comment is being fetched. Supported values: `MESSAGE`, `CASE`, `CAMPAIGN`, `PROFILE`. |
| `entityId` | query | No | Required | String | Unique identifier of the entity — Case Number for `CASE`, Message Id for `MESSAGE`, Campaign Id for `CAMPAIGN`, Profile Id for `PROFILE`. |
| `id` | query | No | Required | String | Comment id(s): one id or a comma-separated list, **maximum 50**, all sharing the same `entityType` and `entityId`. |


```bash
curl --location \
'https://api3.sprinklr.com/{env}/api/v3/comment?entityType=CASE&entityId=116537343&id={commentId}' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'accept: application/json'
```

```json
{
  "data": [
    {
      "id": "6a883e6cd4bb4391d375feea",
      "text": "comment test",
      "commentingUser": 66015421,
      "createdTime": 1787313772664,
      "modifiedTime": 1787313772664,
      "entityType": "CASE",
      "entityId": "116537343",
      "conversationId": "7608262980542680350",
      "externalComment": {
        "channelType": "TIKTOK"
      }
    }
  ],
  "errors": []
}
```

**Response parameters (`Comment`)**

| Parameter | Type | Description |
|  --- | --- | --- |
| `id` | String | Unique id of the comment. |
| `text` | String | Text of the comment. |
| `attachment` | Object (`Attachment`) | Attachment of the comment. |
| `commentingUser` | Long (int64) | Sprinklr user id of the user who made the comment. |
| `createdTime` | Epoch (int64, ms) | Time when the comment was made. |
| `modifiedTime` | Epoch (int64, ms) | Time when the comment was last updated. |
| `entityType` | String | Entity type on which the comment was created. |
| `entityId` | String | Id of the entity on which the comment was created. |
| `conversationId` | String | Conversation id of the entity on which the comment was created, if applicable. |
| `externalComment` | Object (`ExternalComment`) | Details of the channel comment, if applicable. |
| `isPrivate` | Boolean | Private comment — internal only, not synced to third-party integrations. |
| `inReplyToCommentId` | String | Parent comment's id to which this is a reply. |
| `errors` | Array | Error details, if any. |


**`ExternalComment` object**

| Property | Type | Description |
|  --- | --- | --- |
| `channelType` | String | Channel type, e.g. `salesforce`, `zendesk`, `rightnow`. The documented example returns `TIKTOK`. |
| `commentId` | String | Unique id of the third-party comment. |
| `assetId` | String | Unique id of the third-party asset on which the comment was made. |
| `ownerId` | String | Owner of the comment on the third-party channel. |
| `creationTime` | int64 | Channel creation time (epoch ms). |
| `modificationTime` | int64 | Channel modification time (epoch ms). |


> **Note.** The spec declares the `200` body for `GET /comment` as a **bare array of `Comment` objects**, not the `{data, errors}` envelope shown in the documented example. See §10.


## 6. Response format and status codes

### 6.1 Success envelope

Every documented example returns the standard Sprinklr envelope:

```json
{
  "data": { },
  "errors": []
}
```

The declared success schemas differ per operation:

| Operation | Declared `200` schema | Observed in documents |
|  --- | --- | --- |
| `POST /comment` | `CommentCreateRequestDTO` | `{data: {…}, errors: []}` |
| `GET /comment` | `array` of `Comment` | `{data: [{…}], errors: []}` |
| `PUT /comment/{commentId}` | `APIResponse` | `204 No Content` |
| `DELETE /comment` | `APIResponse` | `204 No Content` |


`APIResponse` is `{data: object, errors: Error[], metadata: ResponseMetadata}`.

### 6.2 Error responses

All four operations declare the shared error responses:

| Status | Name | Body |
|  --- | --- | --- |
| 400 | Bad Request | `ErrorResponse` |
| 401 | Unauthorized | `ErrorResponse` |
| 403 | Forbidden | `ErrorResponse` |
| 404 | Not Found | `ErrorResponse` |


`ErrorResponse` is `{data: object|null, errors: Error[], metadata: object}`.

```json
{
  "data": null,
  "errors": [
    {
      "id": "5f9b2c1a4e6d7b8c9a0f1e2d",
      "code": 4001,
      "message": "comment.not.found"
    }
  ],
  "metadata": {}
}
```

`Error` requires `id` (24-character hexadecimal ObjectId), `code` (integer), and `message` (dotted error key, e.g. `account.not.found`).

## 7. V2 → V3 migration

### 7.1 Endpoint mapping

| V2 | V3 | Notes |
|  --- | --- | --- |
| `POST /api/v2/comment/{entityType}/{entityId}` | `POST /api/v3/comment` | `entityType` and `entityId` move from the path into the JSON body. |
| `POST /api/v2/comment/{entityType}/{entityId}/multiple-attachment` | `POST /api/v3/comment` | **Endpoint removed.** Multiple attachments are handled natively by the single create endpoint. |
| `GET /api/v2/comment/{entityType}/{entityId}/{commentId}`[doc:turn1doc5] | `GET /api/v3/comment?entityType=&entityId=&id=` | Addressing moves to query parameters; `id` now accepts up to 50 comma-separated ids. |
| `PUT /api/v2/comment/{entityType}/{entityId}/{commentId}` | `PUT /api/v3/comment/{commentId}?entityType=&entityId=` | Only `commentId` stays in the path. |
| `PUT /api/v2/comment/{entityType}/{entityId}/{commentId}/channel-details` | `PUT /api/v3/comment/{commentId}` | **Sub-path removed.** Use the `channelAssetId`, `channelCommentId`, `channelType`, `channelCreationTime`, and `channelModificationTime` body fields. |
| `DELETE /api/v2/comment/{entityType}/{entityId}/{commentId}` | `DELETE /api/v3/comment?entityType=&entityId=&id=` | Addressing moves to query parameters; supports bulk delete. |


The four consolidated read/update/delete endpoints were identified during development and added to the migration scope on 2026-04-29 (Jira comment by Aman Joshi), after the ticket originally scoped only the two create endpoints.

### 7.2 Field mapping

| V2 | V3 | Change |
|  --- | --- | --- |
| `entityType`, `entityId` (path segments) | Body fields on `POST`; query parameters on `GET`, `PUT`, `DELETE` | **Breaking** — request URLs must be rebuilt. |
| `comment` (multiple-attachment body) | `text` | **Breaking** rename on the multi-attachment flow. `text` was already the field name on the single-comment endpoint[doc:turn1doc2]. |
| `attachment` (single object) | `attachment` per the schema / `attachments` array per the documents | Unresolved — see §10. |
| `attachment.type` enum `IMAGE, DOC, VIDEO, AUDIO`[doc:turn1doc2] | Documented as `IMAGE, VIDEO, DOC` | `AUDIO` is not listed in the V3 documents. Confirm whether it is still accepted. |
| `commentId` (path segment) | `id` query parameter on `GET`/`DELETE`; `commentId` path parameter on `PUT` | **Breaking** — note the parameter is named `id`, not `commentId`, on `GET` and `DELETE`. |
| `createdTime` / `modifiedTime`, epoch ms[doc:turn1doc2] | `createdTime` / `modifiedTime`, epoch ms | Unchanged in the schema. One documented example instead shows ISO 8601 `created_at` / `updated_at` — see §10. |
| `commentingUser`, numeric[doc:turn1doc2] | `commentingUser`, int64 | Unchanged in the schema. |


New in V3 with no V2 equivalent in the public documentation: `conversationId`, `externalComment`, `isPrivate`, `inReplyToCommentId`, and the extended create properties listed in §4.1.

### 7.3 Migration steps

1. Rewrite request URLs. Move `entityType` and `entityId` out of the path — into the JSON body for `POST`, into query parameters for `GET`, `PUT`, and `DELETE`.
2. Replace calls to `/multiple-attachment` with the single `POST /api/v3/comment`.
3. Replace calls to `/channel-details` with `PUT /api/v3/comment/{commentId}` carrying the `channel*` body fields.
4. Rename `comment` to `text` in any multi-attachment payload.
5. On `GET` and `DELETE`, send the comment id as `id`, not `commentId`. Take advantage of batching — up to 50 ids per call, all on the same entity.
6. On `PUT`, if you send `entityType` in the body it **must match** the `entityType` query parameter.
7. Keep parsing `createdTime` / `modifiedTime` as epoch milliseconds, but make the parser tolerant until the timestamp format question in §10 is resolved.
8. Make response parsing tolerant of both the `{data, errors}` envelope and a bare array on `GET`, and of both `200` and `204` on `PUT` and `DELETE`.
9. If you use `AUDIO` attachments, confirm continued support before cutting over.
10. Re-test in a non-production `{env}` first.


## 8. Reference — enums and reusable objects

| Field | Values |
|  --- | --- |
| `entityType` | `MESSAGE`, `OUTBOUND_MESSAGE`, `CASE`, `CAMPAIGN`, `PROFILE` (from the documents; the `EntityType` schema declares no enum) |
| `attachment.type` (documented for comments) | `IMAGE`, `VIDEO`, `DOC` — V2 also listed `AUDIO`[doc:turn1doc2] |
| `attachments` container type (multi-attachment response) | `MULTI_MEDIA` |
| `externalComment.channelType` | Free-form string, e.g. `salesforce`, `zendesk`, `rightnow`, `TIKTOK` |
| `CommentCreateRequestDTO.type` | Comment subtype, e.g. `BROADCAST` for `@here` collaboration comments |


Reusable objects referenced by this API: `Attachment` (the shared discriminated attachment type), `ExternalComment`, `AssetClass`, `UniversalMessageKey`, `APIResponse`, `ErrorResponse`, `Error`, `ResponseMetadata`.

## 9. Use cases and best practices

**Use cases**

- **Sync notes from a third-party CRM.** An agent working in Salesforce or Zendesk adds a note; push it onto the Sprinklr case with `POST /api/v3/comment` and record provenance in `externalComment`.
- **Attach evidence to a case.** Upload a screenshot with the Media Upload API, then create a comment referencing the returned `url` and `previewUrl`.
- **Keep internal notes internal.** Set `isPrivate: true` so the comment is not synced to third-party integrations.
- **Thread a discussion.** Set `inReplyToCommentId` to nest a reply under a parent comment.
- **Hydrate a case view in one call.** Pass up to 50 comma-separated comment ids to `GET /api/v3/comment` instead of issuing 50 requests.
- **Bulk clean-up.** Delete a batch of comments on the same entity in one `DELETE` call.
- **Broadcast to collaborators.** Set `type: BROADCAST` for `@here`-style collaboration comments.


**Best practices**

- Always send `entityType` and `entityId` together — a comment id is only unique within its entity scope, and the batch parameters require a single shared scope.
- Upload media **before** creating the comment; the comment API takes URLs, not file bytes.
- Cap batch reads and deletes at **50 ids**. Chunk larger sets client-side.
- Send timestamps as epoch milliseconds (UTC) when overriding `commentedOnDate`.
- On `PUT`, prefer sending scope **only** in the query parameters to avoid the body/query mismatch rule.
- Deletes are not documented as reversible. Read the comment first if you may need to restore it.
- Do not send the `Cookie: JSESSIONID=…` header seen in the captured samples, and never commit tokens or API keys.
- Test against a non-production `{env}` before cutting over from V2.