> 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/developers/api/quotes.md).

# Quotes

Manage quotes (CPQ). A quote is attached to a deal and/or company and contains line items built from catalog products or entered as custom line items.

#### Financial fields

* `totalAmount` is the total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`.
* `mrr` / `arr` are the recurring revenue portions of the quote.
* `totalAmountInWorkspaceCurrency`, `mrrInWorkspaceCurrency`, and `arrInWorkspaceCurrency` are **derived server-side** from the quote's currency using exchange rates — do not set them in requests.

## List quotes

> Returns quotes the user has access to. Filter by workspace using the \`where\` parameter: \`{"workspaceId": "\<WORKSPACE\_UUID>"}\`, or narrow further, e.g. \`{"workspaceId": "\<WORKSPACE\_UUID>", "status": "accepted"}\`.\
> \
> \### Getting the quotes for a deal\
> \
> Filter by \`dealId\` to fetch the quote(s) attached to a specific deal — for example after receiving a deal webhook:\
> \
> \`\`\`\
> GET /api/quotes?where={"workspaceId": "\<WORKSPACE\_UUID>", "dealId": "\<DEAL\_UUID>"}\
> \`\`\`\
> \
> The same lookup also works from the deal side via relation expansion: \`GET /api/deals/{dealId}?fields=id,quotes.id\` embeds the deal's quote IDs (or \`quotes.\*\` for full quote objects).<br>

````json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.14.0"},"tags":[{"name":"Quotes","description":"Manage quotes (CPQ). A quote is attached to a deal and/or company and contains line items built from catalog products or entered as custom line items.\n\n### Financial fields\n- `totalAmount` is the total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`.\n- `mrr` / `arr` are the recurring revenue portions of the quote.\n- `totalAmountInWorkspaceCurrency`, `mrrInWorkspaceCurrency`, and `arrInWorkspaceCurrency` are **derived server-side** from the quote's currency using exchange rates — do not set them in requests.\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.\n\nSupports **relation expansion** with dot-notation: a path like `company.name` embeds the named field of the related record, and `quotes.id` embeds the `id` of each related quote. Use `.*` to embed full related objects, e.g. `quotes.*`. Related records are returned nested on the response — as an object for to-one relations (e.g. `company`) or an array for to-many relations (e.g. `quotes`). Archived related records are excluded.\n\nExample: `GET /api/deals/{dealId}?fields=id,name,quotes.id` returns the deal with a `quotes` array of `{\"id\": \"<QUOTE_UUID>\"}` entries.\n","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":{"Quote":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true},"dealId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","nullable":true},"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired"]},"lineItems":{"type":"array","items":{"$ref":"#/components/schemas/QuoteLineItem"}},"totalAmount":{"type":"number","nullable":true,"description":"Total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`."},"totalAmountInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `totalAmount` using exchange rates whenever `totalAmount`, `mrr`, `arr`, or `currency` is written — do not set it directly. `null` when the conversion is unavailable."},"currency":{"type":"string","nullable":true,"description":"ISO 4217 currency code of the quote's amounts."},"mrr":{"type":"number","nullable":true,"description":"Monthly recurring revenue portion of the quote."},"arr":{"type":"number","nullable":true,"description":"Annual recurring revenue portion of the quote."},"mrrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `mrr` using exchange rates — do not set it directly."},"arrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `arr` using exchange rates — do not set it directly."},"termMonths":{"type":"integer","nullable":true,"description":"Contract term in months. `totalAmount` is the TCV over this term."},"sentAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date","nullable":true},"acceptedAt":{"type":"string","format":"date-time","nullable":true},"rejectedAt":{"type":"string","format":"date-time","nullable":true},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true}}},"QuoteLineItem":{"type":"object","required":["name","quantity","amount","currency"],"properties":{"productId":{"type":"string","format":"uuid","nullable":true,"description":"Catalog product this line item was created from. Omit for custom line items."},"priceId":{"type":"string","format":"uuid","nullable":true,"description":"Id of the price entry inside the product's `prices` array. Omit for custom line items."},"sku":{"type":"string","nullable":true,"readOnly":true,"description":"SKU of the referenced catalog product, derived server-side whenever the quote's line items are saved. Read-only — values sent in requests are ignored and replaced with the catalog's current SKU (or stripped for custom line items without a product). Null when the product has no SKU; absent on custom line items. A quote that is not re-saved keeps the SKU it was last saved with."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"quantity":{"type":"number"},"amount":{"type":"number","description":"Unit amount per billing interval (or one-time unit amount when `interval` is not set)."},"currency":{"type":"string","description":"ISO 4217 currency code."},"interval":{"type":"string","enum":["day","week","month","quarter","year"],"nullable":true,"description":"Billing interval. Omit or set to `null` for a one-time line item."},"discountType":{"type":"string","enum":["absolute","percentage"],"nullable":true},"discount":{"type":"number","nullable":true,"description":"Discount value — an amount for `absolute` (applied per unit), a percentage (0–100) for `percentage`."},"totalAmount":{"type":"number","nullable":true,"description":"Line total after quantity and discount."}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/quotes":{"get":{"tags":["Quotes"],"summary":"List quotes","description":"Returns quotes the user has access to. Filter by workspace using the `where` parameter: `{\"workspaceId\": \"<WORKSPACE_UUID>\"}`, or narrow further, e.g. `{\"workspaceId\": \"<WORKSPACE_UUID>\", \"status\": \"accepted\"}`.\n\n### Getting the quotes for a deal\n\nFilter by `dealId` to fetch the quote(s) attached to a specific deal — for example after receiving a deal webhook:\n\n```\nGET /api/quotes?where={\"workspaceId\": \"<WORKSPACE_UUID>\", \"dealId\": \"<DEAL_UUID>\"}\n```\n\nThe same lookup also works from the deal side via relation expansion: `GET /api/deals/{dealId}?fields=id,quotes.id` embeds the deal's quote IDs (or `quotes.*` for full quote objects).\n","operationId":"listQuotes","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/Quote"}},"total":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````

