# Custom Activity Types

Manage activity type definitions for a workspace. Each workspace comes with default types (Call, Meeting) and supports creating additional custom types.

## List custom activity types

> Returns custom activity type definitions for a workspace. Filter by workspace using the \`where\` parameter: \`{"workspaceId": "\<WORKSPACE\_UUID>"}\`.\
> \
> Each workspace comes with default types (Call, Meeting). Use this endpoint to discover available types and their custom fields before creating activities.<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activity Types","description":"Manage activity type definitions for a workspace. Each workspace comes with default types (Call, Meeting) and supports creating additional custom types.\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":{"CustomActivityType":{"type":"object","description":"A definition for a type of activity that can be logged in a workspace (e.g. Call, Meeting, Site Visit).\n\nEach type can define custom fields that appear when logging an activity. Default types (Call, Meeting) are created automatically for new workspaces.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Display name of the activity type (e.g. \"Call\", \"Meeting\")"},"icon":{"type":"string","nullable":true,"description":"Icon identifier (e.g. \"phone\", \"calendar\", \"building\")"},"color":{"type":"string","nullable":true,"description":"Hex color code for UI display (e.g. \"#C48E1C\")"},"shortcut":{"type":"string","nullable":true,"description":"Keyboard shortcut key for quick activity logging (e.g. \"K\" for Call, \"M\" for Meeting)"},"description":{"type":"string","nullable":true,"description":"Human-readable description of the activity type"},"customFields":{"type":"array","description":"Custom field definitions for this activity type. When creating an activity with this type, the `custom` object on the activity can contain values keyed by these field IDs.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the custom field. Used as the key in the activity's `custom` object."},"name":{"type":"string","description":"Human-readable field name"},"type":{"type":"string","description":"Field type (e.g. \"select\", \"text\", \"number\")"},"options":{"type":"array","description":"Available options for select-type fields","items":{"type":"object","properties":{"key":{"type":"string","description":"The value stored on the activity"},"name":{"type":"string","description":"Human-readable option name"},"color":{"type":"string","description":"Hex color code for UI display"}}}}}}},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"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/customActivityTypes":{"get":{"tags":["Custom Activity Types"],"summary":"List custom activity types","description":"Returns custom activity type definitions for a workspace. Filter by workspace using the `where` parameter: `{\"workspaceId\": \"<WORKSPACE_UUID>\"}`.\n\nEach workspace comes with default types (Call, Meeting). Use this endpoint to discover available types and their custom fields before creating activities.\n","operationId":"listCustomActivityTypes","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/CustomActivityType"}},"total":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````

## Create a custom activity type

