
## Quote fields

`GET /v1/quotes/fields`

Returns the full list of available fields, including user fields (`ufCrm_*`).

## Examples

### curl — personal key

```bash
curl "https://vibecode.bitrix24.com/v1/quotes/fields" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl "https://vibecode.bitrix24.com/v1/quotes/fields" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/quotes/fields', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
console.log('Fields:', Object.keys(data.fields).length)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/quotes/fields', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { success, data } = await res.json()
```

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data` | object | The quote field schema and the operations available for quotes. Its keys are in the rows below |
| `data.fields` | object | The quote field schema: field name → an object with `type`, `readonly` and `label`. Some fields also carry `description` and extra attributes such as `multiple` and `notReturned`. The standard fields are listed below, and the `ufCrm*` user fields of this Bitrix24 account are added to them |
| `data.relations` | object | The `deal`, `contact` and `company` relations: the quote's deal, contact and company |
| `data.products` | object | Operations on the quote's product rows, the `setWarning` notice that `set` replaces all rows, and the product row field schema. See [Quote product fields](/docs/entities/quotes/products-fields) |
| `data.aggregatable` | array | Standard fields allowed in the aggregation `groupBy`: `amount`, `stageId`, `assignedById`, `currency` |
| `data.batch` | array | Quote write operations available in [batch calls](/docs/batch): `create`, `update`, `delete` |
| `data.import` | object | Method, path and maximum batch size for [importing records](/docs/import) |
| `data.include` | array | The names the `include` parameter accepts: `deal`, `contact`, `company` |

### Standard quote fields

The response elements of `contactIds` are numbers (`number[]`): OpenAPI describes them as `number`, and this endpoint and `fieldsDetailed` in `/v1/guide` publish `readItemSchema: { "type": "number" }`. This describes responses only: `QuoteInput.contactIds` retains its previous `string[]` schema, and accepted values and their order do not change.

| Field | Type | RO | Description |
|------|-----|:--:|---------|
| `id` | number | yes | Quote ID |
| `quoteNumber` | string | | Quote number |
| `title` | string | | Name |
| `amount` | number | | Amount |
| `taxValue` | number | yes | Tax amount for the quote. Computed by Bitrix24 from the product rows and rejected by all write operations. Measured 2026-09-11 on live Bitrix24 accounts: create and update in both amount modes, import in both modes — the read-back is `0` every time. The field is therefore read-only: write attempts are rejected instead of returning a success response and discarding the value. Set the tax through the product rows |
| `currency` | string | | Currency. List: `GET /v1/currencies` |
| `stageId` | string | | Status: `DRAFT`, `SENT`, `APPROVED`. List: `GET /v1/statuses?filter[entityId]=QUOTE_STATUS` |
| `isManualOpportunity` | boolean | | Manual amount mode (`Y`/`N` in Bitrix24, converted to boolean) |
| `opened` | boolean | | Available to everyone |
| `closed` | boolean | yes | Quote is closed |
| `dealId` | number | | Deal ID. Lookup: `GET /v1/deals` |
| `leadId` | number | | Lead ID. Lookup: `GET /v1/leads` |
| `contactId` | number | | Contact ID. Lookup: `GET /v1/contacts` |
| `contactIds` | number[] | | Quote contact IDs. Send the full list — the binding set is replaced, not merged |
| `contacts` | array | yes | Not returned: the Bitrix24 item API never returns this key for quotes, and quotes have no bindings route — the bound contacts are in `contactIds`. Declared so that a write is refused (`400 READONLY_FIELD` instead of a raw Bitrix24 error); selecting it returns `400 SELECT_FIELD_NOT_RETURNED`, and it is not accepted in `filter` or `order` — `400 UNKNOWN_FILTER_FIELD` / `400 UNKNOWN_SORT_FIELD` |
| `clientTitle` | string | yes | Client name from the legacy snapshot. The seven `client*` fields (name, address, contact person, e-mail, phone, taxpayer ID, tax registration code) are not filled by binding a company and a contact and are not accepted by the item API — Bitrix24 discards values submitted during create, update, batch or import operations. The legacy `crm.quote.add` / `crm.quote.update` methods (the ones older integrations use) store them, so they are returned when reading records, can be used in filters and sorting, and are declared read-only. Write attempts are rejected instead of returning a success response and discarding the value: `400 READONLY_FIELD`; `BATCH_ITEM_VALIDATION` in batch, `IMPORT_ITEM_VALIDATION` in import. `null` when nothing was stored, like every other string field. Measured 2026-09-15/16 through a direct webhook on a Bitrix24 test account |
| `clientAddr` | string | yes | Client address from the legacy snapshot — filled and read the same way as `clientTitle` |
| `clientContact` | string | yes | Client contact person from the legacy snapshot — as `clientTitle` |
| `clientEmail` | string | yes | Client e-mail from the legacy snapshot — as `clientTitle` |
| `clientPhone` | string | yes | Client phone from the legacy snapshot — as `clientTitle` |
| `clientTpId` | string | yes | Client taxpayer ID (INN) from the legacy snapshot — as `clientTitle` |
| `clientTpaId` | string | yes | Client tax registration code (KPP) from the legacy snapshot — as `clientTitle` |
| `companyId` | number | | Company ID. Lookup: `GET /v1/companies` |
| `mycompanyId` | number | | Your company details |
| `personTypeId` | number | yes | Payer type |
| `assignedById` | number | | Assignee. List: `GET /v1/users` |
| `createdBy` | number | yes | Creator. Lookup: `GET /v1/users` |
| `updatedBy` | number | yes | Updated by |
| `lastActivityBy` | number | | Last activity author |
| `comments` | string | | Comment |
| `content` | string | | Content |
| `terms` | string | | Terms |
| `locationId` | string | | Location |
| `webformId` | number | | Created by a CRM web form |
| `storageTypeId` | number | | File storage type |
| `storageElementIds` | array | | Storage file IDs |
| `utmSource` | string | | UTM source |
| `utmMedium` | string | | UTM medium |
| `utmCampaign` | string | | UTM campaign |
| `utmContent` | string | | UTM content |
| `utmTerm` | string | | UTM term |
| `beginDate` | datetime | | Start date |
| `closeDate` | datetime | | Close date |
| `actualDate` | datetime | | Valid until |
| `lastActivityTime` | datetime | | Last activity |
| `lastCommunicationTime` | string | yes | Last communication date |
| `lastCommunicationCallTime` | datetime | yes | Last call date |
| `lastCommunicationEmailTime` | datetime | yes | Last email date |
| `lastCommunicationImolTime` | datetime | yes | Last Open Channels dialog date |
| `lastCommunicationWebformTime` | datetime | yes | Last CRM web-form submission date |
| `createdTime` | datetime | yes | Creation date |
| `updatedTime` | datetime | yes | Modification date |

The UTM fields are returned in `list`/`get` but are not accepted in `filter` or in sorting. A request with `filter[utmSource]` returns `400 UNKNOWN_FILTER_FIELD`, one with `sort=utmSource` returns `400 UNKNOWN_SORT_FIELD`, and both errors are returned before Bitrix24 is called.

**User fields** (`ufCrm_*`) are also returned in responses and accepted on create/update.

## Response example

```json
{
  "success": true,
  "data": {
    "fields": {
      "id": { "type": "number", "readonly": true, "label": "Quote ID", "description": "Quote identifier assigned by Bitrix24." },
      "title": { "type": "string", "readonly": false, "label": "Name", "description": "Quote name shown in the list and in the card." },
      "assignedById": { "type": "number", "readonly": false, "label": "Assignee", "description": "Employee responsible for the quote. Available values: GET /v1/users." }
    },
    "relations": {
      "deal": { "type": "one", "entity": "deals", "includable": true },
      "contact": { "type": "one", "entity": "contacts", "includable": true },
      "company": { "type": "one", "entity": "companies", "includable": true }
    },
    "aggregatable": ["amount", "stageId", "assignedById", "currency"],
    "batch": ["create", "update", "delete"],
    "import": { "method": "POST", "path": "/v1/quotes/import", "maxItems": 100 },
    "include": ["deal", "contact", "company"]
  }
}
```

Three fields from `data.fields` are shown, along with the other `data` keys. The `data.products` block is omitted from the example, and the full set of fields is in the tables above.

`label` is a short caption in English, while labels that the platform takes straight from the Bitrix24 account come in the account language. `description` is an extended explanation: what the field is for, where to get the list of allowed values, and how it behaves on write. Request headers do not switch the language. The `stageId` value set is configured in your Bitrix24 account, so its description links to the status list endpoint instead of enumerating fixed values.

What to do with the names from `data.include` is covered on the [Get a quote](/docs/entities/quotes/get#related-data) page. For more information about the `include` parameter, see [Related data](/docs/includes).

## Error response example

403 — the key lacks the `crm` scope:

```json
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'crm' scope",
    "hint": "This request needs the 'crm' scope, which the calling key does not carry. Add 'crm' to this key in the developer cabinet (or through the management API), then repeat the call.",
    "cause": "key_scope_missing",
    "requiredScope": "crm",
    "keyScopes": ["task", "im"],
    "fix": { "action": "edit_key_scopes", "via": "cabinet" },
    "userMessage": "The app's API key lacks the “CRM” permission. You can add it in the key settings in the developer cabinet."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 403 | `SCOPE_DENIED` | The API key lacks the `crm` scope |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |
| 429 | `RATE_LIMITED` | Rate limit exceeded: 300 requests per minute per portal. All API keys of the portal share one limit. The current limit is returned in the `x-ratelimit-limit` header. Retry after the delay in the `Retry-After` header |

For the full list of common API errors, see [Errors](/docs/errors).

## See also

- [Create a quote](/docs/entities/quotes/create)
- [User fields](/docs/userfields)
- [Entity API](/docs/entity-api)
- [Limits and optimization](/docs/optimization)