## Create a quote

> Create a new quote. Attach it to a record via \`dealId\` and/or \`companyId\`.\
> \
> Line items can reference a catalog product price (\`productId\` + \`priceId\`) or be fully custom (name, amount, currency entered directly). \`status\` defaults to \`draft\`.\
> \
> The workspace-currency fields (\`totalAmountInWorkspaceCurrency\`, \`mrrInWorkspaceCurrency\`, \`arrInWorkspaceCurrency\`) are derived server-side — do not send them.<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.14.0"},"tags":[{"name":"Quotes","description":"Manage quotes (CPQ). A quote is attached to a deal and/or company and contains line items built from catalog products or entered as custom line items.\n\n### Financial fields\n- `totalAmount` is the total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`.\n- `mrr` / `arr` are the recurring revenue portions of the quote.\n- `totalAmountInWorkspaceCurrency`, `mrrInWorkspaceCurrency`, and `arrInWorkspaceCurrency` are **derived server-side** from the quote's currency using exchange rates — do not set them in requests.\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":{"QuoteCreate":{"type":"object","required":["workspaceId"],"properties":{"workspaceId":{"type":"string","format":"uuid"},"dealId":{"type":"string","format":"uuid","description":"Deal to attach the quote to. Provide `dealId` and/or `companyId`."},"companyId":{"type":"string","format":"uuid","description":"Company to attach the quote to. Provide `dealId` and/or `companyId`."},"name":{"type":"string"},"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired"],"default":"draft"},"lineItems":{"type":"array","items":{"$ref":"#/components/schemas/QuoteLineItem"}},"totalAmount":{"type":"number","description":"Total contract value (TCV) over `termMonths` in `currency`."},"currency":{"type":"string"},"mrr":{"type":"number"},"arr":{"type":"number"},"termMonths":{"type":"integer"},"sentAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date"}}},"QuoteLineItem":{"type":"object","required":["name","quantity","amount","currency"],"properties":{"productId":{"type":"string","format":"uuid","nullable":true,"description":"Catalog product this line item was created from. Omit for custom line items."},"priceId":{"type":"string","format":"uuid","nullable":true,"description":"Id of the price entry inside the product's `prices` array. Omit for custom line items."},"sku":{"type":"string","nullable":true,"readOnly":true,"description":"SKU of the referenced catalog product, derived server-side whenever the quote's line items are saved. Read-only — values sent in requests are ignored and replaced with the catalog's current SKU (or stripped for custom line items without a product). Null when the product has no SKU; absent on custom line items. A quote that is not re-saved keeps the SKU it was last saved with."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"quantity":{"type":"number"},"amount":{"type":"number","description":"Unit amount per billing interval (or one-time unit amount when `interval` is not set)."},"currency":{"type":"string","description":"ISO 4217 currency code."},"interval":{"type":"string","enum":["day","week","month","quarter","year"],"nullable":true,"description":"Billing interval. Omit or set to `null` for a one-time line item."},"discountType":{"type":"string","enum":["absolute","percentage"],"nullable":true},"discount":{"type":"number","nullable":true,"description":"Discount value — an amount for `absolute` (applied per unit), a percentage (0–100) for `percentage`."},"totalAmount":{"type":"number","nullable":true,"description":"Line total after quantity and discount."}}},"Quote":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true},"dealId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","nullable":true},"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired"]},"lineItems":{"type":"array","items":{"$ref":"#/components/schemas/QuoteLineItem"}},"totalAmount":{"type":"number","nullable":true,"description":"Total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`."},"totalAmountInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `totalAmount` using exchange rates whenever `totalAmount`, `mrr`, `arr`, or `currency` is written — do not set it directly. `null` when the conversion is unavailable."},"currency":{"type":"string","nullable":true,"description":"ISO 4217 currency code of the quote's amounts."},"mrr":{"type":"number","nullable":true,"description":"Monthly recurring revenue portion of the quote."},"arr":{"type":"number","nullable":true,"description":"Annual recurring revenue portion of the quote."},"mrrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `mrr` using exchange rates — do not set it directly."},"arrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `arr` using exchange rates — do not set it directly."},"termMonths":{"type":"integer","nullable":true,"description":"Contract term in months. `totalAmount` is the TCV over this term."},"sentAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date","nullable":true},"acceptedAt":{"type":"string","format":"date-time","nullable":true},"rejectedAt":{"type":"string","format":"date-time","nullable":true},"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/quotes":{"post":{"tags":["Quotes"],"summary":"Create a quote","description":"Create a new quote. Attach it to a record via `dealId` and/or `companyId`.\n\nLine items can reference a catalog product price (`productId` + `priceId`) or be fully custom (name, amount, currency entered directly). `status` defaults to `draft`.\n\nThe workspace-currency fields (`totalAmountInWorkspaceCurrency`, `mrrInWorkspaceCurrency`, `arrInWorkspaceCurrency`) are derived server-side — do not send them.\n","operationId":"createQuote","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteCreate"}}}},"responses":{"200":{"description":"Quote created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Quote"},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Get a quote

