Skip to content
Last updated

Error Handling

When things go wrong with your API requests (and they will), the Sprinklr API gives you detailed information about what happened and how to fix it. This guide shows you how to handle errors gracefully and build resilient integrations.

Why error handling matters

No integration is perfect. Networks fail, credentials expire, users request resources that don't exist, and rate limits get hit. The difference between a good integration and a great one is how it handles these situations.

Bad error handling:

  • Your application crashes
  • Users see cryptic error messages
  • You have no idea what went wrong
  • The same error keeps happening

Good error handling:

  • Your application stays running
  • Users get helpful messages
  • Errors are logged for debugging
  • Your code automatically recovers when possible

Let's build good error handling.

How Sprinklr API errors work

Every error response from the Sprinklr API follows the same structure, making it easy to handle errors consistently across your application.

Error response anatomy

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

Let's break this down:

success: false This tells you immediately that something went wrong. Check this field before trying to access data.

errors array Contains one or more error objects. You might get multiple errors if several things went wrong (e.g., multiple invalid parameters).

code A machine-readable error code you can programmatically handle. Always the same for a given error type.

message A human-readable explanation of what went wrong. Good for logging and debugging.

field (optional) When an error relates to a specific request parameter, this tells you which one. Useful for validation errors.

HTTP status codes

The API also uses standard HTTP status codes to categorize errors:

StatusNameWhat it meansYour action
200OKRequest succeededProcess the data
201CreatedResource createdProcess the new resource
400Bad RequestInvalid parametersFix your request
401UnauthorizedAuthentication failedCheck credentials
403ForbiddenNo permissionCheck access rights
404Not FoundResource doesn't existVerify the ID
429Too Many RequestsRate limitedSlow down, retry later
500Server ErrorSprinklr errorRetry after delay
503Service UnavailableTemporary outageRetry with backoff

Common errors and how to fix them

INVALID_PARAMETER - You sent bad data

This happens when a parameter is missing, malformed, or invalid.

Example:

{
  "success": false,
  "errors": [
    {
      "code": "INVALID_PARAMETER",
      "message": "accountId must be a valid Sprinklr account ID",
      "field": "accountId"
    }
  ]
}

Common causes:

  1. Typo in parameter name

    // ❌ Wrong
    { accoundId: "600057112" }  // Typo: "accound"
    
    // ✅ Correct
    { accountId: "600057112" }
  2. Wrong data type

    // ❌ Wrong
    { accountId: 600057112 }  // Number instead of string
    
    // ✅ Correct
    { accountId: "600057112" }  // String
  3. Invalid format

    // ❌ Wrong
    { startTime: "2026-02-11" }  // Missing time and timezone
    
    // ✅ Correct
    { startTime: "2026-02-11T00:00:00Z" }  // Full ISO 8601
  4. Missing required parameter

    // ❌ Wrong - missing accountId
    GET /api/v3/account
    
    // ✅ Correct
    GET /api/v3/account?accountId=600057112

How to fix it:

  1. Check the error's field property to see which parameter is wrong
  2. Verify the parameter name spelling
  3. Check the API reference for the correct data type and format
  4. Validate your data before sending the request

NOT_FOUND - The resource doesn't exist

The ID you requested doesn't exist or you don't have access to it.

Example:

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

Common causes:

  1. Wrong ID

    • Copy-paste error
    • ID from a different environment (dev vs production)
    • Old ID from a deleted resource
  2. Resource was deleted

    • The account was removed from Sprinklr
    • The case was archived
    • The message was deleted
  3. No access to the resource

    • It belongs to a different Sprinklr instance
    • Your credentials don't have permission
    • It's in a workspace you can't access

How to fix it:

  1. Double-check the ID is correct
  2. Verify the resource exists in your Sprinklr dashboard
  3. Check you're using the right environment (QA vs Production)
  4. Confirm your credentials have access to this resource

Handling NOT_FOUND gracefully:

async function getAccountSafely(accountId) {
  try {
    const response = await getAccount(accountId);
    return response.data;
  } catch (error) {
    if (error.code === 'NOT_FOUND') {
      console.log(`Account ${accountId} doesn't exist or was deleted`);
      return null;  // Return null instead of crashing
    }
    throw error;  // Re-throw other errors
  }
}

UNAUTHORIZED - Authentication failed

Your credentials are missing, expired, or invalid.

Example:

{
  "success": false,
  "errors": [
    {
      "code": "UNAUTHORIZED",
      "message": "Invalid or missing authentication token"
    }
  ]
}

