Custom field definitions API
The endpoints under /api/custom-fields/ manage the schema for custom fields, the field definitions admins create in the settings UI. The actual values you store on individual records use each entity's regular endpoint (see Custom fields feature).
Permissions
- List / read: any authenticated user (the frontend needs definitions to render detail-page forms).
- Create / update / delete: admin role only.
List definitions
GET /api/custom-fields/?target_model=Lead&active_only=true
Authorization: Bearer <token>
{
"definitions": [
{
"id": 17,
"target_model": "Lead",
"key": "industry",
"label": "Industry",
"field_type": "dropdown",
"options": [
{ "value": "saas", "label": "SaaS" },
{ "value": "manufacturing", "label": "Manufacturing" }
],
"is_required": false,
"is_filterable": true,
"is_active": true,
"display_order": 0
}
]
}
Query parameters:
target_model: filter by entity name (Lead,Account,Contact,Opportunity,Task,Case,Invoice,Estimate,RecurringInvoice).active_only=true: exclude soft-deleted definitions.
Create
POST /api/custom-fields/
{
"target_model": "Lead",
"key": "industry",
"label": "Industry",
"field_type": "dropdown",
"options": [
{ "value": "saas", "label": "SaaS" },
{ "value": "manufacturing", "label": "Manufacturing" }
],
"is_required": false,
"is_filterable": true,
"display_order": 0,
"is_active": true
}
Constraints:
keymust match^[a-z][a-z0-9_]*$and be unique per(org, target_model).optionsis required only whenfield_typeisdropdown.target_modelmust be one of the nine supported entities.
Update
PUT /api/custom-fields/<id>/
{ "label": "Industry Vertical", "options": [ … ] }
Immutable fields: key and field_type cannot change after creation. The API returns 400 if either is in the body.
Delete (soft)
DELETE /api/custom-fields/<id>/
Sets is_active=false. Existing values on records are preserved; new writes for the deactivated key are rejected as unknown. Reactivate with PATCH { "is_active": true }.
Errors
{
"error": true,
"errors": {
"key": "must match ^[a-z][a-z0-9_]*$",
"options": "Dropdown fields require a non-empty list of {value, label} pairs"
}
}
See Errors for the full error response shape.