# Lists

Manage lists of contacts, companies, or deals. Lists come in two types:

* **Regular lists** (`filterBased: false`) — records are explicitly added or removed by patching the `listIds` array on the contact/company/deal record.
* **Dynamic lists** (`filterBased: true`) — records are not stored. The UI dynamically shows all workspace records that match the filters defined on the list's views. Dynamic list membership cannot be queried directly via the API — use a regular `GET /api/contacts` (or companies/deals) query with the same filter criteria instead.

#### List + View pairing (required)

A list without a view is not usable in the UI. Always create at least one view immediately after creating a list using `POST /api/views`. The first view should have `settings.isDefault: true` (or set it via a follow-up PATCH on the view). The UI sets `isDefault` automatically when the list is first opened.

#### Icons

Every list must have an `icon` set. A list without an icon will not display correctly in the UI. See the available icon names in the `icon` field description on `ListCreate`.

#### Filter placement

For dynamic lists, filters belong on the **views** (via `filters` on the View object), not on the list itself. The list-level `filters` field should always be left empty (`{}`). Setting filters on the list object has no effect on what records are shown.

Each list can have multiple views, each with its own independent filter. The UI shows records matching each view's own filter when that view is active.

## List lists

> Returns lists in a workspace. Filter by workspace using \`{"workspaceId": "\<WORKSPACE\_UUID>"}\`.\
> \
> Use \`filterBased\` to distinguish between regular and dynamic lists:\
> \- \`{"workspaceId": "\<WS>", "filterBased": false}\` — regular lists only\
> \- \`{"workspaceId": "\<WS>", "filterBased": true}\` — dynamic lists only<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Lists","description":"Manage lists of contacts, companies, or deals. Lists come in two types:\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added or removed by patching the `listIds` array on the contact/company/deal record.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The UI dynamically shows all workspace records that match the filters defined on the list's views. Dynamic list membership cannot be queried directly via the API — use a regular `GET /api/contacts` (or companies/deals) query with the same filter criteria instead.\n\n### List + View pairing (required)\nA list without a view is not usable in the UI. Always create at least one view immediately after creating a list using `POST /api/views`. The first view should have `settings.isDefault: true` (or set it via a follow-up PATCH on the view). The UI sets `isDefault` automatically when the list is first opened.\n\n### Icons\nEvery list must have an `icon` set. A list without an icon will not display correctly in the UI. See the available icon names in the `icon` field description on `ListCreate`.\n\n### Filter placement\nFor dynamic lists, filters belong on the **views** (via `filters` on the View object), not on the list itself. The list-level `filters` field should always be left empty (`{}`). Setting filters on the list object has no effect on what records are shown.\n\nEach list can have multiple views, each with its own independent filter. The UI shows records matching each view's own filter when that view is active.\n"}],"servers":[{"url":"https://api.zero.inc","description":"Production server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"All API requests require a Bearer token in the Authorization header. Contact the Zero team to obtain your API token."}},"parameters":{"fields":{"name":"fields","in":"query","description":"Comma-separated list of fields to return. Defaults to all fields.","schema":{"type":"string"}},"where":{"name":"where","in":"query","description":"JSON-encoded filter object. All top-level conditions are combined with AND logic. Use `$or` for OR logic.\n\nThe available operators depend on the **data type** of the field you are filtering on.\n\n---\n\n## String fields\nFields like `name`, `domain`, `description`, `linkedin`, `source`, `externalId`, `location`.\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| *(exact)* | Exact match | `{\"name\": \"Linear\"}` |\n| `$eq` | Explicit exact match | `{\"name\": {\"$eq\": \"Linear\"}}` |\n| `$not` | Not equal | `{\"source\": {\"$not\": \"import\"}}` |\n| `$in` | Matches any value in array | `{\"domain\": {\"$in\": [\"linear.app\", \"granola.so\"]}}` |\n| `$notIn` | Matches none of the values | `{\"source\": {\"$notIn\": [\"import\", \"api\"]}}` |\n| `$contains` | Case-insensitive word-boundary substring match | `{\"name\": {\"$contains\": \"YC\"}}` |\n| `$notContains` | Does not contain | `{\"name\": {\"$notContains\": \"Test\"}}` |\n| `$containsAny` | Contains any of the given strings | `{\"name\": {\"$containsAny\": [\"YC\", \"Techstars\"]}}` |\n| `$startsWith` | Starts with prefix | `{\"domain\": {\"$startsWith\": \"app.\"}}` |\n| `$endsWith` | Ends with suffix | `{\"email\": {\"$endsWith\": \"@zero.inc\"}}` |\n| `$exists` | Field is present and truthy | `{\"linkedin\": {\"$exists\": true}}` |\n| `$notExists` | Field is absent, null, or empty | `{\"linkedin\": {\"$notExists\": true}}` |\n\n---\n\n## Number fields\nFields like `value`, `confidence`.\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| *(exact)* | Exact match | `{\"value\": 5000}` |\n| `$eq` | Explicit exact match | `{\"value\": {\"$eq\": 5000}}` |\n| `$not` | Not equal | `{\"value\": {\"$not\": 0}}` |\n| `$gt` | Greater than | `{\"value\": {\"$gt\": 10000}}` |\n| `$gte` | Greater than or equal | `{\"value\": {\"$gte\": 5000}}` |\n| `$lt` | Less than | `{\"value\": {\"$lt\": 10000}}` |\n| `$lte` | Less than or equal | `{\"value\": {\"$lte\": 50000}}` |\n| `$in` | Matches any value in array | `{\"confidence\": {\"$in\": [0.25, 0.5, 0.75]}}` |\n| `$notIn` | Matches none of the values | `{\"confidence\": {\"$notIn\": [0, 1]}}` |\n| `$exists` | Field is present and truthy | `{\"value\": {\"$exists\": true}}` |\n| `$notExists` | Field is absent, null, or zero | `{\"value\": {\"$notExists\": true}}` |\n\nMultiple operators can be combined on one field:\n```json\n{\"value\": {\"$gte\": 5000, \"$lt\": 10000}}\n```\n\n---\n\n## Date fields\nFields like `closeDate`, `startDate`, `endDate`, `createdAt`, `updatedAt`.\n\nValues can be ISO 8601 strings (`\"2026-01-01\"`, `\"2026-01-01T00:00:00Z\"`) or **relative time macros**.\n\n**Relative time macros:** `+Nd` / `-Nd` (days), `+Nw` / `-Nw` (weeks), `+Nm` / `-Nm` (months), `+Ny` / `-Ny` (years), `+Nh` / `-Nh` (hours), `+Ns` / `-Ns` (seconds), `now()`.\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| `$gte` | On or after | `{\"closeDate\": {\"$gte\": \"2026-01-01\"}}` |\n| `$lte` | On or before | `{\"closeDate\": {\"$lte\": \"2026-03-31\"}}` |\n| `$gt` | After | `{\"createdAt\": {\"$gt\": \"2026-01-01T00:00:00Z\"}}` |\n| `$lt` | Before | `{\"createdAt\": {\"$lt\": \"now()\"}}` |\n| `$date` | Exact date match (compares date portion only) | `{\"closeDate\": {\"$date\": \"2026-01-15\"}}` |\n| `$exists` | Field is present and truthy | `{\"closeDate\": {\"$exists\": true}}` |\n| `$notExists` | Field is absent or null | `{\"closeDate\": {\"$notExists\": true}}` |\n\nDate range example:\n```json\n{\"closeDate\": {\"$gte\": \"2026-01-01\", \"$lte\": \"2026-03-31\"}}\n```\nRelative date example (closing in next 30 days):\n```json\n{\"closeDate\": {\"$gte\": \"now()\", \"$lte\": \"+30d\"}}\n```\n\n---\n\n## Array fields\nFields like `listIds`, `ownerIds`, `contactIds`.\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| `$includes` | Array contains the given value (use this — bare exact match is not supported) | `{\"listIds\": {\"$includes\": \"<LIST_UUID>\"}}` |\n| `$notIncludes` | Array does not contain the given value | `{\"ownerIds\": {\"$notIncludes\": \"<USER_UUID>\"}}` |\n| `$overlaps` | Array contains at least one of the given values | `{\"ownerIds\": {\"$overlaps\": [\"<UUID_1>\", \"<UUID_2>\"]}}` |\n| `$notOverlaps` | Array contains none of the given values | `{\"listIds\": {\"$notOverlaps\": [\"<UUID_1>\", \"<UUID_2>\"]}}` |\n| `$all` | Array contains all of the given values | `{\"listIds\": {\"$all\": [\"<UUID_1>\", \"<UUID_2>\"]}}` |\n| `$length` | Filter by array length (supports nested operators) | `{\"contactIds\": {\"$length\": {\"$gte\": 2}}}` |\n| `$exists` | Field is present and non-empty | `{\"ownerIds\": {\"$exists\": true}}` |\n| `$notExists` | Field is absent or empty | `{\"ownerIds\": {\"$notExists\": true}}` |\n\n---\n\n## UUID / ID fields\nFields like `id`, `workspaceId`, `companyId`, `stage`.\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| *(exact)* | Exact match | `{\"stage\": \"<PIPELINE_STAGE_UUID>\"}` |\n| `$in` | Matches any value in array | `{\"stage\": {\"$in\": [\"<UUID_1>\", \"<UUID_2>\"]}}` |\n| `$notIn` | Matches none of the values | `{\"stage\": {\"$notIn\": [\"<UUID_1>\"]}}` |\n| `$not` | Not equal | `{\"stage\": {\"$not\": \"<UUID>\"}}` |\n\n---\n\n## Boolean fields\nFields like `archived`.\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| *(exact)* | Exact match | `{\"archived\": false}` |\n| `$not` | Not equal | `{\"archived\": {\"$not\": true}}` |\n\n---\n\n## Logical operators\nThese work across all data types.\n\n`$or` — matches if **any** sub-condition is true:\n```json\n{\n  \"workspaceId\": \"<WORKSPACE_UUID>\",\n  \"$or\": [\n    {\"ownerIds\": {\"$overlaps\": [\"<USER_UUID_1>\", \"<USER_UUID_2>\"]}},\n    {\"closeDate\": {\"$gte\": \"2026-01-01\"}}\n  ]\n}\n```\n\n`$and` — matches if **all** sub-conditions are true (useful when you need multiple conditions on the same field):\n```json\n{\n  \"$and\": [\n    {\"name\": {\"$contains\": \"Enterprise\"}},\n    {\"name\": {\"$notContains\": \"Test\"}}\n  ]\n}\n```\n\n---\n\n## Dot-notation (relation filtering)\nUse dot-syntax to filter records based on properties of related objects:\n```json\n{\"company.name\": \"Linear\"}\n{\"company.domain\": {\"$in\": [\"linear.app\", \"granola.so\"]}}\n{\"company.location.city\": \"San Francisco\"}\n{\"companyProfile.categories\": {\"$overlaps\": [\"Sales\", \"Marketing\"]}}\n```\nAll operators available for the target field's data type can be used with dot-notation.\n\n---\n\n## Custom property filtering\nCustom 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.\n\nFilter on custom properties using `custom.<COLUMN_ID>` with operators appropriate for the column's type.\n\n> **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.\n\n```json\n// Text custom property\n{\"custom.54e1ca7d-69c3-4b77-8266-8085b5834116\": {\"$contains\": \"enterprise\"}}\n\n// Select custom property (use the option key UUID)\n{\"custom.a1b2c3d4-e5f6-7890-abcd-ef1234567890\": \"3e839b5c-b311-4887-b2da-727d2d75cdd6\"}\n\n// Multi-select custom property (use option key UUIDs)\n{\"custom.b2c3d4e5-f6a7-8901-bcde-f12345678901\": {\"$overlaps\": [\"a1b1c1d1-e1f1-1111-aaaa-111111111111\", \"b2b2c2d2-e2f2-2222-bbbb-222222222222\"]}}\n\n// Currency/number custom property\n{\"custom.c3d4e5f6-a7b8-9012-cdef-123456789012\": {\"$gte\": 100000}}\n\n// Date custom property\n{\"custom.d4e5f6a7-b8c9-0123-defa-234567890123\": {\"$gte\": \"2026-01-01\"}}\n\n// Boolean custom property\n{\"custom.e5f6a7b8-c9d0-1234-efab-345678901234\": true}\n\n// Check if custom property has a value\n{\"custom.f6a7b8c9-d0e1-2345-fabc-456789012345\": {\"$exists\": true}}\n```\n\n---\n\n## Complex example\nAll top-level keys are ANDed together:\n```json\n{\n  \"name\": {\"$contains\": \"Zero\"},\n  \"location.city\": \"Helsinki\",\n  \"location.country\": {\"$in\": [\"United Kingdom\", \"Germany\", \"Sweden\"]},\n  \"value\": {\"$gte\": 10000},\n  \"closeDate\": {\"$gte\": \"2026-01-01\", \"$lte\": \"2026-03-31\"},\n  \"ownerIds\": {\"$includes\": \"<USER_UUID>\"},\n  \"stage\": {\"$in\": [\"<UUID_1>\", \"<UUID_2>\"]},\n  \"lastActivity\": {\"$exists\": true},\n  \"companyProfile.categories\": {\"$overlaps\": [\"Sales\", \"Marketing\"]},\n  \"custom.54e1ca7d-69c3-4b77-8266-8085b5834116\": {\"$contains\": \"enterprise\"}\n}\n```\n","schema":{"type":"string"}},"limit":{"name":"limit","in":"query","description":"Maximum number of records to return","schema":{"type":"integer","default":100}},"offset":{"name":"offset","in":"query","description":"Pagination offset","schema":{"type":"integer","default":0}},"orderBy":{"name":"orderBy","in":"query","description":"JSON string for sort order","schema":{"type":"string"}}},"schemas":{"List":{"type":"object","description":"A list groups records of a single entity type (contacts, companies, or deals).\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added via the `listIds` field on contact/company/deal PATCH.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The list shows all records matching the filters defined on its views.\n\nEvery list must have an `icon` set to display correctly in the UI.\nEvery list must have at least one view to be usable in the UI.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string"},"entity":{"type":"string","enum":["contacts","companies","deals"],"description":"The type of records this list contains"},"filterBased":{"type":"boolean","description":"`true` for dynamic lists, `false` for regular lists"},"filters":{"type":"object","description":"Should be left empty (`{}`). Filters for dynamic lists belong on the **views**, not on the list itself.\nThe API will accept and store values here, but the UI uses view-level filters to determine which records are shown — not this field.\n"},"icon":{"type":"string","nullable":true,"description":"Icon name from the Zero icon set. See the `ListCreate` schema for the full list of valid values.\nRequired — lists without an icon do not display correctly in the UI.\n"},"color":{"type":"string","nullable":true,"description":"Hex color code (e.g. `\"#8B5CF6\"`)"},"order":{"type":"integer","nullable":true},"listFolderId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the folder this list belongs to, if any"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/lists":{"get":{"tags":["Lists"],"summary":"List lists","description":"Returns lists in a workspace. Filter by workspace using `{\"workspaceId\": \"<WORKSPACE_UUID>\"}`.\n\nUse `filterBased` to distinguish between regular and dynamic lists:\n- `{\"workspaceId\": \"<WS>\", \"filterBased\": false}` — regular lists only\n- `{\"workspaceId\": \"<WS>\", \"filterBased\": true}` — dynamic lists only\n","operationId":"listLists","parameters":[{"$ref":"#/components/parameters/fields"},{"$ref":"#/components/parameters/where"},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/offset"},{"$ref":"#/components/parameters/orderBy"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/List"}},"total":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````

## Create a list

> Create a new list. Set \`filterBased: true\` to create a dynamic list, or \`filterBased: false\` (default) for a regular list.\
> \
> \*\*Always set an \`icon\`\*\* — lists without an icon do not display correctly in the UI.\
> \
> After creating a list, immediately create at least one view with \`POST /api/views\` to make the list usable. A list without a view cannot be opened in the UI.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Lists","description":"Manage lists of contacts, companies, or deals. Lists come in two types:\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added or removed by patching the `listIds` array on the contact/company/deal record.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The UI dynamically shows all workspace records that match the filters defined on the list's views. Dynamic list membership cannot be queried directly via the API — use a regular `GET /api/contacts` (or companies/deals) query with the same filter criteria instead.\n\n### List + View pairing (required)\nA list without a view is not usable in the UI. Always create at least one view immediately after creating a list using `POST /api/views`. The first view should have `settings.isDefault: true` (or set it via a follow-up PATCH on the view). The UI sets `isDefault` automatically when the list is first opened.\n\n### Icons\nEvery list must have an `icon` set. A list without an icon will not display correctly in the UI. See the available icon names in the `icon` field description on `ListCreate`.\n\n### Filter placement\nFor dynamic lists, filters belong on the **views** (via `filters` on the View object), not on the list itself. The list-level `filters` field should always be left empty (`{}`). Setting filters on the list object has no effect on what records are shown.\n\nEach list can have multiple views, each with its own independent filter. The UI shows records matching each view's own filter when that view is active.\n"}],"servers":[{"url":"https://api.zero.inc","description":"Production server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"All API requests require a Bearer token in the Authorization header. Contact the Zero team to obtain your API token."}},"schemas":{"ListCreate":{"type":"object","required":["workspaceId","name","entity","icon"],"properties":{"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string"},"entity":{"type":"string","enum":["contacts","companies","deals"]},"filterBased":{"type":"boolean","default":false,"description":"`true` for dynamic list, `false` for regular list"},"color":{"type":"string","description":"Hex color code (e.g. `\"#8B5CF6\"`)"},"icon":{"type":"string","description":"Required. Icon name from the Zero icon set.","enum":["access-point","activity-heartbeat","adjustments-alt","adjustments-horizontal","affiliate","alarm","alert-hexagon","alert-triangle","analyze","antenna-bars-5","aperture","api-app","archery-arrow","archive","armchair","arrow-back-up","arrow-bar-to-down","arrow-bar-to-left","arrow-bar-to-right","arrow-bar-to-up","arrow-bear-right","arrow-big-down","arrow-big-left","arrow-bounce","arrow-down-circle","arrow-down-left-circle","arrow-down-right-circle","arrow-forward-up","arrow-left-circle","arrow-narrow-left","arrow-narrow-right","arrow-right-circle","arrow-up-circle","arrow-up-left-circle","arrow-up-right-circle","arrows-diagonal","arrows-diagonal-2","arrows-double-ne-sw","arrows-double-nw-se","arrows-double-se-nw","arrows-double-sw-ne","arrows-exchange","arrows-horizontal","arrows-join","arrows-join-2","arrows-left-down","arrows-left-right","arrows-maximize","arrows-minimize","arrows-right-down","arrows-right-left","arrows-sort","arrows-split","arrows-split-2","arrows-transfer-down","arrows-transfer-up","arrows-vertical","artboard","artboard-off","aspect-ratio","assembly","asset","asterisk","asterisk-simple","at","at-off","atom","augmented-reality","automatic-gearbox","award","award-off","axe","axis-x","axis-y","baby-carriage","backhoe","backpack","badge","badges","ball-american-football","ball-baseball","ball-basketball","ball-bowling","ball-football","ball-tennis","ball-volleyball","balloon","balloon-off","ballpen","ballpen-off","bandage","barbell","barcode","barrel","barrier-block","baseline","basket","basket-off","bath","battery","battery-charging","battery-off","beach","bell","bike","binoculars","bleach","blob","blur","bolt","bookmark","border-all","border-corners","bowl-chopsticks","box","box-model-2","box-multiple","brackets-angle","brain","briefcase","brightness-down","broadcast","brush","bug","building","building-bank","building-castle","bulb","cactus","calculator","calendar","camera","capture","car","car-fan","carambola","cardboards","cash-banknote","chart-bar","chart-funnel","chart-line","chart-pie","check","chess-king","chess-rook","chevron-down","chevron-down-left","chevron-down-right","chevron-left","chevron-right","chevron-up","chevron-up-left","chevron-up-right","chevrons-down","chevrons-down-left","chevrons-down-right","chevrons-left","chevrons-right","chevrons-up","chevrons-up-left","chevrons-up-right","circle","clipboard","clock","cloud","code","coffee","coin","compass","confetti","copy","crane","credit-card","crown","currency-dollar","currency-euro","cut","cylinder","dashboard","database","details","device-desktop","device-gamepad-2","diamond","diamonds","direction-sign","disc","discount","dna","droplet","ear","edit","exchange","eye","eyeglass","feather","file","file-text","filter","fingerprint","flag","flag-3","flame","flask","flower","focus-2","folder","forbid-2","frustum","gauge","geometry","gift","glass-cocktail","golf","graph","hand-finger","hand-love-you","headphones","heart","hexagonal-pyramid","hierarchy","home","hourglass-empty","jacket","key","keyframe","keyframe-align-horizontal","keyframes","label","laurel-wreath","layers-subtract","layout-board","layout-cards","layout-grid","leaf","lemon","license","link","location","lock-open","mail","mailbox","map-pin","mask","medical-cross","message-chatbot","message-dots","microphone","moneybag","mood-empty","mood-happy","mood-sad","mood-share","mood-smile","moon","mouse-2","mug","music","nut","paperclip","phone","plane-tilt","plant","plus-circle","pointer","presentation","rainbow","road","rocket","rosette-discount-check","rotate-dot","rubber-stamp","run","scale","scissors","search","send","settings","shield","shopping-cart","sparkles","speakerphone","spiral","star","sun","tag","tags","target","thumb-down","thumb-up","timeline-event","toggle-left","tool","trash","trending-up","triangle-inverted","trophy","umbrella","upload","user","users","video","volume","volume-2","wallet","webhook","wifi","windmill","world","x"]},"order":{"type":"integer"},"listFolderId":{"type":"string","format":"uuid","nullable":true}}},"List":{"type":"object","description":"A list groups records of a single entity type (contacts, companies, or deals).\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added via the `listIds` field on contact/company/deal PATCH.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The list shows all records matching the filters defined on its views.\n\nEvery list must have an `icon` set to display correctly in the UI.\nEvery list must have at least one view to be usable in the UI.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string"},"entity":{"type":"string","enum":["contacts","companies","deals"],"description":"The type of records this list contains"},"filterBased":{"type":"boolean","description":"`true` for dynamic lists, `false` for regular lists"},"filters":{"type":"object","description":"Should be left empty (`{}`). Filters for dynamic lists belong on the **views**, not on the list itself.\nThe API will accept and store values here, but the UI uses view-level filters to determine which records are shown — not this field.\n"},"icon":{"type":"string","nullable":true,"description":"Icon name from the Zero icon set. See the `ListCreate` schema for the full list of valid values.\nRequired — lists without an icon do not display correctly in the UI.\n"},"color":{"type":"string","nullable":true,"description":"Hex color code (e.g. `\"#8B5CF6\"`)"},"order":{"type":"integer","nullable":true},"listFolderId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the folder this list belongs to, if any"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/lists":{"post":{"tags":["Lists"],"summary":"Create a list","description":"Create a new list. Set `filterBased: true` to create a dynamic list, or `filterBased: false` (default) for a regular list.\n\n**Always set an `icon`** — lists without an icon do not display correctly in the UI.\n\nAfter creating a list, immediately create at least one view with `POST /api/views` to make the list usable. A list without a view cannot be opened in the UI.\n","operationId":"createList","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCreate"}}}},"responses":{"200":{"description":"List created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/List"},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Get a list

