Skip to content
Objects in Lightfield

Fields and relationships

Learn how fields, relationships, and their value types work in the Lightfield API.

Fields and relationships are the core data model for CRM objects in Lightfield. Fields store data on an object (e.g. a name, email, or deal value), while relationships link objects together (e.g. an opportunity’s account or contacts).

When creating or updating objects via the API (or through the SDKs), you pass field values in the fields object. Each key in that object corresponds to a field on the object type.

Field and relationship keys use a $ prefix to distinguish system-defined entries from custom ones:

  • System fields and relationships: Prefixed with $, e.g. $name, $stage, $account.
  • Custom fields and relationships: No prefix, e.g. priority, partners.
{
"fields": {
"$name": "Acme Corp",
"$stage": "opt_...",
"priority": 1
}
}

Writes take bare field values. Record responses wrap each value in an object with valueType and value.

Use the definitions endpoint to discover all fields and relationships available on an object type:

GET /v1/{objectType}/definitions

For example:

Terminal window
curl https://api.lightfield.app/v1/opportunities/definitions \
-H "Authorization: Bearer $API_KEY" \
-H "Lightfield-Version: 2026-03-01"

The response includes the full schema for both fields and relationships:

{
"objectType": "opportunity",
"fieldDefinitions": {
"$name": {
"id": "ad_...",
"slug": "name",
"label": "Name",
"description": null,
"valueType": "TEXT",
"system": true,
"typeConfiguration": {}
},
"$stage": {
"id": "ad_...",
"slug": "stage",
"label": "Stage",
"description": "What stage is the opportunity in?",
"valueType": "SINGLE_SELECT",
"system": true,
"typeConfiguration": {
"options": [
{ "id": "opt_...", "label": "Prospecting", "description": null },
{ "id": "opt_...", "label": "Closed Won", "description": null }
]
}
}
},
"relationshipDefinitions": {
"$account": {
"id": null,
"slug": "account",
"label": "Account",
"description": null,
"system": true,
"cardinality": "HAS_ONE",
"objectType": "account"
}
}
}

This is especially useful for resolving select option IDs to their labels, discovering which keys will appear in record responses, and finding the relationship definition slugs you can use to filter by relationships.

Object typePath
Accounts/v1/accounts/definitions
Contacts/v1/contacts/definitions
Opportunities/v1/opportunities/definitions
Custom objects/v1/objects/{entitySlug}/definitions
PropertyTypeDescription
idstring | nullUnique identifier (prefixed with ad_), or null for synthesized fields.
slugstringInternal slug for the field.
labelstringHuman-readable label.
descriptionstring | nullOptional description.
valueTypestringThe field’s value type. See field value types.
systembooleantrue for built-in fields, false for custom fields.
readOnlybooleantrue for fields that are not writable via the API (e.g. AI-generated summaries). false or absent for writable fields.
typeConfigurationobjectType-specific configuration. See type configuration.
PropertyTypeDescription
idstring | nullUnique identifier (prefixed with rd_), or null for synthesized relationships.
slugstringInternal slug for the relationship.
labelstringHuman-readable label.
descriptionstring | nullOptional description.
systembooleantrue for built-in relationships, false for custom relationships.
cardinalitystringHAS_ONE or HAS_MANY.
objectTypestringThe related object type (e.g. account, contact, user).

For creates, relationship values are entity IDs or arrays of entity IDs. For updates, use add, remove, or replace as allowed by the relationship’s cardinality.

Use a field history endpoint to retrieve the recorded values of one attribute-backed field over time.

Object typeEndpoint
Accounts/v1/accounts/{id}/fields/{fieldKey}/history
Contacts/v1/contacts/{id}/fields/{fieldKey}/history
Opportunities/v1/opportunities/{id}/fields/{fieldKey}/history
Custom objects/v1/objects/{entitySlug}/values/{id}/fields/{fieldKey}/history

Use a $-prefixed key for a system field, such as $stage, and a bare slug for a custom field.

Results are returned newest first, with consecutive identical values collapsed. Responses default to 20 entries and accept a limit of up to 100. Use nextCursor as the after parameter to retrieve older pages.

For example:

Terminal window
curl 'https://api.lightfield.app/v1/opportunities/opp_.../fields/$stage/history?limit=20' \
-H "Authorization: Bearer $API_KEY" \
-H "Lightfield-Version: 2026-03-01"

The response includes the recorded value, its display value, and when it was recorded:

{
"data": [
{
"value": "opt_abc123",
"valueType": "SINGLE_SELECT",
"displayValue": "Closed Won",
"recordedAt": "2026-08-01T17:30:00.000Z",
"isCreate": false
},
{
"value": "opt_def456",
"valueType": "SINGLE_SELECT",
"displayValue": "Qualified",
"recordedAt": "2026-06-20T09:15:00.000Z",
"isCreate": true
}
],
"hasMore": false,
"nextCursor": null
}

See the API reference for accounts, contacts, opportunities, and custom objects.

Every field has a valueType that determines the shape of its value:

TypeValue formatDescription
TEXTstringPlain text.
NUMBERnumberA number with up to 2 decimal places, within safe integer range.
CHECKBOXboolean | nullA true/false value.
CURRENCYnumber | nullA numeric amount. The currency code (e.g. USD) is set in the field’s type configuration.
DATETIMEstring | nullAn ISO 8601 datetime string with timezone offset (e.g. "2026-03-16T12:00:00+00:00"). Stored as UTC.
EMAILstring | string[] | nullEmail address data (RFC 5322). Most EMAIL fields return arrays, but on the meetings resource meeting.$organizerEmail returns a single string. Fields such as meeting.$attendeeEmails still return arrays.
TELEPHONEstring[]An array of phone numbers. See telephone format below.
URLstring | string[] | nullA URL or array of URLs.
ADDRESSobject | nullA structured address object. See address format below.
FULL_NAMEobjectAn object with firstName and lastName properties.
SOCIAL_HANDLEstring | nullA social media handle or profile URL. See social handle format below.
SINGLE_SELECTstring | nullThe id of a select option (opt_... for stages and ordinary selects; pd_... for $pipeline).
MULTI_SELECTstring[]An array of select option ids.
READONLY_MARKDOWNstringRead-only markdown content, typically AI-generated. Not writable via the API.

Address values are objects with the following properties, all optional. For convenience, pass a single null value to unset all properties:

PropertyTypeDescription
streetstringStreet address line 1.
street2stringStreet address line 2 (apartment, suite, etc.).
citystringCity name.
statestringState or region.
postalCodestringPostal or ZIP code.
countrystringISO 3166-1 alpha-2 country code (e.g. "US", "GB"). Must be exactly 2 characters.
latitudenumberLatitude coordinate.
longitudenumberLongitude coordinate.
{
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postalCode": "94105",
"country": "US"
}

Phone numbers are validated and normalized on input:

  • With + prefix: Validated as an international number in E.164 format (e.g. "+12025551234").
  • Without + prefix: Validated as a US number first, then falls back to accepting 7–15 digit local numbers.
  • Extensions: Supported via ;ext= notation (e.g. "+12025551234;ext=100"). Various input formats like x100, ext:100, and #100 are automatically normalized to the ;ext= format.
["+12025551234", "+442071234567;ext=100"]

SOCIAL_HANDLE fields store a social media profile URL. Each social handle field has a handleService in its type configuration that specifies the platform: TWITTER, LINKEDIN, FACEBOOK, or INSTAGRAM.

Values must be a valid profile URL for the configured platform:

PlatformAccepted URL formats
TWITTERhttps://twitter.com/{username}, https://x.com/{username}
LINKEDINhttps://linkedin.com/in/{slug}, https://linkedin.com/company/{slug}
FACEBOOKhttps://facebook.com/{username}, https://fb.com/{username}
INSTAGRAMhttps://www.instagram.com/{username}

