Как подключить кассу к Битрикс24
Scope:
cashboxКто может выполнять методы: администратор
Выберите инструмент для разработки с AI-агентом:
- используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
- используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации
В Битрикс24 можно подключить внешнюю кассу и автоматически печатать чеки. Когда клиент оплатит заказ, Битрикс24 отправит данные чека на заданный URL. Внешний сервис сформирует и зарегистрирует фискальный чек.
В результате сценария в Центре продаж появится REST-касса, а внешний сервис сможет принимать запросы на печать чека и возвращать статус печати.
Сценарий состоит из трех шагов.
- Добавим обработчик кассы методом sale.cashbox.handler.add
- Создадим кассу и привяжем ее к обработчику методом sale.cashbox.add
- Передадим результат печати чека методом sale.cashbox.check.apply, если статус нужно сохранить вручную
Перед началом
Подготовьте значения, которые понадобятся в примерах.
- Входящий вебхук или OAuth-токен пользователя с правами администратора
- Публичный HTTPS-адрес страницы печати чека
PRINT_URL - Публичный HTTPS-адрес страницы проверки статуса чека
CHECK_URL - Уникальный код обработчика кассы, например
my_rest_cashbox - Данные авторизации внешней кассы, которые администратор укажет в настройках кассы
Не размещайте логин, пароль и токены доступа в публичном коде. Передавайте секреты через переменные окружения или защищенное хранилище приложения.
1. Добавим обработчик кассы
Зарегистрируем обработчик с помощью sale.cashbox.handler.add. В метод передадим настройки обработчика и адреса, на которые портал отправляет запросы для печати и проверки статуса чека.
-
CODE— уникальный код обработчика. Укажемmy_rest_cashbox. -
NAME— название обработчика, например,Моя REST-касса. -
SORT— число, которое определяет положение обработчика в списке. -
SETTINGS— объект c настройками обработчика.-
PRINT_URL— адрес, на который Битрикс24 отправляет данные для печати чека. Укажемhttps://example.ru/rest_print.php. -
CHECK_URL— адрес, по которому происходит проверка статуса чека. Передадимhttps://example.ru/rest_check.php. -
CONFIG— поля, которые нужно создать для обработчика. Администратор заполняет эти поля при настройке кассы. Создадим три блока:AUTH— авторизация по логину и паролю,COMPANY— данные об организации,INTERACTION— режим работы кассы.
-
Как использовать примеры в документации
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
// B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
const response = await $b24.actions.v2.call.make({
method: 'sale.cashbox.handler.add',
params: {
CODE: 'my_rest_cashbox',
NAME: 'Моя REST-касса',
SORT: 100,
SETTINGS: {
PRINT_URL: 'https://example.ru/rest_print.php',
CHECK_URL: 'https://example.ru/rest_check.php',
CONFIG: {
AUTH: {
LABEL: 'Авторизация',
ITEMS: {
LOGIN: {
TYPE: 'STRING',
REQUIRED: 'Y',
LABEL: 'Логин'
},
PASSWORD: {
TYPE: 'STRING',
REQUIRED: 'Y',
LABEL: 'Пароль'
}
}
},
COMPANY: {
LABEL: 'Данные об организации',
ITEMS: {
INN: {
TYPE: 'STRING',
REQUIRED: 'Y',
LABEL: 'ИНН организации'
}
}
},
INTERACTION: {
LABEL: 'Настройки взаимодействия с кассой',
ITEMS: {
MODE: {
TYPE: 'ENUM',
REQUIRED: 'N',
LABEL: 'Режим работы с кассой',
OPTIONS: {
ACTIVE: 'боевой',
TEST: 'тестовый'
}
}
}
}
}
}
},
requestId: 'cashbox-handler-add'
})
if (response.isSuccess) {
console.dir(response.getData().result)
} else {
console.error(response.getErrorMessages().join('; '))
}
from b24pysdk import BitrixWebhook, Client
from b24pysdk.errors import BitrixAPIError
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token="user_id/webhook_key",
)
client = Client(token)
try:
response = client.sale.cashbox.handler.add(
code="my_rest_cashbox",
name="Моя REST-касса",
sort=100,
settings={
"PRINT_URL": "https://example.ru/rest_print.php",
"CHECK_URL": "https://example.ru/rest_check.php",
"CONFIG": {
"AUTH": {
"LABEL": "Авторизация",
"ITEMS": {
"LOGIN": {
"TYPE": "STRING",
"REQUIRED": "Y",
"LABEL": "Логин",
},
"PASSWORD": {
"TYPE": "STRING",
"REQUIRED": "Y",
"LABEL": "Пароль",
},
},
},
"COMPANY": {
"LABEL": "Данные об организации",
"ITEMS": {
"INN": {
"TYPE": "STRING",
"REQUIRED": "Y",
"LABEL": "ИНН организации",
}
},
},
"INTERACTION": {
"LABEL": "Настройки взаимодействия с кассой",
"ITEMS": {
"MODE": {
"TYPE": "ENUM",
"REQUIRED": "N",
"LABEL": "Режим работы с кассой",
"OPTIONS": {
"ACTIVE": "боевой",
"TEST": "тестовый",
},
}
},
},
},
},
).response
print(response.result)
except BitrixAPIError as error:
print(error)
<?php
// composer require bitrix24/b24phpsdk:"^3.0"
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = new Logger('b24');
$log->pushHandler(new StreamHandler('php://stdout'));
$sb = (new ServiceBuilderFactory(new EventDispatcher(), $log))
->initFromWebhook('https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/');
$result = $sb->getSaleScope()->cashboxHandler()->add(
'my_rest_cashbox',
'Моя REST-касса',
[
'PRINT_URL' => 'https://example.ru/rest_print.php',
'CHECK_URL' => 'https://example.ru/rest_check.php',
'CONFIG' => [
'AUTH' => [
'LABEL' => 'Авторизация',
'ITEMS' => [
'LOGIN' => [
'TYPE' => 'STRING',
'REQUIRED' => 'Y',
'LABEL' => 'Логин'
],
'PASSWORD' => [
'TYPE' => 'STRING',
'REQUIRED' => 'Y',
'LABEL' => 'Пароль'
],
]
],
'COMPANY' => [
'LABEL' => 'Данные об организации',
'ITEMS' => [
'INN' => [
'TYPE' => 'STRING',
'REQUIRED' => 'Y',
'LABEL' => 'ИНН организации'
]
]
],
'INTERACTION' => [
'LABEL' => 'Настройки взаимодействия с кассой',
'ITEMS' => [
'MODE' => [
'TYPE' => 'ENUM',
'REQUIRED' => 'N',
'LABEL' => 'Режим работы с кассой',
'OPTIONS' => [
'ACTIVE' => 'боевой',
'TEST' => 'тестовый'
]
]
]
]
]
],
100
);
echo '<PRE>';
print_r($result->getId());
echo '</PRE>';
Если обработчик успешно добавлен, метод вернет его идентификатор. Сохраните значение result: оно пригодится для поиска обработчика в списке.
{
"result": 1
}
Теперь обработчик можно использовать для создания касс в интерфейсе Битрикс24. Один обработчик может обслуживать несколько касс с разными реквизитами.

