For the complete documentation index, see llms.txt. This page is also available as Markdown.

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

get

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).

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Query parameters
fieldsstringOptional

Comma-separated list of fields to return. Defaults to all fields.

Supports 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.

Example: GET /api/deals/{dealId}?fields=id,name,quotes.id returns the deal with a quotes array of {"id": "<QUOTE_UUID>"} entries.

Example: id,name,domain
wherestringOptional

JSON-encoded filter object. All top-level conditions are combined with AND logic. Use $or for OR logic.

The available operators depend on the data type of the field you are filtering on.


String fields

Fields like name, domain, description, linkedin, source, externalId, location.

OperatorDescriptionExample
(exact)Exact match{"name": "Linear"}
$eqExplicit exact match{"name": {"$eq": "Linear"}}
$notNot equal{"source": {"$not": "import"}}
$inMatches any value in array{"domain": {"$in": ["linear.app", "granola.so"]}}
$notInMatches none of the values{"source": {"$notIn": ["import", "api"]}}
$containsCase-insensitive word-boundary substring match{"name": {"$contains": "YC"}}
$notContainsDoes not contain{"name": {"$notContains": "Test"}}
$containsAnyContains any of the given strings{"name": {"$containsAny": ["YC", "Techstars"]}}
$startsWithStarts with prefix{"domain": {"$startsWith": "app."}}
$endsWithEnds with suffix{"email": {"$endsWith": "@zero.inc"}}
$existsField is present and truthy{"linkedin": {"$exists": true}}
$notExistsField is absent, null, or empty{"linkedin": {"$notExists": true}}

Number fields

Fields like value, confidence.

OperatorDescriptionExample
(exact)Exact match{"value": 5000}
$eqExplicit exact match{"value": {"$eq": 5000}}
$notNot equal{"value": {"$not": 0}}
$gtGreater than{"value": {"$gt": 10000}}
$gteGreater than or equal{"value": {"$gte": 5000}}
$ltLess than{"value": {"$lt": 10000}}
$lteLess than or equal{"value": {"$lte": 50000}}
$inMatches any value in array{"confidence": {"$in": [0.25, 0.5, 0.75]}}
$notInMatches none of the values{"confidence": {"$notIn": [0, 1]}}
$existsField is present and truthy{"value": {"$exists": true}}
$notExistsField is absent, null, or zero{"value": {"$notExists": true}}

Multiple operators can be combined on one field:

{"value": {"$gte": 5000, "$lt": 10000}}

Date fields

Fields like closeDate, startDate, endDate, createdAt, updatedAt.

Values can be ISO 8601 strings ("2026-01-01", "2026-01-01T00:00:00Z") or relative time macros.

Relative time macros: +Nd / -Nd (days), +Nw / -Nw (weeks), +Nm / -Nm (months), +Ny / -Ny (years), +Nh / -Nh (hours), +Ns / -Ns (seconds), now().

OperatorDescriptionExample
$gteOn or after{"closeDate": {"$gte": "2026-01-01"}}
$lteOn or before{"closeDate": {"$lte": "2026-03-31"}}
$gtAfter{"createdAt": {"$gt": "2026-01-01T00:00:00Z"}}
$ltBefore{"createdAt": {"$lt": "now()"}}
$dateExact date match (compares date portion only){"closeDate": {"$date": "2026-01-15"}}
$existsField is present and truthy{"closeDate": {"$exists": true}}
$notExistsField is absent or null{"closeDate": {"$notExists": true}}

Date range example:

{"closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"}}

Relative date example (closing in next 30 days):

{"closeDate": {"$gte": "now()", "$lte": "+30d"}}

Array fields

Fields like listIds, ownerIds, contactIds.

