# Bulk Import (File Import) API V3 — Developer Guide

- **Applies to:** Sprinklr File Import API V3 (`/api/v3/file-import/...`)
- **V2 API reference:** [Bulk Import Entity | Sprinklr Developer Portal](https://dev.sprinklr.com/bulk-import-entity)


## 1. Overview

You can import supported entities in bulk within Sprinklr via this API and you will get the Id and other related objects as a response after the request is successful.

Bulk import is a **two-call, asynchronous workflow**:

| Step | Operation | Method | Path |
|  --- | --- | --- | --- |
| 1 | Download the import template for an entity type | `GET` | `/api/v3/file-import/template?entityType={type}` |
| 2 | Import entities from the filled-in file | `POST` | `/api/v3/file-import/entity` |


> **Note:** to update the entity you can use the same API call as each entity will have a unique Id, so in the excel sheet, if the system finds an entity with a unique Id it will update, otherwise it will create it.


### 1.1 End-to-end workflow

1. **Download the template.** `GET /api/v3/file-import/template?entityType={type}` returns the Excel template whose headers define the columns for that entity type.
2. **Fill in the template.** Populate one row per entity. Leave the Id column blank to create; supply an existing Id to update.
3. **Publish the file.** Upload the completed file to a publicly reachable URL.
> **Dev Note:** once you fill in all the details in the excel file, you need to upload it to the web using the **Media Upload API**. This will make the file publicly accessible, which can then be configured as a `fileUrl` in the bulk import API call.
4. **Trigger the import.** `POST /api/v3/file-import/entity` with `fileUrl`, `callbackUrl`, `entityType`, and `fileExtension`.
5. **Receive the `taskId`.** The synchronous response returns a task id — the import itself runs asynchronously.
6. **Handle the callback.** On success, a payload is delivered to your `callbackUrl` carrying row counts, status, and a `responseFileUrl` with the per-row outcome.


## 2. Base URLs and environments

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

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

So the two bulk import endpoints are:

```
GET  https://api3.sprinklr.com/{env}/api/v3/file-import/template?entityType={type}
POST https://api3.sprinklr.com/{env}/api/v3/file-import/entity
```

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).

The supplied Postman collection targets the internal QA host `https://qa6-api2.sprinklr.com/api/v3/file-import/...`. Do not use that host for integration work; repoint every request at `https://api3.sprinklr.com/{env}/` first.

## 3. Authentication and common headers

All 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. Read operations

### 4.1 Download template

**`GET /api/v3/file-import/template?entityType={type}`**

Downloads the excel template in which you can fill the details of the entity which you want to import.

#### Query parameters

| Parameter | Required/Optional | Description | Type |
|  --- | --- | --- | --- |
| `entityType` | **Required** | The entity type you want to import, like `UNIVERSAL_PRODUCT`, `USER_GROUP`, etc. | String |


#### Supported entity types

`USER`, `UNIVERSAL_PRODUCT`, `UNIVERSAL_MESSAGE_STATUS`, `MEDIA_ASSET`, `ROLES_AND_PERMISSIONS`, `PARTNER_QUEUE`, `CLIENT_QUEUE`, `PROFILE_LIST`, `PROFILE_TAGGING_RULE`, `CUSTOM_FIELD`, `CAMPAIGN`, `USER_GROUP`, `ACCOUNT_GROUP`, `ACCOUNT`.

#### Request

```bash
curl -X GET \
  'https://api3.sprinklr.com/{env}/api/v3/file-import/template?entityType=UNIVERSAL_PRODUCT' \
  -H 'Authorization: {Enter your Access Token}' \
  -H 'Key: {Enter your API KEY}' \
  -H 'Content-Type: application/json'
```

#### Response

`200 OK`.