Regional subdomains (e.g. https://uk.linkedin.com/in/...) and query parameters are accepted.

"https://x.com/lightfield"
"https://www.linkedin.com/in/jane-doe"
"https://www.instagram.com/lightfield"

Pass null to clear a social handle field.

SINGLE_SELECT and MULTI_SELECT fields reference predefined options by their id. Use the definitions endpoint to discover the available options for a field.

Each option has the following shape:

PropertyTypeDescription
idstringUnique identifier (opt_..., or pd_... for $pipeline).
labelstringDisplay label.
descriptionstring | nullOptional description.
parentIdstringFor a dependent select, the owning option’s ID in the parent field. Absent for ordinary selects.

When setting a SINGLE_SELECT value, pass the option’s id as a string. For MULTI_SELECT, pass an array of option ids.

{
"fields": {
"$stage": "opt_abc123",
"tags": ["opt_def456", "opt_ghi789"]
}
}

A record belongs to at most one pipeline, determined by its selected stage. Stage labels may repeat across pipelines, so use option IDs to identify stages. An ordinary custom field named stage is separate from the system $stage field.

The $pipeline entry in fieldDefinitions lists active pipelines in typeConfiguration.options. Each option’s id is a pd_... pipeline ID and its label is the pipeline name. The $stage definition lists the stages across those pipelines, with parentFieldKey: "$pipeline" and a parentId on each option:

{
"fieldDefinitions": {
"$pipeline": {
"label": "Pipeline",
"valueType": "SINGLE_SELECT",
"readOnly": false,
"typeConfiguration": {
"options": [
{ "id": "pd_sales", "label": "Sales" },
{ "id": "pd_renewals", "label": "Renewals" }
]
}
},
"$stage": {
"label": "Stage",
"valueType": "SINGLE_SELECT",
"typeConfiguration": {
"parentFieldKey": "$pipeline",
"options": [
{
"id": "opt_sales_qualified",
"label": "Qualified",
"parentId": "pd_sales"
},
{
"id": "opt_renewals_qualified",
"label": "Qualified",
"parentId": "pd_renewals"
}
]
}
}
}
}

This is an excerpt; the IDs are placeholders. Match a stage option’s parentId to the chosen pipeline’s id before resolving a label. Do not choose the first matching label across all pipelines.

If $pipeline is absent from definitions, do not send it in writes or filters.

For an object type with configured pipelines:

InputBehavior
$stage option IDSelect that exact stage. Its owning pipeline is derived automatically.
$stage label with $pipelineResolve the label within the selected pipeline. Use the pipeline’s ID or name as the write hint.
$stage option ID with $pipelineAccepted if the stage belongs to the supplied pipeline; a mismatch is rejected.
$stage label onlyFor opportunities, resolve within the default opportunity pipeline for backwards compatibility. Accounts, contacts, and custom objects require a pipeline hint for a label, even if that label is unique.
$stage set to nullClear the stage and pipeline membership.
Stage omittedPreserve the existing stage on update. On create, leave the record unassigned. Opportunity Stage is optional.

Stage labels are case-sensitive on write and must match the label from definitions exactly, including whitespace; stage filters ignore case, trim surrounding whitespace, and collapse repeated whitespace.

For example, select the Renewals pipeline’s Qualified stage:

{
"fields": {
"$pipeline": "pd_renewals",
"$stage": "Qualified"
}
}

You can also send "$stage": "opt_renewals_qualified" without a pipeline hint, or replace "pd_renewals" with the pipeline name "Renewals" in this example.

To move a record to another pipeline, write a stage belonging to that pipeline. $pipeline is only a write hint: it is consumed, and its value is not stored separately. A pipeline hint without a stage, or alongside a null stage, is rejected. Pipeline slugs are not accepted as a separate form of write hint; use an ID or name returned by definitions.

On reads, $stage.value is the stage option ID and $pipeline.value is its pipeline ID, inside the record’s fields object. A configured but unassigned record returns null values for both. This differs from fields being absent because the object type has no configured pipelines or does not support them. Use the individual Retrieve method to verify a write; list methods may lag behind it.

See pipeline filters and pipeline errors for query syntax and resolving rejected inputs.

Some field types include additional configuration via typeConfiguration on the field definition. You can read these from the definitions endpoint.

TypeConfigurationDescription
CURRENCYcurrencyISO 4217 currency code (e.g. "USD").
EMAILunique, multipleValuesWhether values must be unique across objects, and whether the field supports multiple email values.
TELEPHONEunique, multipleValuesSame as email — uniqueness and multiple value support.
URLunique, multipleValuesSame as email — uniqueness and multiple value support.
SOCIAL_HANDLEhandleServicePlatform hint: TWITTER, LINKEDIN, FACEBOOK, or INSTAGRAM.
SINGLE_SELECToptions, parentFieldKeyAvailable options. For a dependent select, parentFieldKey names the field whose selected option determines which options apply.
MULTI_SELECToptionsThe list of available select options.

Types not listed above (such as TEXT, NUMBER, DATETIME, CHECKBOX, ADDRESS, FULL_NAME, and READONLY_MARKDOWN) return an empty typeConfiguration: {}.

Fields and relationships can be either system or custom:

  • System entries are built-in, prefixed with $, and cannot be deleted. Check definitions for the object type’s fields and configuration (e.g. $name on accounts, $account on opportunities, and $pipeline on types with configured pipelines).
  • Custom entries are user-defined and can be created, updated, and removed through the API or the Lightfield UI.

Both system and custom entries follow the same value type rules described above.

Lightfield uses prefixed IDs to distinguish between entity types:

EntityPrefixExample
Accountacc_acc_abc123
Contactcon_con_abc123
Opportunityopp_opp_abc123
Membermem_mem_abc123
Field definitionad_ad_abc123
Relationship definitionrd_rd_abc123
Select optionopt_opt_abc123
Pipelinepd_pd_abc123
Attribute valueav_av_abc123
Relationship valuerv_rv_abc123