Skip to content

Content Template API v3 — Developer Guide

Applies to: Sprinklr API v3 (Content Template V3 tag) — GET /contentTemplate, POST /contentTemplate/search

V2 API reference: Content Template on the Sprinklr Developer Portal [doc:turn1doc1]


1. Overview

Sprinklr Content Template Builder powers cross-channel content management: it lets users consolidate images, videos, and content for non-social channels such as websites, blogs, and email into reusable templates. The Content Template APIs let you fetch details for user-created and standard content templates, and search templates using sorts, filters, and pagination [doc:turn1doc1].

The v3 Content Template API replaces four separate v2 endpoints with a single resource path plus a search sub-resource.

1.1 Operations

#OperationMethod and pathoperationIdDeclared 200 schema
1Fetch standard content template detailsGET /contentTemplateContentTemplateApiV3_fetchContentTemplatesAPIResponse
2Fetch content template details using sorting and filtersPOST /contentTemplate/searchContentTemplateApiV3_searchContentTemplatesPaginatedSearchResponse

Both operations are tagged Content Template V3 and declare the four shared error responses: 400 BadRequest, 401 Unauthorized, 403 Forbidden, 404 NotFound.

For more details refer to the Content Template V3 API Reference.

1.2 Data model and workflow

A content template is identified by a 24-character hexadecimal id. Beyond id and name, the returned object is template-type dependent.

Note (from the source operation document). "The response parameters vary from template to template. The details depend on the template details present on the backend." Treat every field other than id and name as optional and defensively parse the payload.

Fields observed in the reference GET response for an email content template:

FieldTypeObserved value / meaning
idString6a2bfe33703a82b2e91dc02a — template identifier
nameStringmanual ctm template
channelTypeStringEMAIL
accountTypesArray[String]["BULK_EMAIL"]
contentStringStringified JSON describing the template component tree (Canvas → Subject, EmailTitle, PostGallery …), fonts, merge tags, and languages. Parse as JSON after unescaping.
smartTemplateBooleanfalse
isAdvocacyTemplateBooleantrue
templateTypeStringCONTENT_TEMPLATE
advocacyProjectIdString (UUID)f5122f12-f3fb-4ef9-87f5-56b05b2ba4f9
height / widthInteger1457 / 600 (pixels)
projectIdString (UUID)d5b402ad-cb5f-4976-8a23-0ea316767890
locationUrlString (URL)Location of the rendered publisher bundle
publisherStatusStringcompleted
contentTypeStringPUBLISHING
versionInteger0
templateVersionInfoString0.0.1
editDisabledBooleantrue
archivedBooleanfalse
isPurelyAIGeneratedBooleanfalse
reportStringCONTENT_TEMPLATE
governance.visibility.globallyVisibleBooleantrue — the v3 equivalent signal of the v2 fromGlobal flag
clientIdInteger66000002
ownerUserIdInteger66009128
createdTime / modifiedTimeStringJun 12, 2026, 12:40:19 PM / Jul 29, 2026, 09:29:56 AM — formatted date strings, not epoch milliseconds
lastModifiedUserIdInteger66009128
deletedBooleanfalse
canEditBooleanfalse

Typical workflow:

  1. Call POST /contentTemplate/search with filters (for example TEMPLATE_TYPE IN [CONTENT_TEMPLATE]) and a page size to obtain a lightweight list of {id, name} pairs plus hasMore and totalHits.
  2. Call GET /contentTemplate?id={templateId} for each identifier you need in order to retrieve the full template body.

2. Base URLs and environments

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

env is a required path variable. Default: prod. Allowed values declared in the specification:

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

Full endpoint URLs:

GET  https://api3.sprinklr.com/{env}/api/v3/contentTemplate
POST https://api3.sprinklr.com/{env}/api/v3/contentTemplate/search

Important. Use your own partition's environment token.


3. Authentication and common headers

