Skip to content

Listening Query API V3 — Developer Guide


1. Overview

Sprinklr Listening gives brands visibility into online conversations across channels, websites, and news sources. Listening data is organised into Topics (keyword queries that pull in conversations not sent directly to your brand), Topic Groups, Themes, and Keyword Lists.

The Listening Query API V3 lets you run two fundamentally different kinds of query against that data:

You wantEndpointReturns
The individual messages that matched a Listening queryPOST /api/v3/listening/query/streamA paginated list of Message objects
An aggregated count, breakdown, or trend over those messagesPOST /api/v3/listening/query/widgetAggregated buckets (word / id / count)

Both endpoints take the same request body schema (ApiWidgetRequestDTO in the specification). The details.widgetType field is what decides which shape of answer you get — and it is also what decides which of the two endpoints you must call.

1.1 The query model

Every Listening query, on either endpoint, is built from four parts:

PartFieldPurpose
Time rangesinceTime, untilTime, timeField, timezoneOffsetWhich window of messages to consider
Scopefilters[]Which Listening dimensions (Topic, Sentiment, Media Source, …) narrow the set
ShapedetailsWhat kind of answer you want — stream of messages, distribution, trend, users, topic cluster
Measuremetric, trendAggregationPeriodWhat is being counted, and at what granularity

Learn this once and both endpoints become the same API with two output modes.

1.2 Prerequisite: Listening must be enabled

Listening is one of a small number of Sprinklr data sets that is not enabled by default. Per the Sprinklr Help Center, Listening API access requires an explicit request to the Support team when Listening is part of the use case listed in your License Order Form.

If Listening Stream is not enabled, the response body carries:

{
  "message": "Streaming in listening is not enabled for you. Please contact support",
  "data": {}
}

2. Base URLs and environments

All API calls are sent to the production endpoint:

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

So the listening resource in production is:

https://api3.sprinklr.com/{env}/api/v3/listening/query/stream
https://api3.sprinklr.com/{env}/api/v3/listening/query/widget

See the environment list at APIs | Sprinklr Developer Portal.


3. Authentication and common headers

All Listening API calls are authenticated with OAuth 2.0. See API Overview for portal registration, API key and secret generation, and the Authorize flow.

KeyValueDescriptionRequired on
AuthorizationBearer {{accessToken}}Credential used by the API to authenticate a user with the server. For generating the authorization token, refer to the Authorize section on the developer portal.All requests
Key{{apiKey}}API key that authenticates the application with the server. For generating an API key, refer to the Getting Started guide.All requests
Content-Typeapplication/jsonRepresentation header that determines the type of data present in the request body.All requests (both endpoints are POST with a required body)
Acceptapplication/jsonDetermines the acceptable response type from the server.All requests

Governance. Sprinklr's API governance model is tied directly to the user's role and permissions — the API key inherits every permission of the user it was created for. A caller with no visibility of a Listening Topic will not receive its messages, regardless of the filterValues sent.

Credential hygiene. Never commit an access token or API key to source control, never paste one into a ticket or chat, and never log the Authorization or Key header values. Every credential in this guide is a placeholder. If a real token or key has been exposed, revoke and regenerate it immediately.


4. POST /api/v3/listening/query/stream — Query Listening Stream

Operation ID: ListeningApiV3_queryStream · Tag: Listening V3 · Request body: required

Returns the message stream associated with each matching message, containing the required information. It returns StreamWidgetResponse (ListeningStreamV3ResponseDTO in the V3 specification).

Use this endpoint when you need the messages themselves — text, author, permalink, workflow state, enrichments — rather than a count.

4.1 Volume limits

These are hard limits carried forward verbatim from the V2 reference and repeated in the supplied V3 specification:

  • You cannot fetch more than 10,000 messages in a same timestamp.
  • You cannot fetch more than 1,000 messages in one request.

Design your pagination around both numbers. The second caps a single call; the first caps how deep you can page within one timestamp before you must advance the time window (§9.2).

4.2 Request body