Common causes:

  1. Forgot to include credentials

    # ❌ Missing headers
    curl "https://api-v3.sprinklr.com/api/v3/account?accountId=123"
    
    # ✅ Correct
    curl "https://api-v3.sprinklr.com/api/v3/account?accountId=123" \
      -H "Authorization: Bearer YOUR_TOKEN" \
      -H "Key: YOUR_API_KEY"
  2. Typo in credentials

    • Extra space in the token
    • Missing Bearer prefix
    • Copied partial token
  3. Expired token

    • Access tokens can expire
    • Generate a new one in Sprinklr settings
  4. Token was revoked

    • Someone regenerated the token
    • Admin revoked your access

How to fix it:

  1. Verify both Authorization and Key headers are present
  2. Check for typos (especially spaces or line breaks)
  3. Ensure the Bearer prefix is there: Bearer YOUR_TOKEN
  4. Try generating a new access token
  5. Test with a simple request to isolate the issue

Prevention:

// Store credentials in environment variables
const ACCESS_TOKEN = process.env.SPRINKLR_ACCESS_TOKEN;
const API_KEY = process.env.SPRINKLR_API_KEY;

// Validate before making requests
if (!ACCESS_TOKEN || !API_KEY) {
  throw new Error('Missing Sprinklr credentials');
}

FORBIDDEN - Permission denied

Your credentials are valid, but you don't have permission for this operation.

Example:

{
  "success": false,
  "errors": [
    {
      "code": "FORBIDDEN",
      "message": "You do not have permission to access this resource"
    }
  ]
}

Common causes:

  1. Accessing another account's data

    • The account ID belongs to a different Sprinklr instance
    • You're trying to access a competitor's data (obviously won't work!)
  2. Missing permissions

    • Your Sprinklr user lacks the required role
    • The endpoint requires Admin access
    • Your API credentials have restricted scope
  3. Environment mismatch

    • Using production credentials against QA
    • Using QA credentials against production

How to fix it:

  1. Verify the resource belongs to your Sprinklr instance
  2. Contact your Sprinklr admin to check your permissions
  3. Confirm you're using credentials from the right environment
  4. Check if the endpoint requires special permissions

The difference between 401 and 403:

  • 401 UNAUTHORIZED: "I don't know who you are" (authentication problem)
  • 403 FORBIDDEN: "I know who you are, but you can't do that" (authorization problem)

RATE_LIMIT_EXCEEDED - Too many requests

You've made too many API calls in a short time period.

Example:

{
  "success": false,
  "errors": [
    {
      "code": "RATE_LIMIT_EXCEEDED",
      "message": "You have exceeded the rate limit. Please try again in 60 seconds."
    }
  ]
}

Why rate limits exist: Rate limits ensure fair usage and protect the API infrastructure. Without them, one misbehaving integration could slow down the API for everyone.

What to do when rate limited:

  1. Stop making requests immediately Don't keep retrying - you'll just stay rate limited longer

  2. Check the Retry-After header The response includes a Retry-After header telling you how long to wait

  3. Implement exponential backoff Wait progressively longer between retries

  4. Optimize your integration

    • Use batch endpoints (50 resources at once)
    • Cache frequently accessed data
    • Reduce polling frequency

Handling rate limits properly:

async function fetchWithRateLimit(fetchFunction) {
  const maxRetries = 3;
  let retries = 0;

  while (retries < maxRetries) {
    try {
      return await fetchFunction();
    } catch (error) {
      if (error.code === 'RATE_LIMIT_EXCEEDED') {
        retries++;

        if (retries >= maxRetries) {
          throw new Error('Rate limit exceeded after max retries');
        }

        // Exponential backoff: 2^retry seconds
        const waitTime = Math.pow(2, retries) * 1000;
        console.log(`Rate limited. Waiting ${waitTime}ms before retry ${retries}/${maxRetries}`);

        await new Promise(resolve => setTimeout(resolve, waitTime));
      } else {
        throw error;  // Not a rate limit error, re-throw
      }
    }
  }
}

// Usage
const account = await fetchWithRateLimit(() => getAccount('600057112'));

See the Rate Limiting guide for more strategies.

VALIDATION_ERROR - Data validation failed

The data you sent doesn't meet the API's requirements.

Example:

{
  "success": false,
  "errors": [
    {
      "code": "VALIDATION_ERROR",
      "message": "Subject must be between 1 and 500 characters",
      "field": "subject"
    }
  ]
}

Common validation errors:

  1. String too long

    // ❌ Subject is 600 characters
    { subject: "A".repeat(600) }
    
    // ✅ Within 500 character limit
    { subject: "Customer inquiry about pricing" }
  2. Invalid email format

    // ❌ Invalid email
    { email: "not-an-email" }
    
    // ✅ Valid email
    { email: "customer@example.com" }
  3. Required field missing

    // ❌ Missing required fields
    { priority: "HIGH" }
    
    // ✅ All required fields present
    { subject: "Issue", priority: "HIGH", customerId: "123" }

How to prevent validation errors:

function validateCaseData(data) {
  const errors = [];

  if (!data.subject || data.subject.length === 0) {
    errors.push('Subject is required');
  }

  if (data.subject && data.subject.length > 500) {
    errors.push('Subject must be 500 characters or less');
  }

  if (!['LOW', 'MEDIUM', 'HIGH', 'URGENT'].includes(data.priority)) {
    errors.push('Priority must be LOW, MEDIUM, HIGH, or URGENT');
  }

  if (errors.length > 0) {
    throw new Error(`Validation failed: ${errors.join(', ')}`);
  }

  return true;
}

// Use before making API call
validateCaseData(caseData);
const result = await createCase(caseData);

SERVER_ERROR - Something went wrong on Sprinklr's side

The API encountered an internal error. This is rare but does happen.

Example:

{
  "success": false,
  "errors": [
    {
      "code": "SERVER_ERROR",
      "message": "An internal server error occurred. Please try again later."
    }
  ]
}

What to do:

  1. Don't panic - This isn't your fault
  2. Retry the request - It might succeed the second time
  3. Use exponential backoff - Don't hammer the API
  4. Log the error - Include the timestamp and request details
  5. Contact support - If it persists, report it with your logs

Handling server errors:

async function fetchWithRetry(fetchFunction, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fetchFunction();
    } catch (error) {
      const isServerError = error.status >= 500;
      const isLastRetry = i === maxRetries - 1;

      if (isServerError && !isLastRetry) {
        const waitTime = Math.pow(2, i) * 1000;
        console.log(`Server error. Retrying in ${waitTime}ms...`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
      } else {
        throw error;
      }
    }
  }
}

