# Custom Activities

Log and manage custom activities (calls, meetings, and other interactions) linked to companies, contacts, and deals.

## List custom activities

> Returns custom activities the user has access to. Filter by workspace using the \`where\` parameter: \`{"workspaceId": "\<WORKSPACE\_UUID>"}\`.\
> \
> Common filters:\
> \- Activities for a contact: \`{"workspaceId": "\<WS>", "contactIds": {"$includes": "\<CONTACT\_UUID>"}}\`\
> \- Activities by type: \`{"workspaceId": "\<WS>", "typeId": "\<TYPE\_UUID>"}\`\
> \- Activities in a date range: \`{"workspaceId": "\<WS>", "time": {"$gte": "2026-01-01", "$lte": "2026-03-31"}}\`<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activities","description":"Log and manage custom activities (calls, meetings, and other interactions) linked to companies, contacts, and deals.\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":{"CustomActivity":{"type":"object","description":"A logged activity (call, meeting, or custom interaction) linked to companies, contacts, and deals.","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Title or summary of the activity"},"typeId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the custom activity type (e.g. Call, Meeting). Use `GET /api/customActivityTypes` to discover available types."},"type":{"type":"string","nullable":true,"description":"Legacy type string. Prefer using `typeId` for new activities."},"time":{"type":"string","format":"date-time","nullable":true,"description":"When the activity occurred (ISO 8601)"},"content":{"type":"object","nullable":true,"description":"Flexible JSONB object for structured activity data (e.g. call notes, meeting agenda)."},"custom":{"type":"object","nullable":true,"description":"Custom property values defined by the activity type's `customFields`. Keyed by the custom field `id`.\n\nFor example, if the Call type has a custom field with `\"id\": \"call-result\"`, you can store:\n```json\n{\"call-result\": \"connected\"}\n```\n\nWhen updating via PATCH, use dot-notation (e.g. `\"custom.call-result\": \"connected\"`) to avoid overwriting other custom properties.\n"},"userId":{"type":"string","format":"uuid","nullable":true,"description":"The user who performed the activity. Auto-set from the authenticated user on creation if not provided."},"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Multiple users associated with the activity"},"companyIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Companies linked to this activity"},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Contacts linked to this activity"},"dealIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Deals linked to this activity"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"externalId":{"type":"string","nullable":true,"description":"ID from external system for integrations"},"source":{"type":"string","nullable":true}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/customActivities":{"get":{"tags":["Custom Activities"],"summary":"List custom activities","description":"Returns custom activities the user has access to. Filter by workspace using the `where` parameter: `{\"workspaceId\": \"<WORKSPACE_UUID>\"}`.\n\nCommon filters:\n- Activities for a contact: `{\"workspaceId\": \"<WS>\", \"contactIds\": {\"$includes\": \"<CONTACT_UUID>\"}}`\n- Activities by type: `{\"workspaceId\": \"<WS>\", \"typeId\": \"<TYPE_UUID>\"}`\n- Activities in a date range: `{\"workspaceId\": \"<WS>\", \"time\": {\"$gte\": \"2026-01-01\", \"$lte\": \"2026-03-31\"}}`\n","operationId":"listCustomActivities","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/CustomActivity"}},"total":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````

## Create a custom activity

