# Request and data

A detailed breakdown of the codes the Vibecode API returns for a malformed request body, a missing filter, and a call to a record that does not exist.

The summary table of all Vibecode API codes — [Error codes](/docs/errors).

## `VALIDATION_ERROR` (400)

The body or query parameters failed schema validation. Most V1 endpoints handle this through Zod, so the message names the specific fields that failed validation.

```json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "fields.title: Required; fields.stageId: Expected string, received number"
  }
}
```

**Causes:**
- Required fields are missing.
- The value type does not match the schema (a string instead of a number, a wrong date format).
- The `Content-Type: application/json` header is missing. A body that does not parse as JSON is rejected with separate codes — `INVALID_JSON_BODY`, `FST_ERR_CTP_INVALID_JSON_BODY`, or `fst_err_ctp_invalid_json_body` on AI Router routes. Which one arrives depends on the route — see the [summary table of codes](/docs/errors).

**Solution:**
- Check the request body against the endpoint schema in the [API overview](/docs/entity-api) or on the specific endpoint page.
- Pass numbers without quotes and dates in ISO 8601 format (`2026-04-29T10:00:00`).
- Add the `Content-Type: application/json` header.

---

## `NESTED_FIELDS_ENVELOPE` (400)

A create or update body contains an object under its own `fields` key, the entity schema does not declare `fields`, and the route wraps the body fields itself. That call is rejected before the write. Pass entity fields at the JSON root. This includes an empty object and a body that combines `fields` with flat fields. Scalar unknown fields keep their existing behavior. Global batch uses `NESTED_FIELDS_ENVELOPE` as the call error code, while other valid calls in the batch may run. Import and per-entity batch return `IMPORT_ITEM_VALIDATION` and `BATCH_ITEM_VALIDATION` respectively, with `NESTED_FIELDS_ENVELOPE` in the indexed item's message.

## `INVALID_PARAMS` (400)

Bitrix24 or the route handler found an invalid parameter value. Bitrix24 errors of the form `INVALID_PARAMS: ...` arrive under this same code.

```json
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "Path parameter :id must be a positive integer"
  }
}
```

**Causes:**
- An invalid path parameter value (for example, a non-number where a number is expected).
- Bitrix24 rejected a request parameter (for example, an unsupported value of an enum field).
- A write puts an object or an array into a field declared scalar (`string`, `number`, `boolean`, `date`, `datetime`). Bitrix24 stores such a value as the string `Array`, losing the data without an error, so the request is refused before the call. The check runs on entity create and update under `/v1/<entity>`, on both batch write surfaces and on import.
- An employee update puts into `personalPhoto` a value Bitrix24 cannot read as file content: an empty or whitespace-only string, the literal `false`, the booleans `true` and `false`, the number `0`, a string with fewer than two base64-alphabet characters, an inline `[file name, base64]` pair whose content is one of those, and any other structure whose second value is missing, `null` or unreadable (the nested `{fileData: [...]}`, an empty array, a one-element array, an explicit `null` or a structure in the content element). Bitrix24 treats each of them as a command to remove the current photo, so Vibecode refuses the value before the call. To keep the photo, omit the field; to remove it, call [`DELETE /v1/users/:id/personal-photo`](/docs/entities/users/photo-delete).