ParameterSub-parameterRequiredTypeDescription
sinceTimeRequiredLongStart of the time range, in epoch milliseconds.
untilTimeRequiredLongEnd of the time range, in epoch milliseconds.
timeFieldOptionalStringWhich time the range applies to. SN_CREATED_TIME — time the message was created on the social network (default). SYSTEM_CREATED_TIME — time the message was created in Sprinklr.
timezoneOffsetOptionalLongClient timezone UTC offset in milliseconds. Default 0 (UTC). For example, EST is UTC−5, so -(5*60*60*1000) = -18000000.
detailsRequiredObjectWidget configuration. See §4.3.
widgetTypeRequiredStringSTREAM for this endpoint.
filtersOptionalArray of objectsDimension filters applied to the query. Default: empty. See §4.4.
metricOptionalStringMetric to aggregate. MENTIONS (default), REACH, RETWEETS, FAVORITES.
startOptionalIntegerPagination offset. Default 0. Applicable to the STREAM widget only.
rowsOptionalIntegerMaximum number of items in the page. Default 20. Applicable to the STREAM widget only. Bounded by the 1,000-messages-per-request limit in §4.1.
sortKeyOptionalStringField used to sort the returned messages. Takes three values: SYSTEM_CREATED_TIME (system created time), CREATED_TIME (social network created time), MODIFIED_TIME (modified time). Default: CREATED_TIME.
sortOrderOptionalStringSort direction. Stream endpoint only.
messageFormatOptionsOptionalStringComma-delimited formatting values: strip_html (strip HTML from message text), strip_url (strip URLs from message text), include_original (also return the original text in an originalText field).
trendAggregationPeriodOptionalStringTrend bucket size — HOUR, DAY, WEEK, MONTH, QUARTER, YEAR. Applicable to TREND and GROUPED_TREND widgets, not to STREAM.
echoRequestOptionalBooleanWhen true, echoes the request back in the response object.
tagOptionalStringA state parameter, usable as a version attached with the response. It is not modified by the API and is returned as-is.

4.3 The details object (stream)

ParameterRequired/OptionalTypeDescription
widgetTypeRequiredStringRefers to the type of the widget. STREAM on this endpoint.

4.4 The filters[] array

Shared by both endpoints.

ParameterRequired/OptionalTypeDescription
dimensionRequiredStringFilter dimension such as TOPIC, TOPIC_GROUP, SENTIMENT, or MEDIA_SOURCE.
filterValuesRequiredArray of StringList of IDs for the given dimension. For the TOPIC dimension, filterValues is the list of Topic IDs.
excludeOptionalBooleanExcludes matching values when set to true. Default false.
customFieldNameConditionalStringRequired when filtering on custom field dimensions.

To resolve a Topic ID, use the Listening Topic APIs — for example Read Topic 2.0 (GET /api/v2/listening-topic/{topicId}), or the Listening Topic V3 endpoints (/listening/topic) in the V3 specification. filterValues takes IDs, never names.

4.5 Example request

curl --location 'https://api3.sprinklr.com/api/v3/listening/query/stream' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
    "sinceTime": 1488034511000,
    "untilTime": 1786537500000,
    "details": {
      "widgetType": "STREAM"
    },
    "filters": [
      {
        "dimension": "TOPIC",
        "filterValues": ["6a7ae25c298255388c56550a"]
      }
    ],
    "metric": "MENTIONS",
    "rows": 10,
    "start": 0
  }'

4.6 Example response

Illustrative example, reproduced from the supplied specification. Not real customer data and not a guaranteed production response.