KeyValueDescription
AuthorizationBearer {{accessToken}}Credential used by the API to authenticate a user with the server. For generating an authorization token, refer to the Authorize section on the developer portal.
Key{{apiKey}}API key helps authenticate the application with the server. For generating an API key, refer to the Getting Started guide.
Content-Typeapplication/jsonRepresentation header that determines the type of data (media/resource) present in the request body. Required for POST /contentTemplate/search.
Acceptapplication/jsonDetermines the acceptable response type from the server.

4. Fetch standard content template details

GET /api/v3/contentTemplate · operationId ContentTemplateApiV3_fetchContentTemplates

Fetches standard content template details using the template id.

4.1 Request

Endpoint form given in the source operation document:

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

Endpoint form given in the Jira description:

GET /api/v3/contentTemplate?id=templateId1,templateId2

4.2 Query parameters

ParameterRequired / OptionalDescriptionType
idRequiredUnique identifier of the content template to retrieve. Example: 6a2bfe33703a82b2e91dc02a. Use a comma-separated list form (id=templateId1,templateId2) for bulk fetchString

Additional query parameters named in the Jira description as replacements for v2 URL variants, not present in the specification and not exercised in the operation document:

ParameterSourceStatus
fromGlobalJira description — "fromGlobal=true … moved into query params on the standard GET"Undeclared in sprinklr-v3.yaml; unverified
channelTypesJira description — "channelTypes filter moved into query params on the standard GET"Undeclared in sprinklr-v3.yaml; unverified

4.3 Example request

curl --location 'https://api3.sprinklr.com/{env}/api/v3/contentTemplate?id=6a2bfe33703a82b2e91dc02a' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Accept: application/json'

Illustrative example. Replace {env}, {{accessToken}}, {{apiKey}}, and the template id with your own values.

4.4 Example response (abridged)

The content field in the real response is a very large escaped-JSON string containing the full component tree and embedded @font-face declarations. It is elided below as "…"; everything else is reproduced from the source document.

{
  "data": {
    "id": "6a2bfe33703a82b2e91dc02a",
    "name": "manual ctm template",
    "channelType": "EMAIL",
    "accountTypes": [
      "BULK_EMAIL"
    ],
    "content": "…",
    "smartTemplate": false,
    "isAdvocacyTemplate": true,
    "templateType": "CONTENT_TEMPLATE",
    "advocacyProjectId": "f5122f12-f3fb-4ef9-87f5-56b05b2ba4f9",
    "height": 1457,
    "width": 600,
    "projectId": "d5b402ad-cb5f-4976-8a23-0ea316767890",
    "locationUrl": "https://storage.googleapis.com/…/spx-publisher/d5b402ad-cb5f-4976-8a23-0ea316767890/1785317396873",
    "publisherStatus": "completed",
    "contentType": "PUBLISHING",
    "version": 0,
    "templateVersionInfo": "0.0.1",
    "editDisabled": true,
    "archived": false,
    "isPurelyAIGenerated": false,
    "report": "CONTENT_TEMPLATE",
    "governance": {
      "visibility": {
        "globallyVisible": true
      }
    },
    "clientId": 66000002,
    "ownerUserId": 66009128,
    "createdTime": "Jun 12, 2026, 12:40:19 PM",
    "modifiedTime": "Jul 29, 2026, 09:29:56 AM",
    "lastModifiedUserId": 66009128,
    "deleted": false,
    "canEdit": false
  },
  "errors": []
}

4.5 Response fields

data carries the template object described in §1.2. errors is an array of Error objects; an empty array indicates that no errors occurred. See §6.


5. Fetch content template details using sorting and filters

POST /api/v3/contentTemplate/search · operationId ContentTemplateApiV3_searchContentTemplates

Fetches content template id and name details using sorting and filter values. The request body is required and the declared body schema is Request; the declared 200 schema is PaginatedSearchResponse.