2. Настроим кассу
Добавим кассу с помощью sale.cashbox.add. В метод передадим настройки кассы и значения параметра CONFIG из предыдущего шага.
-
REST_CODE— код обработчика. Передадим значениеmy_rest_cashbox, которое указали при добавлении обработчика в параметреCODE. -
NAME— название кассы. УкажемREST касса. -
NUMBER_KKM— внешний идентификатор кассы, например,1. -
OFD— код обработчика ОФД. Передадимbx_firstofd. Список возможных значений смотрите в документации метода sale.cashbox.add. -
EMAIL— адрес электронной почты для уведомлений. Укажемowner@example.ru. -
USE_OFFLINE— флаг, используется ли касса офлайн. Зададим значениеY. -
ACTIVE— активность кассы. УкажемY. -
SETTINGS— данные для полей, которые создали в параметреCONFIGна предыдущем шаге. Их нужно заполнить точно так, как описали при регистрации обработчика:-
AUTH— логин и пароль для авторизации, -
COMPANY— ИНН организации, -
INTERACTION— режим работы, например,ACTIVE.
-
const response = await $b24.actions.v2.call.make({
method: 'sale.cashbox.add',
params: {
REST_CODE: 'my_rest_cashbox',
NAME: 'REST касса',
NUMBER_KKM: '1',
OFD: 'bx_firstofd',
EMAIL: 'owner@example.ru',
USE_OFFLINE: 'Y',
ACTIVE: 'Y',
SETTINGS: {
AUTH: {
LOGIN: 'rest_login',
PASSWORD: 'rest_password'
},
COMPANY: {
INN: '1234567890'
},
INTERACTION: {
MODE: 'ACTIVE'
}
}
},
requestId: 'cashbox-add'
})
if (response.isSuccess) {
console.dir(response.getData().result)
} else {
console.error(response.getErrorMessages().join('; '))
}
try:
response = client.sale.cashbox.add(
rest_code="my_rest_cashbox",
name="REST касса",
email="owner@example.ru",
number_kkm="1",
ofd="bx_firstofd",
use_offline=True,
active=True,
settings={
"AUTH": {
"LOGIN": "rest_login",
"PASSWORD": "rest_password",
},
"COMPANY": {
"INN": "1234567890",
},
"INTERACTION": {
"MODE": "ACTIVE",
},
},
).response
print(response.result)
except BitrixAPIError as error:
print(error)
$result = $sb->getSaleScope()->cashbox()->add([
'REST_CODE' => 'my_rest_cashbox',
'NAME' => 'REST касса',
'NUMBER_KKM' => '1',
'OFD' => 'bx_firstofd',
'EMAIL' => 'owner@example.ru',
'USE_OFFLINE' => 'Y',
'ACTIVE' => 'Y',
'SETTINGS' => [
'AUTH' => [
'LOGIN' => 'rest_login',
'PASSWORD' => 'rest_password'
],
'COMPANY' => [
'INN' => '1234567890'
],
'INTERACTION' => [
'MODE' => 'ACTIVE'
]
]
]);
echo '<PRE>';
print_r($result->getId());
echo '</PRE>';
Если касса успешно добавлена, метод вернет ее идентификатор. Сохраните значение result: оно понадобится для проверки кассы в списке.
{
"result": 1
}
В Центре продаж можно проверить, что касса подключена к Битрикс24.