{
    "data": {
        "result": [
            {
                "sourceType": "ACCOUNT",
                "sourceId": 600049002,
                "content": {
                    "text": "",
                    "isRichText": false
                },
                "channelMessageId": "p234uqy",
                "channelType": "REDDIT",
                "accountType": "SUBREDDIT",
                "channelCreatedTime": 1786033040000,
                "senderProfile": {
                    "channelType": "REDDIT",
                    "followers": -1,
                    "following": -1,
                    "unSubscribed": false,
                    "deleted": false,
                    "snCreatedTime": 0,
                    "snModifiedTime": 0,
                    "statusCount": -1,
                    "accountSpecificInfos": []
                },
                "permalink": "https://www.reddit.com/r/holup/comments/1vh6sg3/natasha/p234uqy",
                "language": "en",
                "messageId": "ACCOUNT_600049002_1786033040000_REDDIT_273_p234uqy",
                "brandPost": false,
                "createdTime": 1786033605300,
                "modifiedTime": 1786348560798,
                "textEntities": {},
                "insights": {},
                "workflow": {
                    "modifiedTime": 1786348560798,
                    "customProperties": {},
                    "queues": [],
                    "spaceWorkflows": []
                },
                "enrichments": {},
                "autoImported": false,
                "autoResponse": false,
                "apiStatus": "Removed fields because of resyndication policy"
            }
        ],
        "hasMore": true
    },
    "errors": []
}

4.7 Response envelope

ParameterTypeDescription
dataObjectContains the API response data.
data.resultArrayList of messages/posts matching the query criteria.
data.hasMoreBooleanIndicates whether additional records are available for retrieval through pagination.
errorsArrayContains any errors returned by the API. An empty array indicates a successful request.

This matches ListeningStreamV3ResponseDTO in the specification, which defines exactly two properties — result (array of Message) and hasMore (boolean).

4.8 Message object — data.result[]

ParameterSub-parameterTypeDescription
sourceType-StringType of source from which the message was collected (for example, ACCOUNT).
sourceId-LongUnique identifier of the source account.
content-ObjectContains the content of the message.
contenttextStringText content of the message. May be empty due to platform resyndication policies.
contentisRichTextBooleanIndicates whether the content contains rich text formatting.
channelMessageId-StringUnique identifier of the message on the native channel.
channelType-StringSocial channel from which the message originated, such as REDDIT or TWITTER.
subType-StringSpecifies the subtype of the message within the social channel, such as a post, comment, reply, mention, or repost.
accountType-StringType of account associated with the message, such as SUBREDDIT or TWITTER.
channelCreatedTime-LongTimestamp (in milliseconds) when the message was originally created on the source channel.
senderProfile-ObjectMetadata associated with the message author.
senderProfilechannelTypeStringSocial channel associated with the sender profile.
senderProfilefollowersIntegerNumber of followers for the sender profile. A value of -1 indicates unavailable data.
senderProfilefollowingIntegerNumber of accounts followed by the sender profile. A value of -1 indicates unavailable data.
senderProfileunSubscribedBooleanIndicates whether the profile is unsubscribed.
senderProfiledeletedBooleanIndicates whether the profile has been deleted.
senderProfilesnCreatedTimeLongTimestamp when the sender profile was created on the social network.
senderProfilesnModifiedTimeLongTimestamp when the sender profile was last updated on the social network.
senderProfilestatusCountIntegerTotal number of posts/messages by the sender. A value of -1 indicates unavailable data.
senderProfileaccountSpecificInfosArrayChannel-specific metadata for the sender profile.
permalink-StringDirect link to the original message or post on the social platform.
language-StringDetected language of the message content.
messageId-StringUnique Sprinklr message identifier.
brandPost-BooleanIndicates whether the message was published by a brand-owned account.
createdTime-LongTimestamp (in milliseconds) when the message was ingested into Sprinklr.
modifiedTime-LongTimestamp (in milliseconds) when the message was last updated in Sprinklr.
textEntities-ObjectContains extracted entities such as people, locations, organizations, hashtags, URLs, and mentions from the message content.
insights-ObjectStores analytics, classifications, and insights generated for the message.
workflow-ObjectWorkflow information associated with the message.
workflowmodifiedTimeLongTimestamp of the most recent workflow update.
workflowcustomPropertiesObjectCustom properties and user-defined fields applied to the message.
workflowqueuesArrayLists queues to which the message has been assigned.
workflow.queues[]queueIdLongUnique identifier of the assigned queue.
workflow.queues[]assignmentTimeLongTimestamp when the message was assigned to the queue.
workflowspaceWorkflowsArrayContains workflow information associated with Spaces.
enrichments-ObjectAdditional enrichment data applied to the message.
autoImported-BooleanIndicates whether the message was automatically imported into the platform.
autoResponse-BooleanIndicates whether an automatic response was sent for the message.
apiStatus-StringProvides status or informational messages related to the API response, such as content restrictions due to platform resyndication policies.

