- V2 API reference: Custom Field | Sprinklr Developer Portal
A Custom Field is a fully customizable property or tag that can be created at several feature levels (for various assets) to organize and categorize content. Custom fields are managed in the Sprinklr UI under All Settings → Manage Workspace → Custom Fields, and through this API.
Custom Field V3 exposes create, read, and update on a single resource path — /api/v3/customField — differentiated by HTTP method:
| Operation | Method | Path |
|---|---|---|
| Create custom field | POST | /api/v3/customField |
| Fetch custom field | GET | /api/v3/customField?fieldName= or ?id= |
| Update custom field (v2-style merge) | PUT | /api/v3/customField?id= or ?fieldName= |
| Update custom field (partial / option edits) | PATCH | /api/v3/customField?id= or ?fieldName= |
This is the central design change from V2, which spread the same capabilities across four separate kebab-case paths (/api/v2/custom-field, /api/v2/custom-field/{customFieldName}, and the option-update endpoint). The V3 change set is:
- Kebab-case paths converted to camelCase (
custom-field→customField). - Path-based parameters replaced by query parameters, per V3 convention.
- No changes to request body fields for
POSTandPUTrequests.
For endpoint-level reference documentation, see the Custom Field V3 tag in the V3 OpenAPI specification (operationId values CustomFieldApiV3_getCustomField, CustomFieldApiV3_createCustomField, CustomFieldApiV3_updateCustomField, CustomFieldApiV3_patchCustomFieldOptions).
| Layer | Object | What it holds | Notes |
|---|---|---|---|
| Identity | id, fieldName, label | Sprinklr ID, API name (_c_…), and human-readable label | fieldName is generated by Sprinklr on create |
| Definition | type, assetTypes, description, category, enabled | What the field is and where it applies | type is the only required property in the schema |
| Options | values / valuesOptions | Picklist options | Applies only to PICKLIST and PICKLIST_MULTISELECT |
| Governance | visibility, permissions | Who sees and who can act on the field | |
| Behavior | customFieldControllerById, optionType, optionKey | Controlling-field (cascading picklist) configuration | |
| i18n | langVsTranslatedFieldValues | Per-language translated labels/values | |
| Audit | createdTime, modifiedTime | Epoch milliseconds | Read-only in practice |
A custom field is addressed in two ways, and the two are mutually exclusive:
- By field name —
fieldName, the API name, for example_c_62fc7b88b893784e3db68fa1 - By Sprinklr ID —
id, for example69f021fb6357c2c9885e0eb5
Both
fieldNameandidonGET,PUT, andPATCH, are "mutually exclusive with" the other. The acceptance criteria isGETby?fieldName=andPUT/PATCHby?id=; both parameters are accepted on all three methods per the specification.
To find fieldName in the UI: hamburger menu → All Settings → Custom Fields (under Manage Workspace) → three dots next to the field → Copy Field Name.
All API calls are sent to the production endpoint:
https://api3.sprinklr.com/{env}/api/v3So the custom field resource in production is:
https://api3.sprinklr.com/{env}/api/v3/customFieldReplace {env} with your assigned environment identifier (prod0, prod2, prod11, and so on — see APIs | Sprinklr Developer Portal for the environment list).
All Custom Field API calls are authenticated with OAuth 2.0. See API Overview for portal registration, API key and secret generation, and the Authorize flow.
| Header | Value | Purpose | Required on |
|---|---|---|---|
Authorization | Bearer {{accessToken}} | Authenticates the user with the server | All requests |
Key | {{apiKey}} | Authenticates the application with the server | All requests |
Content-Type | application/json | Declares the request body media type | POST, PUT, PATCH |
Accept | application/json | Declares the acceptable response type | All requests |
POST /api/v3/customField
Creates a new custom field. The request body is the CustomField schema and is unchanged from API v2.
| Parameter | Sub-parameter | Required | Type | Description |
|---|---|---|---|---|
type | Required | String | Data type of the field. Supported values: TEXT, PICKLIST, PICKLIST_MULTISELECT, NUMBER, DATE, TEXT_MULTI, TEXTAREA. The only field marked required in the V3 schema. | |
label | Required (v2 doc) | String | Label or tag for the custom field. | |
description | Optional | String | Description of the field. Should not exceed 500 characters. | |
assetTypes | Required (v2 doc) | Array[String] | Asset types the field applies to. See §8. | |
values | Optional | Array[KeyLabelPair] | Picklist options as { "key", "label" } pairs. | |
valuesOptions | Optional | Array[CustomFieldOption] | Picklist options with language-translation support, as { "label", "value", "langVsTranslatedFieldValues" }. Preferred on V3. | |
category | Optional | String | Category the field falls under. | |
enabled | Optional | Boolean | If true, the custom field is enabled. | |
visibility | Optional | Object | Visibility of the field. | |
globallyVisible | Optional | Boolean | If true, the field is visible across all users and workspaces. | |
visibilityConfig | Optional | Array[AssetShareConfig] | Sharing configuration. If visibilityConfig is defined, globallyVisible must be false. Each entry: type (CLIENT, CLIENT_GROUP, USER, USER_GROUP) and ids. | |
permissions | Optional | Array[Permission] | Permission levels on the field. | |
spaceType | Required | String | Space type, for example CLIENT, SPACE. | |
spaceId | Required | String | Space in which the permissions are granted. | |
permissionConfigs | Optional | Array | Permissions on the asset: permissions (List[String]; use ALL for all), type (CLIENT, CLIENT_GROUP, USER, USER_GROUP), ids. | |
optionType | Optional | String | Option type for the custom field, for example GENERAL. | |
optionKey | Optional | String | Option key for the custom field. | |
customFieldControllerById | Optional | Object | Controlling-field (cascading) configuration, keyed by the controlling custom field's id. | |
enableReverseMapping | Optional | Boolean | Enables reverse mapping on the controller. | |
controllingValues | Optional | Array[String] | Controlling values of the controller. | |
controllingFieldConfig | Optional | Map[String, Array[String]] | Maps each controlling value to the controlled values it exposes, for example {"option 1": ["test1"]}. | |
langVsTranslatedFieldValues | Optional | Map[String, Map[String, String]] | Translated fields, keyed by locale, for example {"es_ES": {"description": "…"}}. | |
id, fieldName, createdTime, modifiedTime | — | String / Integer(int64) | Present in the schema; server-generated. Do not send on create. |
Dev note: when applying controlling custom field logic, the asset type for both the controlling and the controlled custom field must be the same.
curl --location 'https://api3.sprinklr.com/{env}/api/v3/customField' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"type": "PICKLIST",
"label": "Buy text books",
"description": "Text books",
"assetTypes": [
"UNIVERSAL_CASE"
],
"valuesOptions": [
{ "label": "Hindi Book", "value": "Item3" },
{ "label": "English Book", "value": "Item4" },
{ "label": "Maths Book", "value": "Item5" }
],
"enabled": true,
"visibility": {
"globallyVisible": true,
"visibilityConfig": []
},
"permissions": [],
"optionType": "GENERAL"
}'The response remains wrapped in the { "data": { … }, "errors": [] } envelope, as in V2.
{
"data": {
"id": "6a15774f00f392c2e656e68b",
"fieldName": "_c_6a15774e00f392c2e656e688",
"label": "Buy text books",
"description": "Text books",
"assetTypes": [
"CASE"
],
"type": "PICKLIST",
"valuesOptions": [
{ "label": "Hindi Book", "value": "Item3" },
{ "label": "English Book", "value": "Item4" },
{ "label": "Maths Book", "value": "Item5" }
],
"enabled": true,
"visibility": {
"globallyVisible": true,
"visibilityConfig": []
},
"permissions": [],
"optionType": "GENERAL",
"createdTime": 1779791695119,
"modifiedTime": 1779791695119
},
"errors": []
}Both keys represent picklist options, and they have different shapes:
| Key | Item shape | Translation support |
|---|---|---|
values | { "key": "…", "label": "…" } (KeyLabelPair) | No |
valuesOptions | { "label": "…", "value": "…", "langVsTranslatedFieldValues": {…} } (CustomFieldOption) | Yes |
Note the inversion: values[].key carries the stored value, while valuesOptions[].value carries it. Do not map key → label positionally between the two.
PUT /api/v3/customField?id={customFieldId}
The fields present in the body are merged into the existing custom field. PUT retains full update semantics and that the request body fields are unchanged from V2.
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
id | String | Conditional | Custom field ID. Mutually exclusive with fieldName. | 69f021fb6357c2c9885e0eb5 |
fieldName | String | Conditional | Custom field API name. Mutually exclusive with id. | _c_62fc7b88b893784e3db68fa1 |
Supply exactly one of the two.
Only these fields are merged into the existing field when present:
| Parameter | Type | Description |
|---|---|---|
valuesOptions | Array[CustomFieldOption_metadata] | Replacement set of picklist options. Item fields: label, value, category, additional (Map[String,String]), langVsTranslatedFieldValues. |
description | String | Merged into the existing field when present. |
category | String | Merged into the existing field when present. |
enabled | Boolean | Merged into the existing field when present. |
assetTypes | Array[String] | Merged into the existing field when present. |
langVsTranslatedFieldValues | Map[String, Map[String, String]] | Merged into the existing field when present. |
type, label, and fieldName are not in the update schema. See the type-change caveat below.
curl --location --request PUT 'https://api3.sprinklr.com/{env}/api/v3/customField?id=69f021fb6357c2c9885e0eb5' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"description": "Updated description",
"category": "Support",
"enabled": true,
"assetTypes": [
"UNIVERSAL_CASE"
],
"valuesOptions": [
{ "label": "Yes", "value": "Yes" },
{ "label": "No", "value": "No" },
{ "label": "Maybe", "value": "Maybe" }
],
"langVsTranslatedFieldValues": {
"es_ES": { "description": "Descripción actualizada" }
}
}'PUT responds 204 No Content with no response body.
Updating the field type — for example PICKLIST → PICKLIST_MULTISELECT — is not supported. "the v2 api did not have support for updating the type. The same behaviour exists here as well."
What this means for you: do not send type in an update payload and do not rely on the response status to tell you a type change was rejected. If you need a different type, create a new custom field.
PATCH /api/v3/customField?id={customFieldId}
Adds new picklist options and deletes existing ones without resending the full option set, and optionally applies the same merge fields as PUT. The OpenAPI summary is "Partial update (picklist options and/or PUT-merge fields)".
Identical to PUT: id or fieldName, mutually exclusive.
| Parameter | Type | Description |
|---|---|---|
addedValuesOptions | Array[CustomFieldOption_metadata] | Adds new options to the existing option set. |
removedValuesOptions | Set[String] (LinkedHashSet<String>) | Removes existing options. |
valuesOptions | Array[CustomFieldOption_metadata] | Full option set, as on PUT. |
description | String | PUT-merge field. |
category | String | PUT-merge field. |
enabled | Boolean | PUT-merge field. |
assetTypes | Array[String] | PUT-merge field. |
langVsTranslatedFieldValues | Map[String, Map[String, String]] | PUT-merge field. |
CustomFieldOption_metadata item fields: label, value, category, additional (Map[String,String]), langVsTranslatedFieldValues.
curl --location --request PATCH 'https://api3.sprinklr.com/{env}/api/v3/customField?id=69f179317de8c9de2ad70475' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"addedValuesOptions": [
{ "label": "Optical1", "value": "test1" },
{ "label": "Optical2", "value": "test2" }
],
"removedValuesOptions": [
"Item5"
]
}'PATCH responds 204 No Content with no response body.
Only PICKLIST and PICKLIST_MULTISELECT field types support option updates via PATCH.
POST | PUT | PATCH | |
|---|---|---|---|
| Purpose | Create a new custom field | Merge-update the definition | Add/remove options, plus merge fields |
| Addressing | None — identity is generated | ?id= or ?fieldName= | ?id= or ?fieldName= |
| Body schema | CustomField | CustomFieldV3UpdateRequest | CustomFieldV3PatchRequest |
| Option semantics | Set at creation | valuesOptions — whole set | addedValuesOptions / removedValuesOptions — incremental |
Can change type | Yes (set at creation) | No | No |
| Success response | 200 + {data, errors} | 204, no body | 204, no body |
PUT and PATCH take different body schemas. You cannot reuse one payload for both methods.
Choosing the right option operation:
| Intent | Operation |
|---|---|
| Append one option to a large picklist | PATCH with addedValuesOptions |
| Retire a single option | PATCH with removedValuesOptions |
| Replace the entire option set with an authoritative list | PUT (or PATCH) with valuesOptions |
Using valuesOptions where you meant addedValuesOptions replaces the whole option set and drops every option you did not resend.
Fetches custom field details by field name or by ID. Replaces the V2 path-parameter endpoint.
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
fieldName | String | Optional | Custom field API name (for example _c_field). Mutually exclusive with id. | _c_62fc7b88b893784e3db68fa1 |
id | String | Optional | Custom field ID. Mutually exclusive with fieldName. | 6a15774f00f392c2e656e68b |
# By field name — the primary lookup per IN-12885
curl --location 'https://api3.sprinklr.com/{env}/api/v3/customField?fieldName=_c_62fc7b88b893784e3db68fa1' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Accept: application/json'# By ID
curl --location 'https://api3.sprinklr.com/{env}/api/v3/customField?id=6a15774f00f392c2e656e68b' \
--header 'Authorization: Bearer {{accessToken}}' \
--header 'Key: {{apiKey}}' \
--header 'Accept: application/json'The OpenAPI document types the GET 200 response as an array of CustomField, whereas POST returns a single CustomField. Handle the read response as a collection even when you addressed a single field.
{
"data": [
{
"id": "62fc7b88b893784e3db68fa6",
"fieldName": "_c_62fc7b88b893784e3db68fa1",
"label": "profile check",
"assetTypes": [
"PROFILE"
],
"type": "PICKLIST_MULTISELECT",
"values": [
{ "key": "Tag", "label": "Tag" },
{ "key": "Tag1", "label": "Tag1" }
],
"category": "",
"enabled": true,
"visibility": {
"globallyVisible": true,
"visibilityConfig": []
},
"permissions": []
}
],
"errors": []
}POST responses use the two-part envelope:
{
"data": { },
"errors": []
}| Field | Type | Description |
|---|---|---|
data | Object (or Array on GET) | The custom field object(s) |
errors | Array[Error] | Array of error objects; empty when there are no errors |
PUT and PATCH return no body.
| HTTP code | Method | Scenario |
|---|---|---|
200 OK | GET, POST | Success. Body contains the custom field. |
204 No Content | PUT, PATCH | Success. No response body. |
400 Bad Request | All | Invalid parameters, invalid body, or an unsupported operation such as an option edit on a non-picklist type. |
401 Unauthorized | All | Invalid or missing Authorization token. |
403 Forbidden | All | Insufficient permissions on the custom field or workspace. |
404 Not Found | All | No custom field matches the supplied fieldName or id. |
| V2 | V3 |
|---|---|
POST /api/v2/custom-field (create) | POST /api/v3/customField |
GET /api/v2/custom-field/{customFieldName} (fetch) | GET /api/v3/customField?fieldName= |
| Update Custom Field | PUT /api/v3/customField?id= |
| Update Options with Label (assign a new value or delete an existing value for a given custom field name) | PATCH /api/v3/customField?id= with addedValuesOptions / removedValuesOptions |
The single biggest structural change: V2 used path parameters on kebab-case paths (/custom-field/{customFieldName}); V3 uses query parameters on one camelCase path (/customField?fieldName=).
| Aspect | API V2 | API V3 | Impact |
|---|---|---|---|
| Path casing | custom-field | customField | Update every URL |
| Field addressing | Path parameter {customFieldName} | Query parameter ?fieldName= or ?id= | Update URL construction; id lookup is new |
| Create request body | CustomField | CustomField — unchanged | No payload migration needed for POST |
| Update request body | v2 merge fields | CustomFieldV3UpdateRequest — same fields | No payload migration needed for PUT |
| Update response | V2 response | 204, no body | Stop parsing the update response; treat 2xx as success |
| Option edits | Separate "Update Options with Label" endpoint | PATCH on the same resource | Consolidate to one path and one method |
| Option representation | values (key/label) | values and valuesOptions (value/label + translations) | Prefer valuesOptions for i18n |
| Create response option key | values | Echoes the key you sent (valuesOptions in, valuesOptions out) — fixed under IN-13195 | Parse defensively |
| Envelope | {data, errors} | {data, errors} — unchanged for POST | No change |
| Type | Description |
|---|---|
PICKLIST | Select only one value from the available options. |
PICKLIST_MULTISELECT | Select more than one value from the available options. |
NUMBER | Value in numerical form — phone number, employee ID, and similar. |
DATE | A calendar picker; for example purchase date, complaint date, completion date. |
TEXT | Text details — name, customer ID, description. |
TEXTAREA | Same as text but holds greater length. |
TEXT_MULTI | Like a multi-picklist, but no values are defined at creation; options are created on the go. |
Only PICKLIST and PICKLIST_MULTISELECT accept option definitions and option updates.
ACCOUNT, OUTBOUND_MESSAGE, MESSAGE, PROFILE, MEDIA_ASSET, USER, CAMPAIGN, SUB_CAMPAIGN, COMMUNITY, PRODUCT, PAID_INITIATIVE, AD_SET, AD_VARIANT, CASE, UNIVERSAL_CASE, SURVEY, TASK.
Issue a single POST /api/v3/customField with type: "PICKLIST", the target assetTypes, and the full valuesOptions set. Capture data.fieldName (_c_…) from the response and store it — it is the addressing key for every later read and update, and it is also the key you use when writing values onto a profile or case.
Do not GET, mutate, and PUT the whole option list — a concurrent editor's option would be lost. Use:
{ "addedValuesOptions": [ { "label": "Priority Support", "value": "priority_support" } ] }PATCH takes a distributed lock on the field (added under IN-13211), so concurrent adds do not clobber each other.
{ "removedValuesOptions": ["legacy_plan"] }Removing an option does not delete the field. If you need the whole field out of circulation, PATCH with {"enabled": false} instead — there is no delete endpoint.
Translations live in langVsTranslatedFieldValues, at both field level and option level:
{
"valuesOptions": [
{
"label": "Hindi Book",
"value": "Item3",
"langVsTranslatedFieldValues": {
"es_ES": { "label": "Libro de hindi" }
}
}
],
"langVsTranslatedFieldValues": {
"es_ES": { "description": "Descripción actualizada" }
}
}This is exactly why valuesOptions exists alongside values: KeyLabelPair has no translation slot.
Set customFieldControllerById, keyed by the controlling field's id, on the controlled field:
{
"customFieldControllerById": {
"66b0b924b8f96b59e3003ce3": {
"controllingFieldConfig": {
"option 1": ["test1"],
"option 2": ["test2"]
}
}
}
}When option 1 is selected on the controlling field, only test1 is offered on this field. Both fields must share the same asset type.
GET /api/v3/customField?fieldName=_c_62fc7b88b893784e3db68fa1 returns the definition, including type — check it before sending option edits, since only PICKLIST and PICKLIST_MULTISELECT accept them.
When your system owns the complete option set (for example, a product catalog), compute the delta and send one PATCH:
{
"addedValuesOptions": [
{ "label": "Model X2", "value": "model_x2" }
],
"removedValuesOptions": ["model_w1"]
}A delta PATCH is safer than a wholesale valuesOptions replacement because it leaves options added by other systems intact.
Method selection
PUTandPATCHtake different body schemas. Payloads are not interchangeable.- Use
PATCHfor incremental option work; reserve fullvaluesOptionsreplacement for when you own the entire list. - There is no delete. Plan for
enabled: falseas the retirement mechanism.
Identifiers
fieldNameandidare mutually exclusive onGET,PUT, andPATCH. Send exactly one.fieldNamevalues are prefixed_c_. Copy them from the create response or from the UI (Copy Field Name).- Send option
value/keyas strings, not numbers (IN-13205).
Types
typecannot be changed after creation. Create a new field instead.- Option fields are meaningful only for
PICKLISTandPICKLIST_MULTISELECT.
Response handling
- Treat
200(read/create) and204(update) both as success; do not assert on a single status code. - Do not attempt to parse an update response body — there is none.
- Accept both
valuesandvaluesOptionswhen reading options, and mind thekey↔valueinversion. - Do not assume
assetTypesround-trips exactly as sent.
Governance
- If
visibilityConfigis populated,globallyVisiblemust befalse. permissions[].spaceTypeandpermissions[].spaceIdare both required whenever aPermissionentry is supplied.
Constraints carried from V2
descriptionshould not exceed 500 characters.- A controlling field and its controlled field must share the same asset type.
All JSON payloads in this guide are illustrative examples. 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.