OperatorDescriptionExample
$includesArray contains the given value (use this — bare exact match is not supported){"listIds": {"$includes": "<LIST_UUID>"}}
$notIncludesArray does not contain the given value{"ownerIds": {"$notIncludes": "<USER_UUID>"}}
$overlapsArray contains at least one of the given values{"ownerIds": {"$overlaps": ["<UUID_1>", "<UUID_2>"]}}
$notOverlapsArray contains none of the given values{"listIds": {"$notOverlaps": ["<UUID_1>", "<UUID_2>"]}}
$allArray contains all of the given values{"listIds": {"$all": ["<UUID_1>", "<UUID_2>"]}}
$lengthFilter by array length (supports nested operators){"contactIds": {"$length": {"$gte": 2}}}
$existsField is present and non-empty{"ownerIds": {"$exists": true}}
$notExistsField is absent or empty{"ownerIds": {"$notExists": true}}

UUID / ID fields

Fields like id, workspaceId, companyId, stage.

OperatorDescriptionExample
(exact)Exact match{"stage": "<PIPELINE_STAGE_UUID>"}
$inMatches any value in array{"stage": {"$in": ["<UUID_1>", "<UUID_2>"]}}
$notInMatches none of the values{"stage": {"$notIn": ["<UUID_1>"]}}
$notNot equal{"stage": {"$not": "<UUID>"}}

Boolean fields

Fields like archived.

OperatorDescriptionExample
(exact)Exact match{"archived": false}
$notNot equal{"archived": {"$not": true}}

Logical operators

These work across all data types.

$or — matches if any sub-condition is true:

{
  "workspaceId": "<WORKSPACE_UUID>",
  "$or": [
    {"ownerIds": {"$overlaps": ["<USER_UUID_1>", "<USER_UUID_2>"]}},
    {"closeDate": {"$gte": "2026-01-01"}}
  ]
}

$and — matches if all sub-conditions are true (useful when you need multiple conditions on the same field):

{
  "$and": [
    {"name": {"$contains": "Enterprise"}},
    {"name": {"$notContains": "Test"}}
  ]
}

Dot-notation (relation filtering)

Use dot-syntax to filter records based on properties of related objects:

{"company.name": "Linear"}
{"company.domain": {"$in": ["linear.app", "granola.so"]}}
{"company.location.city": "San Francisco"}
{"companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]}}

All operators available for the target field's data type can be used with dot-notation.


Custom property filtering

Custom 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.

Filter on custom properties using custom.<COLUMN_ID> with operators appropriate for the column's type.

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.

// Text custom property
{"custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}}

// Select custom property (use the option key UUID)
{"custom.a1b2c3d4-e5f6-7890-abcd-ef1234567890": "3e839b5c-b311-4887-b2da-727d2d75cdd6"}

// Multi-select custom property (use option key UUIDs)
{"custom.b2c3d4e5-f6a7-8901-bcde-f12345678901": {"$overlaps": ["a1b1c1d1-e1f1-1111-aaaa-111111111111", "b2b2c2d2-e2f2-2222-bbbb-222222222222"]}}

// Currency/number custom property
{"custom.c3d4e5f6-a7b8-9012-cdef-123456789012": {"$gte": 100000}}

// Date custom property
{"custom.d4e5f6a7-b8c9-0123-defa-234567890123": {"$gte": "2026-01-01"}}

// Boolean custom property
{"custom.e5f6a7b8-c9d0-1234-efab-345678901234": true}

// Check if custom property has a value
{"custom.f6a7b8c9-d0e1-2345-fabc-456789012345": {"$exists": true}}

Complex example

All top-level keys are ANDed together:

{
  "name": {"$contains": "Zero"},
  "location.city": "Helsinki",
  "location.country": {"$in": ["United Kingdom", "Germany", "Sweden"]},
  "value": {"$gte": 10000},
  "closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"},
  "ownerIds": {"$includes": "<USER_UUID>"},
  "stage": {"$in": ["<UUID_1>", "<UUID_2>"]},
  "lastActivity": {"$exists": true},
  "companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]},
  "custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}
}
Example: {"stage":"<PIPELINE_STAGE_UUID>"}
limitintegerOptional

Maximum number of records to return

Default: 100
offsetintegerOptional

Pagination offset

Default: 0
orderBystringOptional

JSON string for sort order

Example: {"name":"asc"}
Responses
200

Successful response

application/json
totalintegerOptional
get/api/quotes
GET /api/quotes HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Accept: */*
{
  "data": [
    {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "workspaceId": "123e4567-e89b-12d3-a456-426614174000",
      "companyId": "123e4567-e89b-12d3-a456-426614174000",
      "dealId": "123e4567-e89b-12d3-a456-426614174000",
      "name": "text",
      "status": "draft",
      "lineItems": [
        {
          "productId": "123e4567-e89b-12d3-a456-426614174000",
          "priceId": "123e4567-e89b-12d3-a456-426614174000",
          "sku": "text",
          "name": "text",
          "description": "text",
          "quantity": 1,
          "amount": 1,
          "currency": "text",
          "interval": "day",
          "discountType": "absolute",
          "discount": 1,
          "totalAmount": 1
        }
      ],
      "totalAmount": 1,
      "totalAmountInWorkspaceCurrency": 1,
      "currency": "text",
      "mrr": 1,
      "arr": 1,
      "mrrInWorkspaceCurrency": 1,
      "arrInWorkspaceCurrency": 1,
      "termMonths": 1,
      "sentAt": "2026-01-01T00:00:00.000Z",
      "expiresAt": "2026-01-01",
      "acceptedAt": "2026-01-01T00:00:00.000Z",
      "rejectedAt": "2026-01-01T00:00:00.000Z",
      "archived": true,
      "createdAt": "2026-01-01T00:00:00.000Z",
      "updatedAt": "2026-01-01T00:00:00.000Z",
      "createdById": "123e4567-e89b-12d3-a456-426614174000"
    }
  ],
  "total": 1
}

Create a quote

post

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.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
workspaceIdstring · uuidRequired
dealIdstring · uuidOptional

Deal to attach the quote to. Provide dealId and/or companyId.

companyIdstring · uuidOptional

Company to attach the quote to. Provide dealId and/or companyId.

namestringOptional
statusstring · enumOptionalDefault: draftPossible values:
totalAmountnumberOptional

Total contract value (TCV) over termMonths in currency.

currencystringOptional
mrrnumberOptional
arrnumberOptional
termMonthsintegerOptional
sentAtstring · date-timeOptional
expiresAtstring · dateOptional
Responses
200

Quote created successfully

application/json
post/api/quotes
POST /api/quotes HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 348

{
  "workspaceId": "workspace-uuid",
  "dealId": "deal-uuid",
  "name": "Enterprise annual quote",
  "status": "draft",
  "currency": "USD",
  "termMonths": 12,
  "totalAmount": 5000,
  "arr": 5000,
  "lineItems": [
    {
      "productId": "product-uuid",
      "priceId": "price-uuid",
      "name": "Enterprise Plan · Annual",
      "quantity": 1,
      "amount": 5000,
      "currency": "USD",
      "interval": "year",
      "totalAmount": 5000
    }
  ]
}
{
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "workspaceId": "123e4567-e89b-12d3-a456-426614174000",
    "companyId": "123e4567-e89b-12d3-a456-426614174000",
    "dealId": "123e4567-e89b-12d3-a456-426614174000",
    "name": "text",
    "status": "draft",
    "lineItems": [
      {
        "productId": "123e4567-e89b-12d3-a456-426614174000",
        "priceId": "123e4567-e89b-12d3-a456-426614174000",
        "sku": "text",
        "name": "text",
        "description": "text",
        "quantity": 1,
        "amount": 1,
        "currency": "text",
        "interval": "day",
        "discountType": "absolute",
        "discount": 1,
        "totalAmount": 1
      }
    ],
    "totalAmount": 1,
    "totalAmountInWorkspaceCurrency": 1,
    "currency": "text",
    "mrr": 1,
    "arr": 1,
    "mrrInWorkspaceCurrency": 1,
    "arrInWorkspaceCurrency": 1,
    "termMonths": 1,
    "sentAt": "2026-01-01T00:00:00.000Z",
    "expiresAt": "2026-01-01",
    "acceptedAt": "2026-01-01T00:00:00.000Z",
    "rejectedAt": "2026-01-01T00:00:00.000Z",
    "archived": true,
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-01-01T00:00:00.000Z",
    "createdById": "123e4567-e89b-12d3-a456-426614174000"
  },
  "sideEffects": []
}

Get a quote

get

Returns a single quote by ID.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
quoteIdstring · uuidRequired
Responses
200

Successful response. If the quote does not exist, the API returns HTTP 200 with an empty body ({}).

application/json
get/api/quotes/{quoteId}
GET /api/quotes/{quoteId} HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Accept: */*
{
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "workspaceId": "123e4567-e89b-12d3-a456-426614174000",
    "companyId": "123e4567-e89b-12d3-a456-426614174000",
    "dealId": "123e4567-e89b-12d3-a456-426614174000",
    "name": "text",
    "status": "draft",
    "lineItems": [
      {
        "productId": "123e4567-e89b-12d3-a456-426614174000",
        "priceId": "123e4567-e89b-12d3-a456-426614174000",
        "sku": "text",
        "name": "text",
        "description": "text",
        "quantity": 1,
        "amount": 1,
        "currency": "text",
        "interval": "day",
        "discountType": "absolute",
        "discount": 1,
        "totalAmount": 1
      }
    ],
    "totalAmount": 1,
    "totalAmountInWorkspaceCurrency": 1,
    "currency": "text",
    "mrr": 1,
    "arr": 1,
    "mrrInWorkspaceCurrency": 1,
    "arrInWorkspaceCurrency": 1,
    "termMonths": 1,
    "sentAt": "2026-01-01T00:00:00.000Z",
    "expiresAt": "2026-01-01",
    "acceptedAt": "2026-01-01T00:00:00.000Z",
    "rejectedAt": "2026-01-01T00:00:00.000Z",
    "archived": true,
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-01-01T00:00:00.000Z",
    "createdById": "123e4567-e89b-12d3-a456-426614174000"
  }
}

