Skip to content

Suppression List API V3

The Suppression List API lets you manage the phone numbers that must not be contacted by your outbound voice campaigns. Use it to add a number the moment a customer opts out, synchronise a do-not-call registry in bulk, and remove a number when consent is regained.

V2 reference: Add Contact in Suppression List · Bulk Add Contacts in Suppression List · Remove Contact from Suppression List


Overview

A suppression list is a list of phone numbers that must not be contacted by outbound campaigns. It typically holds numbers of people who have asked to be placed on a "do not call" list, who have asked to be removed from a calling list, or who are ineligible for certain types of calls for regulatory or compliance reasons.

Maintaining an accurate suppression list is a compliance requirement, not a convenience. Use this API when suppression decisions originate in your own systems — a CRM opt-out flow, a DNC-registry sync, a consent-management platform, or any service that must suppress a number promptly after a customer requests it.

Suppression lists can also be managed directly in the Sprinklr UI under Voice Care → Voice Settings → Suppression List. Both paths act on the same underlying list.

Suppression is time-bounded

Suppression is not permanent by default. A suppressed number will not receive calls until its expiry time, after which it becomes contactable again. Two fields on the create payload express this:

FieldMeaning
expiryTimeAbsolute expiry instant, in epoch milliseconds
expiryIntervalTypeExpiry interval type

Set these deliberately. If a customer has made a permanent do-not-call request, confirm with your Sprinklr account team how your tenant expresses indefinite suppression before relying on a default.

The four operations

OperationMethodPath
Add a single contactPOST/api/v3/suppressionList/contact
Bulk add contacts (asynchronous)POST/api/v3/suppressionList/contact/bulk
Remove a contactDELETE/api/v3/suppressionList/contact
Poll bulk job statusGET/api/v3/suppressionList/bulk/status

Add and remove share a single path and are distinguished by HTTP method.

Reading suppression state

The API provides write and job-status operations. It does not provide an endpoint to list suppression lists, enumerate the contacts on a list, or check whether an individual number is currently suppressed.

Plan for this in your integration:

  • Obtain your suppressionListId from the Sprinklr UI — see Find your suppression list ID.
  • Keep your own authoritative record of every number you have suppressed and removed, along with the API response for each call.
  • Base reconciliation on your own records rather than on a query against Sprinklr.

Base URL and environments

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

Replace {env} with the environment hosting your Sprinklr tenant:

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

If you are unsure which environment applies, see the APIs page or ask your Sprinklr account team. Calling the wrong environment authenticates against a different tenant and the request will fail.


Authentication

Every request requires both credentials:

HeaderValue
AuthorizationBearer {{accessToken}}
Key{{apiKey}}

Requests that send a body also require:

HeaderValue
Content-Typeapplication/json

Credential lifetimes

CredentialLifetime
Authorization code10 minutes
API keyNo expiry
Access token30 days

Only one token pair per API key is valid at a time. Generating a new token pair invalidates the previous one — a common cause of a scheduled job that starts returning 401 without any change on your side.

For setup, see API Key and Secret Generation and Authorize.

Permissions

Authentication and authorization are checked separately. A valid token whose associated user lacks rights to modify the target suppression list returns 403, not 401. Confirm that the user behind your API credentials has suppression-list permissions in Sprinklr.

Credential hygiene. Treat your access token and API key as secrets. Do not commit them to source control, do not write them to logs, and do not paste them into support requests or chat messages. Rotate immediately if a credential is exposed.


Operations

Add a contact

POST /api/v3/suppressionList/contact

Adds a single phone number to a suppression list. Send all fields in the JSON body, including suppressionListId.

Request bodySuppressionListContactCreateRequestDTO (required)
Success200
Errors400, 401, 403, 404

Send suppressionListId and contactValue on every request. The response returns the contact as stored.

Bulk add contacts

POST /api/v3/suppressionList/contact/bulk

Adds many contacts in one call. This operation is asynchronous by default: a 200 confirms that the job was accepted, not that every contact was suppressed.

Request bodyBulkSuppressionListContactRequestDTO (required)
Success200
Errors400, 401, 403, 404

To learn the outcome, choose one of three approaches:

ApproachHowBest for
PollTake the process id from the response, then call the bulk status endpointBatch jobs where you control the schedule
CallbackSupply callbackUrl and let Sprinklr notify you on completionLarge jobs, event-driven pipelines
SynchronousSet syncProcessing: true and read per-record results from the responseSmall batches where a caller is waiting

Choosing synchronous or asynchronous

