For the complete documentation index, see llms.txt. This page is also available as Markdown.

Columns

Manage custom property definitions (called columns in the API) for companies, contacts, and deals. Use GET /api/columns to discover the IDs, types, and options of custom fields before filtering or updating records, and POST / PATCH / DELETE to create, edit, and remove properties.

Definitions vs. values

A column is the definition of a custom property — its name, type, options, and which entity it belongs to. The values live on the records themselves, in the custom object of each company / contact / deal, keyed by the column's id. Creating a column does not touch any records; it just makes custom.<column-id> available for writes, filters, views, and reports.

Column                              Company record
{ "id": "54e1ca7d-…",               { "id": "…",
  "entity": "companies",              "name": "Acme",
  "name": "Industry",                 "custom": {
  "type": "select",                     "54e1ca7d-…": "3e839b5c-…"   ← option key
  "options": [ {"key": "3e839b5c-…", "name": "SaaS"}, … ] }   }
}

Creating a property

POST /api/columns with at least workspaceId, entity, name, and type. For select / multiselect, also pass options — every option needs a client-generated UUID in key; that UUID is what gets stored on records, so it must stay stable for the life of the option. Names and colors can be edited freely later.

Editing a property

PATCH /api/columns/{columnId}. Renaming, changing the description, and editing options are safe. Note that options is replaced wholesale on write — always send the complete list. Removing an option from options does not delete it from records; move it to archivedOptions instead so existing values keep resolving to a name. Changing type is allowed for a limited set of pairs and triggers a background migration of existing values — see PATCH for the supported conversions.

Deleting a property

DELETE /api/columns/{columnId} permanently removes the definition. Values already stored under that id on records are not cleaned up — they simply become invisible/orphaned. Prefer DELETE …?archive=true (soft delete) when you may need to restore the property; restore with PATCH {"archived": false}.

Reserved / built-in fields

Only user-defined properties are columns. Built-in fields (name, domain, stage, value, …) are top-level record fields, not columns, and cannot be created or deleted through this endpoint.

List custom property definitions

get

Returns the custom property (column) definitions for a workspace. Filter by workspace using the where parameter: {"workspaceId": "<WORKSPACE_UUID>"}. Strongly recommended — omitting it returns columns across all workspaces the user has access to.

Use this endpoint to discover the IDs, types, and available options of custom fields before filtering or updating records.

Custom properties are stored in the custom object on companies, contacts, and deals. Each custom property is keyed by its UUID (id from this response).

For example, if this endpoint returns a column with "id": "54e1ca7d-69c3-4b77-8266-8085b5834116" and "type": "select", you can:

  • Filter records using: {"custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$in": ["<OPTION_KEY_UUID>", "<OPTION_KEY_UUID>"]}}

  • Update a record using: {"custom.54e1ca7d-69c3-4b77-8266-8085b5834116": "<OPTION_KEY_UUID>"}

Note: For select and multiselect columns, option values are UUIDs stored in the key field of each option object. Use the key UUID (not the human-readable name) when filtering or updating records.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Query parameters
fieldsstringOptional

Comma-separated list of fields to return. Defaults to all fields.

Supports relation expansion with dot-notation: a path like company.name embeds the named field of the related record, and quotes.id embeds the id of each related quote. Use .* to embed full related objects, e.g. quotes.*. Related records are returned nested on the response — as an object for to-one relations (e.g. company) or an array for to-many relations (e.g. quotes). Archived related records are excluded.

Example: GET /api/deals/{dealId}?fields=id,name,quotes.id returns the deal with a quotes array of {"id": "<QUOTE_UUID>"} entries.

Example: id,name,domain
wherestringOptional

JSON-encoded filter object. All top-level conditions are combined with AND logic. Use $or for OR logic.

The available operators depend on the data type of the field you are filtering on.


String fields

Fields like name, domain, description, linkedin, source, externalId, location.

