Skip to content

Custom Field API V3 — Developer Guide


1. Overview

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:

OperationMethodPath
Create custom fieldPOST/api/v3/customField
Fetch custom fieldGET/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 POST and PUT requests.

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).

1.1 The custom field data model

LayerObjectWhat it holdsNotes
Identityid, fieldName, labelSprinklr ID, API name (_c_…), and human-readable labelfieldName is generated by Sprinklr on create
Definitiontype, assetTypes, description, category, enabledWhat the field is and where it appliestype is the only required property in the schema
Optionsvalues / valuesOptionsPicklist optionsApplies only to PICKLIST and PICKLIST_MULTISELECT
Governancevisibility, permissionsWho sees and who can act on the field
BehaviorcustomFieldControllerById, optionType, optionKeyControlling-field (cascading picklist) configuration
i18nlangVsTranslatedFieldValuesPer-language translated labels/values
AuditcreatedTime, modifiedTimeEpoch millisecondsRead-only in practice

1.2 Addressing a custom field

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 example 69f021fb6357c2c9885e0eb5

Both fieldName and id on GET, PUT, and PATCH, are "mutually exclusive with" the other. The acceptance criteria is GET by ?fieldName= and PUT/PATCH by ?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.


2. Base URLs and environments

All API calls are sent to the production endpoint:

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

So the custom field resource in production is:

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

Replace {env} with your assigned environment identifier (prod0, prod2, prod11, and so on — see APIs | Sprinklr Developer Portal for the environment list).

3. Authentication and common headers

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.

HeaderValuePurposeRequired on
AuthorizationBearer {{accessToken}}Authenticates the user with the serverAll requests
Key{{apiKey}}Authenticates the application with the serverAll requests
Content-Typeapplication/jsonDeclares the request body media typePOST, PUT, PATCH
Acceptapplication/jsonDeclares the acceptable response typeAll requests

4. Write operations

4.1 Create a custom field

POST /api/v3/customField

Creates a new custom field. The request body is the CustomField schema and is unchanged from API v2.

Request body

ParameterSub-parameterRequiredTypeDescription
typeRequiredStringData type of the field. Supported values: TEXT, PICKLIST, PICKLIST_MULTISELECT, NUMBER, DATE, TEXT_MULTI, TEXTAREA. The only field marked required in the V3 schema.
labelRequired (v2 doc)StringLabel or tag for the custom field.
descriptionOptionalStringDescription of the field. Should not exceed 500 characters.
assetTypesRequired (v2 doc)Array[String]Asset types the field applies to. See §8.
valuesOptionalArray[KeyLabelPair]Picklist options as { "key", "label" } pairs.
valuesOptionsOptionalArray[CustomFieldOption]Picklist options with language-translation support, as { "label", "value", "langVsTranslatedFieldValues" }. Preferred on V3.
categoryOptionalStringCategory the field falls under.
enabledOptionalBooleanIf true, the custom field is enabled.
visibilityOptionalObjectVisibility of the field.
globallyVisibleOptionalBooleanIf true, the field is visible across all users and workspaces.
visibilityConfigOptionalArray[AssetShareConfig]Sharing configuration. If visibilityConfig is defined, globallyVisible must be false. Each entry: type (CLIENT, CLIENT_GROUP, USER, USER_GROUP) and ids.
permissionsOptionalArray[Permission]Permission levels on the field.
spaceTypeRequiredStringSpace type, for example CLIENT, SPACE.
spaceIdRequiredStringSpace in which the permissions are granted.
permissionConfigsOptionalArrayPermissions on the asset: permissions (List[String]; use ALL for all), type (CLIENT, CLIENT_GROUP, USER, USER_GROUP), ids.
optionTypeOptionalStringOption type for the custom field, for example GENERAL.
optionKeyOptionalStringOption key for the custom field.
customFieldControllerByIdOptionalObjectControlling-field (cascading) configuration, keyed by the controlling custom field's id.
enableReverseMappingOptionalBooleanEnables reverse mapping on the controller.
controllingValuesOptionalArray[String]Controlling values of the controller.
controllingFieldConfigOptionalMap[String, Array[String]]Maps each controlling value to the controlled values it exposes, for example {"option 1": ["test1"]}.
langVsTranslatedFieldValuesOptionalMap[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.

Request

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"
}'

