Skip to content

Custom Fields

⚠️ Retired for Telesales entities

Effective 2026-08-14, all /api/custom-fields endpoints for the two entities TelesalesLead and TelesalesCallAttempt have been retired and now return HTTP 410 Gone. Non-Telesales entities (Customer, Ticket) are unaffected.

Telesales custom fields are now managed through the Dataset API — each campaign links to one dataset that holds lead-phase and attempt-phase fields plus its own disposition catalogue. See the new Telesales Datasets API documentation.

Retired endpoints ↔ replacements:

Retired (410 Gone)Replacement
GET /api/custom-fields?entity=TelesalesLeadGET /api/v1/telesales/datasets/{id} (filter phase='lead')
GET /api/custom-fields?entity=TelesalesCallAttemptGET /api/v1/telesales/datasets/{id} (filter phase='attempt')
POST /api/custom-fields (Telesales)POST /api/v1/telesales/datasets/{id}/fields
PUT /api/custom-fields/{id} (Telesales)PUT /api/v1/telesales/datasets/{id}/fields/{fid}
DELETE /api/custom-fields/{id} (Telesales)DELETE /api/v1/telesales/datasets/{id}/fields/{fid}

Zorio lets tenant admins extend Lead and Call Attempt data with additional fields — no DB migration required. As an integration partner you discover the field catalogue at runtime, then use each field_code to (a) map CSV columns during lead import and (b) send/receive values on Lead and Call Attempt endpoints.

Catalogue management (create / update / delete / grouping) is handled by tenant admins directly in the Zorio portal — not exposed through the public API.

The section below applies only to Customer / Ticket entities (CSKH module). For Telesales, move to the Datasets page.

Supported entities

Two entity types support custom fields within Telesales:

entity valueWritten throughPurpose
TelesalesLeadLead import + PATCH /api/telesales/leads/{id}Lead-level data — visible to the agent while calling
TelesalesCallAttemptPOST /api/telesales/calls/{uuid}/dispositionCall-level data — the outcome the agent fills in when closing a call

Always filter with ?entity=TelesalesLead or ?entity=TelesalesCallAttempt on the discovery endpoint below.

Field type catalogue

typeCoerced toRules a definition may declareNotes
textstringmax_length, regex_patternSingle-line free text
textareastringmax_lengthMulti-line free text
richtextHTML string (sanitised)max_lengthServer-side HTMLPurifier
numberinteger or decimalmin_value, max_valueStored as decimal(18,4)
dateISO-8601 date (YYYY-MM-DD)
datetimeISO-8601 datetimeServer normalises to UTC
booleantrue / falseAccepts "0"/"1"/"true"/"false"
emailstringRFC-5321 syntactic check
phonestringregex_patternAuto-normalised to 84xxx when possible
urlstringhttp:// or https:// scheme required
selectstringoptions[]Single value from options
multiselectarray of stringsoptions[]Zero or more values from options

Attributes shared across all types:

  • is_required — the pipeline rejects rows and PATCH bodies where the field is missing or empty.
  • is_unique — enforced per (tenant, entity, code).
  • is_encrypted — value is encrypted at rest; list responses mask it as *** unless the caller has the appropriate permission.
  • default_value — applied when input is null/missing (Import only).

GET /api/custom-fields — Discover definitions

Requires the caller to have the crm module (viewer or above). Cached for 60 seconds per (tenant, entity).

http
GET /api/custom-fields?entity=TelesalesLead

Query params:

ParamDescription
entityRequired for Telesales contexts — set to TelesalesLead or TelesalesCallAttempt.
include_inactivetrue / false (default false). Include definitions currently disabled by the admin. Keep the default — inactive definitions no longer accept writes.

Response 200:

json
{
  "data": [
    {
      "id": 41,
      "entity": "TelesalesLead",
      "code": "reference_code",
      "label": "Reference code",
      "type": "text",
      "options": null,
      "is_required": true,
      "is_unique": true,
      "is_encrypted": false,
      "max_length": 32,
      "regex_pattern": "^REF-[0-9]{'{'}4,10{'}'}$",
      "default_value": null,
      "placeholder": "e.g. REF-000123",
      "help_text": "Reference code from the source CRM",
      "display_order": 10
    },
    {
      "id": 42,
      "entity": "TelesalesLead",
      "code": "product_interest",
      "label": "Product interest",
      "type": "multiselect",
      "options": ["Life", "Health", "Investment", "Motor"],
      "is_required": false,
      "help_text": "Multi-select — pick every product the prospect mentioned",
      "display_order": 20
    }
  ]
}

Typical usage:

  1. Onboarding — call once, cache client-side, use it to build the CSV-column → field mapping UI for lead import.
  2. Before every import batch — re-fetch to detect new fields the tenant admin may have added.
  3. Before every PATCH lead / disposition — echo rules on the client side so users see errors before hitting the server.

Server-side validation pipeline

Every endpoint that writes custom_fields runs through the same server-side pipeline with 5 checks:

  1. Reject unknown codes — a key with no active definition → 422 unknown_field.
  2. Coerce types"42" → int; "true" → bool; "2026-01-15" → Date.
  3. Apply rulesmax_length, min_value, max_value, regex_pattern, options membership.
  4. Enforce uniqueness — returns 422 duplicate with conflicting_record_id.
  5. Encrypt — fields with is_encrypted=true are encrypted automatically.

The Import endpoint reports per-field error counters in the 201 response (see Import leads). The Lead PATCH endpoint returns a per-field breakdown in custom_fields_report (see PATCH lead).

Note — do not modify the catalogue via direct SQL

The definition list is cached for 3600 seconds. The cache auto-invalidates when the admin edits definitions through the portal, but if someone modifies custom_field_definitions directly via SQL (bypassing the portal), the cache will hold the old definitions until TTL — the pipeline will then apply outdated rules (e.g. allowing duplicates even after is_unique=1 is set).

The Zorio portal is the single source of truth for the catalogue. If you migrate the database manually between environments, ask the admin to clear the cache after the migration so the pipeline reads the latest definitions.

Cấp phép theo điều khoản sử dụng của Zorio.