5.1 Request body parameters

ParameterSub-parameterRequired / OptionalDefinitionType
sortsOptionalSorting filter that specifies the arrangement of data in the response.Array
key—Field used for sorting the data. Example: MODIFIED_TIME sorts the response by each template's modified time.String
order—Order of data in the response. Example: ASC for ascending, DESC for descending.String
pageOptionalLimits the number of items returned when the response set is large.Object
page—Page number to return. If the field has no value, the first page of results is returned.Integer
size—Number of results to return.Integer
filtersRequiredInformation used to filter the data in the response.List[Object]
fieldOptionalField on which the data is filtered. Example: TEMPLATE_TYPE, PUBLISHER_STATUS.String
filterTypeOptionalType of filter applied. Supported values per the operation document: IN, GT, GTE, LT, LTE, NIN, BETWEEN, STARTS_WITH, CONTAINS, EQUALS, FILTER, EXISTS.String
valuesOptionalValues against which the data is compared. Example: CONTENT_TEMPLATE.List[String, Integer]

Discrepancy — filters requiredness. The operation document marks filters Required while marking every one of its sub-fields Optional, and the same document's dev note says an empty body {} is valid (see §5.4). Those two statements cannot both hold. The specification marks the body required but declares no required array inside Request, so filters is optional at the schema level. Confirm the intended contract.

Discrepancy — filterType enum. In the specification, filters[] resolves to Filter_request, whose filterType is the enum FilterType_Filter with values FILTER, LIMIT, SEARCH, MATCH_PHRASE_PREFIX, ADHOC_SEARCH, EXPRESSION, GEO_DISTANCE, ADVANCED_QUERY, MATCH_NONE, MATCH_ALL. Only FILTER appears in both lists. The value used in the working example — IN — is not in the specification enum, yet QA verified the call. Treat the operation document's list as the behavioural truth and the specification enum as stale, but confirm before generating client code from the spec.

Note — Request is a shared, very wide schema. Request is Sprinklr's generic search/reporting request object. It declares roughly 40 top-level properties (key, timeFilter, previousTimeFilter, query, queries, filters, filter, postFilters, projectionFilters, groupBys, projections, report, permission, tzOffset, timezone, sorts, page, pageForDocuments, sortsForDocuments, merge, excludeFields, additional, and more). Only sorts, page, and filters are documented for this operation. The remaining properties are not documented as supported for content template search — do not assume they are honoured.

Related schema details from sprinklr-v3.yaml:

  • sorts[] → Sort_request: type (string), key (string), order (Order_enums — a bare string with no enum values declared), additional, postProjectionSort.
  • page → Page_request: page (int32), size (int32), skip (int32), cursor (string). Only page and size are documented for this operation.
  • filters[] → Filter_request: field, filterType, values (array of object), plus displayName, negativeFilter, isCompoundFilter, accessibleValues, userFilter, allValuesAllowed, lockedWithValues, hidden, favourite, mandatory, locked, disabled, details — all undocumented for this operation.

5.2 Example request

curl --location 'https://api3.sprinklr.com/{env}/api/v3/contentTemplate/search' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
    "sorts": [
        {
            "key": "MODIFIED_TIME",
            "order": "DESC"
        }
    ],
    "page": {
        "page": 0,
        "size": 5
    },
    "filters": [
        {
            "field": "TEMPLATE_TYPE",
            "filterType": "IN",
            "values": [
                "CONTENT_TEMPLATE"
            ]
        }
    ]
}'

Illustrative example, reproduced from the source operation document with credentials replaced by placeholders.

5.3 Example response