Response — 200 OK

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": []
}

⚠️ values vs valuesOptions — read this before you parse the response

Both keys represent picklist options, and they have different shapes:

KeyItem shapeTranslation 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.


4.2 Update a custom field — full (merge) update

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.

Query parameters

ParameterTypeRequiredDescriptionExample
idStringConditionalCustom field ID. Mutually exclusive with fieldName.69f021fb6357c2c9885e0eb5
fieldNameStringConditionalCustom field API name. Mutually exclusive with id._c_62fc7b88b893784e3db68fa1

Supply exactly one of the two.

Request body — CustomFieldV3UpdateRequest

Only these fields are merged into the existing field when present:

ParameterTypeDescription
valuesOptionsArray[CustomFieldOption_metadata]Replacement set of picklist options. Item fields: label, value, category, additional (Map[String,String]), langVsTranslatedFieldValues.
descriptionStringMerged into the existing field when present.
categoryStringMerged into the existing field when present.
enabledBooleanMerged into the existing field when present.
assetTypesArray[String]Merged into the existing field when present.
langVsTranslatedFieldValuesMap[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.

Request

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" }
  }
}'

Response

PUT responds 204 No Content with no response body.

⚠️ Changing type is not supported

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.


4.3 Update a custom field — partial update and option edits

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)".

Query parameters

Identical to PUT: id or fieldName, mutually exclusive.

Request body — CustomFieldV3PatchRequest

ParameterTypeDescription
addedValuesOptionsArray[CustomFieldOption_metadata]Adds new options to the existing option set.
removedValuesOptionsSet[String] (LinkedHashSet<String>)Removes existing options.
valuesOptionsArray[CustomFieldOption_metadata]Full option set, as on PUT.
descriptionStringPUT-merge field.
categoryStringPUT-merge field.
enabledBooleanPUT-merge field.
assetTypesArray[String]PUT-merge field.
langVsTranslatedFieldValuesMap[String, Map[String, String]]PUT-merge field.

CustomFieldOption_metadata item fields: label, value, category, additional (Map[String,String]), langVsTranslatedFieldValues.

Request

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"
  ]
}'

Response

PATCH responds 204 No Content with no response body.

⚠️ Only PICKLIST and PICKLIST_MULTISELECT support option updates

Only PICKLIST and PICKLIST_MULTISELECT field types support option updates via PATCH.


4.4 Method comparison — when to use which

POSTPUTPATCH
PurposeCreate a new custom fieldMerge-update the definitionAdd/remove options, plus merge fields
AddressingNone — identity is generated?id= or ?fieldName=?id= or ?fieldName=
Body schemaCustomFieldCustomFieldV3UpdateRequestCustomFieldV3PatchRequest
Option semanticsSet at creationvaluesOptions — whole setaddedValuesOptions / removedValuesOptions — incremental
Can change typeYes (set at creation)NoNo
Success response200 + {data, errors}204, no body204, no body

PUT and PATCH take different body schemas. You cannot reuse one payload for both methods.

Choosing the right option operation:

IntentOperation
Append one option to a large picklistPATCH with addedValuesOptions
Retire a single optionPATCH with removedValuesOptions
Replace the entire option set with an authoritative listPUT (or PATCH) with valuesOptions

Using valuesOptions where you meant addedValuesOptions replaces the whole option set and drops every option you did not resend.


5. Read operations

5.1 GET /api/v3/customField — Fetch a custom field

Fetches custom field details by field name or by ID. Replaces the V2 path-parameter endpoint.

ParameterTypeRequiredDescriptionExample
fieldNameStringOptionalCustom field API name (for example _c_field). Mutually exclusive with id._c_62fc7b88b893784e3db68fa1
idStringOptionalCustom 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'

Response — 200 OK

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": []
}

6. Response format and status codes

6.1 The V3 envelope

POST responses use the two-part envelope:

{
  "data": { },
  "errors": []
}
FieldTypeDescription
dataObject (or Array on GET)The custom field object(s)
errorsArray[Error]Array of error objects; empty when there are no errors