> Returns a single quote by ID.

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.14.0"},"tags":[{"name":"Quotes","description":"Manage quotes (CPQ). A quote is attached to a deal and/or company and contains line items built from catalog products or entered as custom line items.\n\n### Financial fields\n- `totalAmount` is the total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`.\n- `mrr` / `arr` are the recurring revenue portions of the quote.\n- `totalAmountInWorkspaceCurrency`, `mrrInWorkspaceCurrency`, and `arrInWorkspaceCurrency` are **derived server-side** from the quote's currency using exchange rates — do not set them in requests.\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":{"Quote":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true},"dealId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","nullable":true},"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired"]},"lineItems":{"type":"array","items":{"$ref":"#/components/schemas/QuoteLineItem"}},"totalAmount":{"type":"number","nullable":true,"description":"Total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`."},"totalAmountInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `totalAmount` using exchange rates whenever `totalAmount`, `mrr`, `arr`, or `currency` is written — do not set it directly. `null` when the conversion is unavailable."},"currency":{"type":"string","nullable":true,"description":"ISO 4217 currency code of the quote's amounts."},"mrr":{"type":"number","nullable":true,"description":"Monthly recurring revenue portion of the quote."},"arr":{"type":"number","nullable":true,"description":"Annual recurring revenue portion of the quote."},"mrrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `mrr` using exchange rates — do not set it directly."},"arrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `arr` using exchange rates — do not set it directly."},"termMonths":{"type":"integer","nullable":true,"description":"Contract term in months. `totalAmount` is the TCV over this term."},"sentAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date","nullable":true},"acceptedAt":{"type":"string","format":"date-time","nullable":true},"rejectedAt":{"type":"string","format":"date-time","nullable":true},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true}}},"QuoteLineItem":{"type":"object","required":["name","quantity","amount","currency"],"properties":{"productId":{"type":"string","format":"uuid","nullable":true,"description":"Catalog product this line item was created from. Omit for custom line items."},"priceId":{"type":"string","format":"uuid","nullable":true,"description":"Id of the price entry inside the product's `prices` array. Omit for custom line items."},"sku":{"type":"string","nullable":true,"readOnly":true,"description":"SKU of the referenced catalog product, derived server-side whenever the quote's line items are saved. Read-only — values sent in requests are ignored and replaced with the catalog's current SKU (or stripped for custom line items without a product). Null when the product has no SKU; absent on custom line items. A quote that is not re-saved keeps the SKU it was last saved with."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"quantity":{"type":"number"},"amount":{"type":"number","description":"Unit amount per billing interval (or one-time unit amount when `interval` is not set)."},"currency":{"type":"string","description":"ISO 4217 currency code."},"interval":{"type":"string","enum":["day","week","month","quarter","year"],"nullable":true,"description":"Billing interval. Omit or set to `null` for a one-time line item."},"discountType":{"type":"string","enum":["absolute","percentage"],"nullable":true},"discount":{"type":"number","nullable":true,"description":"Discount value — an amount for `absolute` (applied per unit), a percentage (0–100) for `percentage`."},"totalAmount":{"type":"number","nullable":true,"description":"Line total after quantity and discount."}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/quotes/{quoteId}":{"get":{"tags":["Quotes"],"summary":"Get a quote","description":"Returns a single quote by ID.","operationId":"getQuote","parameters":[{"name":"quoteId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Successful response. If the quote does not exist, the API returns HTTP 200 with an empty body (`{}`).\n","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Quote"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Delete a quote

