Version 1.0.1 is now available! Looking for a migration guide?
v1.0.1
/
  • Get Started
  • Working
  • GitHub
  • Overview
  • Introduction
  • Actions
  • Call
  • Call
  • CallList
  • CallList
  • FetchList
  • FetchList
  • Batch
  • Batch
  • BatchByChunk
  • BatchByChunk
  • Tools
  • HealthCheck
  • Ping
  • Logger
  • Logger
  • Telegram
  • Limiters
  • Limiters
  • B24Frame
  • Introduction
  • Initialization
  • Auth
  • Dialog
  • Options
  • Parent
  • Placement
  • Slider
  • b24ui
  • b24icons
v1.0.1
  • Get started
  • Working

BatchV2.make

Method for executing batch requests to Bitrix24 REST API version 2. Allows executing up to 50 commands in a single API call.
BatchV2
AjaxResult
AjaxError
SdkError
We are still updating this page. Some data may be missing here — we will complete it shortly.

Overview

Use BatchV2.make() to execute up to 50 REST API commands in a single request. This is especially useful when you need to retrieve or update large amounts of data while minimizing network requests and adhering to REST API limits.

// Basic usage
import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk'

const response = await $b24.actions.v2.batch.make({
  calls: [
    ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: 1 }],
    ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: 2 }]
  ],
  options: {
    isHaltOnError: true,
    returnAjaxResult: true,
    requestId: 'unique-request-id'
  }
})

Method Signature

make<T = unknown>(
  options: ActionBatchV2
): Promise<CallBatchResult<T>>

Parameters

The options object contains the following properties:

ParameterTypeRequiredDescription
callsBatchCommandsArrayUniversal | BatchCommandsObjectUniversal | BatchNamedCommandsUniversalYesCommands to execute in the batch. Supports several formats.
optionsIB24BatchOptionsNoAdditional options for batch request execution.

Command Formats (options.calls)

1. Array of tuples (BatchCommandsArrayUniversal)

calls: [
  ['method1', params1],
  ['method2', params2],
  // ...
]

2. Array of objects (BatchCommandsObjectUniversal)

calls: [
  { method: 'method1', params: params1 },
  { method: 'method2', params: params2 },
  // ...
]

3. Object with named commands (BatchNamedCommandsUniversal)

calls: {
  command1: { method: 'method1', params: params1 },
  command2: ['method2', params2],
  // ...
}

Batch Request Options (options.options)

OptionTypeDefaultDescription
isHaltOnErrorbooleantrueWhether to stop execution on the first error.
returnAjaxResultbooleanfalseWhether to return an AjaxResult object instead of data.
requestIdstring—Unique request identifier for tracking. Used for request deduplication and debugging.

Return Value

Promise<CallBatchResult<T>> — a promise that resolves to a CallBatchResult<T> object.

The result structure depends on the input data format:

  • For array of commands: array of results in the same order.
  • For named commands: object with keys corresponding to command names.

Error Handling

Always check the result using isSuccess and handle errors:

const response = await $b24.actions.v2.batch.make({
  calls: [
    { method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 1 } },
    { method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 2 } }
  ],
  options: {
    isHaltOnError: true,
    returnAjaxResult: true,
    requestId: 'unique-request-id'
  }
})

