Custom fields
Definitions belong to the workspace and values belong to individual contacts. Read GET /fields or GET /fields/{id} with contacts:read. Creating with POST /fields and saving with POST /fields/{id}/save requires segments:write; saving also requires If-Match.
Create a definition
Include Idempotency-Key and a body such as:
{"key": "loyalty_points", "label": "Points", "type": "number"}
Types are text, number, boolean, date, datetime, single_select and multi_select. Selection types require 1–30 options with {id, label} and unique IDs. Other types omit options, including empty arrays.
The key is unique within the workspace. Key, type and existing option IDs remain stable during edits; labels can change and options can be added. Changing a label does not change stored values.
Save a value
Profile custom is keyed by definition ID, not its key or label. This fragment can be part of a contact PATCH with the current revision:
{
"custom": {
"FIELD_ID": {"type": "number", "value": 120}
}
}
Dates use YYYY-MM-DD; datetime uses UTC with Z and at most microsecond precision. Single selection stores an option ID and multiple selection stores an array of IDs. false, 0 and [] are present values; null in a patch removes the value.
POST /contacts/{id}/custom-fields accepts {fieldId, value} with contacts:write and the contact revision. It also accepts {definition: {key, label, type, options?}, value} to create the definition and value atomically; this variant additionally requires segments:write. Failed validation leaves no orphan definition.
Use the data
Values support personalization and audience rules. The server checks workspace, type and options before saving; creating a definition does not assign values to other contacts. Manage definitions in Settings → Custom fields.