> Retrieve a single list by ID.

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Lists","description":"Manage lists of contacts, companies, or deals. Lists come in two types:\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added or removed by patching the `listIds` array on the contact/company/deal record.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The UI dynamically shows all workspace records that match the filters defined on the list's views. Dynamic list membership cannot be queried directly via the API — use a regular `GET /api/contacts` (or companies/deals) query with the same filter criteria instead.\n\n### List + View pairing (required)\nA list without a view is not usable in the UI. Always create at least one view immediately after creating a list using `POST /api/views`. The first view should have `settings.isDefault: true` (or set it via a follow-up PATCH on the view). The UI sets `isDefault` automatically when the list is first opened.\n\n### Icons\nEvery list must have an `icon` set. A list without an icon will not display correctly in the UI. See the available icon names in the `icon` field description on `ListCreate`.\n\n### Filter placement\nFor dynamic lists, filters belong on the **views** (via `filters` on the View object), not on the list itself. The list-level `filters` field should always be left empty (`{}`). Setting filters on the list object has no effect on what records are shown.\n\nEach list can have multiple views, each with its own independent filter. The UI shows records matching each view's own filter when that view is active.\n"}],"servers":[{"url":"https://api.zero.inc","description":"Production server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"All API requests require a Bearer token in the Authorization header. Contact the Zero team to obtain your API token."}},"schemas":{"List":{"type":"object","description":"A list groups records of a single entity type (contacts, companies, or deals).\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added via the `listIds` field on contact/company/deal PATCH.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The list shows all records matching the filters defined on its views.\n\nEvery list must have an `icon` set to display correctly in the UI.\nEvery list must have at least one view to be usable in the UI.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string"},"entity":{"type":"string","enum":["contacts","companies","deals"],"description":"The type of records this list contains"},"filterBased":{"type":"boolean","description":"`true` for dynamic lists, `false` for regular lists"},"filters":{"type":"object","description":"Should be left empty (`{}`). Filters for dynamic lists belong on the **views**, not on the list itself.\nThe API will accept and store values here, but the UI uses view-level filters to determine which records are shown — not this field.\n"},"icon":{"type":"string","nullable":true,"description":"Icon name from the Zero icon set. See the `ListCreate` schema for the full list of valid values.\nRequired — lists without an icon do not display correctly in the UI.\n"},"color":{"type":"string","nullable":true,"description":"Hex color code (e.g. `\"#8B5CF6\"`)"},"order":{"type":"integer","nullable":true},"listFolderId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the folder this list belongs to, if any"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/lists/{listId}":{"get":{"tags":["Lists"],"summary":"Get a list","description":"Retrieve a single list by ID.","operationId":"getList","parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/List"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Delete a list

