#Batch calls

A single HTTP request combines up to 50 operations across different entities. Each call is identified by its own id and processed independently: an error in one call does not cancel the others.

POST /v1/batch

Scope: checked individually per entity (crm, task, im, disk, etc.) | Base URL: https://vibecode.bitrix24.tech/v1 | Authorization: X-Api-Key (APP key)

#Request fields (body)

Field Type Req. Description
calls array Array of calls (1 to 50). Each element is an object; its format is described in the table below.

#Fields of a single call

Field Type Req. Description
id string no Call identifier in the response. If omitted — assigned a sequential index ("0", "1", ...). Up to 64 characters.
entity string Entity name in plural: deals, contacts, companies, tasks, users, files, folders, and others. The full list of entities available to your key is returned by GET /v1/me — see Keys and authorization.
action string Operation: list, get, create, update, delete, fields, search.
entityId number / string for get / update / delete Record identifier.
params object no Operation parameters in the unified entity format (field names in camelCase, filters in filtering syntax).

The parameters inside params match the parameters of a single Entity API endpoint:

  • list and searchfilter, select, order, limit
  • get — the include field, if the entity supports it
  • create and update — entity fields (names in camelCase)
  • delete and fields — no parameters needed
  • smart processes (entity: "items") — entityTypeId is required inside params

The record identifier for get / update / delete is passed in the entityId field at the call level, not in params.id. The call { "entity": "users", "action": "get", "params": { "id": 1 } } without entityId is rejected as MISSING_ENTITY_ID, and the whole batch returns 400 with a validation error. Correct: { "entity": "users", "action": "get", "entityId": 1 }. The params field for get serves only for include.

#Examples

#curl — personal key

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/batch \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "calls": [
      {
        "id": "deals",
        "entity": "deals",
        "action": "list",
        "params": {
          "filter": { "stageId": "NEW" },
          "select": ["id", "title", "amount"],
          "limit": 50
        }
      },
      {
        "id": "contacts",
        "entity": "contacts",
        "action": "list",
        "params": {
          "select": ["id", "name", "lastName"],
          "limit": 20
        }
      },
      {
        "id": "user1",
        "entity": "users",
        "action": "get",
        "entityId": 1
      }
    ]
  }'

#curl — OAuth application

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/batch \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "calls": [
      {
        "id": "deals",
        "entity": "deals",
        "action": "list",
        "params": {
          "filter": { "stageId": "NEW" },
          "select": ["id", "title", "amount"],
          "limit": 50
        }
      },
      {
        "id": "contacts",
        "entity": "contacts",
        "action": "list",
        "params": {
          "select": ["id", "name", "lastName"],
          "limit": 20
        }
      },
      {
        "id": "user1",
        "entity": "users",
        "action": "get",
        "entityId": 1
      }
    ]
  }'

#JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/batch', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    calls: [
      { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50 } },
      { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20 } },
      { id: 'user1', entity: 'users', action: 'get', entityId: 1 }
    ]
  })
})

const { data } = await res.json()
console.log('Deals:', data.results.deals)
console.log('Contacts:', data.results.contacts)
console.log('Summary:', data.summary)

#JavaScript — OAuth application

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/batch', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    calls: [
      { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50 } },
      { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20 } },
      { id: 'user1', entity: 'users', action: 'get', entityId: 1 }
    ]
  })
})

const { data } = await res.json()
console.log('Deals:', data.results.deals)

#Response fields

Field Type Description
success boolean true if the request is accepted. Partial errors inside data.errors do not flip it to false.
data.results object Results keyed by the id of each call. The value is whatever the corresponding Entity API endpoint would return: an array of records for list / search, an object for get / create, a field schema for fields.
data.totals object Total record count matching the filter for list / search calls. Keys are the id values of the corresponding calls.
data.errors object Errors keyed by the id of failed calls. Each value is { "code": "...", "message": "..." }.
data.summary.total number Total number of calls in the request.
data.summary.succeeded number Number of successful calls.
data.summary.failed number Number of failed calls.
data.meta object Additional details keyed by the id of calls with action: "list" or action: "search": total, returned, hasMore, truncated.

#Response example

JSON
{
  "success": true,
  "data": {
    "results": {
      "deals": [
        { "id": 575, "title": "Currency test", "amount": 0 },
        { "id": 741, "title": "Equipment delivery", "amount": 250000 }
      ],
      "contacts": [
        { "id": 1, "name": "Ivan", "lastName": "Petrov" }
      ],
      "user1": [
        { "ID": "1", "NAME": "Letta", "ACTIVE": true }
      ]
    },
    "totals": {
      "deals": 1798,
      "contacts": 305
    },
    "errors": {},
    "summary": {
      "total": 3,
      "succeeded": 3,
      "failed": 0
    },
    "meta": {
      "deals": { "total": 1798, "returned": 2, "hasMore": true, "truncated": false },
      "contacts": { "total": 305, "returned": 1, "hasMore": true, "truncated": false }
    }
  }
}