The V3 Message schema in sprinklr-v3.yaml additionally defines id, draftId, receiverProfile, mentionedProfiles, postId, assetId, and authorId. These are part of the Message type but do not appear in the supplied Listening Stream examples — treat their presence in a Listening stream response as unconfirmed.

apiStatus and empty content

In the supplied example every message returns "content": {"text": ""} alongside "apiStatus": "Removed fields because of resyndication policy". This is expected behaviour, not a defect. Channel resyndication policies (notably Twitter/X) restrict which fields Sprinklr may return over the API. Enabling full Twitter syndication requires an explicit request to Sprinklr Support, per the Sprinklr Help Center.

Always read apiStatus before treating an empty content.text as "no text".


5. POST /api/v3/listening/query/widget — Query Listening Widget

Operation ID: ListeningApiV3_queryWidget · Tag: Listening V3 · Request body: required

Queries Listening widget data — distribution, grouped distribution, trend, users, and topic cluster. Use this endpoint for aggregates, never for raw messages.

5.1 Request body

FieldTypeRequiredDescription
sinceTimelongYesStart of time range (epoch milliseconds).
untilTimelongYesEnd of time range (epoch milliseconds).
timezoneOffsetlongNoClient timezone offset in milliseconds.
detailsobjectYesWidget configuration. See §5.2.
filtersarray of objectsNoDimension filters (default empty). See §4.4.
metricstringNoMetric to aggregate (MENTIONS, REACH, RETWEETS, FAVORITES). Default MENTIONS.
trendAggregationPeriodstringNoBucket size for trend widgets (HOUR, DAY, WEEK, MONTH, QUARTER, YEAR). Required for trend types.
messageFormatOptionsstringNoMessage formatting options passed to the widget engine.
startintegerNoPagination offset (default 0).
rowsintegerNoPage size (default 20). Max depends on widget type (distribution ≤ 100, grouped distribution ≤ 20).
sortKeystringNoNot used on widget endpoint (stream only).
sortOrderstringNoNot used on widget endpoint (stream only).
timeFieldstringNoTime field for filtering (SN_CREATED_TIME, SYSTEM_CREATED_TIME). Default SN_CREATED_TIME.
echoRequestbooleanNoWhen true, echoes the request in the response metadata.
tagstringNoClient-side request version tag (not modified by API).

5.2 The details object (widget)

ParameterRequired/OptionalTypeDescription
widgetTypeRequiredStringWidget type. Supported values include DISTRIBUTION, GROUPED_DISTRIBUTION, TREND, GROUPED_TREND, USERS, and TOPIC_CLUSTER.
subTypeConditionalStringRequired for the USERS widget type.
dimensionConditionalStringPrimary dimension for the widget. For example, SENTIMENT, TOPIC, or MEDIA_SOURCE.
otherDimensionConditionalStringSecondary dimension. Required for GROUPED_DISTRIBUTION.
otherDimensionRowsOptionalIntegerMaximum number of rows for the secondary dimension. Default is 20.
customFieldNameOptionalStringCustom field name when the selected dimension references custom fields.

Which fields each widgetType needs

widgetTypedimensionotherDimensionsubTypetrendAggregationPeriodrows ceiling
DISTRIBUTIONRequired———≤ 100
GROUPED_DISTRIBUTIONRequiredRequired——≤ 20
TRENDRequired——RequiredNot specified
GROUPED_TRENDRequiredRequired—RequiredNot specified
USERSConditional—Required—Not specified
TOPIC_CLUSTERConditional———Not specified
STREAMNot supported here — use /listening/query/stream

Derived from the conditionality notes in the supplied widget specification. The rows ceilings for TREND, GROUPED_TREND, USERS, and TOPIC_CLUSTER are not stated in any supplied source — confirm before relying on large page sizes.

