Skip to main content

Custom fields & formData

Leads, contacts and product/services all accept writes through a single formData object that mixes system fields and custom fields. Understanding how the two are told apart is the key to the whole write API.

The rule​

Inside formData, the server looks at each key:

  • A key that is a valid 24-character ObjectId → a custom field, matched by its _id.
  • Anything else → a system field on the schema.
{
"formData": {
"stage": "Qualified",
"priority": "High",
"665f1a2b3c4d5e6f70819200": "Enterprise"
}
}

stage and priority are system fields; 665f1a... is a custom field id. There is no separate customFields block — one flat object handles both.

Discovering custom fields​

curl "https://api.leadx.in/api/key/protected/custom-field?filters=%7B%22panel%22%3A%22lead%22%7D" \
-H "apikey: $KEY"

panel is one of lead, contact, productService. Each definition carries:

FieldNotes
_idThe key you use in formData.
nameDisplay label.
fieldTypetext, number, textarea, select, multi-select, file, checkbox, date, email, url, object, array
valueTypestring, number, boolean, date, member, file, array, object
optionsFor select / multi-select — the allowed { label, value } entries.
requiredWhether a write must supply it.
defaultValueApplied when omitted.
uniqueFieldIDStable slug, handy for mapping to your own system.
section, order, hidePresentation only.

:::tip Cache the definitions, not the ids Custom field _ids are stable, but building your mapping from uniqueFieldID or name at startup keeps your integration readable and survives a field being recreated. :::

Reading custom field values​

Values come back on customFieldsMap, keyed by field id:

{
"_id": "665f...",
"stage": "Qualified",
"customFieldsMap": {
"665f1a2b3c4d5e6f70819200": {
"value": "Enterprise",
"label": "Enterprise",
"sortValue": "enterprise"
}
}
}

value is what you wrote. label resolves select options to their display text. sortValue is a normalized form the server uses for sorting — ignore it.

The legacy fields array is still present on documents for backward compatibility. Read customFieldsMap; fields is the older representation.

Filtering and sorting by custom field​

Use the field id as the path, exactly as in formData:

?filters={"665f1a2b3c4d5e6f70819200":"Enterprise"}
?sortBy=665f1a2b3c4d5e6f70819200&sortOrder=asc

Appending instead of replacing​

For array-valued custom fields, a bulk update can add rather than overwrite:

{ "ids": ["665f..."], "updateType": "append", "formData": { "665f1a...": ["Tag A"] } }

updateType defaults to replace.

Managing definitions​

MethodEndpointNotes
GET/custom-fieldList. Filter by panel.
POST/custom-fieldCreate. name and fieldType required.
GET/custom-field/:idRead one.
PUT/custom-field/:idUpdate.
DELETE/custom-fieldDelete — { "ids": [...] }.
PUT/custom-field/modifyBulk-modify definitions.
PUT/custom-field/reorderReorder within a section.
PUT/custom-field/reset-systemReset system field configuration to defaults.

Sections (/custom-section) group fields for display and follow the same CRUD-plus-reorder shape.

System fields worth knowing​

Lead​

stage · status · priority · source · notes · enquiryAt · contact · productServices · team · teamMember · plus ad attribution (ad_id, adset_id, campaignName) and UTM fields (utmSource, utmMedium, utmCampaign, utmTerm, utmContent, utmUrl).

FieldAllowed values
stageNew · Contacted · Follow-up Required · Qualified · Interested · Proposal Sent · Negotiation · Won · Lost · On Hold · Closed
statusHot · Warm · Cold
priorityHigh · Medium · Low
sourceBulk Import · Offline · Facebook · Website · AI Generated · Instagram · Whatsapp · SMS · Gmail · Zoho · LinkedIn · Twitter · Threads

An unrecognised source is dropped rather than rejected.

Contact​

name · email · jobTitle · address · country · state · city · postalCode · description · tags · contactcategories, plus nested groups:

  • contactNumber, work_phone_number, whatsapp_contact_number — each { countryCode, number }
  • companyData — { name, website, industry, otherIndustry, size, location }
  • social — { facebook, twitter, linkedin, instagram, youtube, tiktok, personalWebsite }
FieldAllowed values
companyData.sizeSelf-employed · 0-10 · 11-50 · 51-200 · 201-500 · 501-1000 · 1001-5000 · 5001-10000 · 10000+
companyData.industryInformation Technology (IT) · Healthcare · Financial Services · E-commerce · Manufacturing · Education · Real Estate · Logistics · Media & Entertainment · Telecommunications · Automotive · Marketing · Legal Services · NGO · Other

Nested paths can be written either nested or dotted — {"companyData": {"name": "Acme"}} and {"companyData.name": "Acme"} are equivalent.