The syncProcessing flag determines the shape of your integration:

syncProcessingBehaviourWhat you need
false or omittedThe job is queued and processed in the backgroundA process id, plus polling or a callback
trueRecords are processed during the request and per-record results are returned immediatelyNothing further — read the response

Use syncProcessing: true for small, interactive batches where the caller needs to know at once which records failed. Use the asynchronous default for large batches and scheduled synchronisations, where holding an HTTP connection open is a liability.

Keep synchronous batches small. Confirm a safe batch size with your Sprinklr account team before relying on synchronous processing for a large volume.

Poll bulk job status

GET /api/v3/suppressionList/bulk/status?processId={processId}

Returns the status of a bulk job submitted asynchronously.

ParameterInTypeDescription
processIdquerystringBulk process id returned by the bulk add call
Success200
Errors400, 401, 403, 404

Always supply processId. Poll with a widening backoff — start at a few seconds and increase — rather than in a tight loop.

Remove a contact

DELETE /api/v3/suppressionList/contact?suppressionListId={id}&contactValue={phoneNumber}

Removes a phone number from a suppression list, making it contactable again.

ParameterInTypeDescription
suppressionListIdquerystringSuppression list id
contactValuequerystringPhone number to remove
Success200
Errors400, 401, 403, 404

Supply both parameters on every request.

Encode the leading + as %2B

contactValue is a phone number, and E.164 numbers begin with +. Inside a URL query string a literal + is decoded as a space, not a plus sign.

Sending ?contactValue=+14155550142 transmits " 14155550142" — a space followed by digits — which will not match the stored contact.

Percent-encode the plus sign:

?contactValue=%2B14155550142

Use your HTTP library's URL-encoding function rather than building the query string by concatenation. This is the most common error on this API.


Field reference

SuppressionListContactCreateRequestDTO

Request body for adding a contact to a suppression list.

FieldTypeDescription
contactValuestringThe phone number to suppress. Send on every request
suppressionListIdstringThe suppression list to add the contact to. Send on every request
namestringDisplay name for the contact
expiryTimeinteger (int64)Expiry time in epoch milliseconds
expiryIntervalTypestringExpiry interval type
idstringIdentifier of the stored contact. Returned by the service; do not send on create
createdTimeinteger (int64)Creation time in epoch milliseconds. Returned by the service; do not send on create

expiryTime is epoch milliseconds. A ten-digit value is seconds and will resolve to 1970 — multiply by 1000.

For the interval values your tenant accepts in expiryIntervalType, check with your Sprinklr account team.

BulkSuppressionListContactRequestDTO

Bulk suppression list contact request.

FieldTypeDescription
recordsarrayThe contacts to suppress. Each element carries the same fields as a single add request
syncProcessingbooleanWhen true, process records synchronously in-request and return per-record results immediately
callbackUrlstringHTTPS endpoint Sprinklr calls when an asynchronous job completes
callbackUrlHeadersobject (string → string)Optional HTTP headers sent with the callback request

Securing the callback

Use callbackUrlHeaders to authenticate the inbound call, so your receiver can verify the request came from Sprinklr:

"callbackUrl": "https://your-host.example.com/hooks/suppression-complete",
"callbackUrlHeaders": {
  "X-Webhook-Secret": "{{yourWebhookSecret}}"
}

Build the receiver defensively: accept and log the full body before parsing, and do not assume any individual field is present.


Worked examples

Examples use placeholder credentials and the prod2 environment. Identifiers and phone numbers are illustrative. Substitute your own values.

Add a single contact

curl -X POST \
  'https://api3.sprinklr.com/prod2/api/v3/suppressionList/contact' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Content-Type: application/json' \
  -d '{
    "suppressionListId": "0000000000000000000000a1",
    "contactValue": "+14155550142",
    "name": "Jane Doe — DNC request",
    "expiryTime": 1790000000000
  }'

A phone number inside a JSON body does not need percent-encoding. The %2B rule applies only to the DELETE query string.

Bulk add, asynchronous with a callback

curl -X POST \
  'https://api3.sprinklr.com/prod2/api/v3/suppressionList/contact/bulk' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Content-Type: application/json' \
  -d '{
    "syncProcessing": false,
    "callbackUrl": "https://your-host.example.com/hooks/suppression-complete",
    "callbackUrlHeaders": {
      "X-Webhook-Secret": "{{yourWebhookSecret}}"
    },
    "records": [
      {
        "suppressionListId": "0000000000000000000000a1",
        "contactValue": "+14155550142",
        "name": "Jane Doe — DNC request"
      },
      {
        "suppressionListId": "0000000000000000000000a1",
        "contactValue": "+14155550187",
        "name": "John Roe — opt-out"
      }
    ]
  }'