{
  "data": {
    "searchResults": [
      {
        "id": "6a214d2e1d46a76667fd4b9c",
        "name": "pragya testing "
      },
      {
        "id": "6a883d0595239a114d6dbf47",
        "name": "Link"
      },
      {
        "id": "6a883d05e7f1f360e3d4f1c2",
        "name": "Media"
      },
      {
        "id": "6a883d05e7f1f360e3d4f1c3",
        "name": "Text"
      },
      {
        "id": "6a7afc34dff6d5eda924d20e",
        "name": "Thread"
      }
    ],
    "hasMore": true,
    "totalHits": 287
  },
  "errors": []
}

Response fields:

ParameterSub-parameterRequired / OptionalDefinitionType
dataRequiredContains the search results and pagination information returned by the API.Object
searchResultsRequiredList of templates matching the specified search criteria.Array
searchResults[].idRequiredUnique identifier of the template.String
searchResults[].nameRequiredName of the template.String
hasMoreRequiredIndicates whether additional results are available beyond the current response. true means another page can be requested.Boolean
totalHitsRequiredTotal number of records matching the search criteria. 287 means 287 templates match the applied filters.Integer
errorsRequiredDetails of any errors encountered while processing the request. An empty array indicates that no errors occurred.Array

Discrepancy — field names. The declared 200 schema PaginatedSearchResponse uses abbreviated property names: sR (array), tBC (int64), iBC (string), hM (boolean), tH (int64), fR (array of SearchFacetResponse), topHits (map of Tuple_Long_List_T). The verified response instead uses searchResults, hasMore, and totalHits, and is wrapped in a data envelope that PaginatedSearchResponse does not declare. This is almost certainly a serialization-alias mismatch in the published spec. Code against the documented names (data.searchResults, data.hasMore, data.totalHits) and treat the abbreviated spec names as an outstanding spec bug. Also note sR[] is typed "Unresolved type (T)", so the {id, name} shape comes only from the example.

5.4 Empty request body behaviour

Dev note. "If the request has no sorting or filters applied and has a pair of empty curly brackets, i.e., {}, then the response will show details for all the content templates available on a single page. By default, the size of response per page is equal to 100."

So:

  • Body {} → all available content templates, one page.
  • Default page size when page is omitted → 100.
  • Use hasMore and totalHits to decide whether to request the next page.
curl --location 'https://api3.sprinklr.com/{env}/api/v3/contentTemplate/search' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{}'

6. Response format and status codes

6.1 Status codes

CodeMeaningDeclared schema
200SuccessAPIResponse (GET) / PaginatedSearchResponse (POST search)
400Bad Request — shared BadRequest responseErrorResponse
401Unauthorized — shared Unauthorized responseErrorResponse
403Forbidden — shared Forbidden responseErrorResponse
404Not Found — shared NotFound responseErrorResponse

No other status codes are declared for either operation.

6.2 Success envelope

APIResponse:

{
  "data": {},
  "errors": [],
  "metadata": {}
}
FieldTypeNotes
dataobjectUntyped in the specification. The actual shape is documented only by the examples in §4.4 and §5.3.
errorsarray of ErrorEmpty on success.
metadataResponseMetadataDeclared by APIResponse; absent from the captured examples.

6.3 Error envelope

ErrorResponse:

{
  "data": null,
  "errors": [
    {
      "id": "6a2bfe33703a82b2e91dc02a",
      "code": 404,
      "message": "content.template.not.found"
    }
  ],
  "metadata": {}
}

Error requires all three fields:

FieldTypeNotes
idString24-character hexadecimal ObjectId.
codeIntegerNumeric error code.
messageStringDotted message key, for example account.not.found.

Note. The message value shown above is an illustrative key following the platform's dotted-key convention. The specification does not enumerate content-template-specific error codes or keys. Log code and message verbatim; do not pattern-match on message text.


7. V2 → V3 migration

7.1 Endpoint map

