Overview
Use BatchV3.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.v3.batch.make({
calls: [
['tasks.task.get', { id: 1 }],
['tasks.task.get', { id: 2 }]
],
options: {
isHaltOnError: true,
returnAjaxResult: true,
requestId: 'unique-request-id'
}
})
Method Signature
make<T = unknown>(
options: ActionBatchV3
): Promise<CallBatchResult<T>>
Parameters
The options object contains the following properties:
Command Formats (options.calls)
1. Array of tuples (BatchCommandsArrayUniversal)
// @check-ignore: partial snippet — calls array literal, not a valid statement
calls: [
['method1', params1],
['method2', params2],
// ...
]
2. Array of objects (BatchCommandsObjectUniversal)
// @check-ignore: partial snippet — object array literal, not a valid statement
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)
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.
Result Item Data
Each per-command result is returned exactly as the REST API delivered it,
including null when the underlying method legitimately returns no data.
When typing the generic for methods that may return null, declare it as
T | null.
null result was coerced to {}, which broke nullable
type guards on the caller side (see issue #23).Limitations
restApi:v3 batch is all-or-nothing:
- Per-command errors are not returned. If any command in the batch fails, the
whole batch fails and the top-level
response.getErrorMessages()contains the error(s);getData()returns an empty map. timeon eachAjaxResultis the batch-level time, not per-command. The rate-limiter does not attribute the batch duration to individual methods.- If a successful v3 response is missing a result entry for a command (which
indicates a malformed API response), the SDK throws
JSSDK_INTERACTION_BATCH_STRATEGY_V3_EMPTY_COMMAND_RESPONSE.
Error Handling
If any command in calls references a method that is not supported by REST API version 3, the call throws an SdkError with code JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3 before any HTTP request is made — even for the calls that would have been valid. Use BatchV2.make() when the batch contains legacy methods, or split mixed batches by API version.
For successful requests, always check isSuccess and handle errors:
// @check-ignore: top-level return in error-handling illustration
const response = await $b24.actions.v3.batch.make({
calls: [
{ method: 'tasks.task.get', params: { id: 1 } },
{ method: 'tasks.task.get', params: { 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 Some Tasks
// @check-ignore: full example — processResult callback and BatchCommands tuple inference not in scope
import type { AjaxResult, Result } from '@bitrix24/b24jssdk'
import { AjaxError, B24Hook, LoggerFactory, SdkError } from '@bitrix24/b24jssdk'
type TaskItem = {
id: number
title: string
}
const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV))
const $logger = LoggerFactory.createForBrowser('Example:batchTasks', devMode)
const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/')
async function getMultipleItems(itemIds: number[], requestId: string): Promise<TaskItem[]> {
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 calls = itemIds.map(id => [
'tasks.task.get',
{
id,
select: ['id', 'title']
}
])
const response = await $b24.actions.v3.batch.make<{ item: TaskItem }>({
calls,
options: {
isHaltOnError: true,
returnAjaxResult: true,
requestId
}
})
if (!response.isSuccess) {
throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
}
const resultData = (response as Result<AjaxResult<{ item: TaskItem }>[]>).getData() ?? []
const results: TaskItem[] = []
resultData.forEach((resultRow) => {
if (resultRow.isSuccess) {
const item = resultRow.getData()?.result.item
if (item) {
results.push(item)
}
}
})
return results
}
// Usage
const requestId = 'batch/tasks.task.get'
try {
const itemIds = [1, 2, 3]
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 })
}
}
Alternatives and Recommendations
- For sequential requests: Use
Callfor single calls. - For working with lists: Use
CallListfor retrieving large volumes of data. - For step-by-step processing: Use
FetchListfor 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
B24Frameobject.