Capture the process id from the response and use it to poll for completion, or wait for the callback.

Bulk add, synchronous

curl -X POST \
  'https://api3.sprinklr.com/prod2/api/v3/suppressionList/contact/bulk' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Content-Type: application/json' \
  -d '{
    "syncProcessing": true,
    "records": [
      {
        "suppressionListId": "0000000000000000000000a1",
        "contactValue": "+14155550142"
      }
    ]
  }'

With syncProcessing: true the response carries per-record results directly. There is no process id and no polling.

Poll a bulk job

curl -X GET \
  'https://api3.sprinklr.com/prod2/api/v3/suppressionList/bulk/status?processId={{processId}}' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}'

Remove a contact

curl -X DELETE \
  'https://api3.sprinklr.com/prod2/api/v3/suppressionList/contact?suppressionListId=0000000000000000000000a1&contactValue=%2B14155550142' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}'

Note %2B in place of the leading +.

In Python, let the library handle encoding:

import requests

params = {
    "suppressionListId": "0000000000000000000000a1",
    "contactValue": "+14155550142",   # encoded correctly by requests
}

resp = requests.delete(
    "https://api3.sprinklr.com/prod2/api/v3/suppressionList/contact",
    params=params,
    headers={
        "Authorization": "Bearer {{accessToken}}",
        "Key": "{{apiKey}}",
    },
)

In JavaScript, use URLSearchParams:

const params = new URLSearchParams({
  suppressionListId: "0000000000000000000000a1",
  contactValue: "+14155550142",   // encoded correctly by URLSearchParams
});

await fetch(
  `https://api3.sprinklr.com/prod2/api/v3/suppressionList/contact?${params}`,
  {
    method: "DELETE",
    headers: {
      Authorization: "Bearer {{accessToken}}",
      Key: "{{apiKey}}",
    },
  }
);

Response format and status codes

Response envelope

Bulk add, bulk status, and remove return the standard V3 envelope:

{
  "data": { },
  "errors": [ ],
  "metadata": { }
}

Each entry in errors carries:

FieldType
idstring
codestring
messagestring

Check errors even when the status is 200. A bulk job can succeed at the transport level while individual records fail — the HTTP status will not tell you that.

Status codes

CodeMeaning
200Success
400Bad request — a required field or parameter is missing or malformed
401Unauthorized — missing, invalid, or expired credentials
403Forbidden — valid credentials without rights to modify this suppression list
404Not found — unknown suppression list, or wrong environment

Also handle 429 and 5xx with retry and exponential backoff, as you would for any Sprinklr API. See REST API Errors and Status Codes.

Troubleshooting

SymptomLikely causeFix
DELETE succeeds but the number is still suppressedThe leading + was sent literally and decoded as a spacePercent-encode as %2B
400 on DELETEcontactValue or suppressionListId missingSend both parameters
400 on addsuppressionListId or contactValue missing from the bodySend both fields
400 on bulk statusprocessId missing or unrecognisedUse the process id returned by the bulk add call
401 on a job that worked previouslyAccess token expired after 30 days, or a new token pair was generated against the same API keyRe-authorize; remember one token pair per key
403 with valid credentialsThe user lacks rights to modify this suppression listGrant suppression-list permissions in Sprinklr
404Unknown suppressionListId, or the wrong {env} in the base URLVerify the list ID in the UI and confirm your environment
A suppressed number is called anywayThe expiry time has passedSuppression is time-bounded; review expiryTime
Bulk returns 200 but nothing is suppressedThe job was accepted, then failed during processingPoll the bulk status endpoint or inspect the callback
Timestamps resolve to 1970expiryTime sent in secondsUse epoch milliseconds

Migrating from V2

Path mapping

V2V3
POST /api/v2/suppressionList/addContactPOST /api/v3/suppressionList/contact
POST /api/v2/suppressionList/addContactsPOST /api/v3/suppressionList/contact/bulk
POST /api/v2/suppressionList/removeContact/{suppressionListId}/{contactValue}DELETE /api/v3/suppressionList/contact?suppressionListId={id}&contactValue={value}
(new in V3)GET /api/v3/suppressionList/bulk/status?processId={id}

What changed

Verbs moved out of the path. /addContact becomes POST /contact, /addContacts becomes POST /contact/bulk, and /removeContact becomes DELETE /contact. The HTTP method now carries the verb, so one path serves both add and remove.

