Skip to content
Last updated

API Basics

This guide covers the core patterns and techniques you'll use when working with the Sprinklr API. Once you understand these fundamentals, you'll be able to build robust integrations that handle real-world scenarios effectively.

How requests and responses work

Every interaction with the Sprinklr API follows the same basic pattern: you send a request, and you get back a response. Let's break down what that looks like.

Anatomy of a request

Here's a typical API request:

GET /api/v3/account?accountId=600057112 HTTP/1.1
Host: api-v3.sprinklr.com
Authorization: Bearer SPRD_tjACKHVlwb3D7Xd2...
Key: ebgw8cwygvgc7vptgxty2ekq
Content-Type: application/json

Let's examine each part:

1. HTTP method (GET) This tells the API what kind of operation you want to perform. GET retrieves data, POST creates new data, PUT/PATCH updates existing data, and DELETE removes data.

2. Endpoint path (/api/v3/account) This identifies which resource you're working with. The /api/v3/ prefix is on all endpoints, then comes the resource name.

3. Query parameters (?accountId=600057112) These filter or modify the request. Different endpoints support different parameters.

4. Headers

  • Authorization: Your access token for authentication
  • Key: Your API key for identification
  • Content-Type: Tells the API you're sending JSON (for POST/PUT/PATCH)

5. Request body (not shown in this GET request) For POST, PUT, and PATCH requests, you'll send data in JSON format in the request body.

Understanding responses

Every Sprinklr API response uses a consistent structure. This makes it easy to handle responses in your code:

Success response:

{
  "success": true,
  "data": {
    "id": "600057112",
    "accountType": "TWITTER",
    "accountDisplayName": "@YourBrand",
    "followerCount": 15420,
    "status": "ACTIVE"
  }
}

Error response:

{
  "success": false,
  "errors": [
    {
      "code": "NOT_FOUND",
      "message": "Account with ID 600057112 not found",
      "field": "accountId"
    }
  ]
}

Notice the key differences:

  • success is always present and tells you if the request worked
  • Successful responses have a data field with your results
  • Failed responses have an errors array explaining what went wrong
  • Error objects include a machine-readable code, human-readable message, and sometimes a field indicating which parameter caused the problem

This consistent structure means you can write generic error handling code that works across all endpoints.

HTTP methods: What each one does

The Sprinklr API uses standard REST conventions for HTTP methods. Here's when to use each one:

GET - Retrieving data

Use GET when you want to read data without making any changes:

# Get account information
GET /api/v3/account?accountId=600057112

# Search for messages
GET /api/v3/message?messageId=MSG_12345

# Get multiple profiles
GET /api/v3/profile?profileId=PROF_1,PROF_2,PROF_3

GET requests:

  • Don't have a request body
  • Pass all parameters in the URL
  • Are safe to retry - they won't change anything
  • Can be cached by browsers and proxies

POST - Creating or searching

POST has two main uses in the Sprinklr API:

1. Creating new resources:

POST /api/v3/case
Content-Type: application/json

{
  "subject": "Customer inquiry about pricing",
  "priority": "MEDIUM",
  "source": "TWITTER",
  "customerId": "CUST_789"
}

2. Complex searches:

POST /api/v3/message/search
Content-Type: application/json

{
  "startTime": "2026-02-01T00:00:00Z",
  "endTime": "2026-02-11T23:59:59Z",
  "accountIds": ["600057112"],
  "sentiment": ["POSITIVE", "NEUTRAL"],
  "page": 0,
  "size": 50
}

Why use POST for searches? When you need to send complex filter criteria (like arrays, date ranges, or nested conditions), the data doesn't fit well in a URL. POST lets you send structured JSON that's easier to work with.

PUT - Full update

PUT replaces an entire resource with new data:

PUT /api/v3/case/CASE_789
Content-Type: application/json

{
  "subject": "Updated subject",
  "priority": "HIGH",
  "status": "IN_PROGRESS",
  "assignedTo": "agent@yourbrand.com",
  "notes": "Updated by API"
}

With PUT, you typically need to send all fields, not just the ones you're changing. If you omit a field, it might be set to null or left unchanged (depending on the endpoint).

PATCH - Partial update

PATCH lets you update just specific fields:

PATCH /api/v3/case/CASE_789
Content-Type: application/json

