> For the complete documentation index, see [llms.txt](https://docs.zero.inc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.zero.inc/features/api/files.md).

# Files

Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.

## List files

> Returns file records the user has access to. Filter by workspace using the \`where\` parameter: \`{"workspaceId": "\<WORKSPACE\_UUID>"}\`.\
> \
> Files can also be filtered by \`companyId\`, \`contactId\`, \`dealId\`, or \`noteId\` to retrieve files attached to a specific record.\
> \
> \> \*\*Note:\*\* Files are created by uploading via \`POST /api/files/upload\` (multipart/form-data), \*\*not\*\* by a JSON \`POST /api/files\`.<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.11.0"},"tags":[{"name":"Files","description":"Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.\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. Create an API key from [Workspace Settings → API keys](https://app.zero.inc/settings/workspace/api)"}},"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":{"File":{"type":"object","description":"A file or attachment uploaded to a workspace. Created via `POST /api/files/upload` (multipart/form-data).\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true,"description":"Company this file is attached to, if any."},"contactId":{"type":"string","format":"uuid","nullable":true,"description":"Contact this file is attached to, if any."},"dealId":{"type":"string","format":"uuid","nullable":true,"description":"Deal this file is attached to, if any."},"noteId":{"type":"string","format":"uuid","nullable":true,"description":"Note this file is attached to, if any."},"calendarEventId":{"type":"string","format":"uuid","nullable":true},"placement":{"type":"string","nullable":true,"description":"Optional placement/context label for the file."},"url":{"type":"string","nullable":true,"description":"Storage URL for the file. For `type=file` uploads this points to authenticated storage and is not directly accessible — use `GET /api/files/download` to get a signed URL.\n"},"thumbnailUrl":{"type":"string","nullable":true,"description":"Generated thumbnail image URL, or `null` if the content type does not support previews."},"previewUrl":{"type":"string","nullable":true,"description":"Generated preview image URL, or `null` if the content type does not support previews."},"name":{"type":"string","nullable":true,"description":"Original filename."},"description":{"type":"string","nullable":true},"size":{"type":"integer","nullable":true,"description":"File size in bytes."},"type":{"type":"string","nullable":true,"description":"MIME type of the file (e.g. `application/pdf`, `image/png`)."},"metadata":{"type":"object","nullable":true,"description":"Media metadata extracted on upload.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"type":{"type":"string"},"format":{"type":"string"},"pages":{"type":"integer","description":"Number of pages (for multi-page documents such as PDFs)."},"duration":{"type":"number","description":"Duration in seconds (for audio/video)."}}},"assetId":{"type":"string","nullable":true,"description":"Cloudinary asset ID."},"publicId":{"type":"string","nullable":true,"description":"Cloudinary public ID."},"googleCloudStorageId":{"type":"string","nullable":true,"description":"Internal storage key. Use `GET /api/files/download` rather than referencing this directly."},"externalId":{"type":"string","nullable":true,"description":"ID from an external system for integrations."},"importId":{"type":"string","format":"uuid","nullable":true},"archived":{"type":"boolean"},"archivedById":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"updatedById":{"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/files":{"get":{"tags":["Files"],"summary":"List files","description":"Returns file records the user has access to. Filter by workspace using the `where` parameter: `{\"workspaceId\": \"<WORKSPACE_UUID>\"}`.\n\nFiles can also be filtered by `companyId`, `contactId`, `dealId`, or `noteId` to retrieve files attached to a specific record.\n\n> **Note:** Files are created by uploading via `POST /api/files/upload` (multipart/form-data), **not** by a JSON `POST /api/files`.\n","operationId":"listFiles","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/File"}},"total":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````

## Upload a file