#Partial errors

If some calls fail validation or return an error on the Bitrix24 side, successful results stay in data.results, failed ones go to data.errors under the same id:

JSON
{
  "success": true,
  "data": {
    "results": {
      "deals": [
        { "id": 575, "title": "Currency test" }
      ]
    },
    "totals": {
      "deals": 1798
    },
    "errors": {
      "unknown": {
        "code": "UNKNOWN_ENTITY",
        "message": "Unknown entity \"foobar\". Check GET /v1/guide for available entities."
      }
    },
    "summary": {
      "total": 2,
      "succeeded": 1,
      "failed": 1
    },
    "meta": {
      "deals": { "total": 1798, "returned": 1, "hasMore": true, "truncated": false }
    }
  }
}

#Error response example

If all calls fail validation, 400 INVALID_REQUEST is returned with a per-id breakdown in data.errors:

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "All calls in the batch failed validation"
  },
  "data": {
    "errors": {
      "x": {
        "code": "MISSING_ENTITY_ID",
        "message": "Action \"get\" requires entityId."
      }
    }
  }
}

#Errors

HTTP Code Description
400 INVALID_REQUEST The request body does not match the schema, or all calls failed validation.
400 UNKNOWN_ENTITY One of the calls passed an unknown entity name.
400 ACTION_NOT_SUPPORTED The entity does not support the specified action (e.g. delete for a reference entity without deletion).
400 MISSING_ENTITY_ID Actions get, update, delete require entityId.
400 MISSING_DYNAMIC_PARAM For smart processes (entity: "items"), entityTypeId was not passed inside params.
400 INVALID_DYNAMIC_PARAM entityTypeId for smart processes is set incorrectly (not a positive integer).
400 USE_DEDICATED_ENTITY A dedicated entity exists for the passed entityTypeId — use it instead of items.
400 ENTITY_CUSTOM_ROUTES The entity works only through specialized routes (e.g. task-comments — via /v1/tasks/:taskId/comments).
400 INVALID_CALL The call object is missing the required entity and action fields.
401 TOKEN_MISSING The key has no configured OAuth tokens, or for an OAuth application no Authorization: Bearer ... was passed.
401 TOKEN_REFRESH_FAILED Failed to refresh the portal OAuth token.
403 MANAGEMENT_KEY_NO_ENTITY_ACCESS The request came from a management key — batch calls are available only to APP keys.
403 SCOPE_NOT_ALLOWED All calls requested scopes the key does not have. If at least one call passes — this code is returned inside data.errors for the specific calls, and the request itself succeeds.
422 BITRIX_ERROR Bitrix24 rejected the call. The response body contains bitrixError.error and bitrixError.error_description.
502 BITRIX_UNAVAILABLE Bitrix24 responded with a 5xx error.
503 QUEUE_OVERFLOW Too many concurrent Bitrix24 calls have accumulated on the portal (by default more than 100 pending). The response is returned instantly with an HTTP header Retry-After: N (seconds) — the client must wait for it and retry with exponential backoff + jitter. Body: error.code = QUEUE_OVERFLOW, error.retryAfter duplicates the header.
504 QUEUE_TIMEOUT The request waited in the portal queue for more than 30 seconds. The response contains userMessage and hint.
500 INTERNAL_ERROR Internal proxy error.

Full list of common API errors — Error codes.

#Known specifics

search and list with limit > 50 bypass the native Bitrix24 batch call. These calls run as separate sequential requests with paging up to 5000 records — each consumes its own Bitrix24 rate-limit quota independently. The remaining calls — list with limit ≤ 50, get, create, update, delete, fields — are combined into a single batch call on the Bitrix24 side and cost one rate-limit unit in total.

Cost of list in Bitrix24 rate-limit units. Every 50 records = 1 unit. With limit > 50 the auto-paginator makes several calls:

limit Bitrix24 units
1–50 1 (native batch)
51–2 550 2
2 551–5 000 3

If an action in one call fails, the rest keep executing. Errors land in data.errors under the same id, successful results — in data.results. The success field stays true; check data.summary.failed or the presence of the expected id in data.results.

users.get returns an array, not an object. This is an Entity API specific: the get response for users is [ { ID, NAME, ... } ]. The first element is the requested record.

Batch changes for a single entity. If you need to create, update, or delete many records of one entity (up to 500), use the specialized endpoint POST /v1/{entity}/batch with the body { "action": "create" | "update" | "delete", "items" | "ids": [...] }. It runs the operations in internal batches of 50 records and returns an array of results with a success flag for each element.

#See also