> Delete a list. By default performs a hard delete (\`data: 1\`). Pass \`?archive=true\` for a soft delete.\
> \
> \> \*\*Note:\*\* Deleting a list does not delete the records within it. For regular lists, the records simply lose their association with the list.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Lists","description":"Manage lists of contacts, companies, or deals. Lists come in two types:\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added or removed by patching the `listIds` array on the contact/company/deal record.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The UI dynamically shows all workspace records that match the filters defined on the list's views. Dynamic list membership cannot be queried directly via the API — use a regular `GET /api/contacts` (or companies/deals) query with the same filter criteria instead.\n\n### List + View pairing (required)\nA list without a view is not usable in the UI. Always create at least one view immediately after creating a list using `POST /api/views`. The first view should have `settings.isDefault: true` (or set it via a follow-up PATCH on the view). The UI sets `isDefault` automatically when the list is first opened.\n\n### Icons\nEvery list must have an `icon` set. A list without an icon will not display correctly in the UI. See the available icon names in the `icon` field description on `ListCreate`.\n\n### Filter placement\nFor dynamic lists, filters belong on the **views** (via `filters` on the View object), not on the list itself. The list-level `filters` field should always be left empty (`{}`). Setting filters on the list object has no effect on what records are shown.\n\nEach list can have multiple views, each with its own independent filter. The UI shows records matching each view's own filter when that view is active.\n"}],"servers":[{"url":"https://api.zero.inc","description":"Production server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"All API requests require a Bearer token in the Authorization header. Contact the Zero team to obtain your API token."}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/lists/{listId}":{"delete":{"tags":["Lists"],"summary":"Delete a list","description":"Delete a list. By default performs a hard delete (`data: 1`). Pass `?archive=true` for a soft delete.\n\n> **Note:** Deleting a list does not delete the records within it. For regular lists, the records simply lose their association with the list.\n","operationId":"deleteList","parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"archive","in":"query","schema":{"type":"boolean","default":false},"description":"If true, soft-deletes (archives) the list instead of permanently deleting it"}],"responses":{"200":{"description":"Deletion result","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"oneOf":[{"type":"integer","description":"`1` on hard delete success, `0` if not found"},{"type":"array","description":"Archived list object(s) on soft delete"}]},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Update a list

> Update a list's metadata (name, color, icon, etc.). Returns only the changed fields.\
> \`entity\` is immutable and cannot be changed after creation.

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Lists","description":"Manage lists of contacts, companies, or deals. Lists come in two types:\n\n- **Regular lists** (`filterBased: false`) — records are explicitly added or removed by patching the `listIds` array on the contact/company/deal record.\n- **Dynamic lists** (`filterBased: true`) — records are not stored. The UI dynamically shows all workspace records that match the filters defined on the list's views. Dynamic list membership cannot be queried directly via the API — use a regular `GET /api/contacts` (or companies/deals) query with the same filter criteria instead.\n\n### List + View pairing (required)\nA list without a view is not usable in the UI. Always create at least one view immediately after creating a list using `POST /api/views`. The first view should have `settings.isDefault: true` (or set it via a follow-up PATCH on the view). The UI sets `isDefault` automatically when the list is first opened.\n\n### Icons\nEvery list must have an `icon` set. A list without an icon will not display correctly in the UI. See the available icon names in the `icon` field description on `ListCreate`.\n\n### Filter placement\nFor dynamic lists, filters belong on the **views** (via `filters` on the View object), not on the list itself. The list-level `filters` field should always be left empty (`{}`). Setting filters on the list object has no effect on what records are shown.\n\nEach list can have multiple views, each with its own independent filter. The UI shows records matching each view's own filter when that view is active.\n"}],"servers":[{"url":"https://api.zero.inc","description":"Production server"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"All API requests require a Bearer token in the Authorization header. Contact the Zero team to obtain your API token."}},"schemas":{"ListUpdate":{"type":"object","description":"All fields are optional. Multiple fields can be updated in a single PATCH request.","properties":{"name":{"type":"string"},"color":{"type":"string"},"icon":{"type":"string"},"filterBased":{"type":"boolean","description":"Convert between regular and dynamic list. When switching to `true`, set filters on each view rather than on the list itself."},"filters":{"type":"object","description":"The API accepts and stores values here, but the UI uses view-level filters to determine which records are shown.\nRecommended to leave as `{}` and set filters on views instead.\n"},"order":{"type":"integer"},"listFolderId":{"type":"string","format":"uuid","nullable":true}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/lists/{listId}":{"patch":{"tags":["Lists"],"summary":"Update a list","description":"Update a list's metadata (name, color, icon, etc.). Returns only the changed fields.\n`entity` is immutable and cannot be changed after creation.","operationId":"updateList","parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListUpdate"}}}},"responses":{"200":{"description":"List updated. Only changed fields are returned in `data`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```