OperatorDescriptionExample
(exact)Exact match{"name": "Linear"}
$eqExplicit exact match{"name": {"$eq": "Linear"}}
$notNot equal{"source": {"$not": "import"}}
$inMatches any value in array{"domain": {"$in": ["linear.app", "granola.so"]}}
$notInMatches none of the values{"source": {"$notIn": ["import", "api"]}}
$containsCase-insensitive word-boundary substring match{"name": {"$contains": "YC"}}
$notContainsDoes not contain{"name": {"$notContains": "Test"}}
$containsAnyContains any of the given strings{"name": {"$containsAny": ["YC", "Techstars"]}}
$startsWithStarts with prefix{"domain": {"$startsWith": "app."}}
$endsWithEnds with suffix{"email": {"$endsWith": "@zero.inc"}}
$existsField is present and truthy{"linkedin": {"$exists": true}}
$notExistsField is absent, null, or empty{"linkedin": {"$notExists": true}}

Number fields

Fields like value, confidence.

OperatorDescriptionExample
(exact)Exact match{"value": 5000}
$eqExplicit exact match{"value": {"$eq": 5000}}
$notNot equal{"value": {"$not": 0}}
$gtGreater than{"value": {"$gt": 10000}}
$gteGreater than or equal{"value": {"$gte": 5000}}
$ltLess than{"value": {"$lt": 10000}}
$lteLess than or equal{"value": {"$lte": 50000}}
$inMatches any value in array{"confidence": {"$in": [0.25, 0.5, 0.75]}}
$notInMatches none of the values{"confidence": {"$notIn": [0, 1]}}
$existsField is present and truthy{"value": {"$exists": true}}
$notExistsField is absent, null, or zero{"value": {"$notExists": true}}

Multiple operators can be combined on one field:

{"value": {"$gte": 5000, "$lt": 10000}}

Date fields

Fields like closeDate, startDate, endDate, createdAt, updatedAt.

Values can be ISO 8601 strings ("2026-01-01", "2026-01-01T00:00:00Z") or relative time macros.

Relative time macros: +Nd / -Nd (days), +Nw / -Nw (weeks), +Nm / -Nm (months), +Ny / -Ny (years), +Nh / -Nh (hours), +Ns / -Ns (seconds), now().

OperatorDescriptionExample
$gteOn or after{"closeDate": {"$gte": "2026-01-01"}}
$lteOn or before{"closeDate": {"$lte": "2026-03-31"}}
$gtAfter{"createdAt": {"$gt": "2026-01-01T00:00:00Z"}}
$ltBefore{"createdAt": {"$lt": "now()"}}
$dateExact date match (compares date portion only){"closeDate": {"$date": "2026-01-15"}}
$existsField is present and truthy{"closeDate": {"$exists": true}}
$notExistsField is absent or null{"closeDate": {"$notExists": true}}

Date range example:

{"closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"}}

Relative date example (closing in next 30 days):

{"closeDate": {"$gte": "now()", "$lte": "+30d"}}

Array fields

Fields like listIds, ownerIds, contactIds.

OperatorDescriptionExample
$includesArray contains the given value (use this — bare exact match is not supported){"listIds": {"$includes": "<LIST_UUID>"}}
$notIncludesArray does not contain the given value{"ownerIds": {"$notIncludes": "<USER_UUID>"}}
$overlapsArray contains at least one of the given values{"ownerIds": {"$overlaps": ["<UUID_1>", "<UUID_2>"]}}
$notOverlapsArray contains none of the given values{"listIds": {"$notOverlaps": ["<UUID_1>", "<UUID_2>"]}}
$allArray contains all of the given values{"listIds": {"$all": ["<UUID_1>", "<UUID_2>"]}}
$lengthFilter by array length (supports nested operators){"contactIds": {"$length": {"$gte": 2}}}
$existsField is present and non-empty{"ownerIds": {"$exists": true}}
$notExistsField is absent or empty{"ownerIds": {"$notExists": true}}

UUID / ID fields

Fields like id, workspaceId, companyId, stage.

OperatorDescriptionExample
(exact)Exact match{"stage": "<PIPELINE_STAGE_UUID>"}
$inMatches any value in array{"stage": {"$in": ["<UUID_1>", "<UUID_2>"]}}
$notInMatches none of the values{"stage": {"$notIn": ["<UUID_1>"]}}
$notNot equal{"stage": {"$not": "<UUID>"}}

Boolean fields

Fields like archived.

OperatorDescriptionExample
(exact)Exact match{"archived": false}
$notNot equal{"archived": {"$not": true}}

Logical operators

These work across all data types.