**Boundaries of the value checks:**
- A name absent from the entity schema is checked against what Bitrix24 itself reports about it in its field list (`GET /v1/<entity>/fields` shows the same list). These are the fields an entity returns on read but does not declare — `utmSource` and `locationId` on deals, `birthdate`, `honorific` and `categoryId` on contacts, `employees` on companies, for example — and the custom fields `UF_*`. The rules are the same as for declared fields, with the two exceptions below, and so is the `INVALID_PARAMS` code: an object or an array in a field Bitrix24 reports as string-like (`string`, `text`, `crm_status`, `crm_currency`, `location`, `url`), numeric (`integer`, `double`, `crm_category`, `user`, `employee`, `crm_contact`, `crm_company`, `crm_lead`, `crm_deal`), boolean (`boolean`, `char`) or date-like (`date`, `datetime`) is refused; so is a non-numeric string in a numeric field. In a Bitrix24 boolean field only the shape is checked: such a value travels to Bitrix24 unconverted, so string forms like `"yes"` are not promised here — send `Y`/`N`. An empty string (exactly `""`) in a link field (`user`, `employee`, `crm_contact`, `crm_company`, `crm_lead`, `crm_deal`) or in a custom numeric field (`UF_*`) is not refused — that is how Bitrix24 unlinks and clears a value; in a core numeric field and in a category (`crm_category`) it stays refused: there it turns into `0` — a contact with `categoryId: ""` moves to category 0. Without this check Bitrix24 stored such a structure as the string `Array`, a non-numeric string in `categoryId` as `0`, and an object there as `1` (the contact moved to another category) — all with a success response. Not checked: fields Bitrix24 reports as multi-value or read-only; fields immutable after creation (`isImmutable`) — on update, where Bitrix24 ignores them (on create and import they are checked); fields of types outside those listed (file, the multi-value contact field, enumeration, money); names absent from the Bitrix24 field list (a typo stays with the `UNRECOGNIZED_WRITE_FIELD` hint); entities whose field list carries no multiplicity flag (tasks). The Bitrix24 field list is requested only when the body carries such a name and is kept in memory for five minutes; if Bitrix24 did not return it, the check stays silent, the value travels as before, and for the next thirty seconds the list is not requested again before a write. Not covered: employee fields (`user.fields` reports no types), list elements, the `POST /v1/users/invite` wrapper, catalog products and entities for which Bitrix24 returns no live field list (orders, payments, calendar, sites, departments, workgroups and others — their `GET /v1/<entity>/fields` shows only the entity description).
- A number or a boolean in a string field is accepted: Bitrix24 stores `123456` and `1`, and nothing is lost. The shape check accepts `null` too. The exception is `users.personalPhoto` on UPDATE: the booleans `true` and `false`, the number `0` and every other value Bitrix24 cannot turn into a file (an empty string, a whitespace-only string, the literal `false`, a string with fewer than two base64-alphabet characters, and an inline pair with such content) are refused with `INVALID_PARAMS` on all three update surfaces — the single `PATCH /v1/users/:id`, the per-entity batch write and `POST /v1/batch`. `null` stands apart from them: it is refused only on UPDATE in `POST /v1/batch`, because the global batch encoder would turn it into an empty command. On the single PATCH and in the per-entity batch, `null` reaches no removal branch and removes no photo, which is why it is not refused there.
- For the remaining scalar types the check also judges the VALUE against the declared type, not only its shape. A number field accepts a JSON number or a numeric string using a dot as the decimal separator (`"1234.56"`); leading and trailing whitespace around such a string is ignored (`" 1234.56 "` is accepted), but a comma (`"1234,56"` — the ru/de/fr/es/it/br convention) is not: the value is refused with `INVALID_PARAMS` pointing at the dot, rather than silently reinterpreted. A boolean field accepts the JS `true`/`false` or a recognized string form, case-insensitive and trimmed (`"true"`/`"false"`, `"yes"`/`"no"`, `"y"`/`"n"`, `"1"`/`"0"`) — the JSON number `1` or `0` does not count as such a form and is refused too. The `tasks.priority` and `tasks.status` number fields are additionally checked for membership in their declared value list — a value outside the list is refused with `INVALID_PARAMS`; every other `enum` field in the registry has an open list, and this check does not run on them. The empty string is an exception that applies ONLY to a string field (see above): in a number or boolean field it does not clear the value — it is refused as a type mismatch, because otherwise Bitrix24 would turn it into `0` or `false` under a success response. Fields declared `date` and `datetime` do not yet get this value check: a structured value (an object, an array) in them is still refused (see above), but a malformed string is not — it travels to Bitrix24 as is.
- A string field with a declared length limit (today only `order-statuses.color`, limited to 10 characters) refuses a value past the limit with `INVALID_PARAMS` rather than silently truncating it to the database column width. A string field without a declared limit is not checked for length.
- Fields declared `object`, `array` or multi-value take structures as before.
- One deliberate exception is the file field: `users.personalPhoto` accepts, on write, an array of exactly two non-empty strings `[file name, base64]`, and only on the single-route `POST /v1/users` and `PATCH /v1/users/:id`. Any other structure in it — including the nested `{fileData: [...]}`, which Bitrix24 accepts with success while CLEARING the photo — and the same shape on batch routes are refused: a batch sub-call travels as a query string under the global body cap, and past its length limit the value would be truncated while still answering success. On UPDATE through the single PATCH or either batch route, any value Bitrix24 cannot turn into a file is refused with `INVALID_PARAMS`: an empty string, a whitespace-only string, the literal `false`, the booleans `true` and `false`, the number `0`, a string with fewer than two base64-alphabet characters, and the same inline pair when its content is one of those (a shape of two non-empty strings says nothing about the content being decodable). To keep the photo, omit the field; to remove it, call [`DELETE /v1/users/:id/personal-photo`](/docs/entities/users/photo-delete). On CREATE in `POST /v1/users`, an empty string does not get the new refusal. Details: [Update an employee](/docs/entities/users/update). The `POST /v1/users/invite` wrapper accepts the same inline pair, translates the field name, and validates it separately with its own `PERSONAL_PHOTO_INVALID` code, but its body limit is still the GLOBAL one (1 MiB against the 40 MiB of the single routes), so an ordinary phone snapshot hits the size cap there: for a real photo use `POST /v1/users` or `PATCH /v1/users/:id`.
- The refusal shape differs by surface, and so does its reach. The [global batch](/docs/batch) refuses ONLY its own sub-call: the failure arrives in `data.errors["<call id>"]` with separate `code` and `message` fields, and neighbouring sub-calls still run. If every sub-call is refused before dispatch, the overall response remains `400 INVALID_REQUEST`. The per-entity batch write (`POST /v1/{entity}/batch`) and import refuse the WHOLE request: a `400` arrives with code `BATCH_ITEM_VALIDATION` or `IMPORT_ITEM_VALIDATION`, while the element index and `INVALID_PARAMS` live inside `message`, shaped `Item at index N: INVALID_PARAMS — …`. Such a response carries neither `data` nor per-item `results`, and nothing reaches Bitrix24: the check runs before the dispatch.
- A few bespoke write routes are not covered yet: `POST /v1/addresses`, `PATCH /v1/addresses`, task comments (`/v1/tasks/:taskId/comments`), `POST /v1/doc-templates`, Open Channels config and product rows (`/v1/{entity}/:id/products`). There the previous behaviour still applies.

