# API overview

Vibecode provides a single REST interface for working with Bitrix24 entities: CRM, tasks, users, calendar, drive, catalog, workflows, and others. All entities share the same set of operations.

> Base URL: `https://vibecode.bitrix24.com`
> Authorization: `X-Api-Key: your_key` header
> `vibe_app_…` keys additionally require an `Authorization: Bearer` header with a session token on every entity request. For unattended jobs (cron, a scheduler) with no user at the screen, use a `vibe_api_…` key. More details — [Creating and using a key](./keys-auth.md).

## Available operations

Every entity supports the standard set of operations. The path follows the `/v1/{entity}` template.

### List — `GET /v1/{entity}`

Fetch records with pagination, sorting, and field selection.

```bash
curl -H "X-Api-Key: $KEY" \
  "https://vibecode.bitrix24.com/v1/deals?limit=100&offset=0"
```

Parameters:

| Parameter | Type | Description |
|----------|-----|---------|
| `limit` | number | Number of records (default 50, maximum 5000) |
| `offset` | number | Skip N records |
| `select` | string[] | Field selection: `?select=id,title,amount` |
| `order` | object | Sorting: `?order[createdAt]=desc` |

**Auto-pagination:** when `limit > 50`, Vibecode automatically requests several pages from Bitrix24 and returns all records in a single response.

### Get by ID — `GET /v1/{entity}/{id}`

```bash
curl -H "X-Api-Key: $KEY" \
  "https://vibecode.bitrix24.com/v1/deals/123"
```

Response: `{ success: true, data: { id: 123, title: "...", ... } }`

The `select` parameter also works when fetching a record by `id` — the response contains only the listed fields. Three forms are supported: a comma-separated list `?select=id,title,stageId`, a repeated key `?select[]=id&select[]=title`, and an indexed form `?select[0]=id&select[1]=title`. The `id` field is always returned; unknown fields are skipped. The parameter is compatible with `include` — related data is resolved before the fields are selected.

### Create — `POST /v1/{entity}`

```bash
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  "https://vibecode.bitrix24.com/v1/deals" \
  -d '{"title": "New deal", "stageId": "NEW", "amount": 150000}'
```

Response: `{ success: true, data: { id: 456, ... } }` (HTTP 201)

A body with no field returns `400 EMPTY_CREATE_BODY` — [Error codes](./errors.md).

### Update — `PATCH /v1/{entity}/{id}`

```bash
curl -X PATCH -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  "https://vibecode.bitrix24.com/v1/deals/123" \
  -d '{"stageId": "WON", "amount": 200000}'
```

A body with no field returns `400 EMPTY_UPDATE_BODY` — [Error codes](./errors.md).

### Delete — `DELETE /v1/{entity}/{id}`

```bash
curl -X DELETE -H "X-Api-Key: $KEY" \
  "https://vibecode.bitrix24.com/v1/deals/123"
```

### Search — `POST /v1/{entity}/search`

Search with filtering. More on filter syntax: [Filtering](./filtering.md)

```bash
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  "https://vibecode.bitrix24.com/v1/deals/search" \
  -d '{"filter": {"stageId": "NEW", "amount": {"$gte": 100000}}, "sort": {"createdAt": "desc"}, "limit": 200}'
```

Parameters:

| Parameter | Type | Description |
|----------|-----|---------|
| `filter` | object | Filtering conditions ([three syntaxes](./filtering.md)) |
| `sort` | string \| object \| array | Sorting. Supported: `"id"` / `"-amount"` / `"id,-createdAt"` (string), `{ id: "asc", amount: "desc" }` or `{ id: 1, amount: -1 }` (object), `["id", "-amount"]` (array). Invalid type → `400 INVALID_SORT_TYPE`. More on pagination — see [filtering.md](./filtering.md#pagination). |
| `limit` | number | Number of records (default 50, maximum 5000, auto-pagination when > 50) |
| `offset` | number | Skip N records |
| `autoWindow` | boolean | `false` — disable date windowing for large selections |

**Windowed search:** for large datasets, search automatically splits the request into time windows. If this causes timeouts — disable it via `autoWindow: false`.

### Aggregation — `POST /v1/{entity}/aggregate`

Counts and numeric aggregations (`sum`, `avg`, `min`, `max`) with filtering.

```bash
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  -d '{
    "aggregate": [
      { "field": "amount", "function": "sum" },
      { "field": "amount", "function": "avg" }
    ],
    "filter": { "stageId": "WON" }
  }' \
  "https://vibecode.bitrix24.com/v1/deals/aggregate"
```

Parameters (body):

| Parameter | Type | Description |
|----------|-----|---------|
| `aggregate` | array | Array of aggregations: `{ "field": "amount", "function": "sum" }`. Functions: `count`, `sum`, `avg`, `min`, `max`. Without an array — only `count` |
| `filter` | object | Filtering by entity fields |
| `groupBy` | string \| string[] | Field or array of fields to group by (maximum 5). Allowed values come from the entity's `aggregatable` list. For entities without `aggregatable` (items, requisites) the parameter is not supported |

> **How it works:** `count` is computed with a single fast call to Bitrix24. For `sum`/`avg`/`min`/`max` the platform loads the records matching the filter (up to 5000 — beyond that it is flagged `meta.truncated: true`) and computes on the Vibecode side. For an invalid field the response includes the list of available ones.

> **User fields (UF)** are supported in `sum`/`avg`/`min`/`max` for the UF types `integer`, `double`, `money`. `groupBy` accepts UF fields of any type. Details — in the [Aggregation POST — UF fields](#aggregation-post-uf-fields) section below.

> **Smart processes (items)** use a path parameter: `POST /v1/items/:entityTypeId/aggregate`. Reserved `entityTypeId` values (1, 2, 3, 4, 7, 31) are served by the dedicated APIs for deals, leads, contacts, companies, quotes, and invoices.

### Aggregation POST — UF fields

The canonical POST variant of aggregation accepts an array of expressions and supports user fields (`UF_CRM_*`, `ufCrm_*`).

```bash
curl -X POST https://vibecode.bitrix24.com/v1/deals/aggregate \
  -H "X-Api-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "aggregate": [
      { "function": "sum", "field": "amount" },
      { "function": "sum", "field": "UF_CRM_BUDGET" },
      { "function": "avg", "field": "UF_CRM_SCORE" }
    ],
    "groupBy": "UF_CRM_PRIORITY"
  }'
```

**UF support rules:**

| Function | Accepts UF types |
|---------|-------------------|
| `sum`, `avg`, `min`, `max` | only `integer`, `double`, `money` |
| `groupBy` | any UF type (string, enumeration, date, integer, …) |

**Money fields** are stored in Bitrix24 as the string `"amount|currency"` (for example `"1500.50|USD"`). The aggregate extracts the numeric part before `|` — all arithmetic operations are correct.

**Errors:**

| HTTP | Code | When |
|------|-----|-------|
| 400 | `INVALID_PARAMS` | UF type not in the `integer`/`double`/`money` list for `sum`/`avg`/`min`/`max` — the actual type is given in `message` |
| 400 | `INVALID_PARAMS` | Field not found in the schema or the UF cache — the available standard and UF fields are listed in `message` |

**UF field cache:** one call to `crm.{entity}.fields` per `portal+entity` combination (+entityTypeId for items). TTL 5 minutes — repeat aggregates within the window incur no extra requests.

### Field schema — `GET /v1/{entity}/fields`

Get the description of all entity fields with their types.

```bash
curl -H "X-Api-Key: $KEY" \
  "https://vibecode.bitrix24.com/v1/deals/fields"
```

Each field's metadata in the response carries the display name `label` and a purpose note `description`, where they are defined for the field. Field names do not need a separate reference — they arrive with the schema.

### Batch operations — `POST /v1/{entity}/batch`

Bulk create, update, or delete records of a single entity.

```json
{ "action": "create", "items": [{ "title": "Deal 1" }, { "title": "Deal 2" }] }
```

To work with **different entities** in one request, use the [Batch API](./batch.md).

## Response format

All endpoints return a single format:

```json
{
  "success": true,
  "data": [ ... ],
  "meta": { "total": 150, "hasMore": true }
}
```

| Field | Description |
|------|---------|
| `success` | `true` on successful execution |
| `data` | Array of records (list/search) or an object (get/create) |
| `meta.total` | Total number of records matching the filter (for list/search) |
| `meta.hasMore` | Whether there are more records to load |
| `meta.pageErrorSample` | Arrives for a list or a search when some pages failed to load: the `code` and `message` of the first error. The response then holds a contiguous prefix of the selection, not every record |
| `meta.windowErrorSample` | The same for a windowed search: the `code` and `message` of the first failed window. Arrives together with `meta.windowErrors`, the number of failed windows. On a total failure the search returns an error rather than a partial response |

## Field transformation

Vibecode automatically transforms field names when sending a request. Always use camelCase in requests:

```json
{ "title": "Deal", "stageId": "NEW", "assignedById": 1 }
```

In responses the field format depends on the Bitrix24 API of the specific entity:

| Response format | Entities | Response example |
|---------------|----------|---------------|
| camelCase | CRM (deals, contacts, companies, leads, quotes, invoices), **tasks**, catalog, sale, documents, bookings | `{ "id": 1, "title": "Deal", "stageId": "NEW" }` |
| UPPER_CASE (raw/undeclared fields only) | users, departments, files, folders, calendar-events, activities, workgroups | `{ "ID": 1, "NAME": "…" }` |

> Entities with a declared field schema (including **tasks**) return the **documented** fields in camelCase (`id`/`title`/`status`/`responsibleId`/…). `tasks` was previously mislisted in the UPPER_CASE row — its `list`/`get` responses are fully camelCase. The UPPER_CASE form may persist only for raw/undeclared fields of the entities in the second row.

It's not just the case that differs — for some fields the name itself differs. For example, the deal amount is called `amount` in Vibecode, while the source name of this field in Bitrix24 is `opportunity`. The Vibecode name is shown in the Field column of the `GET /v1/{entity}/fields` schema, and the source Bitrix24 name is in the Bitrix24 column. In requests and when reading the response, use the name from the Field column — the field is returned under it, and the source Bitrix24 name is not returned. The mapping for each entity is on its fields page, for example [Deal fields](./entities/deals/fields.md).

## Multi-value fields (email, phone, web)

The contact fields `email`, `phone`, and `web` hold several values with types. The set depends on the entity — `email` and `phone` exist on contacts, companies, and leads, `web` only on companies. The format differs on input and on output.

**On input** — an array of objects `[{ "value": "contact@example.com", "typeId": "WORK" }]`. A single string `"contact@example.com"` and an array of strings are also accepted. The `typeId` depends on the field — `WORK` / `HOME` / `MOBILE` / `OTHER` for phone, `WORK` / `HOME` / `MAILING` / `OTHER` for email. Default `WORK`.

```json
{ "email": [{ "value": "contact@example.com", "typeId": "WORK" }] }
```

The UPPER form with `VALUE` and `VALUE_TYPE` keys is not accepted — `400 INVALID_MULTIFIELD_SHAPE`. Use camelCase `value` and `typeId`.

**On output** — the primary value comes as a string (`"email": "contact@example.com"`), and the full list of values with types is in the `fm` array. Per-type values are available in dedicated fields (`emailWork`, `phoneMobile`).

The exact set of `typeId` values and output fields for each entity is on its page, for example [Contacts](./entities/contacts.md) and [Companies](./entities/companies.md).

## User fields (UF)

User fields are passed and returned **without name transformation**. Both Bitrix24 formats are supported:

- Legacy API: `UF_CRM_1234567890`
- SPA API: `ufCrm_1234567890`

```json
{ "UF_CRM_1234567890": "value" }
```

The field name in the response matches what Bitrix24 returns. To get the list of user fields, use `GET /v1/userfields/:entity`.

Managing user fields: [Custom Fields](./userfields.md)

## Special entities

### Smart Processes (Items)

Smart processes use `entityTypeId` in the URL: `GET /v1/items/{entityTypeId}`.

```bash
# List of smart-process records with entityTypeId = 1058
curl -H "X-Api-Key: $KEY" \
  "https://vibecode.bitrix24.com/v1/items/1058?limit=10"
```

List of available smart processes: `GET /v1/smart-processes`.

### Calendar Events

Require mandatory parameters: `type` (user/group/company) and `ownerId`.

```bash
curl -H "X-Api-Key: $KEY" \
  "https://vibecode.bitrix24.com/v1/calendar-events?type=user&ownerId=1"
```

### Files

Require `folderId`. Obtain it from `GET /v1/storages` → the `rootFolderId` field.

## Rate Limit

10 requests/second — the Bitrix24 account-level limit, shared across all keys.

**How to stay within the limit:**
- [Batch API](./batch.md) — 50 calls per 1 limit unit
- `POST /v1/{entity}/batch` — up to 500 CRUD records for 10 units (not 500)
- `POST /v1/{entity}/aggregate` — `count` runs as a single fast call; `sum`/`avg`/`min`/`max` load up to 5000 records and are computed on the Vibecode side
- The `select` parameter — loading only the needed fields reduces the response size

More: [Optimization](./optimization.md) — patterns for dashboards, bulk operations, scanning large volumes

## Writing with a read-only key

A key in read-only access mode performs reads and receives `403 WRITE_BLOCKED_READONLY_KEY` on any write call — create, update, delete, or an action on an entity. The full description of the code and the `details` fields — [Error codes](./errors.md). How to switch the mode and how the Bitrix24 account policy works — [Access mode](./keys-auth/access-mode.md).

## Usage patterns

| Task | Approach |
|--------|--------|
| Dashboard / analytics | `POST /v1/{entity}/aggregate` — counters and sums by filter |
| Bulk update | `POST /v1/{entity}/batch` with action=update |
| Data from several entities | `POST /v1/batch` — deals + tasks + contacts in 1 request |
| Record + related data | `?include=company,contact` — [related data](./includes.md) in one response |
| Scanning 1000+ records | `POST /v1/{entity}/search` with limit + offset |

## Related sections

- [Related data (include)](./includes.md) — loading related entities in one request
- [Filtering](./filtering.md) — three filter syntaxes, dates, NOT filters
- [Batch API](./batch.md) — up to 50 calls in one request
- [All entities](./entities-index.md) — full list of entities with links
- [Optimization](./optimization.md) — rate limits, performance patterns
- [Error codes](./errors.md) — platform error reference