5.3 Example request

curl -X POST 'https://api3.sprinklr.com/api/v3/listening/query/widget' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Content-Type: application/json' \
  -d '{
    "sinceTime": 1488034511000,
    "untilTime": 1490972111000,
    "details": {
      "widgetType": "DISTRIBUTION",
      "dimension": "SENTIMENT"
    },
    "filters": [
      {
        "dimension": "TOPIC",
        "filterValues": ["595c50dbe4b064e21f85d074"]
      }
    ],
    "metric": "MENTIONS"
  }'

5.4 Example response

Illustrative example, reproduced from the supplied specification.

{
  "data": [
    {
      "word": "Twitter",
      "id": "TWITTER",
      "count": 21,
      "values": {},
      "additional": {}
    },
    {
      "word": "Blogs/Websites",
      "id": "BLOGS",
      "count": 9,
      "values": {},
      "additional": {}
    }
  ]
}

5.5 Response parameters

ParameterTypeDescription
dataArrayWidget data returned by the API.
data[].wordStringDisplay label of the result bucket.
data[].idStringUnique identifier for the bucket.
data[].countLongAggregated metric count.
data[].valuesObjectAdditional metric breakdown values.
data[].additionalObjectAdditional metadata associated with the bucket.

6. Response format and status codes

6.1 Envelopes at a glance

EndpointEnvelopeResult locationMore-pages flag
/listening/query/stream{ "data": { "result": [], "hasMore": bool }, "errors": [] }data.resultdata.hasMore
/listening/query/widget{ "data": [ … ] } per example; APIResponse per specificationdataNot documented

6.2 The errors array

sprinklr-v3.yaml defines each Error with three required properties:

FieldTypeDescription
idString24-character hex ObjectId
codeIntegerError code
messageStringDotted error key (for example, account.not.found)

Because message is a dotted error key rather than prose, do not surface it directly to end users. Map codes to your own copy.

6.3 Response codes

Both operations declare the same responses in sprinklr-v3.yaml:

HTTP CodeScenarioDescription
200 OKSuccessQuery executed; results returned in the envelope.
400 Bad RequestInvalid requestMalformed body, missing required field, or an invalid widgetType / dimension combination.
401 UnauthorizedAuthentication failedInvalid or missing Authorization token.
403 ForbiddenInsufficient permissionsThe API key's user lacks permission on the requested Listening data.
404 Not FoundNot foundReferenced resource not found.

500 Internal Server Error is not declared on these two operations in the supplied specification. Still handle it — but note the specification omission (§12).

Always inspect the errors array even on a 200.


7. V2 → V3 migration

This section is for developers already running against POST /api/v2/listening/query/stream.

7.1 The headline: almost nothing changes

  • POST /api/v2/listening/query/stream — path simplified
  • Request body fields (sinceTime, untilTime, filters, rows, start, etc.) remain unchanged
  • Response wrapped in { "data": { "result": [...] }, "errors": [] } envelope — already V3 compliant, no change needed

So for the stream endpoint the migration is, in the common case, a base-URL change and nothing else. Your existing V2 request bodies and your existing V2 response-parsing code both continue to work.

7.2 Endpoint mapping

V2V3
POST /api/v2/listening/query/streamPOST /api/v3/listening/query/stream
No documented V2 equivalent in the supplied sourcesPOST /api/v3/listening/query/widget

The widget endpoint is the new capability in this release. The V2 Listening Streams page documents widgetType values for TREND / GROUPED_TREND in trendAggregationPeriod


8. Dimensions, metrics, and widget types — reference

Values below are only those attested in the supplied sources. These lists are not exhaustive; the widget specification says "Supported values include".

details.widgetType — STREAM (stream endpoint only), DISTRIBUTION, GROUPED_DISTRIBUTION, TREND, GROUPED_TREND, USERS, TOPIC_CLUSTER

metric — MENTIONS (default), REACH, RETWEETS, FAVORITES

filters[].dimension — TOPIC, TOPIC_GROUP, SENTIMENT, MEDIA_SOURCE