**Solution:**
- Check the endpoint page for the values allowed for each parameter.
- For `filter`, use the field list from `GET /v1/<entity>/fields`.

---

## `MISSING_REQUIRED_FILTER` (400)

A required filter was not passed on a list endpoint that needs context.

```json
{
  "success": false,
  "error": {
    "code": "MISSING_REQUIRED_FILTER",
    "message": "GET /v1/timelines requires filter fields: entityType, entityId. Example: GET /v1/timelines?filter[entityType]=...&filter[entityId]=..."
  }
}
```

**Causes:**
- The timeline record list requires the pair of parent identifiers `entityType` + `entityId`.
- The catalog product and section lists require `iblockId`, and the value list of a list property requires `propertyId`.
- [Activity aggregation](/docs/entities/activities/aggregate) requires a narrowing filter: the pair `ownerTypeId` + `ownerId`, or `responsibleId`, or a date bound on `createdAt` / `updatedAt` / `deadline`. Here the requirement is not "all of the above" but "any one of them" — Bitrix24 cannot count every activity of the account within the time allotted to the call. The platform enables the requirement per account. Check the state in `data.aggregateFilterRequirement.enforcement` in the `GET /v1/activities/fields` response.

The check runs before the call to Bitrix24 and applies to `GET /v1/{entity}`, `POST /v1/{entity}/search`, and `POST /v1/{entity}/aggregate`.

**Solution:**
- Add the required filter parameters listed in `message` or on the endpoint page.

---

## `BATCH_LIMIT_EXCEEDED` (400)

The request exceeds the item limit of a bulk operation. At the `/v1/batch` level the limit is reported through `INVALID_REQUEST` referencing `Array must contain at most 50 element(s)`. On domain endpoints for bulk operations (for example, `chats`, `task-comments`) there is a separate code, `BATCH_LIMIT_EXCEEDED`.

```json
{
  "success": false,
  "error": {
    "code": "BATCH_LIMIT_EXCEEDED",
    "message": "Maximum 50 dialogs per bulk request (Bitrix24 batch limit)."
  }
}
```

**Causes:**
- The array holds more than 50 items.

**Solution:**
- Split the operation into several requests of 50 items each.
- Use [batch requests](/docs/batch) for sequential calls with a single key.

---

## `ENTITY_NOT_FOUND` (404)

The CRM entity record with the given `id` does not exist or has been deleted.

```json
{
  "success": false,
  "error": {
    "code": "ENTITY_NOT_FOUND",
    "message": "Item not found"
  }
}
```

**Causes:**
- A record with this `id` really does not exist.
- The record was deleted by a parallel process.
- The entity was mixed up: the request goes to `/v1/deals/:id` while the ID belongs to a lead.

**Solution:**
- Check that the record exists through the entity's list endpoint.
- Restore it from the Bitrix24 recycle bin (through the account interface) if the record was deleted recently.

## See also

- [Error codes](/docs/errors)
- [API overview](/docs/entity-api)
- [Filtering syntax](/docs/filtering)
- [Batch](/docs/batch)
- [Retries and error handling in code](/docs/errors/handling)