v2 operationv2 endpointv3 equivalentNotes
Fetch User-Created Content Template DetailsGET /api/v2/contentTemplate/{templateId}GET /api/v3/contentTemplate?id={templateId}Path segment becomes a query parameter.
Fetch Standard Content Template DetailsGET /api/v2/contentTemplate/{templateId}?fromGlobal=trueGET /api/v3/contentTemplate?id={templateId} (+ fromGlobal per the Jira description)The v3 operation document covers this operation ("Fetch Standard Content Template Details"). fromGlobal is named only in the Jira description and is undeclared in the spec. The returned object exposes governance.visibility.globallyVisible.
Fetch Content Template Details Using Sorting and FiltersPOST /api/v2/contentTemplate/searchContentTemplatesPOST /api/v3/contentTemplate/searchSub-path renamed from searchContentTemplates to search.
Fetch Content Template Details by Channel TypeGET /api/v2/contentTemplate/findAll?channelTypes={channelType} [doc:turn1doc4]GET /api/v3/contentTemplate (+ channelTypes per the Jira description)findAll is removed. channelTypes is named only in the Jira description and is undeclared in the spec.
— (did not exist)—Not deliveredThe Jira description announces PUT, PATCH, and DELETE on /api/v3/contentTemplate. QA confirmed they are out of scope and the spec does not define them.

7.2 Field and payload changes

Areav2v3
Base path/api/v2/contentTemplate/…/api/v3/contentTemplate
Template addressingPath segment /{templateId}Query parameter ?id=
Global/standard templatesDistinct URL variant ?fromGlobal=trueSame GET; governance.visibility.globallyVisible on the returned object
Channel filteringDedicated /findAll?channelTypes= endpointPer the Jira description, a query parameter on the standard GET (undeclared in the spec) — or use POST /search with a filters entry
Search sub-pathsearchContentTemplatessearch
findAll response shape{"data": [{"id": …, "name": …}], "errors": []} — data is a flat array [doc:turn1doc4]{"data": {"searchResults": [{"id": …, "name": …}], "hasMore": …, "totalHits": …}, "errors": []} — data is an object with pagination metadata
Response envelopedata + errorsdata + errors (+ metadata per APIResponse); all responses wrapped in a { "data": … } envelope per v3 convention
Pagination signalNot present on findAllhasMore, totalHits, default page size 100

7.3 Migration steps

  1. Change the base path from /api/v2/ to /api/v3/ and confirm your {env} token is in the v3 environment enum (§2).
  2. Move the template id out of the path. Replace GET /api/v2/contentTemplate/{templateId} with GET /api/v3/contentTemplate?id={templateId}.
  3. Retire the ?fromGlobal=true URL variant. Call the single GET and read governance.visibility.globallyVisible from the response. Confirm with the API owner whether a fromGlobal query parameter is actually accepted before depending on it.
  4. Retire /findAll?channelTypes=. Replace it with POST /api/v3/contentTemplate/search using a filters entry, or confirm the channelTypes query parameter with the API owner.
  5. Rename the search sub-path from searchContentTemplates to search. The sorts / page / filters body structure is unchanged in the documented examples.
  6. Update your search response parser. data is now an object, not an array. Read data.searchResults instead of data, and start consuming hasMore / totalHits.
  7. Adopt pagination. v2 findAll returned an unpaginated list. In v3, omitting page returns 100 results; loop on hasMore and increment page.page.
  8. Harden your GET parser. The full template object varies by template type, and content is an escaped JSON string that must be unescaped before parsing.
  9. Update error handling to the ErrorResponse / Error shape (id, code, message) and to the 400/401/403/404 set.
  10. Do not plan on v3 write operations. PUT, PATCH, and DELETE are not delivered. Keep using existing platform mechanisms for template mutation.

8. Reference

8.1 Documented filter fields

FieldSourceExample values
TEMPLATE_TYPEOperation documentCONTENT_TEMPLATE
PUBLISHER_STATUSOperation documentNot exemplified; the GET response exposes publisherStatus: "completed"

No complete list of filterable fields is published in any source.

8.2 Filter types