> Upload a file or image using \`multipart/form-data\`. Unlike the JSON CRUD endpoints, this endpoint does \*\*not\*\* accept a JSON body — send the binary in a \`file\` form part alongside text form fields.\
> \
> The maximum file size is \*\*32 MB\*\*; larger uploads are rejected with HTTP 413.\
> \
> \### Upload types\
> \
> The \`type\` form field selects how the file is stored and what is returned:\
> \
> \- \*\*\`file\`\*\* — A general document or attachment (PDF, image, video, etc.). The binary is stored in cloud storage and thumbnails/previews are generated for supported content types. Requires \`workspaceId\`. Can be linked to a record via \`companyId\`, \`contactId\`, \`dealId\`, or \`noteId\`. Returns the full file record (see the \`File\` schema).\
> \- \*\*\`image\`\*\* — An image asset, typically for \`logos\`, \`avatars\`, or inline \`attachments\`. Requires \`folder\`. Returns a lightweight object with the hosted image URL.\
> \
> \### Thumbnails & previews\
> \
> For \`type=file\`, \`thumbnailUrl\` and \`previewUrl\` are generated automatically for these content types: \`image/jpeg\`, \`image/png\`, \`image/gif\`, \`image/webp\`, \`application/pdf\`, \`video/mp4\`, \`video/mpeg\`, \`video/ogg\`, \`video/webm\`, \`video/quicktime\`. For other types they are \`null\`.\
> \
> \### Downloading\
> \
> For \`type=file\`, the stored \`url\` points to authenticated storage and is not directly accessible. Use \`GET /api/files/download?fileId=\<FILE\_ID>\` to obtain a short-lived signed URL, and \`GET /api/files/pages?fileId=\<FILE\_ID>\` to list per-page preview images for multi-page documents.\
> \
> \### Example (curl)\
> \
> \`\`\`bash\
> curl -X POST <https://api.zero.inc/api/files/upload> \\\
> &#x20; -H "Authorization: Bearer YOUR\_API\_TOKEN" \\\
> &#x20; -F "type=file" \\\
> &#x20; -F "workspaceId=\<WORKSPACE\_UUID>" \\\
> &#x20; -F "companyId=\<COMPANY\_UUID>" \\\
> &#x20; -F "file=@/path/to/proposal.pdf"\
> \`\`\`<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.11.0"},"tags":[{"name":"Files","description":"Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.\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. Create an API key from [Workspace Settings → API keys](https://app.zero.inc/settings/workspace/api)"}},"schemas":{"File":{"type":"object","description":"A file or attachment uploaded to a workspace. Created via `POST /api/files/upload` (multipart/form-data).\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true,"description":"Company this file is attached to, if any."},"contactId":{"type":"string","format":"uuid","nullable":true,"description":"Contact this file is attached to, if any."},"dealId":{"type":"string","format":"uuid","nullable":true,"description":"Deal this file is attached to, if any."},"noteId":{"type":"string","format":"uuid","nullable":true,"description":"Note this file is attached to, if any."},"calendarEventId":{"type":"string","format":"uuid","nullable":true},"placement":{"type":"string","nullable":true,"description":"Optional placement/context label for the file."},"url":{"type":"string","nullable":true,"description":"Storage URL for the file. For `type=file` uploads this points to authenticated storage and is not directly accessible — use `GET /api/files/download` to get a signed URL.\n"},"thumbnailUrl":{"type":"string","nullable":true,"description":"Generated thumbnail image URL, or `null` if the content type does not support previews."},"previewUrl":{"type":"string","nullable":true,"description":"Generated preview image URL, or `null` if the content type does not support previews."},"name":{"type":"string","nullable":true,"description":"Original filename."},"description":{"type":"string","nullable":true},"size":{"type":"integer","nullable":true,"description":"File size in bytes."},"type":{"type":"string","nullable":true,"description":"MIME type of the file (e.g. `application/pdf`, `image/png`)."},"metadata":{"type":"object","nullable":true,"description":"Media metadata extracted on upload.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"type":{"type":"string"},"format":{"type":"string"},"pages":{"type":"integer","description":"Number of pages (for multi-page documents such as PDFs)."},"duration":{"type":"number","description":"Duration in seconds (for audio/video)."}}},"assetId":{"type":"string","nullable":true,"description":"Cloudinary asset ID."},"publicId":{"type":"string","nullable":true,"description":"Cloudinary public ID."},"googleCloudStorageId":{"type":"string","nullable":true,"description":"Internal storage key. Use `GET /api/files/download` rather than referencing this directly."},"externalId":{"type":"string","nullable":true,"description":"ID from an external system for integrations."},"importId":{"type":"string","format":"uuid","nullable":true},"archived":{"type":"boolean"},"archivedById":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"updatedById":{"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/files/upload":{"post":{"tags":["Files"],"summary":"Upload a file","description":"Upload a file or image using `multipart/form-data`. Unlike the JSON CRUD endpoints, this endpoint does **not** accept a JSON body — send the binary in a `file` form part alongside text form fields.\n\nThe maximum file size is **32 MB**; larger uploads are rejected with HTTP 413.\n\n### Upload types\n\nThe `type` form field selects how the file is stored and what is returned:\n\n- **`file`** — A general document or attachment (PDF, image, video, etc.). The binary is stored in cloud storage and thumbnails/previews are generated for supported content types. Requires `workspaceId`. Can be linked to a record via `companyId`, `contactId`, `dealId`, or `noteId`. Returns the full file record (see the `File` schema).\n- **`image`** — An image asset, typically for `logos`, `avatars`, or inline `attachments`. Requires `folder`. Returns a lightweight object with the hosted image URL.\n\n### Thumbnails & previews\n\nFor `type=file`, `thumbnailUrl` and `previewUrl` are generated automatically for these content types: `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `application/pdf`, `video/mp4`, `video/mpeg`, `video/ogg`, `video/webm`, `video/quicktime`. For other types they are `null`.\n\n### Downloading\n\nFor `type=file`, the stored `url` points to authenticated storage and is not directly accessible. Use `GET /api/files/download?fileId=<FILE_ID>` to obtain a short-lived signed URL, and `GET /api/files/pages?fileId=<FILE_ID>` to list per-page preview images for multi-page documents.\n\n### Example (curl)\n\n```bash\ncurl -X POST https://api.zero.inc/api/files/upload \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\" \\\n  -F \"type=file\" \\\n  -F \"workspaceId=<WORKSPACE_UUID>\" \\\n  -F \"companyId=<COMPANY_UUID>\" \\\n  -F \"file=@/path/to/proposal.pdf\"\n```\n","operationId":"uploadFile","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","type"],"properties":{"file":{"type":"string","format":"binary","description":"The binary file contents. Maximum 32 MB."},"type":{"type":"string","enum":["file","image"],"description":"`file` stores a general document/attachment; `image` stores an image asset (logos, avatars, inline attachments).\n"},"workspaceId":{"type":"string","format":"uuid","description":"Required when `type=file`. Optional when `type=image`."},"folder":{"type":"string","enum":["logos","avatars","attachments"],"description":"Required when `type=image`. Storage folder for the image."},"transformation":{"type":"string","description":"`type=image` only. When set to any non-empty value, the image is scaled down to a maximum of 128×128 px WebP (aspect ratio preserved; used for avatars and logos).\n"},"companyId":{"type":"string","format":"uuid","description":"`type=file` only. Link the file to a company."},"contactId":{"type":"string","format":"uuid","description":"`type=file` only. Link the file to a contact."},"dealId":{"type":"string","format":"uuid","description":"`type=file` only. Link the file to a deal."},"noteId":{"type":"string","format":"uuid","description":"`type=file` only. Link the file to a note."},"placement":{"type":"string","description":"`type=file` only. Optional placement/context label for the file."},"description":{"type":"string","description":"`type=file` only. Optional human-readable description."},"externalId":{"type":"string","description":"Optional ID from an external system for integrations."}}}}}},"responses":{"200":{"description":"File uploaded successfully.\n\nFor `type=file`, `data` is the full file record. For `type=image`, `data` is a lightweight object with the hosted image URL.\n","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"oneOf":[{"$ref":"#/components/schemas/File"},{"type":"object","description":"Returned for `type=image` uploads.","properties":{"id":{"type":"string","format":"uuid"},"assetId":{"type":"string","description":"Cloudinary asset ID."},"publidId":{"type":"string","description":"Cloudinary public ID. (The response field is spelled `publidId`.)"},"url":{"type":"string","format":"uri","description":"Hosted image URL."}}}]}}}}}},"400":{"description":"Bad request — for example, `workspaceId` is missing for a `type=file` upload.\n","content":{"application/json":{"schema":{"type":"object","properties":{"statusMessage":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"File too large — the file exceeds the 32 MB limit.","content":{"application/json":{"schema":{"type":"object","properties":{"statusMessage":{"type":"string"}}}}}}}}}}}
````