details.dimension — SENTIMENT, TOPIC, MEDIA_SOURCE

timeField — SN_CREATED_TIME (default), SYSTEM_CREATED_TIME

sortKey (stream only) — CREATED_TIME (default), SYSTEM_CREATED_TIME, MODIFIED_TIME

trendAggregationPeriod — HOUR, DAY, WEEK, MONTH, QUARTER, YEAR

messageFormatOptions — strip_html, strip_url, include_original (comma-delimited)

channelType values seen in responses — REDDIT, TWITTER, INSTAGRAM; accountType — SUBREDDIT, TWITTER; sourceType — ACCOUNT, LISTENING


9. Use cases

9.1 Replace client-side counting with a distribution widget

Scenario: you currently page the whole stream for a Topic just to count mentions by sentiment.

Stop. Call the widget endpoint once:

{
  "sinceTime": 1488034511000,
  "untilTime": 1490972111000,
  "details": { "widgetType": "DISTRIBUTION", "dimension": "SENTIMENT" },
  "filters": [{ "dimension": "TOPIC", "filterValues": ["595c50dbe4b064e21f85d074"] }],
  "metric": "MENTIONS"
}

One request replaces an unbounded pagination loop, and it is unaffected by the 1,000-per-request stream cap.

9.2 Export a full day of mentions safely

Scenario: nightly export of every mention on a Topic.

The two limits in §4.1 interact. A single request returns at most 1,000 messages, and you cannot fetch more than 10,000 messages in a same timestamp. So:

  1. Split the day into windows using sinceTime / untilTime.
  2. Within a window, page with start and rows (rows ≤ 1,000).
  3. Continue while data.hasMore is true.
  4. If a window approaches 10,000 messages, narrow the window rather than paging deeper.
  5. Pin timeField explicitly — SN_CREATED_TIME for "when it was posted", SYSTEM_CREATED_TIME for "when Sprinklr saw it". A backfill will scatter across the two very differently.
async function fetchWindow(sinceTime, untilTime, topicId) {
  const rows = 1000;                 // per-request maximum
  let start = 0;
  const all = [];

  while (true) {
    const res = await post('/api/v3/listening/query/stream', {
      sinceTime, untilTime,
      timeField: 'SN_CREATED_TIME',
      details: { widgetType: 'STREAM' },
      filters: [{ dimension: 'TOPIC', filterValues: [topicId] }],
      metric: 'MENTIONS',
      sortKey: 'CREATED_TIME',
      rows, start
    });

    if (res.errors && res.errors.length) {
      handleErrors(res.errors);      // dotted keys, e.g. account.not.found
      break;
    }

    all.push(...res.data.result);
    if (!res.data.hasMore) break;    // note: nested under data, not at root

    start += rows;
    if (start >= 10000) {            // same-timestamp ceiling — narrow the window
      throw new Error('Window too dense; split the time range');
    }
  }
  return all;
}

9.3 Idempotent incremental sync

Scenario: poll every 15 minutes for new mentions.

Use timeField: "SYSTEM_CREATED_TIME" and window on Sprinklr's ingestion time, not the social network's. A message posted three days ago but ingested five minutes ago will be missed entirely by an SN_CREATED_TIME window — this is the single most common cause of "the API is dropping messages" reports.

Use tag to stamp each poll with your own cursor version; the API returns it unchanged, which makes correlating a response to the request that produced it trivial in logs.

9.4 Build a sentiment-by-channel matrix

Scenario: a dashboard cell showing sentiment split within each media source.

{
  "sinceTime": 1488034511000,
  "untilTime": 1490972111000,
  "details": {
    "widgetType": "GROUPED_DISTRIBUTION",
    "dimension": "MEDIA_SOURCE",
    "otherDimension": "SENTIMENT",
    "otherDimensionRows": 5
  },
  "filters": [{ "dimension": "TOPIC", "filterValues": ["595c50dbe4b064e21f85d074"] }],
  "metric": "MENTIONS",
  "rows": 20
}

GROUPED_DISTRIBUTION caps rows at 20. Do not request more.

9.5 Plot a volume trend