$or — matches if any sub-condition is true:

{
  "workspaceId": "<WORKSPACE_UUID>",
  "$or": [
    {"ownerIds": {"$overlaps": ["<USER_UUID_1>", "<USER_UUID_2>"]}},
    {"closeDate": {"$gte": "2026-01-01"}}
  ]
}

$and — matches if all sub-conditions are true (useful when you need multiple conditions on the same field):

{
  "$and": [
    {"name": {"$contains": "Enterprise"}},
    {"name": {"$notContains": "Test"}}
  ]
}

Dot-notation (relation filtering)

Use dot-syntax to filter records based on properties of related objects:

{"company.name": "Linear"}
{"company.domain": {"$in": ["linear.app", "granola.so"]}}
{"company.location.city": "San Francisco"}
{"companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]}}

All operators available for the target field's data type can be used with dot-notation.


Custom property filtering

Custom properties are stored in the custom object on records, keyed by UUID. Use GET /api/columns to discover the available custom property IDs, types, and options for a workspace.

Filter on custom properties using custom.<COLUMN_ID> with operators appropriate for the column's type.

Note: For select and multiselect columns, option values are UUIDs (the key field from the column's options array). Use the UUID, not the human-readable name.

// Text custom property
{"custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}}

// Select custom property (use the option key UUID)
{"custom.a1b2c3d4-e5f6-7890-abcd-ef1234567890": "3e839b5c-b311-4887-b2da-727d2d75cdd6"}

// Multi-select custom property (use option key UUIDs)
{"custom.b2c3d4e5-f6a7-8901-bcde-f12345678901": {"$overlaps": ["a1b1c1d1-e1f1-1111-aaaa-111111111111", "b2b2c2d2-e2f2-2222-bbbb-222222222222"]}}

// Currency/number custom property
{"custom.c3d4e5f6-a7b8-9012-cdef-123456789012": {"$gte": 100000}}

// Date custom property
{"custom.d4e5f6a7-b8c9-0123-defa-234567890123": {"$gte": "2026-01-01"}}

// Boolean custom property
{"custom.e5f6a7b8-c9d0-1234-efab-345678901234": true}

// Check if custom property has a value
{"custom.f6a7b8c9-d0e1-2345-fabc-456789012345": {"$exists": true}}

Complex example

All top-level keys are ANDed together:

{
  "name": {"$contains": "Zero"},
  "location.city": "Helsinki",
  "location.country": {"$in": ["United Kingdom", "Germany", "Sweden"]},
  "value": {"$gte": 10000},
  "closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"},
  "ownerIds": {"$includes": "<USER_UUID>"},
  "stage": {"$in": ["<UUID_1>", "<UUID_2>"]},
  "lastActivity": {"$exists": true},
  "companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]},
  "custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}
}
Example: {"stage":"<PIPELINE_STAGE_UUID>"}
limitintegerOptional

Maximum number of records to return

Default: 100
offsetintegerOptional

Pagination offset

Default: 0
orderBystringOptional

JSON string for sort order

Example: {"name":"asc"}
Responses
200

Successful response

application/json
totalintegerOptional

Total number of custom property definitions

get/api/columns
GET /api/columns HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Accept: */*
{
  "data": [
    {
      "id": "54e1ca7d-69c3-4b77-8266-8085b5834116",
      "workspaceId": "dd66c03b-1a84-4c9d-b118-3cc54e21d019",
      "name": "Industry",
      "type": "select",
      "entity": "companies",
      "options": [
        {
          "key": "3e839b5c-b311-4887-b2da-727d2d75cdd6",
          "name": "SaaS",
          "color": "#4CAF50"
        },
        {
          "key": "7f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
          "name": "Fintech",
          "color": "#2196F3"
        }
      ]
    },
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "workspaceId": "dd66c03b-1a84-4c9d-b118-3cc54e21d019",
      "name": "ARR",
      "type": "currency",
      "entity": "companies",
      "options": null
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "workspaceId": "dd66c03b-1a84-4c9d-b118-3cc54e21d019",
      "name": "Tags",
      "type": "multiselect",
      "entity": "deals",
      "options": [
        {
          "key": "a1b1c1d1-e1f1-1111-aaaa-111111111111",
          "name": "Enterprise",
          "color": "#FF9800"
        },
        {
          "key": "b2b2c2d2-e2f2-2222-bbbb-222222222222",
          "name": "Strategic",
          "color": "#9C27B0"
        }
      ]
    }
  ],
  "total": 3
}

Create a custom property

post

Create a new custom property definition on companies, contacts, or deals. The property immediately becomes available for filtering, views, reports, and for writing values into custom.<column-id> on records of that entity.

Always send workspaceId, entity, name, and type.

No server-side validation. The API does not validate these fields or the type / entity enums. Omitting type or workspaceId fails with a 500 Database insert query failed; omitting name or entity, or sending an unknown type / entity, succeeds and silently creates a definition the app cannot render. Values written to custom.<column-id> on records are likewise stored as sent, without being checked against the column type — the per-type table on Column describes what the app, filters, and reports expect, not an enforced contract.

Select / multiselect options

For select and multiselect types, pass the initial options in options. Each option's key must be a UUID that you generate — it becomes the value stored on records, so it must be unique within the column and stable over time. name is the display label; color is an optional hex color.

{
  "workspaceId": "dd66c03b-1a84-4c9d-b118-3cc54e21d019",
  "entity": "companies",
  "name": "Industry",
  "type": "select",
  "options": [
    { "key": "3e839b5c-b311-4887-b2da-727d2d75cdd6", "name": "SaaS",    "color": "#4CAF50" },
    { "key": "7f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c", "name": "Fintech", "color": "#2196F3" }
  ]
}

Using the new property on records

The response contains the column id. Write values with dot-notation on the record — never by replacing the whole custom object:

curl -X PATCH "https://api.zero.inc/api/companies/COMPANY_UUID" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"custom.54e1ca7d-69c3-4b77-8266-8085b5834116": "3e839b5c-b311-4887-b2da-727d2d75cdd6"}'

See the type field on Column for the value shape each type expects. The PATCH response echoes only the touched sub-key ("custom": {"<column-id>": value}), not the whole custom object — other keys are preserved; re-GET the record if you need the merged object. Setting a value to null keeps the key in custom with a null value rather than removing it.

AI properties

Set ai: true together with aiPrompt to create an AI-filled property. AI properties are configured most reliably in the app; the API accepts the fields but does not validate the prompt structure.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
workspaceIdstring · uuidRequired
entitystring · enumRequired

Which record type the property is added to. Not validated server-side — other values are stored but unusable. Do not change it later.

Possible values:
namestringRequired

Display name of the property.

descriptionstring · nullableOptional

Optional help text shown in the app.

typestring · enumRequired

The data type. See the type table on Column for the value shape each type stores on records.

Possible values:
settingsobjectOptional

Type-specific display settings. Omit unless you know you need it.

aibooleanOptional

Set true to create an AI-filled property. Requires aiPrompt.

Default: false
aiPromptobject · nullableOptional

Prompt document for AI-filled properties. Easiest to author in the app and copy from an existing AI column.

aiSettingsobjectOptional

Data sources the AI may use, e.g. {"scraping": false, "emails": false, "calendarEvents": false, "linkedinMessages": false, "files": false, "notes": false}.

aiTriggersstring[] · nullableOptional

Events that re-run the AI property.

Responses
200

Custom property created successfully

application/json
post/api/columns
POST /api/columns HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 324

{
  "workspaceId": "dd66c03b-1a84-4c9d-b118-3cc54e21d019",
  "entity": "companies",
  "name": "Industry",
  "description": "Primary industry vertical",
  "type": "select",
  "options": [
    {
      "key": "3e839b5c-b311-4887-b2da-727d2d75cdd6",
      "name": "SaaS",
      "color": "#4CAF50"
    },
    {
      "key": "7f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
      "name": "Fintech",
      "color": "#2196F3"
    }
  ]
}
{
  "data": {
    "id": "54e1ca7d-69c3-4b77-8266-8085b5834116",
    "workspaceId": "dd66c03b-1a84-4c9d-b118-3cc54e21d019",
    "entity": "companies",
    "name": "Industry",
    "description": "Primary industry vertical",
    "type": "select",
    "options": [
      {
        "key": "3e839b5c-b311-4887-b2da-727d2d75cdd6",
        "name": "SaaS",
        "color": "#4CAF50"
      },
      {
        "key": "7f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
        "name": "Fintech",
        "color": "#2196F3"
      }
    ],
    "archivedOptions": null,
    "ai": false,
    "archived": false,
    "createdAt": "2026-08-17T09:12:44.000Z",
    "updatedAt": "2026-08-17T09:12:44.000Z"
  },
  "sideEffects": []
}

Get a custom property

get

Returns a single custom property definition by ID.

An unknown or deleted ID returns 200 with an empty data object ({}), not a 404.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
columnIdstring · uuidRequired
Query parameters
fieldsstringOptional

Comma-separated list of fields to return. Defaults to all fields.

Supports relation expansion with dot-notation: a path like company.name embeds the named field of the related record, and quotes.id embeds the id of each related quote. Use .* to embed full related objects, e.g. quotes.*. Related records are returned nested on the response — as an object for to-one relations (e.g. company) or an array for to-many relations (e.g. quotes). Archived related records are excluded.

Example: GET /api/deals/{dealId}?fields=id,name,quotes.id returns the deal with a quotes array of {"id": "<QUOTE_UUID>"} entries.

Example: id,name,domain
Responses
200

Successful response

application/json
get/api/columns/{columnId}
GET /api/columns/{columnId} HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Accept: */*
{
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "workspaceId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": "companies",
    "name": "text",
    "description": "text",
    "key": "text",
    "type": "text",
    "options": [
      {
        "key": "123e4567-e89b-12d3-a456-426614174000",
        "name": "text",
        "color": "text"
      }
    ],
    "archivedOptions": [
      {
        "key": "123e4567-e89b-12d3-a456-426614174000",
        "name": "text",
        "color": "text"
      }
    ],
    "settings": {},
    "ai": true,
    "aiPrompt": {},
    "aiSettings": {},
    "aiTriggers": [
      "text"
    ],
    "source": "text",
    "externalId": "text",
    "importId": "123e4567-e89b-12d3-a456-426614174000",
    "aiContextIds": [
      "123e4567-e89b-12d3-a456-426614174000"
    ],
    "archived": true,
    "archivedAt": "2026-01-01T00:00:00.000Z",
    "archivedById": "123e4567-e89b-12d3-a456-426614174000",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-01-01T00:00:00.000Z",
    "createdById": "123e4567-e89b-12d3-a456-426614174000",
    "updatedById": "123e4567-e89b-12d3-a456-426614174000"
  }
}

Delete a custom property

delete

Remove a custom property definition.

Permanent delete (default)

DELETE /api/columns/{columnId} permanently deletes the definition. Returns {"data": 1} on success and {"data": 0} when no matching non-archived column exists. There is no undo.

Soft delete (archive)

DELETE /api/columns/{columnId}?archive=true sets archived: true instead. The response is {"data": [<archived column>]} — an array containing the full row with archived: true, archivedAt, and archivedById set (or [] if nothing was archived). Archived columns are hidden from the app and excluded from default GET /api/columns results; GET /api/columns/{columnId} returns 200 {} for them. List them with {"archived": true} in where, and restore with PATCH /api/columns/{columnId} {"archived": false}. An archived column cannot be hard-deleted directly — DELETE without ?archive=true returns {"data": 0} — restore it first, then delete.

Warning: Deleting a property does not remove its values from records. Any custom.<column-id> values already stored on companies, contacts, or deals stay in the custom object as orphaned keys — they are no longer shown in the app, filters, or reports. Views that reference the column in settings.columns or filters keep the stale custom.<column-id> reference in their stored JSON; the app simply can no longer resolve it. The id cannot be re-created, so a new property with the same name will not pick the old values back up.

A non-UUID columnId returns 500, not 404.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
columnIdstring · uuidRequired
Query parameters
archivebooleanOptional

Set to true to soft-delete (archive) instead of permanently deleting. Omit for a permanent delete.

Responses
200

Deletion result. data is an integer for a permanent delete and an array of archived rows when ?archive=true was used.

application/json
dataone ofOptional
integerOptional

Permanent delete: 1 if deleted, 0 if not found

or
delete/api/columns/{columnId}
DELETE /api/columns/{columnId} HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Accept: */*
{
  "data": 1,
  "sideEffects": []
}

Update a custom property

patch

Update a custom property definition. Only the fields you send are changed. The response data echoes the fields you sent (even if unchanged) plus id, updatedAt, and updatedById. Unknown fields are silently ignored; an unknown columnId returns 200 with no data rather than a 404.

Renaming / description

Send name and/or description. Values on records are unaffected — they are keyed by the column id, not the name.

Editing options (select / multiselect)

options is replaced as a whole on every write. To add, rename, recolor, or reorder options, send the full desired list. Keep the existing key UUIDs for options that already exist — changing a key orphans every record value that used the old one.

To retire an option without breaking records that still hold it, remove it from options and add it to archivedOptions. Archived options are no longer offered when editing records, but existing values keep resolving to their name. To restore, move it back. Both arrays are replaced wholesale, so send the complete list for each. Option objects are stored as sent — the API does not check that each has a key, so make sure you include one.

{
  "options": [
    { "key": "3e839b5c-b311-4887-b2da-727d2d75cdd6", "name": "SaaS",  "color": "#4CAF50" },
    { "key": "9c8b7a6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d", "name": "Health", "color": "#E91E63" }
  ],
  "archivedOptions": [
    { "key": "7f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c", "name": "Fintech", "color": "#2196F3" }
  ]
}

Changing the type

Changing type between the pairs below kicks off a background migration of the values already stored on records. The PATCH returns immediately (before the migration runs; sideEffects stays []), so re-read records afterwards rather than expecting the PATCH response to reflect it. Locally the migration finishes within milliseconds; on large workspaces allow a little longer. Only non-archived records are migrated.

From → To
What happens to existing values

text / number / percentage / boolean / link / currency / email / phone → select or multiselect

Each distinct plain value becomes an option (matched by name against existing active and archived options; new options are appended to options with a generated key and no color); record values are rewritten to the option key.

select / multiselect → any plain type above

Option keys are resolved to the option's name (active or archived). Target text / link / email / phone gets the name; multiselect → text joins multiple names with ", ". Target number / currency / percentage keeps only numeric names, otherwise null. Target boolean maps true/false/yes/no, otherwise null. For multiselect → numeric/boolean only the first value is considered. The options array stays on the definition (it is not cleared).

select → multiselect, user → users, company → companies, contact → contacts, deal → deals, task → tasks

Single values are wrapped in an array (whatever the value is, active or archived option).

The reverse of each pair above

Arrays are collapsed to their first element.

Any other type change (e.g. text → number, select → date) is accepted on the definition but does not migrate values — records keep whatever was stored, which will usually render as empty or invalid under the new type. type is not validated, so a typo is stored as-is. Avoid changes outside the listed pairs.

Fields you should not change

workspaceId and entity are set at creation and must not be changed — values stored under this column id live on the original entity's records and would be orphaned. To move a property between entities, create a new property on the target entity instead.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
columnIdstring · uuidRequired
Body

Fields that can be patched on a custom property. Send only what you want to change. options and archivedOptions are replaced wholesale — always send the complete list.

namestringOptional
descriptionstring · nullableOptional
typestringOptional

New data type. Only the conversions listed on PATCH /api/columns/{columnId} migrate existing record values (plain ↔ select/multiselect, single ↔ multi). Other changes leave record values untouched and usually unusable.

settingsobjectOptional
aibooleanOptional
aiPromptobject · nullableOptional
aiSettingsobjectOptional
aiTriggersstring[] · nullableOptional
archivedbooleanOptional

Set false to restore a property that was soft-deleted with DELETE …?archive=true.

Responses
200

Property updated. data contains the fields you sent plus id, updatedAt, and updatedById.

application/json
dataobjectOptional
patch/api/columns/{columnId}
PATCH /api/columns/{columnId} HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 85

{
  "name": "Industry vertical",
  "description": "Primary industry the company operates in"
}
{
  "data": {
    "id": "54e1ca7d-69c3-4b77-8266-8085b5834116",
    "name": "Industry vertical",
    "description": "Primary industry the company operates in",
    "updatedAt": "2026-08-17T11:48:37.281Z",
    "updatedById": "b373353e-1a84-4c9d-b118-3cc54e21d019"
  },
  "sideEffects": []
}

Last updated