{
  "priority": "URGENT",
  "assignedTo": "senior-agent@yourbrand.com"
}

This is more convenient than PUT because you only send what you want to change. Other fields remain untouched.

DELETE - Removing data

DELETE removes a resource:

DELETE /api/v3/case/CASE_789

Be careful with DELETE operations - they're usually permanent. Some resources might support soft deletes (marking as inactive) instead of hard deletes (permanent removal).

Working with single resources

The simplest pattern is fetching a single resource by its ID:

curl "https://api-v3.sprinklr.com/api/v3/account?accountId=600057112" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Key: YOUR_API_KEY"

Response:

{
  "success": true,
  "data": {
    "id": "600057112",
    "accountType": "TWITTER",
    "accountDisplayName": "@YourBrand",
    "accountScreenName": "YourBrand",
    "verified": true,
    "followerCount": 15420,
    "status": "ACTIVE",
    "createdTime": "2024-03-15T10:30:00Z"
  }
}

Even though you requested one account, data is still an array (in some endpoints) or a single object (in others). Check the API reference for each endpoint to see which structure it uses.

Batch operations: Your new best friend

One of the most powerful features of the Sprinklr API is batch operations. Instead of making multiple individual requests, you can fetch up to 50 resources at once.

Why batching matters

Without batching:

// 10 separate API calls
// Takes ~3-5 seconds
// Uses 10 of your rate limit quota
const accounts = [];
for (const id of accountIds) {
  const account = await fetchAccount(id);
  accounts.push(account);
}

With batching:

// 1 API call
// Takes ~300ms
// Uses 1 of your rate limit quota
const accounts = await fetchAccounts(accountIds);

The difference becomes huge when you're dealing with hundreds or thousands of resources.

How to use batch requests

Just provide comma-separated IDs in your request:

curl "https://api-v3.sprinklr.com/api/v3/account?accountId=600057112,600057113,600057114" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Key: YOUR_API_KEY"

Response:

{
  "success": true,
  "data": [
    {
      "id": "600057112",
      "accountType": "TWITTER",
      "accountDisplayName": "@YourBrand",
      "followerCount": 15420
    },
    {
      "id": "600057113",
      "accountType": "FACEBOOK",
      "accountDisplayName": "Your Brand",
      "followerCount": 28500
    },
    {
      "id": "600057114",
      "accountType": "INSTAGRAM",
      "accountDisplayName": "@yourbrand",
      "followerCount": 42300
    }
  ]
}

Handling partial failures

What happens if some IDs exist but others don't? The API returns what it can and tells you about the failures:

Request:

GET /api/v3/account?accountId=600057112,999999999,600057114

Response:

{
  "success": false,
  "data": [
    {
      "id": "600057112",
      "accountDisplayName": "@YourBrand"
    },
    {
      "id": "600057114",
      "accountDisplayName": "@yourbrand"
    }
  ],
  "errors": [
    {
      "code": "NOT_FOUND",
      "message": "Account with ID 999999999 not found",
      "field": "accountId"
    }
  ]
}

Notice:

  • success is false because the request partially failed
  • data contains the accounts that were found
  • errors lists what went wrong

Here's how to handle this in code:

async function getAccountsWithErrorHandling(accountIds) {
  const response = await fetchAccounts(accountIds);

  // Track which ones succeeded
  const foundAccounts = response.data || [];
  console.log(`Found ${foundAccounts.length} accounts`);

  // Track which ones failed
  if (response.errors && response.errors.length > 0) {
    console.log(`${response.errors.length} accounts not found:`);
    response.errors.forEach(error => {
      console.log(`  - ${error.message}`);
    });
  }

  return foundAccounts;
}

Batch size limits

You can request up to 50 resources in a single batch:

# ✅ Valid - 50 IDs
GET /api/v3/account?accountId=1,2,3,...,50

# ❌ Invalid - 51 IDs (will return an error)
GET /api/v3/account?accountId=1,2,3,...,51

If you need more than 50, break your request into multiple batches:

function chunkArray(array, size) {
  const chunks = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
}

async function getAllAccounts(accountIds) {
  const chunks = chunkArray(accountIds, 50);
  const results = [];

  for (const chunk of chunks) {
    const response = await fetchAccounts(chunk);
    if (response.data) {
      results.push(...response.data);
    }
  }

  return results;
}