## Get a file download URL

> Returns a short-lived signed URL for downloading a \`type=file\` upload from storage. The URL expires \*\*15 minutes\*\* after it is issued.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.11.0"},"tags":[{"name":"Files","description":"Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.\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. Create an API key from [Workspace Settings → API keys](https://app.zero.inc/settings/workspace/api)"}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/files/download":{"get":{"tags":["Files"],"summary":"Get a file download URL","description":"Returns a short-lived signed URL for downloading a `type=file` upload from storage. The URL expires **15 minutes** after it is issued.\n","operationId":"getFileDownloadUrl","parameters":[{"name":"fileId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Signed download URL","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Signed, time-limited download URL (valid for 15 minutes)."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"description":"Returned when the `fileId` does not exist or is not accessible in the caller's workspace. The handler currently raises an unhandled error, surfaced as HTTP 500 with the message `File not found` (a future release may return 404 instead).\n","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}}}}
```

## Get file page previews

> Returns per-page thumbnail and preview image URLs for a file, useful for multi-page documents such as PDFs.\
> \
> If the file's content type does not support previews, \`data\` is \`false\`.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.11.0"},"tags":[{"name":"Files","description":"Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.\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. Create an API key from [Workspace Settings → API keys](https://app.zero.inc/settings/workspace/api)"}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/files/pages":{"get":{"tags":["Files"],"summary":"Get file page previews","description":"Returns per-page thumbnail and preview image URLs for a file, useful for multi-page documents such as PDFs.\n\nIf the file's content type does not support previews, `data` is `false`.\n","operationId":"getFilePages","parameters":[{"name":"fileId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Page previews. `data` is `false` when the file type does not support previews.\n","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"oneOf":[{"type":"boolean"},{"type":"object","properties":{"pages":{"type":"array","items":{"type":"object","properties":{"thumbnailUrl":{"type":"string","format":"uri"},"previewUrl":{"type":"string","format":"uri"}}}}}}]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"description":"Returned when the `fileId` does not exist or is not accessible in the caller's workspace. The handler currently raises an unhandled error, surfaced as HTTP 500 with the message `File not found` (a future release may return 404 instead).\n","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}}}}
```

## Get a file

> Returns a single file record by ID.\
> \
> If the file does not exist, the API returns HTTP 200 with an empty body (\`{}\`).\
> \
> To obtain a downloadable URL for the file contents, use \`GET /api/files/download?fileId=\<FILE\_ID>\`.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.11.0"},"tags":[{"name":"Files","description":"Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.\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. Create an API key from [Workspace Settings → API keys](https://app.zero.inc/settings/workspace/api)"}},"schemas":{"File":{"type":"object","description":"A file or attachment uploaded to a workspace. Created via `POST /api/files/upload` (multipart/form-data).\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true,"description":"Company this file is attached to, if any."},"contactId":{"type":"string","format":"uuid","nullable":true,"description":"Contact this file is attached to, if any."},"dealId":{"type":"string","format":"uuid","nullable":true,"description":"Deal this file is attached to, if any."},"noteId":{"type":"string","format":"uuid","nullable":true,"description":"Note this file is attached to, if any."},"calendarEventId":{"type":"string","format":"uuid","nullable":true},"placement":{"type":"string","nullable":true,"description":"Optional placement/context label for the file."},"url":{"type":"string","nullable":true,"description":"Storage URL for the file. For `type=file` uploads this points to authenticated storage and is not directly accessible — use `GET /api/files/download` to get a signed URL.\n"},"thumbnailUrl":{"type":"string","nullable":true,"description":"Generated thumbnail image URL, or `null` if the content type does not support previews."},"previewUrl":{"type":"string","nullable":true,"description":"Generated preview image URL, or `null` if the content type does not support previews."},"name":{"type":"string","nullable":true,"description":"Original filename."},"description":{"type":"string","nullable":true},"size":{"type":"integer","nullable":true,"description":"File size in bytes."},"type":{"type":"string","nullable":true,"description":"MIME type of the file (e.g. `application/pdf`, `image/png`)."},"metadata":{"type":"object","nullable":true,"description":"Media metadata extracted on upload.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"type":{"type":"string"},"format":{"type":"string"},"pages":{"type":"integer","description":"Number of pages (for multi-page documents such as PDFs)."},"duration":{"type":"number","description":"Duration in seconds (for audio/video)."}}},"assetId":{"type":"string","nullable":true,"description":"Cloudinary asset ID."},"publicId":{"type":"string","nullable":true,"description":"Cloudinary public ID."},"googleCloudStorageId":{"type":"string","nullable":true,"description":"Internal storage key. Use `GET /api/files/download` rather than referencing this directly."},"externalId":{"type":"string","nullable":true,"description":"ID from an external system for integrations."},"importId":{"type":"string","format":"uuid","nullable":true},"archived":{"type":"boolean"},"archivedById":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"updatedById":{"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/files/{fileId}":{"get":{"tags":["Files"],"summary":"Get a file","description":"Returns a single file record by ID.\n\nIf the file does not exist, the API returns HTTP 200 with an empty body (`{}`).\n\nTo obtain a downloadable URL for the file contents, use `GET /api/files/download?fileId=<FILE_ID>`.\n","operationId":"getFile","parameters":[{"name":"fileId","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/File"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Delete a file

> Delete a file. Use \`archive=true\` for soft delete (recoverable), or omit for permanent deletion.

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.11.0"},"tags":[{"name":"Files","description":"Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.\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. Create an API key from [Workspace Settings → API keys](https://app.zero.inc/settings/workspace/api)"}},"schemas":{"File":{"type":"object","description":"A file or attachment uploaded to a workspace. Created via `POST /api/files/upload` (multipart/form-data).\n","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true,"description":"Company this file is attached to, if any."},"contactId":{"type":"string","format":"uuid","nullable":true,"description":"Contact this file is attached to, if any."},"dealId":{"type":"string","format":"uuid","nullable":true,"description":"Deal this file is attached to, if any."},"noteId":{"type":"string","format":"uuid","nullable":true,"description":"Note this file is attached to, if any."},"calendarEventId":{"type":"string","format":"uuid","nullable":true},"placement":{"type":"string","nullable":true,"description":"Optional placement/context label for the file."},"url":{"type":"string","nullable":true,"description":"Storage URL for the file. For `type=file` uploads this points to authenticated storage and is not directly accessible — use `GET /api/files/download` to get a signed URL.\n"},"thumbnailUrl":{"type":"string","nullable":true,"description":"Generated thumbnail image URL, or `null` if the content type does not support previews."},"previewUrl":{"type":"string","nullable":true,"description":"Generated preview image URL, or `null` if the content type does not support previews."},"name":{"type":"string","nullable":true,"description":"Original filename."},"description":{"type":"string","nullable":true},"size":{"type":"integer","nullable":true,"description":"File size in bytes."},"type":{"type":"string","nullable":true,"description":"MIME type of the file (e.g. `application/pdf`, `image/png`)."},"metadata":{"type":"object","nullable":true,"description":"Media metadata extracted on upload.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"type":{"type":"string"},"format":{"type":"string"},"pages":{"type":"integer","description":"Number of pages (for multi-page documents such as PDFs)."},"duration":{"type":"number","description":"Duration in seconds (for audio/video)."}}},"assetId":{"type":"string","nullable":true,"description":"Cloudinary asset ID."},"publicId":{"type":"string","nullable":true,"description":"Cloudinary public ID."},"googleCloudStorageId":{"type":"string","nullable":true,"description":"Internal storage key. Use `GET /api/files/download` rather than referencing this directly."},"externalId":{"type":"string","nullable":true,"description":"ID from an external system for integrations."},"importId":{"type":"string","format":"uuid","nullable":true},"archived":{"type":"boolean"},"archivedById":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true},"updatedById":{"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/files/{fileId}":{"delete":{"tags":["Files"],"summary":"Delete a file","description":"Delete a file. Use `archive=true` for soft delete (recoverable), or omit for permanent deletion.","operationId":"deleteFile","parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"archive","in":"query","description":"If true, soft deletes (archives) the file instead of permanently deleting it.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"File 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 file object.\n","oneOf":[{"type":"integer"},{"type":"array","items":{"$ref":"#/components/schemas/File"}}]},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Update file metadata

> Update metadata on an existing file (e.g. \`name\`, \`description\`, or the record it is linked to). The file's binary contents cannot be changed — re-upload via \`POST /api/files/upload\` to replace contents.\
> \
> \> \*\*Note:\*\* The response only returns the fields that were changed — not the full file object.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.11.0"},"tags":[{"name":"Files","description":"Upload and manage files and attachments. Files are uploaded with `multipart/form-data` via `POST /api/files/upload` and can be linked to companies, contacts, deals, and notes.\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. Create an API key from [Workspace Settings → API keys](https://app.zero.inc/settings/workspace/api)"}},"schemas":{"FileUpdate":{"type":"object","description":"Editable file metadata. The file's binary contents cannot be changed via PATCH — re-upload to replace them.","properties":{"name":{"type":"string"},"description":{"type":"string"},"placement":{"type":"string"},"companyId":{"type":"string","format":"uuid"},"contactId":{"type":"string","format":"uuid"},"dealId":{"type":"string","format":"uuid"},"noteId":{"type":"string","format":"uuid"},"externalId":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/files/{fileId}":{"patch":{"tags":["Files"],"summary":"Update file metadata","description":"Update metadata on an existing file (e.g. `name`, `description`, or the record it is linked to). The file's binary contents cannot be changed — re-upload via `POST /api/files/upload` to replace contents.\n\n> **Note:** The response only returns the fields that were changed — not the full file object.\n","operationId":"updateFile","parameters":[{"name":"fileId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUpdate"}}}},"responses":{"200":{"description":"File updated successfully. Only the fields that were changed are returned in `data`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Partial file object containing only the updated fields plus `updatedAt` and `updatedById`."},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.zero.inc/features/api/files.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