> Delete a quote. Use archive=true for soft delete.

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.14.0"},"tags":[{"name":"Quotes","description":"Manage quotes (CPQ). A quote is attached to a deal and/or company and contains line items built from catalog products or entered as custom line items.\n\n### Financial fields\n- `totalAmount` is the total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`.\n- `mrr` / `arr` are the recurring revenue portions of the quote.\n- `totalAmountInWorkspaceCurrency`, `mrrInWorkspaceCurrency`, and `arrInWorkspaceCurrency` are **derived server-side** from the quote's currency using exchange rates — do not set them in requests.\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":{"Quote":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","nullable":true},"dealId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","nullable":true},"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired"]},"lineItems":{"type":"array","items":{"$ref":"#/components/schemas/QuoteLineItem"}},"totalAmount":{"type":"number","nullable":true,"description":"Total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`."},"totalAmountInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `totalAmount` using exchange rates whenever `totalAmount`, `mrr`, `arr`, or `currency` is written — do not set it directly. `null` when the conversion is unavailable."},"currency":{"type":"string","nullable":true,"description":"ISO 4217 currency code of the quote's amounts."},"mrr":{"type":"number","nullable":true,"description":"Monthly recurring revenue portion of the quote."},"arr":{"type":"number","nullable":true,"description":"Annual recurring revenue portion of the quote."},"mrrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `mrr` using exchange rates — do not set it directly."},"arrInWorkspaceCurrency":{"type":"number","nullable":true,"description":"Derived server-side from `arr` using exchange rates — do not set it directly."},"termMonths":{"type":"integer","nullable":true,"description":"Contract term in months. `totalAmount` is the TCV over this term."},"sentAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date","nullable":true},"acceptedAt":{"type":"string","format":"date-time","nullable":true},"rejectedAt":{"type":"string","format":"date-time","nullable":true},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdById":{"type":"string","format":"uuid","nullable":true}}},"QuoteLineItem":{"type":"object","required":["name","quantity","amount","currency"],"properties":{"productId":{"type":"string","format":"uuid","nullable":true,"description":"Catalog product this line item was created from. Omit for custom line items."},"priceId":{"type":"string","format":"uuid","nullable":true,"description":"Id of the price entry inside the product's `prices` array. Omit for custom line items."},"sku":{"type":"string","nullable":true,"readOnly":true,"description":"SKU of the referenced catalog product, derived server-side whenever the quote's line items are saved. Read-only — values sent in requests are ignored and replaced with the catalog's current SKU (or stripped for custom line items without a product). Null when the product has no SKU; absent on custom line items. A quote that is not re-saved keeps the SKU it was last saved with."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"quantity":{"type":"number"},"amount":{"type":"number","description":"Unit amount per billing interval (or one-time unit amount when `interval` is not set)."},"currency":{"type":"string","description":"ISO 4217 currency code."},"interval":{"type":"string","enum":["day","week","month","quarter","year"],"nullable":true,"description":"Billing interval. Omit or set to `null` for a one-time line item."},"discountType":{"type":"string","enum":["absolute","percentage"],"nullable":true},"discount":{"type":"number","nullable":true,"description":"Discount value — an amount for `absolute` (applied per unit), a percentage (0–100) for `percentage`."},"totalAmount":{"type":"number","nullable":true,"description":"Line total after quantity and discount."}}}},"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/quotes/{quoteId}":{"delete":{"tags":["Quotes"],"summary":"Delete a quote","description":"Delete a quote. Use archive=true for soft delete.","operationId":"deleteQuote","parameters":[{"name":"quoteId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"archive","in":"query","description":"If true, soft deletes (archives) the quote instead of permanently deleting it.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Quote 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 quote object.\n","oneOf":[{"type":"integer"},{"type":"array","items":{"$ref":"#/components/schemas/Quote"}}]},"sideEffects":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Update a quote