Delete a quote

delete

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

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
quoteIdstring · uuidRequired
Query parameters
archivebooleanOptional

If true, soft deletes (archives) the quote instead of permanently deleting it.

Default: false
Responses
200

Quote deleted successfully

application/json
dataone ofOptional

Hard delete (archive omitted or false): returns 1 on success. Soft delete (archive=true): returns a single-element array containing the archived quote object.

integerOptionalExample: 1
or
delete/api/quotes/{quoteId}
DELETE /api/quotes/{quoteId} HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Accept: */*
{
  "data": 1,
  "sideEffects": []
}

Update a quote

patch

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).

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
quoteIdstring · uuidRequired
Body
dealIdstring · uuidOptional
companyIdstring · uuidOptional
namestringOptional
statusstring · enumOptionalPossible values:
totalAmountnumberOptional
currencystringOptional
mrrnumberOptional
arrnumberOptional
termMonthsintegerOptional
sentAtstring · date-timeOptional
expiresAtstring · dateOptional
acceptedAtstring · date-timeOptional
rejectedAtstring · date-timeOptional
Responses
200

Only the changed fields are returned in data. Use GET on the record to retrieve the full updated object.

application/json
dataobjectOptional

Only the changed fields, not the full object.

patch/api/quotes/{quoteId}
PATCH /api/quotes/{quoteId} HTTP/1.1
Host: api.zero.inc
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 602

{
  "dealId": "123e4567-e89b-12d3-a456-426614174000",
  "companyId": "123e4567-e89b-12d3-a456-426614174000",
  "name": "text",
  "status": "draft",
  "lineItems": [
    {
      "productId": "123e4567-e89b-12d3-a456-426614174000",
      "priceId": "123e4567-e89b-12d3-a456-426614174000",
      "name": "text",
      "description": "text",
      "quantity": 1,
      "amount": 1,
      "currency": "text",
      "interval": "day",
      "discountType": "absolute",
      "discount": 1,
      "totalAmount": 1
    }
  ],
  "totalAmount": 1,
  "currency": "text",
  "mrr": 1,
  "arr": 1,
  "termMonths": 1,
  "sentAt": "2026-01-01T00:00:00.000Z",
  "expiresAt": "2026-01-01",
  "acceptedAt": "2026-01-01T00:00:00.000Z",
  "rejectedAt": "2026-01-01T00:00:00.000Z"
}
{
  "data": {},
  "sideEffects": []
}

Last updated