Scenario: daily mention volume over a quarter.

Set widgetType: "TREND" and — this is mandatory for trend types — trendAggregationPeriod: "DAY". Omitting it is a 400.

{
  "sinceTime": 1488034511000,
  "untilTime": 1490972111000,
  "details": { "widgetType": "TREND", "dimension": "TOPIC" },
  "trendAggregationPeriod": "DAY",
  "filters": [{ "dimension": "TOPIC", "filterValues": ["595c50dbe4b064e21f85d074"] }],
  "metric": "MENTIONS",
  "timezoneOffset": -18000000
}

Set timezoneOffset deliberately on any trend query. It defaults to 0 (UTC), so a "daily" trend for a US brand will otherwise bucket on UTC midnight and shift every peak by five hours.

9.6 Exclude a noisy sub-topic

Scenario: a Topic is polluted by one recurring source.

Add a second filter with exclude: true:

"filters": [
  { "dimension": "TOPIC", "filterValues": ["595c50dbe4b064e21f85d074"] },
  { "dimension": "MEDIA_SOURCE", "filterValues": ["BLOGS"], "exclude": true }
]

9.7 Strip markup before indexing message text

Scenario: you are pushing message text into a search index that chokes on HTML and URLs.

Set messageFormatOptions: "strip_html,strip_url,include_original". You get clean text for indexing plus the untouched original in originalText for display and audit.

9.8 Reconcile "the API returns empty text"

Scenario: support reports blank message bodies.

Check apiStatus on the affected messages first (§4.8). "Removed fields because of resyndication policy" means the channel — not Sprinklr, and not your code — withheld the field. Resolution is a Sprinklr Support request to enable the relevant syndication (for example, Twitter Syndication), not a code change.


10. Caveats and best practices

Choosing the endpoint

  • Messages → /listening/query/stream. Aggregates → /listening/query/widget.
  • STREAM is not a valid widgetType on the widget endpoint.
  • Both endpoints share one request schema. Build one request-builder, parameterise details.

Volume and pagination

  • Max 1,000 messages per request. Max 10,000 messages in a same timestamp.
  • start and rows apply to STREAM only.
  • Page while data.hasMore is true — note it is nested under data, unlike other V3 APIs.
  • DISTRIBUTION caps rows at 100; GROUPED_DISTRIBUTION caps at 20.

Time handling

  • sinceTime and untilTime are epoch milliseconds, not seconds and not ISO-8601.
  • timeField defaults to SN_CREATED_TIME. Choose it explicitly.
  • timezoneOffset defaults to 0 (UTC) and is expressed in milliseconds — EST is -18000000.

Filters

  • filterValues takes IDs, not names. Resolve Topic IDs through the Listening Topic APIs.
  • exclude: true inverts a filter; default is false.
  • customFieldName is required when filtering on custom-field dimensions.
  • Filter values you cannot see under governance return nothing rather than an error.

Trends

  • trendAggregationPeriod is required for TREND and GROUPED_TREND, and ignored elsewhere.

Entitlement and content

  • Listening is not enabled by default — it requires an explicit Support request.
  • Empty content.text with an apiStatus note is a resyndication restriction, not a bug.
  • -1 in senderProfile.followers, following, or statusCount means unavailable, not zero. Do not sum it.

Error handling

  • Inspect errors on every response, including 200.
  • errors[].message is a dotted key (account.not.found), not user-facing prose. Map it.
  • 500 is not declared on these operations in the specification, but handle it anyway.

Operational

  • tag round-trips unchanged — use it as a request correlation ID.
  • echoRequest: true returns your request alongside the response; useful in debugging, wasteful in production.
  • Rate limits for these two endpoints are not documented in any supplied source. Implement retry with exponential backoff regardless, and confirm the actual limits with the API owner.

All JSON payloads in this guide are illustrative examples derived from the supplied specifications and published references. They are not real customer data and are not guaranteed production responses. All credentials are placeholders ({{accessToken}}, {{apiKey}}) and must never be committed or logged. No API call was executed and no linting or validation tool was run in the course of producing this guide.