Building robust error handling

Here's a complete example of production-ready error handling:

Comprehensive error handler

class SprinklrError extends Error {
  constructor(code, message, statusCode, field = null) {
    super(message);
    this.name = 'SprinklrError';
    this.code = code;
    this.statusCode = statusCode;
    this.field = field;
  }
}

async function callSprinklrAPI(fetchFunction) {
  try {
    const response = await fetchFunction();

    if (response.success) {
      return response.data;
    } else {
      // API returned errors
      const error = response.errors[0];
      throw new SprinklrError(
        error.code,
        error.message,
        response.status,
        error.field
      );
    }
  } catch (error) {
    // Network error or HTTP error
    if (error instanceof SprinklrError) {
      throw error;  // Already a Sprinklr error
    }

    // Handle HTTP errors
    if (error.response) {
      const { status, data } = error.response;
      const apiError = data.errors?.[0] || {};

      throw new SprinklrError(
        apiError.code || 'UNKNOWN_ERROR',
        apiError.message || 'An error occurred',
        status,
        apiError.field
      );
    }

    // Network error (no response from server)
    throw new SprinklrError(
      'NETWORK_ERROR',
      'Failed to connect to Sprinklr API',
      0
    );
  }
}

// Usage with specific error handling
async function getAccountWithErrorHandling(accountId) {
  try {
    return await callSprinklrAPI(() => getAccount(accountId));
  } catch (error) {
    switch (error.code) {
      case 'NOT_FOUND':
        console.log(`Account ${accountId} not found`);
        return null;

      case 'UNAUTHORIZED':
        console.error('Authentication failed - check credentials');
        throw error;

      case 'RATE_LIMIT_EXCEEDED':
        console.log('Rate limited - waiting before retry');
        await new Promise(resolve => setTimeout(resolve, 5000));
        return getAccountWithErrorHandling(accountId);  // Retry

      case 'SERVER_ERROR':
        console.error('Server error - will retry');
        await new Promise(resolve => setTimeout(resolve, 2000));
        return getAccountWithErrorHandling(accountId);  // Retry

      default:
        console.error(`Unexpected error: ${error.code} - ${error.message}`);
        throw error;
    }
  }
}

Error handling best practices

