Standard entities are Sprinklr's pre-defined structured objects. They work like cases and messages, but they exist so you can store and manage your own external data inside the platform using a defined schema.
The Standard Entity API 3.0 gives you full CRUD across three layers: the definition that describes an entity type, the fields that make up its schema, and the records that hold your data.
A standard entity has three parts, and every integration works with all three:
| Layer | What it holds | What you can do |
|---|---|---|
| Definition | The entity type itself, such as _s_Consent. Its name, description, icon, and permission settings. | Read |
| Field | One column on a definition. Has an API name, a data type, and optional picklist values, defaults, and constraints. | Create, read, update, delete |
| Record | One row of data stored against a definition. | Create, read, update, patch, upsert, delete |
Definitions are created and managed in Entity Studio. This API reads them; it does not create them. Fields and records are fully manageable through the API.
Related Knowledge Base Article Entity Studio - An Overview
The platform uses two prefixes consistently, and recognising them makes the API much easier to read:
| Prefix | Means | Example |
|---|---|---|
_s_ | A standard, platform-supplied entity type or field | _s_Consent |
_c_ | A custom field you created | _c_ConsentName |
Three identifiers appear across this API. They are not interchangeable:
| Identifier | Identifies | Notes |
|---|---|---|
entityDefinitionId / entityType | A definition, such as _s_Consent | Also travels in a record payload as type |
entityId | A record | One of the record's primary fields. You may set it yourself at create time; if you do not, the platform generates one |
recordId | A record | An alternative record lookup key |
The Standard Entity API 3.0 is available on Core, Care, and Lite editions and is enabled by default. No configuration is required.
https://api3.sprinklr.com/{env}/api/v3/standardEntityReplace {env} with the environment your Sprinklr workspace is hosted in:
prod, prod0, prod2, prod3, prod4, prod5, prod6, prod8, prod11, prod12, prod15, prod16, prod17, prod18, prod19, prod21, prod25
Calling a different environment with otherwise valid credentials returns 401 Unauthorized. If you are seeing unexplained 401 responses, check the environment first.
Every request must carry both an access token and an API key. Sending only one of them is the most common cause of a 401 for developers new to the platform.
| Header | Value | Required |
|---|---|---|
Authorization | Bearer {{accessToken}} | Yes |
Key | {{apiKey}} | Yes |
Content-Type | application/json | On requests with a body |
Accept | application/json | Recommended |
Each API key supports one active token pair. Generating a new access token invalidates the previous one. If two services share an API key, refreshing the token for one will break the other. Give each integration its own key.
A typical integration works top-down:
- Read the definition to learn what entity type you are working with.
- Read the fields to learn the schema — what columns exist, which are mandatory, what types they hold.
- Add any custom fields your integration needs.
- Read and write records against that schema.
You only need steps 1 to 3 once, at setup. Steps 4 runs continuously.
The following paths and methods are supported:
| Path | Methods |
|---|---|
/standardEntity/definition | GET |
/standardEntity/field | GET, POST, PUT, DELETE |
/standardEntity/record | GET, POST, PUT, PATCH, DELETE |
/standardEntity/record/upsert | POST |
Retrieve the definition of a standard platform entity by entity type.
GET /api/v3/standardEntity/definition| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
entityType | query | string | Yes | The entity type to fetch, for example _s_Consent. Supported entity Ids: _s_Consent, _s_PublishingQueue, _s_ConsentCatalogue, _s_PriceBook, _s_PublisherSettings |
Request
curl -X GET \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/definition?entityType=_s_Consent' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Accept: application/json'Response fields
| Field | Type | Description |
|---|---|---|
id | string | Id of the definition |
name | string | Name for the entity |
pluralName | string | Plural name for the entity |
description | string | Description for the entity |
baseDefinitionId | string | Id of the base entity definition, if this is an extended entity |
icon | string | Icon for the entity |
permissionEnabled | boolean | Whether the entity is permission controlled |
script | string | Script for external entity |
scriptVersion | string | Script version. A compiled script is cached for some time; to update the script, update the version |
createdTime | integer (int64) | Created time, epoch milliseconds |
modifiedTime | integer (int64) | Last modified time, epoch milliseconds |
Fetch fields by ID or by field name, with pagination.
GET /api/v3/standardEntity/field| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
fieldId | query | string | Conditional | Comma-separated list of field IDs |
fieldName | query | string | Conditional | Field name |
entityDefinitionId | query | string | Conditional | The definition the field belongs to. Required when identifying a field by fieldName |
pageNumber | query | integer | No | Page number, 0-based |
pageSize | query | integer | No | Number of results per page. Maximum 100 |
Supply exactly one identifier — fieldId or fieldName, never both and never neither. Supplying both returns 400; supplying neither also returns 400.
Field names are unique only within a definition, so when you look a field up by fieldName you must also send entityDefinitionId.
Request
curl -X GET \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/field?fieldName=_c_ConsentName&entityDefinitionId=_s_Consent' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Accept: application/json'Returns an array of field objects. See Field reference.
POST /api/v3/standardEntity/fieldSend the field definition in the request body. There are no query parameters.
| Body field | Type | Required | Description |
|---|---|---|---|
apiName | string | Yes | The API name for the field. Prefix custom fields with _c_ |
name | string | No | A human-readable name describing the field's purpose |
type | string | Yes | The field's data type. Supported values include TEXT, DATE, BOOLEAN, NUMBER, DOUBLE, INTEGER |
entityDefinitionId | string | Yes | The definition to add the field to |
Request
curl -X POST \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/field' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Content-Type: application/json' \
-d '{
"apiName": "_c_ConsentName",
"name": "User Consent Name",
"type": "TEXT",
"entityDefinitionId": "_s_Consent"
}'Returns the created field, including its generated id. Store that id — it is the most reliable way to reference the field later.
PUT /api/v3/standardEntity/field| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
fieldId | query | string | Conditional | The field ID |
fieldName | query | string | Conditional | The field name |
entityDefinitionId | query | string | Conditional | Required when using fieldName |
Send the updated field object in the request body. Identify the field by either fieldId or fieldName, not both.
Request
curl -X PUT \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/field?fieldName=_c_ConsentName&entityDefinitionId=_s_Consent' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Content-Type: application/json' \
-d '{
"apiName": "_c_ConsentName",
"name": "Consent Full Name",
"type": "TEXT",
"entityDefinitionId": "_s_Consent"
}'DELETE /api/v3/standardEntity/field| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | query | string | Conditional | Comma-separated list of field IDs |
fieldName | query | string | Conditional | The field name |
entityDefinitionId | query | string | Conditional | Required when using fieldName |
Request
curl -X DELETE \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/field?id=0000000000000000000000a1,0000000000000000000000a2&entityDefinitionId=_s_Consent' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}'Deleting a field removes it from the definition. Data stored in that field on existing records is no longer retrievable through the API. Confirm before you delete.
Fetch records by entity ID, record ID, primary key, or primary key prefix.
GET /api/v3/standardEntity/record| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
entityType | query | string | Yes | The definition to search in, for example _s_Consent |
entityId | query | string | Conditional | Comma-separated list of entity IDs |
recordId | query | string | Conditional | Comma-separated list of record IDs |
primaryKey | query | string | Conditional | Primary key exact lookup |
primaryKeyPrefix | query | string | Conditional | Primary key prefix lookup |
pageNumber | query | integer | No | Page number, 0-based |
pageSize | query | integer | No | Number of results per page. Maximum 100 |
Always send entityType, plus exactly one of entityId, recordId, or primaryKey. entityType tells the platform which definition to look in; the identifier tells it which record.
Primary key lookup only works on entity types that have primary key columns defined. Types without them return 400.
Request
curl -X GET \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/record?entityType=_s_Consent&entityId=6321e6684eed2b006dc0abdb' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Accept: application/json'POST /api/v3/standardEntity/recordSend the record in the request body. There are no query parameters.
Request
curl -X POST \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/record' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Content-Type: application/json' \
-d '{
"type": "_s_Consent",
"entityId": "consent-jane-doe-001",
"identityType": "PHONE",
"identityId": "15550100",
"channel": "FACEBOOK"
}'The exact payload depends on the definition. type always carries the definition id. The remaining fields are the fields defined on that definition — read them first with Fetch fields, and note which are marked mandatory.
Some fields on a definition are primary fields. On _s_Consent, these are identityType, identityId, and channel.
At least one primary field must be present on every create and update, and the primary fields you send on update must match those you sent on create. Changing a primary field does not edit the record — it fails to match the original record entirely. This is the single most common source of updates that appear to do nothing.
If you do not supply an entityId, the platform generates one and returns it in the response. Setting a meaningful entityId yourself — one derived from your own system's key — makes every later lookup, update, and upsert simpler.
PUT /api/v3/standardEntity/record| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
entityType | query | string | Yes | The definition |
entityId | query | string | Conditional | The entity ID |
recordId | query | string | Conditional | The record ID |
PUT replaces the record with the body you send. Include the primary fields, and make sure they match the values used at create time.
curl -X PUT \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/record?entityType=_s_Consent&entityId=consent-jane-doe-001' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Content-Type: application/json' \
-d '{
"type": "_s_Consent",
"entityId": "consent-jane-doe-001",
"identityType": "PHONE",
"identityId": "15550100",
"channel": "FACEBOOK"
}'PATCH /api/v3/standardEntity/recordTakes the same query parameters as PUT, but the body names only the fields you want to change.
| Body field | Type | Required | Description |
|---|---|---|---|
updateFields | array | Yes | List of updates to apply |
updateFields[].fieldName | string | Yes | The field to change |
updateFields[].value | any | Yes | The new value |
updateFields[].op | string | Yes | The operation to apply. One of FIND, INSERT, PATCH, UPDATE, DELETE |
Request
curl -X PATCH \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/record?entityType=_s_Consent&entityId=consent-jane-doe-001' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Content-Type: application/json' \
-d '{
"updateFields": [
{ "fieldName": "_c_ConsentName", "value": "Jane Doe", "op": "UPDATE" }
]
}'Prefer PATCH over PUT for routine writes. It touches only the fields you name, it does not require you to reconstruct the whole record, and it avoids accidentally clearing a field you forgot to include.
POST /api/v3/standardEntity/record/upsertCreates the record if it does not exist, updates it if it does. Send the record in the request body; there are no query parameters.
curl -X POST \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/record/upsert' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Content-Type: application/json' \
-d '{
"type": "_s_Consent",
"entityId": "consent-jane-doe-001",
"identityType": "PHONE",
"identityId": "15550100",
"channel": "FACEBOOK"
}'Upsert is the right choice for synchronisation jobs, where you do not know or do not care whether a record already exists.
DELETE /api/v3/standardEntity/record| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
entityType | query | string | Yes | The definition |
entityId | query | string | Conditional | Comma-separated list of entity IDs |
recordId | query | string | Conditional | Comma-separated list of record IDs |
curl -X DELETE \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/record?entityType=_s_Consent&entityId=consent-jane-doe-001,consent-jane-doe-002' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}'When you delete several records in one call, some may succeed while others fail. The response reports both outcomes:
{
"data": [
{ "id": "consent-jane-doe-001", "message": "Successfully Deleted" }
],
"errors": [
{
"id": "0000000000000000000000a1",
"code": 404,
"message": "StandardEntity not found for entityId: 'consent-jane-doe-002'. Verify the standardEntity exists and you have access permissions."
}
]
}Always inspect both data and errors after a multi-record delete. The HTTP status alone does not tell you whether every record was removed.
| Field | Type | Description |
|---|---|---|
id | string | Id of the field |
apiName | string | API name for the field |
name | string | Name of the field |
description | string | Description of the field |
type | string | Type of the field |
entityDefinitionId | string | Id of the definition this field is a part of |
lookupType | string | For a LOOKUP field, which entity is the reference for lookup |
parentChild | boolean | For a LOOKUP field with a parent-child relationship, whether the entity holding the referenced value is deleted when the referenced entity is deleted |
form | object | For a FORM field, its definition |
multivalued | boolean | Whether the field holds multiple values |
mandatory | boolean | Whether the field is mandatory |
controllingField | string | The id of the field controlling this field's values, if any |
picklistValues | array | Picklist values defined for the field, if any |
defaultValue | any | Default value for the field, if any |
additional | object | Additional information based on the field's type |
langVsTranslatedFieldValues | object | Translated field values, keyed by language code |
Check mandatory before writing records — a mandatory field must be present in every record write for that definition.
| Field | Type | Description |
|---|---|---|
id | string | Platform identifier for the record |
entityId | string | Entity identifier. Settable at create time |
type | string | The definition id |
baseType | string | The base definition id, for extended entities |
name | string | Record name |
image | string | Image associated with the record |
detail | string | Record detail |
values | object | Field values held on the record |
processedValues | object | Processed field values |
tags | array of string | Tags applied to the record |
archived | boolean | Whether the record is archived |
entityPriority | integer | Record priority |
createdBy | integer (int64) | User who created the record |
canEdit | boolean | Whether the caller can edit this record |
importId | string | Import identifier, if the record arrived through an import |
langVsTranslatedFieldValues | object | Translated field values, keyed by language code then field |
entityMetadata | object | Record metadata |
shares | object | Sharing configuration |
scorecard | object | Scorecard associated with the record |
All responses use the standard envelope:
{
"data": {},
"errors": [],
"metadata": {}
}Each entry in errors has this shape:
| Field | Type | Description |
|---|---|---|
id | string | 24-character hex ObjectId for the error occurrence |
code | integer | The status code |
message | string | A dotted error key or a descriptive message |
| Code | Meaning | Common causes |
|---|---|---|
200 | Success | |
400 | Bad request | No identifier supplied, two identifiers supplied where one is allowed, pageSize above 100, negative pageNumber, primary key lookup on a type without primary keys |
401 | Unauthorized | Missing, expired, or mismatched credentials; wrong {env} in the URL |
403 | Forbidden | The API key owner lacks permission on the definition |
404 | Not found | The field or record does not exist, or is not visible to you |
The Standard Entity API returns detailed, specific error messages that name the offending parameter and state the constraint. Log them and show them to your users rather than replacing them with a generic message.
API 2.0 carried every identifier in the URL path. API 3.0 moves every identifier into a query parameter, leaving stable, predictable resource paths. Field and payload names are unchanged.
There is also a spelling change that is easy to overlook: the path segment was standard-entity in API 2.0 and is standardEntity in API 3.0.
| Operation | API 2.0 | API 3.0 |
|---|---|---|
| Fetch definition | GET /api/v2/standard-entity/definition/{entityDefinitionId} | GET /api/v3/standardEntity/definition?entityType= |
| Create field | POST /api/v2/standard-entity/field/{entityDefinitionId} | POST /api/v3/standardEntity/field |
| Fetch fields | GET /api/v2/standard-entity/field/... | GET /api/v3/standardEntity/field?entityDefinitionId= |
| Fetch field by API name | GET /api/v2/standard-entity/field/... | GET /api/v3/standardEntity/field?fieldName=&entityDefinitionId= |
| Update field | PUT /api/v2/standard-entity/field/... | PUT /api/v3/standardEntity/field?fieldName=&entityDefinitionId= |
| Create record | POST /api/v2/standard-entity/entity/... | POST /api/v3/standardEntity/record |
| Fetch record by entity id | GET /api/v2/standard-entity/entity/... | GET /api/v3/standardEntity/record?entityType=&entityId= |
| Fetch record by primary key | GET /api/v2/standard-entity/entity/... | GET /api/v3/standardEntity/record?entityType=&primaryKey= |
| Fetch record by primary key prefix | GET /api/v2/standard-entity/entity/... | GET /api/v3/standardEntity/record?entityType=&primaryKeyPrefix= |
| Update record | PUT /api/v2/standard-entity/entity/{entityDefinitionId}/{entityId} | PUT /api/v3/standardEntity/record?entityType=&entityId= |
| Partial update | PUT /api/v2/standard-entity/entity/... | PATCH /api/v3/standardEntity/record?entityType=&entityId= |
| Delete record | DELETE /api/v2/standard-entity/entity/... | DELETE /api/v3/standardEntity/record?entityType=&entityId= |
| Upsert by entity id | POST /api/v2/standard-entity/entity/upsert/{entityDefinitionId}/{entityId} | POST /api/v3/standardEntity/record/upsert |
| Upsert by primary key | POST /api/v2/standard-entity/entity/upsert/... | POST /api/v3/standardEntity/record/upsert |
Fourteen API 2.0 endpoints become eleven API 3.0 operations. Two consolidations do the work:
- The three record fetches — by entity id, by primary key, by primary key prefix — become one
GET /standardEntity/recorddistinguished by which query parameter you send. - The two upserts — by entity id and by primary key — become one
POST /standardEntity/record/upsert.
curl -X GET \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/field?entityDefinitionId=_s_Consent&pageNumber=0&pageSize=100' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}'Look at mandatory and type on every field returned. Those two properties tell you exactly what a valid record payload must contain.
curl -X POST \
'https://api3.sprinklr.com/{env}/api/v3/standardEntity/field' \
-H 'Authorization: Bearer {{accessToken}}' \
-H 'Key: {{apiKey}}' \
-H 'Content-Type: application/json' \
-d '{
"apiName": "_c_LoyaltyTier",
"name": "Loyalty Tier",
"type": "TEXT",
"entityDefinitionId": "_s_Consent"
}'Use POST /standardEntity/record/upsert with an entityId derived from your own system's primary key. Every sync run then becomes idempotent — no existence check, no branch between create and update.
Use PATCH with a single entry in updateFields. This is safer than PUT, which replaces the whole record.
Start at pageNumber=0, request pageSize=100, and stop when a page returns fewer than 100 results.
- Set your own
entityIdat create time. Derive it from your source system's key. Every later lookup, update, upsert, and delete becomes trivial, and your integration stops needing a local id mapping table. - Read the field list before you write records. The
mandatoryflag is the authoritative list of what a payload must contain — do not hard-code it. - Prefer
PATCHtoPUT. It avoids clearing fields you forgot to include and avoids the primary-field matching trap. - Prefer
upsertfor synchronisation jobs. It removes an entire round trip and a race condition. - Never change a primary field on an update. It will not update the record.
- Give every integration its own API key. Sharing a key across services means refreshing one token silently breaks the others.
- Cache the definition and field list. They change rarely. Re-reading them on every record write is wasted latency.
- Store the field
idreturned at create time. Referencing a field byidavoids having to sendentityDefinitionIdalongsidefieldNameon every call. - Check
dataanderrorson every multi-id call. Partial success is a normal outcome, not an edge case. - Batch conservatively. Comma-separated id lists are supported, but keep them to a reasonable size so that a partial failure is easy to interpret and retry.
| Message or symptom | Cause | Fix |
|---|---|---|
Valid query params must be provided for standardEntityField retrieval. Provide one from: 'fieldName' or 'id' along with any additional required param as per documentation. | No field identifier was sent | Send either fieldName (with entityDefinitionId) or the field id |
Only one of 'fieldName' or 'id' can be provided for StandardEntityField retrieval. Provided: 'fieldName' and 'id'. Choose the appropriate identifier. | Both identifiers were sent | Send exactly one |
Valid query params must be provided for standardEntity retrieval. Provide one from: 'recordId' or 'entityId' or 'primaryKey' along with any additional required param as per documentation. | No record identifier was sent | Send one of recordId, entityId, or primaryKey, together with entityType |
Invalid 'pageSize' parameter. Must be a positive integer not exceeding 100. | Page size above 100, or zero or negative | Use a value from 1 to 100 |
Invalid 'pageNumber' parameter. Must be a non-negative integer (page number begins with 0). | Page number is negative, or your client starts paging at 1 | Start at 0 |
Entity type _s_SurveyResponseTranslation does not have primary key columns defined | Primary key lookup attempted on a type with no primary keys | Look the record up by entityId or recordId instead |
StandardEntityField not found for fieldName: '...'. Verify the standardEntityField exists and you have access permissions. | The field does not exist on that definition, or you cannot see it | Check the apiName spelling and the entityDefinitionId; confirm the key owner's permissions |
StandardEntity not found for entityId: '...'. Verify the standardEntity exists and you have access permissions. | The record does not exist, or you cannot see it | Confirm the entityId and entityType; confirm permissions |
401 Unauthorized on every call | Missing Key header, expired token, or wrong {env} | Send both Authorization and Key; confirm the environment; regenerate the token if older than 30 days |
401 appearing intermittently across services | Two services share one API key, and each token refresh invalidates the other | Issue a separate API key per integration |
| An update returns success but the record is unchanged | A primary field value differs from the one used at create time, so no record matched | Keep identityType, identityId, and channel identical to the create call |
A PUT cleared fields you did not intend to change | PUT replaces the whole record | Use PATCH with updateFields |
| A multi-record delete "succeeded" but records remain | Delete reports per-record outcomes | Read the errors array as well as data |