> Create a new custom activity in a workspace.\
> \
> Activities can be linked to multiple companies, contacts, and deals simultaneously via \`companyIds\`, \`contactIds\`, and \`dealIds\`.\
> \
> Use \`typeId\` to associate the activity with a custom activity type (e.g. Call, Meeting). Use \`GET /api/customActivityTypes\` to discover available types.\
> \
> The \`content\` field is a flexible JSONB object for storing structured data about the activity (e.g. call notes, meeting agenda). The \`custom\` field stores custom property values defined on the activity type's \`customFields\`.<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activities","description":"Log and manage custom activities (calls, meetings, and other interactions) linked to companies, contacts, and deals.\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":{"CustomActivityCreate":{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Title or summary of the activity"},"typeId":{"type":"string","format":"uuid","description":"ID of the custom activity type. Use `GET /api/customActivityTypes` to discover available types."},"time":{"type":"string","format":"date-time","description":"When the activity occurred. Defaults to now if not provided."},"content":{"type":"object","description":"Flexible JSONB object for structured activity data."},"custom":{"type":"object","description":"Custom property values keyed by the activity type's custom field IDs."},"userId":{"type":"string","format":"uuid","description":"The user who performed the activity. Auto-set from the authenticated user if not provided."},"userIds":{"type":"array","items":{"type":"string","format":"uuid"}},"companyIds":{"type":"array","items":{"type":"string","format":"uuid"}},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"}},"dealIds":{"type":"array","items":{"type":"string","format":"uuid"}},"externalId":{"type":"string"},"source":{"type":"string"}}},"CustomActivity":{"type":"object","description":"A logged activity (call, meeting, or custom interaction) linked to companies, contacts, and deals.","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Title or summary of the activity"},"typeId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the custom activity type (e.g. Call, Meeting). Use `GET /api/customActivityTypes` to discover available types."},"type":{"type":"string","nullable":true,"description":"Legacy type string. Prefer using `typeId` for new activities."},"time":{"type":"string","format":"date-time","nullable":true,"description":"When the activity occurred (ISO 8601)"},"content":{"type":"object","nullable":true,"description":"Flexible JSONB object for structured activity data (e.g. call notes, meeting agenda)."},"custom":{"type":"object","nullable":true,"description":"Custom property values defined by the activity type's `customFields`. Keyed by the custom field `id`.\n\nFor example, if the Call type has a custom field with `\"id\": \"call-result\"`, you can store:\n```json\n{\"call-result\": \"connected\"}\n```\n\nWhen updating via PATCH, use dot-notation (e.g. `\"custom.call-result\": \"connected\"`) to avoid overwriting other custom properties.\n"},"userId":{"type":"string","format":"uuid","nullable":true,"description":"The user who performed the activity. Auto-set from the authenticated user on creation if not provided."},"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Multiple users associated with the activity"},"companyIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Companies linked to this activity"},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Contacts linked to this activity"},"dealIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Deals linked to this activity"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"externalId":{"type":"string","nullable":true,"description":"ID from external system for integrations"},"source":{"type":"string","nullable":true}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/customActivities":{"post":{"tags":["Custom Activities"],"summary":"Create a custom activity","description":"Create a new custom activity in a workspace.\n\nActivities can be linked to multiple companies, contacts, and deals simultaneously via `companyIds`, `contactIds`, and `dealIds`.\n\nUse `typeId` to associate the activity with a custom activity type (e.g. Call, Meeting). Use `GET /api/customActivityTypes` to discover available types.\n\nThe `content` field is a flexible JSONB object for storing structured data about the activity (e.g. call notes, meeting agenda). The `custom` field stores custom property values defined on the activity type's `customFields`.\n","operationId":"createCustomActivity","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomActivityCreate"}}}},"responses":{"200":{"description":"Custom activity created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomActivity"},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````

## Get a custom activity

> Returns a single custom activity by ID.\
> \
> If the activity 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 Activities","description":"Log and manage custom activities (calls, meetings, and other interactions) linked to companies, contacts, and deals.\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":{"CustomActivity":{"type":"object","description":"A logged activity (call, meeting, or custom interaction) linked to companies, contacts, and deals.","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Title or summary of the activity"},"typeId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the custom activity type (e.g. Call, Meeting). Use `GET /api/customActivityTypes` to discover available types."},"type":{"type":"string","nullable":true,"description":"Legacy type string. Prefer using `typeId` for new activities."},"time":{"type":"string","format":"date-time","nullable":true,"description":"When the activity occurred (ISO 8601)"},"content":{"type":"object","nullable":true,"description":"Flexible JSONB object for structured activity data (e.g. call notes, meeting agenda)."},"custom":{"type":"object","nullable":true,"description":"Custom property values defined by the activity type's `customFields`. Keyed by the custom field `id`.\n\nFor example, if the Call type has a custom field with `\"id\": \"call-result\"`, you can store:\n```json\n{\"call-result\": \"connected\"}\n```\n\nWhen updating via PATCH, use dot-notation (e.g. `\"custom.call-result\": \"connected\"`) to avoid overwriting other custom properties.\n"},"userId":{"type":"string","format":"uuid","nullable":true,"description":"The user who performed the activity. Auto-set from the authenticated user on creation if not provided."},"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Multiple users associated with the activity"},"companyIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Companies linked to this activity"},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Contacts linked to this activity"},"dealIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Deals linked to this activity"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"externalId":{"type":"string","nullable":true,"description":"ID from external system for integrations"},"source":{"type":"string","nullable":true}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/customActivities/{customActivityId}":{"get":{"tags":["Custom Activities"],"summary":"Get a custom activity","description":"Returns a single custom activity by ID.\n\nIf the activity does not exist, the API returns HTTP 200 with an empty body (`{}`).\n","operationId":"getCustomActivity","parameters":[{"name":"customActivityId","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/CustomActivity"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````

## Delete a custom activity

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

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activities","description":"Log and manage custom activities (calls, meetings, and other interactions) linked to companies, contacts, and deals.\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":{"CustomActivity":{"type":"object","description":"A logged activity (call, meeting, or custom interaction) linked to companies, contacts, and deals.","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Title or summary of the activity"},"typeId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the custom activity type (e.g. Call, Meeting). Use `GET /api/customActivityTypes` to discover available types."},"type":{"type":"string","nullable":true,"description":"Legacy type string. Prefer using `typeId` for new activities."},"time":{"type":"string","format":"date-time","nullable":true,"description":"When the activity occurred (ISO 8601)"},"content":{"type":"object","nullable":true,"description":"Flexible JSONB object for structured activity data (e.g. call notes, meeting agenda)."},"custom":{"type":"object","nullable":true,"description":"Custom property values defined by the activity type's `customFields`. Keyed by the custom field `id`.\n\nFor example, if the Call type has a custom field with `\"id\": \"call-result\"`, you can store:\n```json\n{\"call-result\": \"connected\"}\n```\n\nWhen updating via PATCH, use dot-notation (e.g. `\"custom.call-result\": \"connected\"`) to avoid overwriting other custom properties.\n"},"userId":{"type":"string","format":"uuid","nullable":true,"description":"The user who performed the activity. Auto-set from the authenticated user on creation if not provided."},"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Multiple users associated with the activity"},"companyIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Companies linked to this activity"},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Contacts linked to this activity"},"dealIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Deals linked to this activity"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"externalId":{"type":"string","nullable":true,"description":"ID from external system for integrations"},"source":{"type":"string","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/customActivities/{customActivityId}":{"delete":{"tags":["Custom Activities"],"summary":"Delete a custom activity","description":"Delete a custom activity. Use `archive=true` for soft delete.","operationId":"deleteCustomActivity","parameters":[{"name":"customActivityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"archive","in":"query","description":"If true, soft deletes (archives) the activity instead of permanently deleting it.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Custom activity 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 activity object.\n","oneOf":[{"type":"integer"},{"type":"array","items":{"$ref":"#/components/schemas/CustomActivity"}}]},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
````

## Update a custom activity

> Update an existing custom activity.\
> \
> \> \*\*⚠️ Important:\*\* Array fields (\`contactIds\`, \`companyIds\`, \`dealIds\`, \`userIds\`) are \*\*replaced\*\* on PATCH, not merged. Always include all desired IDs.\
> \
> \### Updating custom properties\
> \
> \> \*\*⚠️ Important:\*\* Do \*\*not\*\* pass the entire \`custom\` object when updating custom properties — this will overwrite all existing custom property values on the record.\
> \
> Instead, use \*\*dot-notation\*\* to update individual custom properties:\
> \
> \`\`\`json\
> // ✅ Correct — only updates the specific custom property\
> {"custom.call-result": "connected"}\
> \
> // ❌ Wrong — overwrites the entire custom object\
> {"custom": {"call-result": "connected"}}\
> \`\`\`<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.9.5"},"tags":[{"name":"Custom Activities","description":"Log and manage custom activities (calls, meetings, and other interactions) linked to companies, contacts, and deals.\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":{"CustomActivityUpdate":{"type":"object","description":"All fields are optional. Array fields (`contactIds`, `companyIds`, `dealIds`, `userIds`) replace the existing array entirely on update.\n","properties":{"name":{"type":"string"},"typeId":{"type":"string","format":"uuid"},"time":{"type":"string","format":"date-time"},"content":{"type":"object"},"custom":{"type":"object"},"userId":{"type":"string","format":"uuid"},"userIds":{"type":"array","items":{"type":"string","format":"uuid"}},"companyIds":{"type":"array","items":{"type":"string","format":"uuid"}},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"}},"dealIds":{"type":"array","items":{"type":"string","format":"uuid"}},"externalId":{"type":"string"},"source":{"type":"string"}}},"CustomActivity":{"type":"object","description":"A logged activity (call, meeting, or custom interaction) linked to companies, contacts, and deals.","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Title or summary of the activity"},"typeId":{"type":"string","format":"uuid","nullable":true,"description":"ID of the custom activity type (e.g. Call, Meeting). Use `GET /api/customActivityTypes` to discover available types."},"type":{"type":"string","nullable":true,"description":"Legacy type string. Prefer using `typeId` for new activities."},"time":{"type":"string","format":"date-time","nullable":true,"description":"When the activity occurred (ISO 8601)"},"content":{"type":"object","nullable":true,"description":"Flexible JSONB object for structured activity data (e.g. call notes, meeting agenda)."},"custom":{"type":"object","nullable":true,"description":"Custom property values defined by the activity type's `customFields`. Keyed by the custom field `id`.\n\nFor example, if the Call type has a custom field with `\"id\": \"call-result\"`, you can store:\n```json\n{\"call-result\": \"connected\"}\n```\n\nWhen updating via PATCH, use dot-notation (e.g. `\"custom.call-result\": \"connected\"`) to avoid overwriting other custom properties.\n"},"userId":{"type":"string","format":"uuid","nullable":true,"description":"The user who performed the activity. Auto-set from the authenticated user on creation if not provided."},"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Multiple users associated with the activity"},"companyIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Companies linked to this activity"},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Contacts linked to this activity"},"dealIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Deals linked to this activity"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"externalId":{"type":"string","nullable":true,"description":"ID from external system for integrations"},"source":{"type":"string","nullable":true}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/customActivities/{customActivityId}":{"patch":{"tags":["Custom Activities"],"summary":"Update a custom activity","description":"Update an existing custom activity.\n\n> **⚠️ Important:** Array fields (`contactIds`, `companyIds`, `dealIds`, `userIds`) are **replaced** on PATCH, not merged. Always include all desired IDs.\n\n### Updating custom properties\n\n> **⚠️ Important:** Do **not** pass the entire `custom` object when updating custom properties — this will overwrite all existing custom property values on the record.\n\nInstead, use **dot-notation** to update individual custom properties:\n\n```json\n// ✅ Correct — only updates the specific custom property\n{\"custom.call-result\": \"connected\"}\n\n// ❌ Wrong — overwrites the entire custom object\n{\"custom\": {\"call-result\": \"connected\"}}\n```\n","operationId":"updateCustomActivity","parameters":[{"name":"customActivityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomActivityUpdate"}}}},"responses":{"200":{"description":"Custom activity updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomActivity"},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````