// Fetch 237 accounts in 5 batches (50+50+50+50+37)
const accounts = await getAllAccounts(array237Ids);

Searching and filtering

For more complex queries, you'll use search endpoints that accept POST requests with JSON filter criteria.

Simple filters

Let's find all open customer service cases with high priority:

curl -X POST "https://api-v3.sprinklr.com/api/v3/case/search" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": ["OPEN"],
    "priority": ["HIGH"],
    "page": 0,
    "size": 20,
    "sort": "createdTime,desc"
  }'

This returns the 20 most recent high-priority open cases.

Date range filters

Many searches support date ranges:

curl -X POST "https://api-v3.sprinklr.com/api/v3/message/search" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "startTime": "2026-02-01T00:00:00Z",
    "endTime": "2026-02-11T23:59:59Z",
    "accountIds": ["600057112"],
    "messageTypes": ["TWITTER_POST", "TWITTER_REPLY"]
  }'

Important: Dates must be in ISO 8601 format with UTC timezone:

  • ✅ 2026-02-11T14:30:00Z
  • ❌ 2026-02-11 (missing time)
  • ❌ 02/11/2026 (wrong format)
  • ❌ 2026-02-11 14:30:00 (missing timezone)

Combining multiple filters

You can combine filters to narrow your search:

{
  "startTime": "2026-02-01T00:00:00Z",
  "endTime": "2026-02-11T23:59:59Z",
  "accountIds": ["600057112", "600057113"],
  "messageTypes": ["TWITTER_POST"],
  "sentiment": ["NEGATIVE"],
  "hasMedia": true,
  "minEngagement": 100,
  "page": 0,
  "size": 50,
  "sort": "engagementScore,desc"
}

This finds negative sentiment posts with media and at least 100 engagements, sorted by engagement score.

Understanding AND vs OR logic

Most filters use AND logic by default:

{
  "status": ["OPEN"],
  "priority": ["HIGH"]
}

This means: status = OPEN AND priority = HIGH

When you provide multiple values for a single filter, it's usually OR logic:

{
  "status": ["OPEN", "PENDING"]
}

This means: status = OPEN OR status = PENDING

Check the API reference for each endpoint to understand its specific filter behavior.

Sorting results

Most list and search endpoints support sorting with the sort parameter:

# Sort by creation time, newest first
sort=createdTime,desc

# Sort by creation time, oldest first
sort=createdTime,asc

# Sort by name alphabetically
sort=name,asc

The format is: fieldName,direction

  • asc = ascending (A→Z, 0→9, oldest→newest)
  • desc = descending (Z→A, 9→0, newest→oldest)

Multiple sort fields

Some endpoints support sorting by multiple fields:

# Sort by priority first, then by creation time
sort=priority,desc&sort=createdTime,desc

This means: sort by priority (urgent first), and within each priority level, sort by creation time (newest first).

Working with timestamps

The Sprinklr API uses ISO 8601 format with UTC timezone for all timestamps.

Reading timestamps

Timestamps in responses look like this:

{
  "createdTime": "2026-02-11T14:30:00Z",
  "modifiedTime": "2026-02-11T15:45:00Z"
}

The Z at the end means UTC (Coordinated Universal Time). All times from the API are in UTC, regardless of your local timezone.

Sending timestamps

When you send timestamps in requests, use the same format:

// ✅ Correct
{
  "startTime": "2026-02-01T00:00:00Z",
  "endTime": "2026-02-11T23:59:59Z"
}

// ❌ Wrong - missing time
{
  "startTime": "2026-02-01"
}

// ❌ Wrong - missing timezone
{
  "startTime": "2026-02-01T00:00:00"
}

Converting from your local timezone

Always convert your local times to UTC before sending them to the API:

// JavaScript example
const localDate = new Date('2026-02-11 14:30:00'); // Your local time
const utcString = localDate.toISOString(); // "2026-02-11T14:30:00.000Z"

// Python example
from datetime import datetime, timezone

local_time = datetime(2026, 2, 11, 14, 30, 0)
utc_time = local_time.astimezone(timezone.utc)
utc_string = utc_time.isoformat().replace('+00:00', 'Z')

