v1.3.0

BatchV3.make

Method for executing batch requests to Bitrix24 REST API version 3. Allows executing up to 50 commands in a single API call.

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:

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)

// @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)

OptionTypeDefaultDescription
isHaltOnErrorbooleantrueWhether to stop execution on the first error.
returnAjaxResultbooleanfalseWhether to return an AjaxResult object instead of data.
requestIdstringUnique 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.

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.

Prior to v1.1.1, a 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.
  • time on each AjaxResult is 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.

Passing data between commands ($ref / $refArray)

A v3 batch can feed one command's output into a later command's params. Give the source command an as alias, then reference it with a $ref (single value) or $refArray (a field collected across the source's items[]) marker. The server performs the substitution — the SDK just passes the marker through. Use the BatchRefV3 helper to build the markers (it validates the path client-side):

import { BatchRefV3 as R } from '@bitrix24/b24jssdk'

const response = await $b24.actions.v3.batch.make({
  calls: [
    { method: 'tasks.task.list', as: 'tasks', params: { select: ['id'] } },
    {
      method: 'tasks.task.list',
      // the server expands this to `['id', 'in', [<ids collected from tasks.items>]]`
      params: { select: ['id', 'title'], filter: [['id', 'in', R.refArray('tasks.id')]] }
    }
  ]
})
  • R.ref('alias.path.to.field'){ $ref: '…' } — a single value. Only item (get) and items (list/tail) land in context; add → id / update → bool do not.
  • R.refArray('alias.field'){ $refArray: '…' } — collects field across the alias's items[]. The path must contain a dot.
  • A bad path or an unresolved reference fails the batch with BITRIX_REST_V3_EXCEPTION_INVALIDSELECTEXCEPTION.
  • v3 only. These markers are not substituted in a v2 batch (actions.v2.batch.make) — there they become literal filter values and silently yield wrong/empty results.

Error Handling

The SDK no longer pre-validates batch methods against a client-side v3 list: every command is sent to the v3 batch endpoint and the server validates each one. A command that names a non-v3 method comes back as a server error for that command (and, per v3 batch semantics, an error aborts the batch). 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

BatchTasks.ts
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 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.