> Create a new activity type definition in a workspace. Activity types define the categories of activities users can log (e.g. Call, Meeting, Site Visit).\
> \
> Each type can have custom fields that appear when logging an activity of that type.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activity Types","description":"Manage activity type definitions for a workspace. Each workspace comes with default types (Call, Meeting) and supports creating additional custom types.\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":{"CustomActivityTypeCreate":{"type":"object","required":["workspaceId","name"],"properties":{"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Display name of the activity type"},"icon":{"type":"string","description":"Icon identifier"},"color":{"type":"string","description":"Hex color code"},"shortcut":{"type":"string","description":"Keyboard shortcut key"},"description":{"type":"string"},"customFields":{"type":"array","description":"Custom field definitions for this activity type","items":{"type":"object","required":["id","name","type"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"options":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"color":{"type":"string"}}}}}}}}},"CustomActivityType":{"type":"object","description":"A definition for a type of activity that can be logged in a workspace (e.g. Call, Meeting, Site Visit).\n\nEach type can define custom fields that appear when logging an activity. Default types (Call, Meeting) are created automatically for new workspaces.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Display name of the activity type (e.g. \"Call\", \"Meeting\")"},"icon":{"type":"string","nullable":true,"description":"Icon identifier (e.g. \"phone\", \"calendar\", \"building\")"},"color":{"type":"string","nullable":true,"description":"Hex color code for UI display (e.g. \"#C48E1C\")"},"shortcut":{"type":"string","nullable":true,"description":"Keyboard shortcut key for quick activity logging (e.g. \"K\" for Call, \"M\" for Meeting)"},"description":{"type":"string","nullable":true,"description":"Human-readable description of the activity type"},"customFields":{"type":"array","description":"Custom field definitions for this activity type. When creating an activity with this type, the `custom` object on the activity can contain values keyed by these field IDs.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the custom field. Used as the key in the activity's `custom` object."},"name":{"type":"string","description":"Human-readable field name"},"type":{"type":"string","description":"Field type (e.g. \"select\", \"text\", \"number\")"},"options":{"type":"array","description":"Available options for select-type fields","items":{"type":"object","properties":{"key":{"type":"string","description":"The value stored on the activity"},"name":{"type":"string","description":"Human-readable option name"},"color":{"type":"string","description":"Hex color code for UI display"}}}}}}},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"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/customActivityTypes":{"post":{"tags":["Custom Activity Types"],"summary":"Create a custom activity type","description":"Create a new activity type definition in a workspace. Activity types define the categories of activities users can log (e.g. Call, Meeting, Site Visit).\n\nEach type can have custom fields that appear when logging an activity of that type.\n","operationId":"createCustomActivityType","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomActivityTypeCreate"}}}},"responses":{"200":{"description":"Custom activity type created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomActivityType"},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Get a custom activity type

> Returns a single custom activity type by ID.\
> \
> If the type does not exist, the API returns HTTP 200 with an empty body (\`{}\`).<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activity Types","description":"Manage activity type definitions for a workspace. Each workspace comes with default types (Call, Meeting) and supports creating additional custom types.\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":{"CustomActivityType":{"type":"object","description":"A definition for a type of activity that can be logged in a workspace (e.g. Call, Meeting, Site Visit).\n\nEach type can define custom fields that appear when logging an activity. Default types (Call, Meeting) are created automatically for new workspaces.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Display name of the activity type (e.g. \"Call\", \"Meeting\")"},"icon":{"type":"string","nullable":true,"description":"Icon identifier (e.g. \"phone\", \"calendar\", \"building\")"},"color":{"type":"string","nullable":true,"description":"Hex color code for UI display (e.g. \"#C48E1C\")"},"shortcut":{"type":"string","nullable":true,"description":"Keyboard shortcut key for quick activity logging (e.g. \"K\" for Call, \"M\" for Meeting)"},"description":{"type":"string","nullable":true,"description":"Human-readable description of the activity type"},"customFields":{"type":"array","description":"Custom field definitions for this activity type. When creating an activity with this type, the `custom` object on the activity can contain values keyed by these field IDs.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the custom field. Used as the key in the activity's `custom` object."},"name":{"type":"string","description":"Human-readable field name"},"type":{"type":"string","description":"Field type (e.g. \"select\", \"text\", \"number\")"},"options":{"type":"array","description":"Available options for select-type fields","items":{"type":"object","properties":{"key":{"type":"string","description":"The value stored on the activity"},"name":{"type":"string","description":"Human-readable option name"},"color":{"type":"string","description":"Hex color code for UI display"}}}}}}},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"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/customActivityTypes/{customActivityTypeId}":{"get":{"tags":["Custom Activity Types"],"summary":"Get a custom activity type","description":"Returns a single custom activity type by ID.\n\nIf the type does not exist, the API returns HTTP 200 with an empty body (`{}`).\n","operationId":"getCustomActivityType","parameters":[{"name":"customActivityTypeId","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/CustomActivityType"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Delete a custom activity type

> Delete a custom activity type. Use \`archive=true\` for soft delete.

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activity Types","description":"Manage activity type definitions for a workspace. Each workspace comes with default types (Call, Meeting) and supports creating additional custom types.\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":{"CustomActivityType":{"type":"object","description":"A definition for a type of activity that can be logged in a workspace (e.g. Call, Meeting, Site Visit).\n\nEach type can define custom fields that appear when logging an activity. Default types (Call, Meeting) are created automatically for new workspaces.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Display name of the activity type (e.g. \"Call\", \"Meeting\")"},"icon":{"type":"string","nullable":true,"description":"Icon identifier (e.g. \"phone\", \"calendar\", \"building\")"},"color":{"type":"string","nullable":true,"description":"Hex color code for UI display (e.g. \"#C48E1C\")"},"shortcut":{"type":"string","nullable":true,"description":"Keyboard shortcut key for quick activity logging (e.g. \"K\" for Call, \"M\" for Meeting)"},"description":{"type":"string","nullable":true,"description":"Human-readable description of the activity type"},"customFields":{"type":"array","description":"Custom field definitions for this activity type. When creating an activity with this type, the `custom` object on the activity can contain values keyed by these field IDs.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the custom field. Used as the key in the activity's `custom` object."},"name":{"type":"string","description":"Human-readable field name"},"type":{"type":"string","description":"Field type (e.g. \"select\", \"text\", \"number\")"},"options":{"type":"array","description":"Available options for select-type fields","items":{"type":"object","properties":{"key":{"type":"string","description":"The value stored on the activity"},"name":{"type":"string","description":"Human-readable option name"},"color":{"type":"string","description":"Hex color code for UI display"}}}}}}},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"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"}}}}}},"NotFound":{"description":"The requested resource was not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/customActivityTypes/{customActivityTypeId}":{"delete":{"tags":["Custom Activity Types"],"summary":"Delete a custom activity type","description":"Delete a custom activity type. Use `archive=true` for soft delete.","operationId":"deleteCustomActivityType","parameters":[{"name":"customActivityTypeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"archive","in":"query","description":"If true, soft deletes (archives) the type instead of permanently deleting it.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Custom activity type deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"Hard delete (`archive` omitted or `false`): returns `1` on success.\nSoft delete (`archive=true`): returns a single-element array containing the archived type object.\n","oneOf":[{"type":"integer"},{"type":"array","items":{"$ref":"#/components/schemas/CustomActivityType"}}]},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Update a custom activity type

> Update an existing custom activity type.\
> \
> \> \*\*⚠️ Important:\*\* The \`customFields\` array is \*\*replaced\*\* entirely on update, not merged. Always include all desired custom fields when patching.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activity Types","description":"Manage activity type definitions for a workspace. Each workspace comes with default types (Call, Meeting) and supports creating additional custom types.\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":{"CustomActivityTypeUpdate":{"type":"object","description":"All fields are optional. The `customFields` array replaces the existing array entirely on update — always include all desired fields.\n","properties":{"name":{"type":"string"},"icon":{"type":"string"},"color":{"type":"string"},"shortcut":{"type":"string"},"description":{"type":"string"},"customFields":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"options":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"color":{"type":"string"}}}}}}}}},"CustomActivityType":{"type":"object","description":"A definition for a type of activity that can be logged in a workspace (e.g. Call, Meeting, Site Visit).\n\nEach type can define custom fields that appear when logging an activity. Default types (Call, Meeting) are created automatically for new workspaces.\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Display name of the activity type (e.g. \"Call\", \"Meeting\")"},"icon":{"type":"string","nullable":true,"description":"Icon identifier (e.g. \"phone\", \"calendar\", \"building\")"},"color":{"type":"string","nullable":true,"description":"Hex color code for UI display (e.g. \"#C48E1C\")"},"shortcut":{"type":"string","nullable":true,"description":"Keyboard shortcut key for quick activity logging (e.g. \"K\" for Call, \"M\" for Meeting)"},"description":{"type":"string","nullable":true,"description":"Human-readable description of the activity type"},"customFields":{"type":"array","description":"Custom field definitions for this activity type. When creating an activity with this type, the `custom` object on the activity can contain values keyed by these field IDs.\n","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the custom field. Used as the key in the activity's `custom` object."},"name":{"type":"string","description":"Human-readable field name"},"type":{"type":"string","description":"Field type (e.g. \"select\", \"text\", \"number\")"},"options":{"type":"array","description":"Available options for select-type fields","items":{"type":"object","properties":{"key":{"type":"string","description":"The value stored on the activity"},"name":{"type":"string","description":"Human-readable option name"},"color":{"type":"string","description":"Hex color code for UI display"}}}}}}},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"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/customActivityTypes/{customActivityTypeId}":{"patch":{"tags":["Custom Activity Types"],"summary":"Update a custom activity type","description":"Update an existing custom activity type.\n\n> **⚠️ Important:** The `customFields` array is **replaced** entirely on update, not merged. Always include all desired custom fields when patching.\n","operationId":"updateCustomActivityType","parameters":[{"name":"customActivityTypeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomActivityTypeUpdate"}}}},"responses":{"200":{"description":"Custom activity type updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomActivityType"},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```