Converting to your local timezone

When displaying times to users, convert from UTC to their local timezone:

// JavaScript example
const utcString = "2026-02-11T14:30:00Z";
const localDate = new Date(utcString);
const localString = localDate.toLocaleString(); // Displays in user's timezone

Pagination: Handling large datasets

When you're working with endpoints that return lots of results (like searching messages or cases), the API breaks the results into pages.

How pagination works

curl -X POST "https://api-v3.sprinklr.com/api/v3/case/search" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": ["OPEN"],
    "page": 0,
    "size": 20,
    "sort": "createdTime,desc"
  }'

Response:

{
  "success": true,
  "data": [
    {...}, {...}, ... // 20 cases
  ],
  "pagination": {
    "page": 0,
    "size": 20,
    "totalElements": 847,
    "totalPages": 43,
    "hasNext": true,
    "hasPrevious": false,
    "first": true,
    "last": false
  }
}

The pagination object tells you:

  • page: Which page you're on (0-indexed, so 0 is the first page)
  • size: How many items per page
  • totalElements: Total number of matching items across all pages
  • totalPages: Total number of pages
  • hasNext: Whether there are more pages after this one
  • hasPrevious: Whether there are pages before this one
  • first: Whether this is the first page
  • last: Whether this is the last page

Fetching the next page

To get the next page, just increment the page parameter:

{
  "status": ["OPEN"],
  "page": 1,    // ← Changed from 0 to 1
  "size": 20,
  "sort": "createdTime,desc"
}

Iterating through all pages

Here's how to fetch all results across multiple pages:

async function getAllCases(filters) {
  const allCases = [];
  let page = 0;
  let hasMore = true;

  while (hasMore) {
    const response = await searchCases({
      ...filters,
      page,
      size: 50
    });

    if (response.success && response.data) {
      allCases.push(...response.data);
    }

    hasMore = response.pagination?.hasNext || false;
    page++;

    // Optional: Add a small delay to avoid rate limits
    if (hasMore) {
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }

  return allCases;
}

// Usage
const cases = await getAllCases({ status: ["OPEN", "PENDING"] });
console.log(`Found ${cases.length} total cases`);

Choosing page sizes

The API supports page sizes from 1 to 100. Here's how to choose:

Page sizeBest forProsCons
20-30Real-time UIFast responses, responsiveMore API calls needed
50-75Background processingBalancedMiddle ground
100Bulk exportsFewest API callsSlower responses, more memory

General guideline: Start with 50 items per page and adjust based on your needs.

Common parameters

Most endpoints support these standard parameters:

page

  • Type: Integer
  • Default: 0
  • Range: 0 to totalPages-1
  • Description: Which page of results to return (0-indexed)
page=0  # First page
page=1  # Second page

size

  • Type: Integer
  • Default: 20
  • Range: 1 to 100
  • Description: How many items per page
size=20   # 20 items per page
size=50   # 50 items per page
size=100  # Maximum allowed

sort

  • Type: String
  • Format: fieldName,direction
  • Description: How to sort results
sort=createdTime,desc     # Newest first
sort=name,asc             # Alphabetically
sort=priority,desc        # Highest priority first

Data types and formats

Understanding the data types used in the API helps you construct valid requests and interpret responses correctly.

String

Plain text values:

{
  "accountDisplayName": "@YourBrand",
  "subject": "Customer inquiry",
  "notes": "This is a text field"
}

Integer

Whole numbers (no decimals):

{
  "followerCount": 15420,
  "priority": 3,
  "retweetCount": 234
}

Boolean

True or false values:

{
  "verified": true,
  "hasMedia": false,
  "isPublic": true
}

Array

Lists of values:

{
  "accountIds": ["600057112", "600057113"],
  "tags": ["urgent", "vip", "escalated"],
  "messageTypes": ["TWITTER_POST", "TWITTER_REPLY"]
}

Object

Nested structures:

{
  "customerProfile": {
    "name": "John Customer",
    "email": "john@example.com",
    "vipStatus": true
  },
  "engagementMetrics": {
    "likes": 234,
    "shares": 45,
    "comments": 12
  }
}

Null

Explicitly absent values:

{
  "assignedTo": null,
  "resolvedTime": null,
  "parentCaseId": null
}

Limits and constraints

The API has several limits to ensure reliability and fair usage:

Batch size limit: 50 resources

You can request up to 50 resources at once in batch operations:

# ✅ Valid
GET /api/v3/account?accountId=1,2,3,...,50

# ❌ Invalid - will return error
GET /api/v3/account?accountId=1,2,3,...,51

Page size limit: 100 items

Paginated endpoints return at most 100 items per page:

{
  "page": 0,
  "size": 100  // Maximum
}

If you specify size: 150, the API will either return an error or silently cap it at 100 (check the specific endpoint documentation).

Request timeout: 30 seconds

API requests that take longer than 30 seconds will timeout. If you're hitting timeouts:

  • Add more specific filters to your search
  • Reduce your page size
  • Break large batch requests into smaller ones

Rate limits

API calls are rate-limited based on your Sprinklr plan. See the Rate Limiting guide for details.

Best practices for production

1. Always handle errors

Don't assume requests will succeed. Always check the success field and handle errors:

async function getAccountSafely(accountId) {
  try {
    const response = await fetchAccount(accountId);

    if (response.success) {
      return response.data;
    } else {
      // Handle API-level errors
      console.error('API Error:', response.errors);
      throw new Error(response.errors[0]?.message || 'Unknown error');
    }
  } catch (error) {
    // Handle network errors, timeouts, etc.
    console.error('Request failed:', error);
    throw error;
  }
}

2. Use batch operations aggressively

Whenever you need multiple resources, batch them:

// ❌ Bad - 10 API calls
const accounts = [];
for (const id of accountIds) {
  accounts.push(await getAccount(id));
}

// ✅ Good - 1 API call
const accounts = await getAccounts(accountIds);

3. Implement exponential backoff

When requests fail (especially rate limits), don't immediately retry. Use exponential backoff:

async function fetchWithRetry(fetchFunction, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fetchFunction();
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      // Wait 2^i seconds before retrying (1s, 2s, 4s, 8s...)
      const waitTime = Math.pow(2, i) * 1000;
      console.log(`Retry ${i + 1}/${maxRetries} after ${waitTime}ms`);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }
  }
}

