
Привет! Меня зовут Алексей Никитин, руководитель отдела автоматизации направления внедрений в Битрикс24.
REST Битрикс24 можно удобно использовать из Python — для интеграций, миграций, аналитики и служебных скриптов.
Разбираем библиотеку a24wh: шесть функций, которые упрощают запросы, пагинацию, batch-вызовы и обработку ошибок.
Когда говорят про Битрикс24, рядом почти автоматически всплывает PHP. Это нормально: сам продукт исторически вырос рядом с этой экосистемой. Но при этом для внешних интеграций REST Битрикс24 не обязывает писать доработки именно на PHP.
Если задача находится снаружи продукта, задачи примерно такие:
Выгрузить сделки.
Перенести данные между порталами.
Собрать аналитику.
Написать служебный микросервис.
Сделать разовую миграцию.
Во всех этих сценариях Python чувствует себя более чем уверенно.
За время работы я пришёл к простой мысли: сам REST не проблема. Проблема начинается вокруг него: собрать запрос, обработать ошибку, не утонуть в пагинации и не переписывать одну и ту же обвязку в каждом новом скрипте. Постепенно у меня накопился набор рабочих helper-функций.
Я довёл свои наработки до состояния полноценной библиотеки и 12 апреля 2026 года выложил в PyPI.
Что такое библиотека a24wh и зачем она нужна
a24wh не пытается быть большим фреймворком. Это маленькая, понятная и минималистичная библиотека для работы со входящими вебхуками Битрикс24 из Python. Её главная задача простая: взять REST-метод из документации, передать параметры и без лишней боли получить реальные данные портала.
На сегодня актуальная версия библиотеки — a24wh 0.1.2, и ставится она одной командой:
pip install a24wh
Почему Python хорошо подходит для внешних доработок Битрикс24
REST хорош тем, что ему всё равно, на каком языке написан клиент. Если система умеет принимать HTTP-запросы и отдавать JSON, дальше уже можно выбирать инструмент под задачу.
В случае внешних доработок Python мне нравится по нескольким причинам:
На нём быстро писать прикладные скрипты.
Он отлично подходит для миграций и промежуточных обработчиков.
Удобно брать для анализа данных, особенно вместе с
pandas.Python хорошо встраивается в сервисы на Django и Flask.
Одинаково удобно делать и маленькую разовую утилиту, и долгоживущий сервис.
Если нужно не залезать внутрь ядра продукта, а что-то получить из Битрикс24, преобразовать и пересчитать, Python хорошо подходит для таких прикладных задач.
Типовой пример: выгрузили сделки или элементы смарт-процесса, собрали из них DataFrame, посчитали суммы и потери и отдали результат в отчёт, файл или любой другой портал. Именно для таких задач удобен тонкий слой над REST API: он берет на себя запросы, пагинацию и обработку ошибок, но оставляет структуру методов Битрикс24 понятной разработчику.
Как быстро стартовать со входящих вебхуков
Если вы только начинаете работать с REST Битрикс24, входящий вебхук почти всегда самый быстрый путь к первому результату.
На стороне портала это выглядит просто. Что нужно сделать:
Открыть раздел для разработчиков.
Создать входящий вебхук для вызова REST API.
Выбрать нужные права.
Получить URL вебхука.
Хук выглядит так:
https://example.bitrix24.ru/rest/1/xxxxxxxxxxxxxxxx/
Обратите внимание на три вещи.
Скоупы лучше выдавать ровно под задачу. Практическое правило простое: чем уже вебхук заточен под конкретную роль, тем лучше и для безопасности, и для поддержки.
Не надо включать права, если не знаете точно, что они нужны. Если работаете только с CRM, обычно достаточно crm. Если хотите слать технические сообщения в чат, нужно поставить im.
Вебхук не обходит права пользователя. Для интеграций это очень здоровая логика безопасности.
Вебхук работает в контексте прав того пользователя, от имени которого он создан. Если пользователь не должен видеть определенные сделки, лиды или элементы, вебхук тоже не будет давать к ним доступ.
Секрет вебхука не надо светить в коде. URL вебхука содержит чувствительную часть. Поэтому хранить его лучше в переменных окружения или в защищённой конфигурации.
Шесть главных функций
Долгое время у меня была не библиотека, а скорее набор функций. Отдельные модули переезжали из проекта в проект, копировались из старых интеграций или дорабатывались уже по месту использования.
Такой подход работает, пока вы один и весь контекст умещается у вас в голове. Но чем больше задач и чем чаще вы возвращаетесь к одним и тем же сценариям, тем сильнее повторяющуюся механику хочется упаковать. Так выросла a24wh.
Мне хотелось сохранить две вещи:
Минимализм.
Достаточность для большинства повседневных задач.
Сейчас публичный API библиотеки состоит из шести функций:
request24— основной помощник для классического REST Битрикс24.req24— похожий helper для REST v3.save_jsonсохраняет ответ в JSON.batch_listмассово читает списочные методы через batch.batch_by_paramsзапускает один метод с разными наборами параметров.to_chatотправляет служебное сообщение в чат портала.
Главная идея здесь прямолинейная: библиотека не прячет REST Битрикс24, а делает его использование короче, стабильнее и предсказуемее.
1. request24 — основной метод
Главный повседневный сценарий. Берём метод из документации, собираем параметры и вызываем REST. Например, нужно получить сделку:
# подключаем модуль для работы с переменными окружения import os from dotenv import load_dotenv load_dotenv() # импортируем функцию для вызова классических REST-методов Битрикс24 from a24wh import request24 # получаем URL входящего вебхука из переменной окружения webhook = os.getenv("A24WH_DEFAULT_WEBHOOK_URL") # запрашиваем сделку по ее идентификатору response = request24( # указываем метод получения сделки method="crm.deal.get", # передаем идентификатор сделки parameters={"id": 42}, # передаем URL входящего вебхука webhook_url=webhook, ) # проверяем, произошла ли ошибка при выполнении запроса if "error_result" in response: # выводим сообщение об ошибке print("Ошибка:", response["error_message"]) else: # выводим данные полученной сделки print(response["result"])
Что тут хорошо:
Имя метода совпадает с документацией Битрикс24.
Параметры передаются обычным словарём Python.
На выходе всегда
dict.Для ошибок есть единый и понятный контракт.
По сути, это и есть главное обещание библиотеки: минимум лишнего кода между вами и реальным ответом портала.
Что приходит на выходе: единый контракт ответа
Очень удобно, когда библиотека стандартизирует не только вызов, но и то, как вы потом работаете с результатом.
У a24wh запросные функции всегда возвращают dict.
Успешный случай выглядит так:
{"result": ...}
Ошибка выглядит так:
{ "error_result": True, "error_type": "http_error", "error_code": "500", "error_message": "Bitrix24 returned HTTP 500.", "method": "crm.deal.get", "portal": "example.bitrix24.ru", "status_code": 500, }
Поэтому в прикладном коде достаточно проверить наличие error_result:
if "error_result" in response: print(response["error_type"]) print(response["error_code"]) print(response["error_message"]) else: print(response["result"])
Если после ошибки продолжать работу нельзя, можно вызвать исключение и сразу остановить скрипт:
if "error_result" in response: raise RuntimeError( f"{response['method']} failed: " f"{response['error_type']} / {response['error_code']} / {response['error_message']}" )
Это особенно удобно в автоматизации, потому что не надо каждый раз вспоминать, что вернёт конкретная ветка внутренней обвязки. Вы заранее знаете, как библиотека сообщает об ошибке.
2. req24 — отдельный helper для REST 3.0
В Битрикс24 постепенно появляется REST 3.0. Методы новой версии вызываются по другому адресу: после /rest/ в URL добавляется сегмент /api/. Для таких методов в библиотеке есть отдельная функция req24:
# подключаем модуль для работы с переменными окружения import os from dotenv import load_dotenv load_dotenv() # импортируем функцию для вызова методов REST 3.0 from a24wh import req24 # получаем URL входящего вебхука из переменной окружения webhook = os.getenv("A24WH_DEFAULT_WEBHOOK_URL") # вызываем метод REST 3.0 для получения задачи response = req24( # указываем метод из документации Битрикс24 method="tasks.task.get", # передаем параметры запроса parameters={ # указываем идентификатор задачи "id": 42, # выбираем дополнительные поля ответственного "select": [ "responsible.name", "responsible.email", ], }, # передаем URL входящего вебхука webhook_url=webhook, ) # проверяем, вернула ли библиотека ошибку if "error_result" in response: # выводим понятное сообщение об ошибке print("Ошибка:", response["error_message"]) else: # получаем задачу из ответа Битрикс24 task = response["result"]["item"] # выводим название задачи print(task["title"]) # выводим данные ответственного print(task.get("responsible"))
В примере мы получаем задачу и сразу запрашиваем имя и почту ответственного. REST 3.0 позволяет обращаться к полям связанных объектов через точку, поэтому для этих данных не приходится отдельно вызывать метод получения пользователя.
По способу использования req24 похожа на request24: передаём имя метода, словарь параметров и URL вебхука, а затем проверяем наличие error_result. Разница находится внутри библиотеки. req24 формирует адрес REST 3.0, отправляет JSON и разбирает новый формат ошибок.
Выбирать функцию нужно по документации конкретного метода:
request24(...) — классический REST Битрикс24
req24(...) — REST 3.0
Если метод относится к REST 3.0, в документации для него будет указан адрес с /rest/api/.
3. save_json: почему полезно сохранять сырой JSON
Один из самых недооценённых приёмов в интеграционной работе — сохранить исходный ответ до того, как вы начнёте выбирать из него нужные поля и преобразовывать данные под свою задачу.
Когда вы впервые вызываете новый метод, особенно на сложной CRM-сущности, очень полезно увидеть исходный ответ Битрикс24 как он есть: какие поля пришли, как они вложены и какие значения вернул конкретный портал. Для этого в библиотеке есть save_json:
# импортируем функции для вызова REST-методов и сохранения ответа в JSON from a24wh import request24, save_json # запрашиваем список сделок response = request24( # указываем метод получения списка сделок method="crm.deal.list", # передаем параметры запроса parameters={ # сортируем сделки по идентификатору "order": {"ID": "ASC"}, # выбираем сделки из воронки с идентификатором 0 "filter": {"=CATEGORY_ID": 0}, # указываем поля, которые нужно получить "select": ["ID", "TITLE", "STAGE_ID"], }, # передаем URL входящего вебхука webhook_url=webhook, # автоматически получаем все страницы списка all_iters=True, ) # сохраняем ответ в JSON-файл file_path = save_json( response, file_title="crm.deal.list.debug", ) # выводим путь к сохраненному файлу print(file_path)
В реальной жизни это дает сразу несколько преимуществ:
JSON удобно читать глазами.
По нему проще понять вложенность и реальные поля.
Его можно приложить к задаче или техразбору.
Его можно отдавать ИИ-агентам как фактический материал для анализа.
Последний пункт сейчас особенно практичен. Если уж использовать ИИ в инженерной работе, то лучше кормить его не выдуманной схемой, а живым ответом с конкретного портала.
4. batch_list(...) — Как забирать много данных
На маленьких объемах хватает обычного request24. Но как только дело доходит до сотен и тысяч записей, нужны более удобные режимы.
В a24wh для этого есть два основных маршрута.
Первый вариант
Это самый простой способ сказать библиотеке: “собери мне все страницы списка”.
# запрашиваем список сделок response = request24( # указываем метод получения списка сделок method="crm.deal.list", # передаем параметры запроса parameters={ # сортируем сделки по идентификатору "order": {"ID": "ASC"}, # выбираем сделки из воронки с идентификатором 16 "filter": {"=CATEGORY_ID": 16}, # получаем только идентификаторы сделок "select": ["ID"], }, # передаем URL входящего вебхука webhook_url=webhook, # автоматически получаем все страницы списка all_iters=True, )
Такой режим хорош, когда данных немного, хочется быстро получить всё без отдельной логики пагинации и сам списочный метод не слишком тяжёлый для портала. Для повседневных рабочих сценариев это приемлемый баланс между простотой и удобством.
Второй вариант
Если списочные данные нужно забирать интенсивнее, можно использовать batch_list.
# импортируем функцию для получения данных через batch-запросы from a24wh import batch_list # запрашиваем список сделок через batch response = batch_list( # указываем метод получения списка сделок method="crm.deal.list", # передаем параметры запроса parameters={ # сортируем сделки по идентификатору "order": {"ID": "ASC"}, # выбираем сделки из воронки с идентификатором 14 "filter": {"=CATEGORY_ID": 14}, # указываем поля, которые нужно получить "select": ["ID", "TITLE", "STAGE_ID", "CONTACT_ID"], }, # передаем URL входящего вебхука webhook_url=webhook, )
Этот подход удобен там, где хочется читать не “по одной странице за раз”, а более собранно, через batch-запросы.
5. batch_by_params — практический шаблон. Сначала ID, потом детали
Особенно полезно в рабочей практике.
Иногда выборка большого набора объектов сразу со многими полями в select оказывается для сервера тяжелее, чем сначала получить только ID, а потом уже пакетно добрать детали.
В таких случаях полезна схема:
Сначала запрашиваем только ID по фильтру.
Затем через
batch_by_paramsзапрашиваем полные карточки по 50 штук в одном batch.
Пример со сделками:
# импортируем функции для обычного REST-запроса и пакетной загрузки данных from a24wh import request24, batch_by_params # запрашиваем идентификаторы сделок ids_response = request24( # указываем метод получения списка сделок method="crm.deal.list", # передаем параметры запроса parameters={ # сортируем сделки по идентификатору "order": {"ID": "ASC"}, # выбираем сделки из основной воронки, измененные после указанной даты "filter": { "=CATEGORY_ID": 0, ">DATE_MODIFY": "2026-01-01T00:00:00+03:00", }, # получаем только идентификаторы сделок "select": ["ID"], }, # передаем URL входящего вебхука webhook_url=webhook, # автоматически получаем все страницы списка all_iters=True, ) # проверяем, произошла ли ошибка при получении идентификаторов if "error_result" in ids_response: # останавливаем выполнение и выводим сообщение об ошибке raise RuntimeError(ids_response["error_message"]) # создаем список параметров для получения каждой сделки по идентификатору params_list = [ {"id": int(item["ID"])} for item in ids_response["result"] ] # пакетно запрашиваем полные данные сделок deals_response = batch_by_params( # указываем метод получения сделки method="crm.deal.get", # передаем список параметров с идентификаторами сделок params_list=params_list, # передаем URL входящего вебхука webhook_url=webhook, )
На нагруженных порталах это часто оказывается заметно лучше, чем просить сразу всё и во всех полях, потому что:
Серверу проще отдать легкий список ID.
Детальные карточки потом получаются через
get.batchрежет вызовы на аккуратные пачки.
Пример со смарт-процессом и req24
Со смарт-процессами идея ровно та же. Ничего специального для них не требуется:
# импортируем функцию для вызова методов REST from a24wh import request24 # вызываем метод для получения элементов смарт-процесса response = request24( # указываем метод Битрикс24 method="crm.item.list", # передаем параметры запроса parameters={ # указываем идентификатор типа смарт-процесса "entityTypeId": 190, # выбираем элементы из воронки с идентификатором 3 "filter": {"=categoryId": 3}, # указываем поля, которые нужно получить "select": ["id", "title", "stageId", "assignedById"], }, # передаем URL входящего вебхука webhook_url=webhook, ) # проверяем, вернула ли библиотека ошибку if "error_result" in response: # выводим сообщение об ошибке print(response["error_message"]) else: # выводим полученные элементы print(response["result"])
Дальше уже всё зависит от объема. Где-то хватит одного запроса, где-то пригодится all_iters, где-то будет разумнее сначала собрать ID, а потом детализировать их batch-вызовами.
Живой кейс: миграция данных между порталами
Один из самых естественных сценариев для Python рядом с Битрикс24 — межпортальная миграция. Пример: на одном портале собрали сделки, преобразовали данные и создали сделки на другом портале.
Упрощённый пример может выглядеть так:
# подключаем модуль для работы с переменными окружения import os # импортируем функцию для вызова классических REST-методов Битрикс24 from a24wh import request24 # получаем вебхук исходного портала source_webhook = os.getenv("SRC_WEBHOOK") # получаем вебхук целевого портала target_webhook = os.getenv("DST_WEBHOOK") # запрашиваем сделки на исходном портале source = request24( # указываем метод получения списка сделок method="crm.deal.list", # передаем параметры запроса parameters={ # выбираем сделки из воронки с идентификатором 0 "filter": {"=CATEGORY_ID": 0}, # указываем поля, которые нужно получить "select": ["ID", "TITLE", "OPPORTUNITY", "COMMENTS"], }, # передаем вебхук исходного портала webhook_url=source_webhook, # автоматически получаем все страницы списка all_iters=True, ) # проверяем, произошла ли ошибка при получении сделок if "error_result" in source: # останавливаем выполнение и выводим сообщение об ошибке raise RuntimeError(source["error_message"]) # перебираем полученные сделки for deal in source["result"]: # создаем сделку на целевом портале add_response = request24( # указываем метод создания сделки method="crm.deal.add", # передаем поля новой сделки parameters={ "fields": { # копируем название сделки "TITLE": deal.get("TITLE"), # копируем сумму сделки "OPPORTUNITY": deal.get("OPPORTUNITY"), # копируем комментарий "COMMENTS": deal.get("COMMENTS"), }, }, # передаем вебхук целевого портала webhook_url=target_webhook, ) # проверяем, удалось ли создать сделку if "error_result" in add_response: # выводим идентификатор исходной сделки и сообщение об ошибке print( "Не удалось перенести запись:", deal.get("ID"), add_response["error_message"], )
В реальной миграции к этому каркасу почти наверняка добавляется логика конкретного проекта:
Таблица соответствия стадий.
Преобразование пользовательских полей.
Сопоставление пользователей.
Журналирование.
Архивирование исходных ответов в JSON.
Но сам каркас сценария получается очень прозрачным. И в этом, на мой взгляд, большая сила Python в интеграциях: сначала быстро делаем рабочее решение, потом постепенно наращиваем вокруг него дисциплину.
6. to_chat: отправка техсообщений в портал
Когда скрипт работает долго, когда идет перенос данных, когда ночной обмен падает посреди выполнения или когда просто хочется видеть статус не в консоли сервера, а прямо в Битрикс24, очень выручает отправка сообщений в чат.
Для этого в a24wh есть to_chat:
import os from a24wh import to_chat response = to_chat( text="Миграция сделок завершена. Перенесено 248 записей.", chat_id="chat11111", webhook_url=os.getenv("WEBHOOK_CHAT"), )
Функция маленькая, но очень полезная. Под капотом используется im.message.add, а значит нужен scope im.
Какие удобные вещи можно делать на практике:
Отправлять сообщения о старте.
Писать прогресс по этапам.
Уведомлять об ошибках.
Закрывать процесс финальным статусом.
В итоге скрипт перестает быть чёрным ящиком в планировщике и начинает разговаривать с командой в привычном рабочем контуре.
Логирование как часть нормальной инженерной жизни
Отдельно хотелось, чтобы библиотека хорошо жила в реальных Python-проектах, а не только в одноразовых локальных скриптах. У a24wh есть свой логгер a24wh и набор переменных окружения:
A24WH_DEFAULT_WEBHOOK_URL= A24WH_TIMEOUT=60 A24WH_RETRY_COUNT=3 A24WH_RETRY_DELAY=1.0 A24WH_REQUEST_DELAY=1.0 A24WH_AUTO_CONFIGURE_LOGGING=0 A24WH_LOG_LEVEL=INFO A24WH_LOG_TO_CONSOLE=1 A24WH_LOG_TO_FILE=0 A24WH_LOG_FILE=a24wh.log
Библиотека не лезет без спроса управлять логированием всего приложения. Пока вы сами не включили автоконфигурацию, она нормально сосуществует с существующим logging config проекта. Это особенно полезно, если вы работаете в Django, Flask и любом сервисе с единым конфигом логирования. То есть логи библиотеки не живут отдельной жизнью, а могут органично встраиваться в общую систему наблюдаемости проекта.
Библиотека умеет брать вебхук по умолчанию из A24WH_DEFAULT_WEBHOOK_URL. Это удобно для простых локальных сценариев. Но на практике довольно часто приходится работать сразу с несколькими порталами, например: забрать данные с одного портала, перенести в другой, отправить статусы в третий.
При работе с несколькими порталами удобнее хранить их вебхуки в отдельных переменных и явно передавать нужный адрес в каждый вызов:
source_webhook = os.getenv("SRC_WEBHOOK")
target_webhook = os.getenv("DST_WEBHOOK")
chat_webhook = os.getenv("CHAT_WEBHOOK")
У такого подхода есть несколько плюсов. Во-первых, проще читать код. Во-вторых, так меньше риска случайно отправить данные не туда. В-третьих, тут очень к месту старое питоновское правило: явное лучше неявного.
Небольшой пример с pandas
Раз уж Python хорош не только для интеграций, но и для аналитики, покажу совсем короткий пример. Главная польза — библиотека сама получает все страницы и возвращает обычные данные Python, которые сразу можно передать в pandas.
# подключаем pandas для анализа табличных данных import pandas as pd # импортируем функцию для вызова REST-методов Битрикс24 from a24wh import request24 # запрашиваем список сделок response = request24( method="crm.deal.list", parameters={ "order": {"ID": "ASC"}, "filter": {"=CATEGORY_ID": 0}, "select": ["ID", "TITLE", "OPPORTUNITY", "STAGE_ID"], }, webhook_url=webhook, all_iters=True, ) # останавливаем скрипт, если запрос завершился с ошибкой if "error_result" in response: raise RuntimeError(response["error_message"]) # преобразуем полученные сделки в таблицу pandas df = pd.DataFrame(response["result"]) # группируем сделки по стадиям и считаем их количество print(df.groupby("STAGE_ID")["ID"].count())