if (!response.isSuccess) {
  // Handling error
  console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`))
  return
}

// Working with a successful result
const data = response.getData()

Examples

Getting Multiple CRM Companies

import type { AjaxResult, Result, BatchCommandsArrayUniversal } from '@bitrix24/b24jssdk'
import { B24Hook, EnumCrmEntityTypeId, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk'

type Company = {
  id: number
  title: string
  [key: string]: any
}

const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV)
const $logger = LoggerFactory.createForBrowser('Example:batchCrmItems', devMode)
const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/')

async function getMultipleItems(itemIds: number[], requestId: string): Promise<Company[]> {
  if (itemIds.length < 1 || itemIds.length > 50) {
    throw new SdkError({
      code: 'MY_APP_GET_PROBLEM',
      description: `The number of elements must be between 1 and 50`,
      status: 404
    })
  }

  const batchCalls: BatchCommandsArrayUniversal = itemIds.map(id => [
    'crm.item.get',
    {
      entityTypeId: EnumCrmEntityTypeId.company,
      id
    }
  ])

  const response = await $b24.actions.v2.batch.make<{ item: Company }>({
    calls: batchCalls,
    options: {
      isHaltOnError: true,
      returnAjaxResult: true,
      requestId
    }
  })

  if (!response.isSuccess) {
    throw new SdkError({
      code: 'MY_APP_GET_PROBLEM',
      description: `Problem ${response.getErrorMessages().join('; ')}`,
      status: 404
    })
  }

  const resultData = (response as Result<AjaxResult<{ item: Company }>[]>).getData()!
  const results: Company[] = []
  resultData.forEach((resultRow, _index) => {
    if (resultRow.isSuccess) {
      results.push(resultRow.getData()!.result.item)
    }
  })

  return results
}

// Usage
const requestId = 'batch/crm.item.get'
try {
  const itemIds = [2, 4]
  const items = await getMultipleItems(itemIds, requestId)

  $logger.info(`Retrieved ${items.length} items`, {
    expected: itemIds.length,
    retrieved: items.length,
    items: items.map(c => ({ id: c.id, title: c.title }))
  })
} catch (error) {
  if (error instanceof AjaxError) {
    $logger.critical(error.message, { requestId, code: error.code })
  } else {
    $logger.alert('Problem', { requestId, error })
  }
}

Init Data Storage

This code automates the creation and initialization of data storages in Bitrix24 via the REST API.

It checks the existence of the specified storages and, if they don't exist, creates them along with the specified properties, using batch requests for efficiency.

batch-rest-api-ver2-data-storage.ts
import type { BatchNamedCommandsUniversal } from '@bitrix24/b24jssdk'
import { B24Hook, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk'

type DataStorageParams = {
  ENTITY: string
  NAME: string
  ACCESS: Record<string, 'R' | 'W' | 'X'>
}

type PropertyParams = {
  PROPERTY: string
  NAME: string
  TYPE: 'S' | 'N' | 'F'
}

type DataStorage = {
  isInit: boolean
  dataStorage: DataStorageParams
  props: PropertyParams[]
}

const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV)
const $logger = LoggerFactory.createForBrowser('Example:batchDataStorage', devMode)
const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/')

async function initDataStorageList(dataStorageMap: Map<string, DataStorage>, requestId: string): Promise<void> {
  // get current list
  const response = await $b24.actions.v2.call.make<{ ENTITY: string, NAME: string }[]>({
    method: 'entity.get',
    params: {},
    requestId: `${requestId}/init:getCurrentList`
  })

  if (!response.isSuccess) {
    throw new SdkError({
      code: 'MY_APP_GET_PROBLEM',
      description: `Problem ${response.getErrorMessages().join('; ')}`,
      status: 404
    })
  }

  const currentDataStorageList = response.getData()!.result as { ENTITY: string, NAME: string }[]

  for (const dataStorage of dataStorageMap.values()) {
    const isInit = currentDataStorageList.some(row => row.ENTITY === dataStorage.dataStorage.ENTITY)
    if (isInit) {
      dataStorage.isInit = true
    } else {
      await initDataStorage(dataStorage, requestId)
      dataStorage.isInit = true
    }
  }
}

async function initDataStorage(dataStorage: DataStorage, requestId: string): Promise<void> {
  const callBatch: BatchNamedCommandsUniversal = {
    AddEntity: {
      method: 'entity.add',
      params: dataStorage.dataStorage
    }
  }

  for (const property of dataStorage.props) {
    callBatch[`prop${property.PROPERTY}`] = {
      method: 'entity.item.property.add',
      params: {
        ...property,
        ENTITY: dataStorage.dataStorage.ENTITY
      }
    }
  }

  const response = await $b24.actions.v2.batch.make({
    calls: callBatch,
    options: {
      isHaltOnError: true,
      returnAjaxResult: false,
      requestId: `${requestId}/init:${dataStorage.dataStorage.ENTITY}`
    }
  })

  if (!response.isSuccess) {
    throw new SdkError({
      code: 'MY_APP_GET_PROBLEM',
      description: `Problem ${response.getErrorMessages().join('; ')}`,
      status: 404
    })
  }
}

// Usage
const requestId = 'batch/DataStorage'
try {
  const dataStorageMap: Map<string, DataStorage> = new Map([
    ['DataStorage1', {
      isInit: false,
      dataStorage: {
        ENTITY: 'DS1',
        NAME: 'Data Storage 1',
        ACCESS: {
          U1: 'X',
          AU: 'R'
        }
      },
      props: [
        {
          PROPERTY: 'PropertyN',
          NAME: 'Property N',
          TYPE: 'N'
        }
      ]
    }],
    ['DataStorage2', {
      isInit: false,
      dataStorage: {
        ENTITY: 'DS2',
        NAME: 'Data Storage 2',
        ACCESS: {
          U1: 'X',
          AU: 'R'
        }
      },
      props: [
        {
          PROPERTY: 'PropertyS',
          NAME: 'Property S',
          TYPE: 'S'
        }
      ]
    }],
    ['DataStorage3', {
      isInit: false,
      dataStorage: {
        ENTITY: 'DS3',
        NAME: 'Data Storage 3',
        ACCESS: {
          U1: 'X',
          AU: 'R'
        }
      },
      props: [
        {
          PROPERTY: 'PropertyF',
          NAME: 'Property F',
          TYPE: 'F'
        }
      ]
    }]
  ])

  await initDataStorageList(dataStorageMap, requestId)

  $logger.info(`dataStorageList`, {
    items: [...dataStorageMap.values()].map(c => ({
      entity: c.dataStorage.ENTITY,
      isInit: c.isInit,
      title: c.dataStorage.NAME,
      props: c.props
    }))
  })
} catch (error) {
  if (error instanceof AjaxError) {
    $logger.critical(error.message, { requestId, code: error.code })
  } else {
    $logger.alert('Problem', { requestId, error })
  }
}

Delete Data Storage

This code deletes multiple data storages in the Bitrix24 system via the REST API.

It sequentially sends delete requests for each data storage specified in the dataStorageMap using the entity.delete method.

batch-rest-api-ver2-data-storage-delete.ts
import { B24Hook, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk'

type DataStorageParams = {
  ENTITY: string
  NAME: string
}

type DataStorage = {
  dataStorage: DataStorageParams
}

const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV)
const $logger = LoggerFactory.createForBrowser('Example:batchDataStorageDelete', devMode)
const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/')

async function removeDataStorageList(dataStorageMap: Map<string, DataStorage>, requestId: string): Promise<void> {
  for (const dataStorage of dataStorageMap.values()) {
    const response = await $b24.actions.v2.call.make({
      method: 'entity.delete',
      params: {
        ENTITY: dataStorage.dataStorage.ENTITY
      },
      requestId: `${requestId}/init:getCurrentList`
    })

    if (!response.isSuccess) {
      throw new SdkError({
        code: 'MY_APP_GET_PROBLEM',
        description: `Problem ${response.getErrorMessages().join('; ')}`,
        status: 404
      })
    }
  }
}

// Usage
const requestId = 'batch/DataStorageRemove'
try {
  const dataStorageMap: Map<string, DataStorage> = new Map([
    ['DataStorage1', {
      dataStorage: {
        ENTITY: 'DS1',
        NAME: 'Data Storage 1'
      }
    }],
    ['DataStorage2', {
      dataStorage: {
        ENTITY: 'DS2',
        NAME: 'Data Storage 2'
      }
    }],
    ['DataStorage3', {
      dataStorage: {
        ENTITY: 'DS3',
        NAME: 'Data Storage 3'
      }
    }]
  ])

  await removeDataStorageList(dataStorageMap, requestId)
} catch (error) {
  if (error instanceof AjaxError) {
    $logger.critical(error.message, { requestId, code: error.code })
  } else {
    $logger.alert('Problem', { requestId, error })
  }
}

Alternatives and Recommendations

  • For sequential requests: Use Call for single calls.
  • For working with lists: Use CallList for retrieving large volumes of data.
  • For step-by-step processing: Use FetchList for processing data as it arrives.
  • To run more commands (more than 50): Use BatchByChunk, which automatically splits commands into chunks of 50.
  • On the client-side (browser): Use the built-in B24Frame object.

FetchList

Returns an AsyncGenerator that allows processing data from list methods of Bitrix24 REST API version 2 as it is received without loading the entire array into memory at once. This is especially useful when working with very large volumes of data.

BatchByChunk

Method for executing batch requests with automatic chunking for any number of commands. Automatically splits large command sets into batches of 50 and executes them sequentially. Use only arrays of tuples or arrays of objects.

On this page

  • Overview
  • Method Signature
    • Parameters
    • Command Formats (options.calls)
    • Batch Request Options (options.options)
    • Return Value
  • Error Handling
  • Examples
    • Getting Multiple CRM Companies
    • Init Data Storage
    • Delete Data Storage
  • Alternatives and Recommendations
Releases
Published under MIT License.

Copyright © 2024-present Bitrix24