PUT and PATCH return no body.

6.2 Response codes

HTTP codeMethodScenario
200 OKGET, POSTSuccess. Body contains the custom field.
204 No ContentPUT, PATCHSuccess. No response body.
400 Bad RequestAllInvalid parameters, invalid body, or an unsupported operation such as an option edit on a non-picklist type.
401 UnauthorizedAllInvalid or missing Authorization token.
403 ForbiddenAllInsufficient permissions on the custom field or workspace.
404 Not FoundAllNo custom field matches the supplied fieldName or id.

7. V2 → V3 migration

7.1 Endpoint mapping

V2V3
POST /api/v2/custom-field (create)POST /api/v3/customField
GET /api/v2/custom-field/{customFieldName} (fetch)GET /api/v3/customField?fieldName=
Update Custom FieldPUT /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=).

7.2 What changed and what did not

AspectAPI V2API V3Impact
Path casingcustom-fieldcustomFieldUpdate every URL
Field addressingPath parameter {customFieldName}Query parameter ?fieldName= or ?id=Update URL construction; id lookup is new
Create request bodyCustomFieldCustomField — unchangedNo payload migration needed for POST
Update request bodyv2 merge fieldsCustomFieldV3UpdateRequest — same fieldsNo payload migration needed for PUT
Update responseV2 response204, no bodyStop parsing the update response; treat 2xx as success
Option editsSeparate "Update Options with Label" endpointPATCH on the same resourceConsolidate to one path and one method
Option representationvalues (key/label)values and valuesOptions (value/label + translations)Prefer valuesOptions for i18n
Create response option keyvaluesEchoes the key you sent (valuesOptions in, valuesOptions out) — fixed under IN-13195Parse defensively
Envelope{data, errors}{data, errors} — unchanged for POSTNo change

8. Supported types and asset types

8.1 Custom field types

TypeDescription
PICKLISTSelect only one value from the available options.
PICKLIST_MULTISELECTSelect more than one value from the available options.
NUMBERValue in numerical form — phone number, employee ID, and similar.
DATEA calendar picker; for example purchase date, complaint date, completion date.
TEXTText details — name, customer ID, description.
TEXTAREASame as text but holds greater length.
TEXT_MULTILike 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.

8.2 Supported asset types

ACCOUNT, OUTBOUND_MESSAGE, MESSAGE, PROFILE, MEDIA_ASSET, USER, CAMPAIGN, SUB_CAMPAIGN, COMMUNITY, PRODUCT, PAID_INITIATIVE, AD_SET, AD_VARIANT, CASE, UNIVERSAL_CASE, SURVEY, TASK.


9. Use cases

9.1 Provision a case-tagging picklist from your deployment pipeline

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.

9.2 Add one option to a live picklist without disturbing the rest

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.

9.3 Retire an option that is no longer offered

{ "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.

9.4 Localize a picklist for a new market

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.

9.5 Build a cascading (controlling) picklist

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.

9.6 Resolve a fieldName you copied from the UI

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.

9.7 Reconcile a picklist against an authoritative external list

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.


10. Caveats and best practices

Method selection

  • PUT and PATCH take different body schemas. Payloads are not interchangeable.
  • Use PATCH for incremental option work; reserve full valuesOptions replacement for when you own the entire list.
  • There is no delete. Plan for enabled: false as the retirement mechanism.

Identifiers

  • fieldName and id are mutually exclusive on GET, PUT, and PATCH. Send exactly one.
  • fieldName values are prefixed _c_. Copy them from the create response or from the UI (Copy Field Name).
  • Send option value / key as strings, not numbers (IN-13205).

Types

  • type cannot be changed after creation. Create a new field instead.
  • Option fields are meaningful only for PICKLIST and PICKLIST_MULTISELECT.

Response handling

  • Treat 200 (read/create) and 204 (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 values and valuesOptions when reading options, and mind the key ↔ value inversion.
  • Do not assume assetTypes round-trips exactly as sent.

Governance

  • If visibilityConfig is populated, globallyVisible must be false.
  • permissions[].spaceType and permissions[].spaceId are both required whenever a Permission entry is supplied.

Constraints carried from V2

  • description should 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.