Здесь Python очень красиво раскрывается рядом с Битрикс24. a24wh собирает все страницы ответа в обычный список словарей. Его можно сразу преобразовать в DataFrame и перейти к анализу без ручной обработки пагинации.
Почему a24wh получилась именно такой
Мне не хотелось делать огромный комбайн на все случаи жизни. Хотелось сделать библиотеку, которую можно быстро:
Поставить.
Прочитать.
Понять.
Встроить в проект.
При необходимости спокойно обложить своей бизнес-логикой.
Поэтому a24wh сознательно маленькая. Она не пытается заменить документацию Битрикс24 и не строит поверх REST собственный мир. Наоборот, она исходит из того, что документация уже является главным источником правды, а задача библиотеки — сделать путь от документации до рабочего Python-кода коротким и надежным.
В этом смысле основной сценарий всегда один и тот же:
Нашли нужный метод в документации Битрикс24.
Собрали параметры.
Вызвали
request24илиreq24.Проверили
error_result.Обработали
result.
Итог
Если вы работаете с Битрикс24 извне, язык не должен быть ограничением. REST Битрикс24 спокойно живет не только в PHP-мире, а Python отлично подходит для интеграций, миграций, служебных скриптов и небольших сервисов.
Ценность a24wh для меня в трех вещах:
Быстрый вход в REST Битрикс24 из Python.
Единый контракт ответа и ошибок.
Достаточный набор утилит для большинства повседневных задач.
Если интересно попробовать, для начала установите библиотеку командой pip install a24wh. Затем выберите REST-метод в документации, передайте его параметры и получите данные портала в Python.
dmitrijtest24
В данном предложении не совсем верно утверждение, что продукт «исторически вырос рядом с этой экосистемой» (PHP).
Правильнее сказать, что Битрикс24 исторически вырос на этой экосистеме или в этой экосистеме.