1. Always check the success field

// ❌ Don't assume success
const accounts = response.data;

// ✅ Check first
if (response.success) {
  const accounts = response.data;
} else {
  console.error('Request failed:', response.errors);
}

2. Log errors with context

console.error('API Error:', {
  code: error.code,
  message: error.message,
  endpoint: '/api/v3/account',
  accountId: '600057112',
  timestamp: new Date().toISOString()
});

3. Don't expose raw errors to users

// ❌ Don't do this
alert(error.message);  // Shows technical details to user

// ✅ Do this
console.error('API Error:', error);
alert('Unable to load account. Please try again.');

4. Implement circuit breakers

class CircuitBreaker {
  constructor(threshold = 5, timeout = 60000) {
    this.failureCount = 0;
    this.threshold = threshold;
    this.timeout = timeout;
    this.state = 'CLOSED';  // CLOSED, OPEN, HALF_OPEN
    this.nextAttempt = Date.now();
  }

  async call(fn) {
    if (this.state === 'OPEN') {
      if (Date.now() < this.nextAttempt) {
        throw new Error('Circuit breaker is OPEN');
      }
      this.state = 'HALF_OPEN';
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  onSuccess() {
    this.failureCount = 0;
    this.state = 'CLOSED';
  }

  onFailure() {
    this.failureCount++;
    if (this.failureCount >= this.threshold) {
      this.state = 'OPEN';
      this.nextAttempt = Date.now() + this.timeout;
    }
  }
}

// Usage
const breaker = new CircuitBreaker();
const account = await breaker.call(() => getAccount('600057112'));

5. Monitor and alert on errors

const errorCounts = new Map();

function trackError(error) {
  const key = error.code;
  errorCounts.set(key, (errorCounts.get(key) || 0) + 1);

  // Alert if too many errors
  if (errorCounts.get('RATE_LIMIT_EXCEEDED') > 10) {
    sendAlert('Too many rate limit errors - check integration');
  }

  if (errorCounts.get('UNAUTHORIZED') > 3) {
    sendAlert('Authentication failing - credentials may be expired');
  }
}

Testing your error handling

Don't wait for production to find out your error handling doesn't work. Test it during development:

Simulate errors

// Create a mock API that returns errors
function mockSprinklrAPI(scenario) {
  const scenarios = {
    NOT_FOUND: {
      success: false,
      errors: [{
        code: 'NOT_FOUND',
        message: 'Account not found'
      }]
    },
    RATE_LIMITED: {
      success: false,
      errors: [{
        code: 'RATE_LIMIT_EXCEEDED',
        message: 'Rate limit exceeded'
      }]
    },
    UNAUTHORIZED: {
      success: false,
      errors: [{
        code: 'UNAUTHORIZED',
        message: 'Invalid token'
      }]
    }
  };

  return Promise.resolve(scenarios[scenario]);
}

// Test your error handling
async function testErrorHandling() {
  console.log('Testing NOT_FOUND handling...');
  try {
    await handleResponse(await mockSprinklrAPI('NOT_FOUND'));
  } catch (error) {
    console.log('✓ NOT_FOUND handled correctly');
  }

  console.log('Testing RATE_LIMITED handling...');
  try {
    await handleResponse(await mockSprinklrAPI('RATE_LIMITED'));
  } catch (error) {
    console.log('✓ RATE_LIMITED handled correctly');
  }
}

Quick reference: All error codes

CodeHTTPCauseSolution
INVALID_PARAMETER400Bad parameterCheck format and type
VALIDATION_ERROR400Data validation failedFix data values
UNAUTHORIZED401Auth failedCheck credentials
FORBIDDEN403No permissionCheck access rights
NOT_FOUND404Resource missingVerify ID exists
RATE_LIMIT_EXCEEDED429Too many requestsImplement backoff
SERVER_ERROR500Sprinklr errorRetry with delay
SERVICE_UNAVAILABLE503Temporary outageRetry with backoff

Next steps

Now that you understand error handling:

  1. Learn about rate limiting - Avoid rate limit errors
  2. Follow best practices - Build resilient integrations
  3. Get support - Get help when you're stuck

Getting help

If you're encountering errors you can't resolve:

  • Support & FAQ - Common issues and solutions
  • Email support - api-support@sprinklr.com with error logs
  • Include details - Error code, full error message, request details, timestamp

Remember: Good error handling is what separates hobby projects from production-ready integrations. Take the time to handle errors properly, and your future self will thank you.