> Update an existing quote.\
> \
> \`lineItems\` is replaced as a whole — include every line item that should remain, not just the changed ones.\
> \
> Changing \`totalAmount\`, \`mrr\`, \`arr\`, or \`currency\` recomputes the derived workspace-currency fields server-side. To record status transitions, set \`status\` together with the matching timestamp (\`sentAt\`, \`acceptedAt\`, or \`rejectedAt\`).<br>

```json
{"openapi":"3.0.3","info":{"title":"Zero API","version":"1.14.0"},"tags":[{"name":"Quotes","description":"Manage quotes (CPQ). A quote is attached to a deal and/or company and contains line items built from catalog products or entered as custom line items.\n\n### Financial fields\n- `totalAmount` is the total contract value (TCV) over the contract term (`termMonths`) in the quote's `currency`.\n- `mrr` / `arr` are the recurring revenue portions of the quote.\n- `totalAmountInWorkspaceCurrency`, `mrrInWorkspaceCurrency`, and `arrInWorkspaceCurrency` are **derived server-side** from the quote's currency using exchange rates — do not set them in requests.\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":{"QuoteUpdate":{"type":"object","properties":{"dealId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired"]},"lineItems":{"type":"array","description":"Replaced as a whole — include every line item that should remain.","items":{"$ref":"#/components/schemas/QuoteLineItem"}},"totalAmount":{"type":"number"},"currency":{"type":"string"},"mrr":{"type":"number"},"arr":{"type":"number"},"termMonths":{"type":"integer"},"sentAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date"},"acceptedAt":{"type":"string","format":"date-time"},"rejectedAt":{"type":"string","format":"date-time"}}},"QuoteLineItem":{"type":"object","required":["name","quantity","amount","currency"],"properties":{"productId":{"type":"string","format":"uuid","nullable":true,"description":"Catalog product this line item was created from. Omit for custom line items."},"priceId":{"type":"string","format":"uuid","nullable":true,"description":"Id of the price entry inside the product's `prices` array. Omit for custom line items."},"sku":{"type":"string","nullable":true,"readOnly":true,"description":"SKU of the referenced catalog product, derived server-side whenever the quote's line items are saved. Read-only — values sent in requests are ignored and replaced with the catalog's current SKU (or stripped for custom line items without a product). Null when the product has no SKU; absent on custom line items. A quote that is not re-saved keeps the SKU it was last saved with."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"quantity":{"type":"number"},"amount":{"type":"number","description":"Unit amount per billing interval (or one-time unit amount when `interval` is not set)."},"currency":{"type":"string","description":"ISO 4217 currency code."},"interval":{"type":"string","enum":["day","week","month","quarter","year"],"nullable":true,"description":"Billing interval. Omit or set to `null` for a one-time line item."},"discountType":{"type":"string","enum":["absolute","percentage"],"nullable":true},"discount":{"type":"number","nullable":true,"description":"Discount value — an amount for `absolute` (applied per unit), a percentage (0–100) for `percentage`."},"totalAmount":{"type":"number","nullable":true,"description":"Line total after quantity and discount."}}}},"responses":{"Unauthorized":{"description":"Authentication failed or token is invalid/expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"paths":{"/api/quotes/{quoteId}":{"patch":{"tags":["Quotes"],"summary":"Update a quote","description":"Update an existing quote.\n\n`lineItems` is replaced as a whole — include every line item that should remain, not just the changed ones.\n\nChanging `totalAmount`, `mrr`, `arr`, or `currency` recomputes the derived workspace-currency fields server-side. To record status transitions, set `status` together with the matching timestamp (`sentAt`, `acceptedAt`, or `rejectedAt`).\n","operationId":"updateQuote","parameters":[{"name":"quoteId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteUpdate"}}}},"responses":{"200":{"description":"Only the changed fields are returned in `data`. Use `GET` on the record to retrieve the full updated object.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Only the changed fields, not the full object."},"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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.zero.inc/developers/api/quotes.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