Identifiers moved to query parameters. V2's path-segment form /removeContact/{suppressionListId}/{contactValue} becomes DELETE /contact?suppressionListId={id}&contactValue={value}.

This is the change most likely to break existing code. In V2 the phone number was a path segment; in V3 it is a query parameter, where a literal + decodes to a space. Code that built the V2 URL by string concatenation will produce a silently incorrect request in V3 — the call returns success and the number stays suppressed. Switch to a proper URL encoder and verify that + becomes %2B.

Bulk add became a sub-resource. Plural /addContacts becomes /contact/bulk. The array of contacts is now wrapped in an object as the records field, alongside syncProcessing, callbackUrl, and callbackUrlHeaders, rather than being posted as a bare array.

Remove is now DELETE. V2 used POST /removeContact. V3 uses DELETE with query parameters, matching REST conventions. Confirm that your HTTP client handles a DELETE with no request body — some libraries treat this awkwardly.

Business behaviour is unchanged

V3 is an interface redesign. Adding and removing a contact produce the same outcome as the equivalent V2 calls.

Migration checklist

  • Change the remove call from POST to DELETE.
  • Move suppressionListId and contactValue from path segments to query parameters on the remove call.
  • Replace manual URL string-building with a URL encoder, and verify + becomes %2B.
  • Wrap the bulk array in { "records": [...] } instead of posting a bare array.
  • Decide syncProcessing per call site — true for small interactive batches, false for scheduled synchronisations.
  • For asynchronous bulk, implement polling or a callback receiver. Do not treat 200 as completion.
  • If you use a callback, set callbackUrlHeaders with a shared secret so you can authenticate the inbound call.
  • Confirm the accepted expiryIntervalType values for your tenant.
  • Update base URLs to https://api3.sprinklr.com/{env}/api/v3/....
  • Add the Key header alongside Authorization on every request.
  • Test the 403 path — permissions are checked separately from authentication.
  • Confirm expiryTime values are epoch milliseconds.
  • Keep your own record of suppressions, since V3 has no read endpoint to reconcile against.

Common tasks

Find your suppression list ID

There is no API to list suppression lists. Read the ID from the Sprinklr UI:

  1. Open Voice Care within the Sprinklr Service module.
  2. In the Voice Settings menu on the far left, select Suppression List.
  3. Click the three dots beside the suppression list you want to use.
  4. Select View from the drop-down menu.
  5. The suppression list ID is the ID appended in the page URL.

Store the ID in your configuration. It is stable, and every add and remove call needs it.

Suppress a number when a customer opts out

Call POST /suppressionList/contact from your opt-out handler with contactValue set to the customer's number. Because this write is compliance-critical, do not fire and forget: check the response, and queue a retry if the call fails.

Set expiryTime only when the opt-out is genuinely temporary.

Synchronise a do-not-call registry nightly

Use asynchronous bulk. Post the batch with syncProcessing: false and a callbackUrl, store the process id, and let the callback report completion. Poll the bulk status endpoint as a fallback if the callback has not arrived within your expected window.

Because there is no read endpoint, compute the nightly delta against your own record of what you last sent.

Call DELETE /suppressionList/contact with both query parameters, correctly encoded. Record the removal in your own system — you cannot query the list to confirm it later.


Best practices

Always URL-encode the phone number on DELETE. The leading + must become %2B. Use your library's encoder rather than string concatenation.

Send suppressionListId and contactValue on every call. Both are required in practice for add and remove.

Treat a bulk 200 as acceptance, not completion. Confirm the outcome by polling the status endpoint, handling the callback, or using syncProcessing: true.

Inspect the errors array even on 200. Bulk jobs can partially succeed, with some records rejected as invalid or already present.

Deduplicate and validate before you send. Remove duplicate numbers from a batch and reject empty arrays client-side rather than depending on server-side handling.

Normalise phone numbers to E.164 before sending. Consistent formatting makes later removal reliable, since the value you send on DELETE must match what was stored.

Use epoch milliseconds for expiryTime. Seconds-based timestamps resolve to 1970.

Maintain your own suppression record. V3 has no read endpoint. Log every request and response so you can prove what was suppressed, when, and why — valuable for compliance audits.

Authenticate your callback receiver. Set a shared secret in callbackUrlHeaders and verify it on every inbound call.

Implement retry with exponential backoff for 429 and 5xx, and poll bulk status with a widening interval rather than in a tight loop.

Choose syncProcessing deliberately. Synchronous for small interactive batches; asynchronous for volume and scheduled jobs.