4. Cache rarely-changing data

Some data doesn't change often. Cache it to reduce API calls:

class AccountCache {
  constructor() {
    this.cache = new Map();
    this.ttl = 60 * 60 * 1000; // 1 hour
  }

  async getAccount(accountId) {
    const cached = this.cache.get(accountId);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }

    const account = await fetchAccount(accountId);
    this.cache.set(accountId, {
      data: account,
      timestamp: Date.now()
    });

    return account;
  }
}

5. Log for debugging

Log your API calls to help with debugging:

async function fetchWithLogging(url, options) {
  const startTime = Date.now();

  console.log(`→ ${options.method || 'GET'} ${url}`);

  try {
    const response = await fetch(url, options);
    const duration = Date.now() - startTime;
    const data = await response.json();

    console.log(`← ${response.status} in ${duration}ms`);

    return data;
  } catch (error) {
    const duration = Date.now() - startTime;
    console.error(`✗ Failed after ${duration}ms:`, error.message);
    throw error;
  }
}

6. Validate input before sending

Check your data before making API calls:

function validateCaseSearch(filters) {
  // Check date range
  if (filters.startTime && filters.endTime) {
    const start = new Date(filters.startTime);
    const end = new Date(filters.endTime);

    if (start > end) {
      throw new Error('startTime must be before endTime');
    }

    // Warn if range is very large
    const daysDiff = (end - start) / (1000 * 60 * 60 * 24);
    if (daysDiff > 90) {
      console.warn('Date range spans more than 90 days - this might be slow');
    }
  }

  // Check page size
  if (filters.size && (filters.size < 1 || filters.size > 100)) {
    throw new Error('Page size must be between 1 and 100');
  }

  return true;
}

Next steps

Now that you understand API basics, you're ready to:

  1. Handle errors properly - Learn about all error codes and how to fix them
  2. Understand rate limiting - Optimize your API usage
  3. Master pagination - Handle large datasets efficiently
  4. Explore specific APIs - Dive into accounts, messages, cases, and more

The patterns in this guide apply to all Sprinklr API endpoints. Once you master these basics, working with any endpoint becomes straightforward.