SourceValues
Operation document (behavioural)IN, GT, GTE, LT, LTE, NIN, BETWEEN, STARTS_WITH, CONTAINS, EQUALS, FILTER, EXISTS
sprinklr-v3.yaml — FilterType_FilterFILTER, LIMIT, SEARCH, MATCH_PHRASE_PREFIX, ADHOC_SEARCH, EXPRESSION, GEO_DISTANCE, ADVANCED_QUERY, MATCH_NONE, MATCH_ALL

The two lists overlap only on FILTER. See the discrepancy note in §5.1.

8.3 Sort keys and order

ItemDocumented valuesSpecification
sorts[].keyMODIFIED_TIME (only example given)Sort_request.key — bare string, no enum
sorts[].orderASC, DESCOrder_enums — bare string, no enum values declared

8.4 Observed enumerated values in the GET response

These values are observed in the reference example only; none is declared as an enum in the specification.

FieldObserved value
channelTypeEMAIL
accountTypes[]BULK_EMAIL
templateTypeCONTENT_TEMPLATE
contentTypePUBLISHING
publisherStatuscompleted
reportCONTENT_TEMPLATE

8.5 Schema index

SchemaUsed byNotes
APIResponseGET /contentTemplate 200{data, errors, metadata}; data untyped
PaginatedSearchResponsePOST /contentTemplate/search 200Abbreviated property names — see §5.3
RequestPOST /contentTemplate/search bodyGeneric, wide search/reporting request
Sort_requestRequest.sorts[]
Page_requestRequest.pagepage, size, skip, cursor
Filter_requestRequest.filters[]field, filterType, values, + many undocumented flags
FilterType_FilterFilter_request.filterTypeEnum — conflicts with the documented list
ErrorResponse / Error400/401/403/404

9. Use cases and best practices

9.1 Use cases

  • Template catalogue sync. Page through POST /contentTemplate/search with {} or a TEMPLATE_TYPE filter to mirror the id/name catalogue into an external CMS or DAM, then fetch full bodies on demand.
  • Most-recently-edited view. Sort by MODIFIED_TIME DESC with a small page.size to power a "recently updated templates" panel.
  • Channel-scoped picker. Filter the search results to the channel your integration publishes to, replacing the v2 findAll?channelTypes= call.
  • Template rendering/preview. Retrieve the full object with GET, unescape content, and hand the component tree to your renderer; use height, width, and locationUrl for layout and asset resolution.
  • Governance auditing. Read governance.visibility.globallyVisible, editDisabled, canEdit, archived, deleted, ownerUserId, and lastModifiedUserId to report on template access and lifecycle.

9.2 Best practices

  1. Search first, fetch second. The search response is a lightweight {id, name} list; the GET response can be hundreds of kilobytes because of the embedded content string. Do not fetch full bodies to build a list view.
  2. Always send page. Relying on the default of 100 makes your integration silently sensitive to a server-side default change.
  3. Loop on hasMore, verify against totalHits. Stop when hasMore is false; use totalHits for progress and sanity checks.
  4. Unescape content before parsing. It is a JSON string, not a nested object.
  5. Parse the GET response defensively. Per the source dev note, fields vary by template. Guard every field except id and name.
  6. Treat createdTime / modifiedTime as formatted strings. They arrive as Jun 12, 2026, 12:40:19 PM, not epoch milliseconds. Parse with an explicit format and confirm the emitting timezone with the API owner.
  7. Do not send Cookie: JSESSIONID=…. Authenticate with Authorization + Key only.
  8. Do not use undocumented Request properties. Only sorts, page, and filters are documented for this operation.
  9. Filter on the server. Send filters rather than pulling all templates and filtering client-side.
  10. Handle errors even on 200. The envelope carries an errors array independently of the HTTP status; check that it is empty before trusting data.
  11. Pin the environment. Ensure {env} matches your partition; a wrong environment yields 401/403 rather than empty results.