> **Dev Note:** once you fill in all the details in the excel file, you need to upload it to the web using the [Media Upload API](#). This will make the file publicly accessible, which can then be configured as a `fileUrl` in the bulk import API call.


## 5. Write operations

### 5.1 Import entity

**`POST /api/v3/file-import/entity`**

Once you have downloaded the template and filled in the details as per the headers in the excel sheet, you can now make this API call to import the entity in bulk.

#### Request body — `ImportRequest`

| Parameter | Required/Optional | Description | Type |
|  --- | --- | --- | --- |
| `fileUrl` | **Required** | The public URL of the file. | String |
| `callbackUrl` | **Required** | On success, a payload will be sent to the callback URL. **Note:** the callback URL can be public or with authentication and should return a `200` response on receiving an empty payload. This is used for verification purposes; if the callback URL verification is failing, please check with the Sprinklr team that they have valid certificates installed. | String |
| `callbackUrlHeaders` | Optional | You can use this field for authenticating the call coming to the callback URL specified above. Sent as a key–value object. | String (object of string values) |
| `entityType` | **Required** | The supported entity type. See [§4.1](#41-download-template) for the list. | String |
| `fileExtension` | **Required** | The file extension. Supported file extensions are `.xls`, `.xlt`, `.xltx`, `.xlsx`, `.csv`, `.txt` | String |
| `outputFileExtension` | Optional | File extension of output, either `.csv` or `.xlsx`. **Default value is `.xlsx`.** | String |
| `onlyFailedOutput` | Optional | Whether to include all rows or only failed rows in the output. **Default value `false`.** | Boolean |
| `isGlobal` | Optional | Only used for `PROFILE_TAGGING_RULE`. `true` if partner level asset, `false` if workspace level asset. | String |
| `contentZipUrl` | Optional | URL of zip file corresponding to social assets. | String |


#### Request

```bash
curl -X POST \
  'https://api3.sprinklr.com/{env}/api/v3/file-import/entity' \
  -H 'Authorization: {Enter your Access Token}' \
  -H 'Key: {Enter your API KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "fileUrl": "https://docs.google.com/uc?export=download&id=1A8oSr6rmkJ9-LNMrUI5cxROLIGRdJFpk",
  "callbackUrl": "https://webhook.site/9d9962ae-9907-4f45-8c6f-074e213c4761",
  "entityType": "UNIVERSAL_PRODUCT",
  "fileExtension": "xlsx",
  "outputFileExtension": "csv",
  "onlyFailedOutput": true
}'
```

With callback authentication headers:

```bash
curl -X POST \
  'https://api3.sprinklr.com/{env}/api/v3/file-import/entity' \
  -H 'Authorization: {Enter your Access Token}' \
  -H 'Key: {Enter your API KEY}' \
  -H 'Content-Type: application/json' \
  -d '{
  "fileUrl": "",
  "callbackUrl": "",
  "entityType": " ",
  "outputFileExtension": "csv",
  "onlyFailedOutput": "true",
  "callbackUrlHeaders": {
    "Key1": "Value1",
    "Key2": "Value2"
  },
  "fileExtension": "xlsx"
}'
```

#### Response

`200 Success`, body `APIResponse`.

**Response**

```json
{
    "data": "{\"taskId\":\"6026440df0f98a17b6529eb6\"}",
    "errors": []
}
```

Note that `data` is a **JSON string**, not a nested object — you must parse it a second time to read `taskId`.

### 5.2 Callback payload

On success, a payload will be sent to the callback URL. The Id will be the same as the output from the above call.

```json
{
    "id": "6026440df0f98a17b6529eb6",
    "entityType": "Universal Product",
    "userId": ,
    "uploadedAt": ,
    "numberOfRows": ,
    "numberOfRowsCreated": ,
    "numberOfRowsUpdated": ,
    "status": "",
    "fileUrl": "",
    "responseFileUrl": "",
    "clientId": ,
    "partnerId": ,
    "skippedRows": 
}
```

| Field | Meaning |
|  --- | --- |
| `id` | Task id — identical to the `taskId` returned by `POST /file-import/entity` |
| `entityType` | The imported entity type, rendered as a display label (for example `Universal Product`, not `UNIVERSAL_PRODUCT`) |
| `userId` | User who triggered the import |
| `uploadedAt` | Upload timestamp |
| `numberOfRows` | Total rows processed from the file |
| `numberOfRowsCreated` | Rows that resulted in a new entity |
| `numberOfRowsUpdated` | Rows that matched an existing Id and were updated |
| `status` | Terminal status of the import job |
| `fileUrl` | The input file URL you supplied |
| `responseFileUrl` | Output file with the per-row result, in `outputFileExtension` format |
| `clientId` | Workspace id |
| `partnerId` | Partner id |
| `skippedRows` | Rows that were neither created nor updated |


**Callback contract:** the callback URL can be public or authenticated, and must return `200` on receiving an **empty payload** — Sprinklr sends an empty probe to verify the endpoint before delivering the real payload. If verification fails, check with the Sprinklr team that valid certificates are installed.

### 5.3 Operation comparison

|  | `GET` template | `POST` entity |
|  --- | --- | --- |
| Purpose | Fetch the column template for an entity type | Trigger a bulk create/update job |
| Input | `entityType` query parameter | `ImportRequest` JSON body |
| Body | None | Required |
| Execution | Synchronous | **Asynchronous** — returns a `taskId` |
| Response schema | `string` | `APIResponse` |
| Result delivery | Response body | `callbackUrl` payload + `responseFileUrl` |


## 6. Response format and status codes

### 6.1 Response bodies

| Operation | Declared `200` schema |
|  --- | --- |
| `GET /file-import/download/template` | `string` |
| `POST /file-import/entity` | `APIResponse` (`data`, `errors`) |


The `POST` uses the standard V3 `APIResponse` envelope with `data` and `errors`. The `data` value is a serialized JSON string containing `taskId`.

### 6.2 Response codes

Declared on both operations:

| HTTP Code | Scenario | Description |
|  --- | --- | --- |
| `200 OK` | Success | Template returned, or import job accepted |
| `400 Bad Request` | Invalid parameters | Unsupported `entityType`, unsupported `fileExtension`, missing required field, or unreachable `fileUrl` |
| `401 Unauthorized` | Authentication failed | Invalid or missing `Authorization` token |
| `403 Forbidden` | Insufficient permissions | Caller lacks rights to import that entity type in the target workspace |
| `404 Not Found` | Not found | No template exists for the requested entity type |


`500 Internal Server Error` is not declared on these operations; handle it defensively regardless.

**A `200` on `POST /file-import/entity` means the job was accepted, not that the rows imported.** Row-level success and failure are reported only through the callback payload and `responseFileUrl`.

## 7. V2 → V3 migration

| Aspect | API V2 | API V3 | Impact |
|  --- | --- | --- | --- |
| Base path | `/api/v2/file-import` | `/api/v3/file-import` | Change the version segment |
| Template path segment | `/download/template` | `/template` per your specification; `/download/template` per yaml and Postman | **Unresolved** — verify before migrating |
| Request body | `fileUrl`, `callbackUrl`, `callbackUrlHeaders`, `entityType`, `fileExtension`, `outputFileExtension`, `onlyFailedOutput` | Same, **plus** `isGlobal` and `contentZipUrl` | Additive; existing payloads transfer unchanged |


**This is primarily a version-prefix migration.** All seven V2 request fields carry over with identical names, types, and defaults.

**Migration steps**

1. **Update the base URL.** Change `/api/v2/file-import` to `/api/v3/file-import`.
2. **Confirm the template path.** Test both `/file-import/template` and `/file-import/download/template` against your environment before switching.
3. **Retain your existing request payloads.** No V2 field was renamed, removed, or retyped.
4. **Re-verify your supported entity types.** V3 types `entityType` as an open `string` with no enum, so the V2 list of 14 is the only published inventory.
5. **Keep your callback endpoint unchanged**, but re-run the empty-payload verification handshake against the V3 environment.
6. **Consider the new fields.** `isGlobal` if you import `PROFILE_TAGGING_RULE`; `contentZipUrl` if your import references social assets.


## 8. Supported enums and reference tables

### 8.1 Supported entity types

| Entity type |
|  --- |
| `USER` |
| `UNIVERSAL_PRODUCT` |
| `UNIVERSAL_MESSAGE_STATUS` |
| `MEDIA_ASSET` |
| `ROLES_AND_PERMISSIONS` |
| `PARTNER_QUEUE` |
| `CLIENT_QUEUE` |
| `PROFILE_LIST` |
| `PROFILE_TAGGING_RULE` |
| `CUSTOM_FIELD` |
| `CAMPAIGN` |
| `USER_GROUP` |
| `ACCOUNT_GROUP` |
| `ACCOUNT` |


### 8.2 Supported file extensions

| Field | Supported values | Default |
|  --- | --- | --- |
| `fileExtension` (input) | `.xls`, `.xlt`, `.xltx`, `.xlsx`, `.csv`, `.txt` | None — required |
| `outputFileExtension` (output) | `.csv`, `.xlsx` | `.xlsx` |


### 8.3 Other defaults

| Field | Default |
|  --- | --- |
| `onlyFailedOutput` | `false` — all rows are included in the output |
| `outputFileExtension` | `.xlsx` |


## 9. Use cases

### 9.1 Bulk-create a product catalog

**Scenario:** load several thousand products into Sprinklr.

1. `GET /api/v3/file-import/template?entityType=UNIVERSAL_PRODUCT`
2. Fill one row per product, leaving the Id column blank.
3. Upload the file via the Media Upload API to obtain a public `fileUrl`.
4. `POST /api/v3/file-import/entity` with `entityType: "UNIVERSAL_PRODUCT"` and `fileExtension: "xlsx"`.
5. Read `taskId` from `data`, then wait for the callback.


### 9.2 Bulk-update existing entities

There is no separate update endpoint. Export or reproduce the entities' existing Ids into the Id column of the template and re-run the same `POST /api/v3/file-import/entity` call — rows carrying a known Id are updated, rows without one are created. Confirm the split afterwards via `numberOfRowsUpdated` versus `numberOfRowsCreated` in the callback payload.

### 9.3 Retrieve only the rows that failed

Set `"onlyFailedOutput": true` and `"outputFileExtension": "csv"`. The `responseFileUrl` in the callback then contains just the failing rows in CSV form — the smallest artifact to feed into a retry pipeline. With the default `false`, every row appears in the output regardless of outcome.

### 9.4 Authenticate the callback

If your callback endpoint is protected, pass credentials via `callbackUrlHeaders`:

```json
{
  "fileUrl": "https://example.com/products.xlsx",
  "callbackUrl": "https://api.example.com/sprinklr/import-complete",
  "callbackUrlHeaders": {
    "X-Api-Key": "******",
    "X-Tenant": "acme"
  },
  "entityType": "UNIVERSAL_PRODUCT",
  "fileExtension": "xlsx"
}
```

Your endpoint must still return `200` for the empty verification payload sent before the real callback.

### 9.5 Import partner-level profile tagging rules

`PROFILE_TAGGING_RULE` is the only entity type that reads `isGlobal`. Set `"isGlobal": "true"` for a partner-level asset and `"isGlobal": "false"` for a workspace-level asset. Note the value is a **string**, not a boolean, in the V3 schema.

### 9.6 Import social assets with attached content

When the rows reference social assets, supply the accompanying media as a zip archive via `contentZipUrl` alongside `fileUrl`. This field exists only in V3.

### 9.7 Correlate a job to its callback

The `taskId` in the `POST` response and the `id` in the callback payload are the same value. Persist the `taskId` when you fire the import, then match it on receipt:

```javascript
const res  = await post('/api/v3/file-import/entity', body);
const task = JSON.parse(res.data).taskId;   // data is a JSON *string*
await store.record(task, { entityType: body.entityType, submittedAt: Date.now() });
```

### 9.8 Onboard users in bulk

Use `entityType: "USER"` for user records or `"USER_GROUP"` for group membership. For SCIM-shaped identity provisioning with per-user response bodies, use the SCIM APIs instead — file import is the right tool when the source of truth is a spreadsheet, not an IdP.