Печать чеков
Касса использует два адреса. На PRINT_URL портал отправляет данные для печати. На CHECK_URL Битрикс24 уточняет, напечатан ли чек и есть ли ошибки.
Страница PRINT_URL
Страница PRINT_URL — адрес, на который Битрикс24 отправляет данные для печати чека. Структуру запроса смотрите в разделе Страница PRINT_URL метода sale.cashbox.handler.add.
По адресу PRINT_URL происходит обработка входных данных, формирование документа и возвращение результата печати.
Минимальная логика страницы PRINT_URL:
- Принять данные чека от Битрикс24
- Проверить, что в запросе есть данные для печати
- Передать чек во внешнюю кассу
- Вернуть
UUID, если чек принят в печать, или массивERRORS, если печать невозможна - Сохранить связь
UUIDс заказом или чеком во внешней системе, чтобы страницаCHECK_URLмогла вернуть статус
Пример обработчика PRINT_URL на Node.js:
import express from 'express'
import { randomUUID } from 'crypto'
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
const checks = new Map()
app.post('/rest_print.php', async (req, res) => {
const payload = req.body
if (!payload || Object.keys(payload).length === 0) {
res.json({
ERRORS: ['Данные чека не переданы']
})
return
}
const uuid = randomUUID()
checks.set(uuid, {
status: 'WAIT',
createdAt: Date.now(),
payload
})
res.json({
UUID: uuid
})
})
В рабочем сервисе храните UUID, статус и данные чека в базе данных, а не в памяти процесса.
-
Если печать не удалась, массив JSON имеет вид:
{ "ERRORS": [ "Сообщение об ошибке", "Сообщение об ошибке", ... ] } -
Если чек передан в печать, массив имеет вид:
{ "UUID": "00112233-4455-6677-8899-aabbccddeeff" }
Страница CHECK_URL
Страница CHECK_URL — адрес, по которому портал проверяет, готов ли чек и есть ли ошибки.
Запрос по адресу CHECK_URL выполняется по обращению менеджера или запускается автоматически спустя время после успешной печати чека. Структуру запроса смотрите в разделе Страница CHECK_URL метода sale.cashbox.handler.add.
Запрос по адресу CHECK_URL возвращает данные о чеке, данные об ошибке при печати чека, либо статус «в ожидании печати».
Минимальная логика страницы CHECK_URL:
- Принять
UUIDчека - Найти чек во внешней системе
- Если чек еще печатается, вернуть
STATUS: WAIT - Если печать завершилась ошибкой, вернуть
STATUS: ERRORи текст ошибки - Если чек напечатан, вернуть
STATUS: DONEи фискальные реквизиты
Пример обработчика CHECK_URL на Node.js:
app.post('/rest_check.php', async (req, res) => {
const uuid = req.body.UUID
if (!uuid || !checks.has(uuid)) {
res.json({
STATUS: 'ERROR',
ERROR: 'Чек с таким UUID не найден'
})
return
}
const check = checks.get(uuid)
if (check.status === 'WAIT') {
res.json({
STATUS: 'WAIT'
})
return
}
if (check.status === 'ERROR') {
res.json({
STATUS: 'ERROR',
ERROR: check.error
})
return
}
res.json({
STATUS: 'DONE',
UUID: uuid,
REG_NUMBER_KKT: '000111222333',
FISCAL_DOC_ATTR: '33445500',
FISCAL_DOC_NUMBER: 123,
FISCAL_RECEIPT_NUMBER: 10,
FN_NUMBER: '0011223344556677',
SHIFT_NUMBER: 12,
PRINT_END_TIME: Math.floor(Date.now() / 1000)
})
})
-
Формат данных при ошибке печати чека:
{ "STATUS": "ERROR", "ERROR": "Сообщение об ошибке" } -
Формат данных, если чек не напечатан:
{ "STATUS": "WAIT" } -
Формат данных при успешной отправке чека:
{ "STATUS": "DONE", "UUID": "00112233-4455-6677-8899-aabbccddeeff", "REG_NUMBER_KKT": "000111222333", "FISCAL_DOC_ATTR": "33445500", "FISCAL_DOC_NUMBER": 123, "FISCAL_RECEIPT_NUMBER": 10, "FN_NUMBER": "0011223344556677", "SHIFT_NUMBER": 12, "PRINT_END_TIME": 1609452000 }
Полный список полей совпадает с параметрами метода sale.cashbox.check.apply.
Данные от CHECK_URL сохраняются в Битрикс24 и используются для генерации ссылки на чек.
Передадим результат печати вручную
Данные о чеке можно передать с помощью метода sale.cashbox.check.apply, когда PRINT_URL вернул UUID и чек сохранен в Битрикс24.
Подготовьте поля для sale.cashbox.check.apply.
-
UUID— уникальный идентификатор чека, который вернул обработчик в ответе наPRINT_URL. -
PRINT_END_TIME— время окончания печати чека. -
REG_NUMBER_KKT— регистрационный номер кассы. -
FISCAL_DOC_ATTR— фискальный признак документа, который сформировала касса. -
FISCAL_DOC_NUMBER— номер фискального документа. -
FISCAL_RECEIPT_NUMBER— номер чека внутри смены. -
FN_NUMBER— номер фискального накопителя. -
SHIFT_NUMBER— номер смены, в которую попал чек.
const response = await $b24.actions.v2.call.make({
method: 'sale.cashbox.check.apply',
params: {
UUID: '00112233-4455-6677-8899-aabbccddeeff',
PRINT_END_TIME: '1609459200',
REG_NUMBER_KKT: '000111222333',
FISCAL_DOC_ATTR: '33445500',
FISCAL_DOC_NUMBER: '123',
FISCAL_RECEIPT_NUMBER: '10',
FN_NUMBER: '0011223344556677',
SHIFT_NUMBER: '12'
},
requestId: 'cashbox-check-apply'
})
if (response.isSuccess) {
console.dir(response.getData().result)
} else {
console.error(response.getErrorMessages().join('; '))
}
try:
response = client.sale.cashbox.check.apply(
uuid="00112233-4455-6677-8899-aabbccddeeff",
print_end_time="1609459200",
reg_number_kkt="000111222333",
fiscal_doc_attr="33445500",
fiscal_doc_number="123",
fiscal_receipt_number="10",
fn_number="0011223344556677",
shift_number="12",
).response
print(response.result)
except BitrixAPIError as error:
print(error)
$result = $sb->getSaleScope()->cashbox()->checkApply([
'UUID' => '00112233-4455-6677-8899-aabbccddeeff',
'PRINT_END_TIME' => '1609459200',
'REG_NUMBER_KKT' => '000111222333',
'FISCAL_DOC_ATTR' => '33445500',
'FISCAL_DOC_NUMBER' => '123',
'FISCAL_RECEIPT_NUMBER' => '10',
'FN_NUMBER' => '0011223344556677',
'SHIFT_NUMBER' => '12'
]);
echo '<PRE>';
print_r($result->isSuccess());
echo '</PRE>';
Если чек успешно сохранен, метод вернет true.
{
"result": true
}
Проверим результат
После настройки кассы откройте Центр продаж и проверьте, что REST-касса доступна в списке касс. После тестовой оплаты проверьте, что внешний сервис получил запрос на PRINT_URL, вернул UUID, а Битрикс24 получил статус через CHECK_URL или через метод sale.cashbox.check.apply.
Через REST проверьте обработчик и кассу методами sale.cashbox.handler.list и sale.cashbox.list.
const handlerResponse = await $b24.actions.v2.call.make({
method: 'sale.cashbox.handler.list',
params: {},
requestId: 'cashbox-handler-list',
})
const cashboxResponse = await $b24.actions.v2.call.make({
method: 'sale.cashbox.list',
params: {
SELECT: ['ID', 'NAME', 'ACTIVE', 'EMAIL'],
FILTER: { '=NAME': 'REST касса' },
},
requestId: 'cashbox-list',
})
console.log(handlerResponse.getData().result)
console.log(cashboxResponse.getData().result)
handlers = token.call_method("sale.cashbox.handler.list", {})
cashboxes = token.call_method(
"sale.cashbox.list",
{
"SELECT": ["ID", "NAME", "ACTIVE", "EMAIL"],
"FILTER": {"=NAME": "REST касса"},
},
)
print(handlers)
print(cashboxes)
$handlerResponse = $sb->core->call('sale.cashbox.handler.list', []);
$cashboxResponse = $sb->core->call('sale.cashbox.list', [
'SELECT' => ['ID', 'NAME', 'ACTIVE', 'EMAIL'],
'FILTER' => ['=NAME' => 'REST касса'],
]);
print_r($handlerResponse->getResponseData()->getResult());
print_r($cashboxResponse->getResponseData()->getResult());
Успешное выполнение сценария подтверждают три результата:
- метод
sale.cashbox.handler.addвернул идентификатор обработчика - метод
sale.cashbox.addвернул идентификатор кассы - метод
sale.cashbox.check.applyвернулtrue, если результат печати передавался вручную
Ошибки и диагностика
Если метод вернул ошибку, проверьте данные запроса и состояние внешнего сервиса.
|
Код или текст ошибки |
Причина и действие |
|
|
Метод вызвал пользователь без прав администратора CRM на изменение настроек |
|
|
Не передано обязательное поле или значение поля не прошло проверку. Проверьте |
|
|
Обработчик с таким |
|
|
Чек с указанным |
|
|
Ошибка при добавлении обработчика, создании кассы или сохранении результата печати. Подробности смотрите в |
|
Ошибка печати на |
Верните массив |
|
Статус |
Чек еще не напечатан. Повторите проверку статуса после обработки чека внешней кассой |
Что важно учитывать
- Повторный запуск примера с тем же
CODEможет вернуть ошибку, потому что код обработчика должен быть уникальным - Адреса
PRINT_URLиCHECK_URLдолжны быть доступны из интернета по HTTPS - Данные из настроек кассы, например логин и пароль, храните на стороне приложения и не выводите в интерфейс без маскирования