================
B24PySDK is the official Python SDK for the Bitrix24 REST API.
Build integrations faster with a clean, Pythonic interface to Bitrix24: strong typing, convenient helpers, and battle‑tested request logic so you can focus on your business logic.
- Authentication via OAuth tokens or incoming webhooks
- Native Python types for arguments and responses
- Helpful type hints for available method parameters and their types
- Runtime validation of argument types
- Efficient pagination helpers and batch operations
The REST API documentation can be found on Bitrix24 REST API.
Requirements: Python 3.9+
Install from PyPI:
pip install b24pysdk
Local development and tests run inside Docker containers only. Nothing is installed to your host Python.
Two images are used:
- CI image: mirrors GitHub Actions, bakes sources; slower for iteration (rebuild on code change).
- Dev image: tools-only; build once, then run tests/lint against your working tree via bind mounts.
Common Makefile targets:
- Build dev image once:
make build-dev
- Run unit tests (mounted repo, editable install):
make test
- Run linter:
make lint
- Optional shell in dev container:
make shell
Notes:
- The repository is mounted at /work inside the container; sources are not copied into the image.
- If you add dependencies to
pyproject.toml
,make test
reinstalls them in the container on next run.
- Unit tests: fast, isolated; always run with
make test
. - Integration tests: hit real Bitrix24 REST API; opt‑in and require credentials.
Run integration tests using one of the flows below.
- Using an env file (.env.local preferred):
- Place credentials in
.env.local
(or.env
). See.env.example
template. - Run:
make test-int
(auto-detects.env.local
or.env
, prints which is used).
- Passing credentials via variables:
- Webhook:
make test-int-webhook B24_DOMAIN=... B24_WEBHOOK=...
- OAuth:
make test-int-oauth B24_DOMAIN=... B24_CLIENT_ID=... B24_CLIENT_SECRET=... B24_ACCESS_TOKEN=...[ B24_REFRESH_TOKEN=...]
Environment variables:
- Common
B24_DOMAIN
: portal host only, e.g.example.bitrix24.com
(no scheme). Helpers normalize/validate.
- Webhook
B24_WEBHOOK
: incoming webhook in formatuser_id/hook_key
.
- OAuth
B24_CLIENT_ID
,B24_CLIENT_SECRET
,B24_ACCESS_TOKEN
, optionalB24_REFRESH_TOKEN
.
Behavior and skips:
- If credentials are missing, integration tests are skipped with a clear reason.
- The helpers will normalize
B24_DOMAIN
(strip scheme/slashes) and validateB24_WEBHOOK
.
CI note:
- GitHub Actions runs linter and unit tests on push/PR (Python 3.9–3.12 matrix).
- Integration tests that call the real REST API do not auto‑run in CI.
- Client — entry point for all Bitrix24 calls:
client.crm
,client.user
,client.department
,client.socialnetwork
. - Authentication:
- BitrixWebhook — incoming webhook auth
- BitrixToken — OAuth 2.0 token auth (paired with BitrixApp)
- BitrixApp — your Bitrix24 app credentials (client_id, client_secret)
- Responses expose
result
andtime
(including execution duration)
This section provides a short guide to help you get started with B24PySDK.
To call the Bitrix24 API, import Client
and use either BitrixWebhook
or BitrixToken
for authentication.
There are two ways to authenticate:
- Using a permanent incoming local webhook code: https://apidocs.bitrix24.com/local-integrations/local-webhooks.html
from b24pysdk import BitrixWebhook
# For webhook URL: https://example.bitrix24.com/rest/user_id/webhook_key/
# Use domain without protocol and auth_token in format "user_id/webhook_key"
bitrix_token = BitrixWebhook(domain="example.bitrix24.com", auth_token="user_id/webhook_key")
- Using a temporary OAuth 2.0 authorization token: https://apidocs.bitrix24.com/api-reference/oauth/index.html
For any type of apps:
from b24pysdk import BitrixToken, BitrixApp
bitrix_app = BitrixApp(client_id="app_code", client_secret="app_key")
bitrix_token = BitrixToken(
domain="example.bitrix24.com",
auth_token="auth_token_of_the_app",
refresh_token="refresh_token_of_the_app", # optional parameter
bitrix_app=bitrix_app,
)
For local apps:
from b24pysdk import BitrixTokenLocal, BitrixAppLocal
bitrix_app = BitrixAppLocal(
domain="example.bitrix24.com",
client_id="app_code",
client_secret="app_key",
)
bitrix_token = BitrixTokenLocal(
auth_token="auth_token_of_the_app",
refresh_token="refresh_token_of_the_app", # optional parameter
bitrix_app=bitrix_app,
)
The Client
is your entry point to the API. All supported methods are available via properties on the created instance.
from b24pysdk import Client
client = Client(bitrix_token)
For example, to get a description of deal fields you can call the crm.deal.fields
method:
request = client.crm.deal.fields()
Most Bitrix24 REST API methods accept parameters. Pass them as positional or keyword arguments to the corresponding Python method.
To illustrate, we can get a deal by calling:
request = client.crm.deal.get(bitrix_id=2)
B24PySDK uses deferred method calls. To invoke a method and obtain its result, access the corresponding property.
The JSON response retrieved from the server is parsed into an object: response.result
contains the value returned by the API method, while response.time
provides the execution time of the request.
from b24pysdk import BitrixWebhook, Client
bitrix_token = BitrixWebhook(domain="example.bitrix24.com", auth_token="user_id/webhook_key")
client = Client(bitrix_token)
request = client.crm.deal.update(bitrix_id=10, fields={"TITLE": "New title"})
print(f'Updated successfully: {request.result}')
print(f'Call took {request.time.duration} seconds')
Updated successfully: True
Call took 0.40396690368652344 seconds
For list methods, you can use .as_list()
and .as_list_fast()
to explicitly retrieve all records.
See documentation: Handling large datasets
By default, list methods returns up to 50 records only.
request = client.crm.deal.list()
deals = request.result # up to 50 records
The .as_list()
method automatically retrieves all records.
request = client.crm.deal.list()
deals = request.as_list().result # full list of records
The .as_list_fast()
method is optimized for large datasets.
It uses a more efficient algorithm and is recommended for receiving many records.
request = client.crm.deal.list()
deals = request.as_list_fast().result # generator
for deal in deals: # requests are made lazily during iteration
print(deal["TITLE"])
You can execute multiple API calls in a single request using call_batch
:
Method .call_batch() is used when you need to execute 50 or less API calls only.
from b24pysdk import Client, BitrixWebhook
bitrix_token = BitrixWebhook(domain="example.bitrix24.com", auth_token="user_id/webhook_key")
client = Client(bitrix_token)
requests_data = {
"deal1": client.crm.deal.get(bitrix_id=1),
"deal2": client.crm.deal.get(bitrix_id=2),
# ...more requests
}
batch_request = client.call_batch(requests_data)
for key, deal in batch_request.result.result.items():
print(f"{key}: {deal['TITLE']}")
For very large workloads you can send multiple batches sequentially via call_batches
:
Method .call_batches() can execute more than 50 API calls.
requests = [
client.crm.deal.get(bitrix_id=1),
client.crm.deal.get(bitrix_id=2),
# ...more requests
]
batches_request = client.call_batches(requests)
for deal in batches_request.result.result:
print(deal["TITLE"])
List responses may include pagination metadata:
request = client.crm.deal.list()
print(request.response.total) # total number of records (if provided by API)
print(request.response.next) # next page offset (if provided by API)
You can tweak default timeouts and retry behavior using Config
:
from b24pysdk import Config
cfg = Config()
cfg.default_timeout = 30 # seconds or (connect_timeout, read_timeout)
cfg.max_retries = 3 # number of retries on transient errors
cfg.initial_retry_delay = 0.5 # seconds
cfg.retry_delay_increment = 0.5 # seconds
Common exceptions you may want to handle:
BitrixRequestError
/BitrixTimeout
: network and timeout issuesBitrixAPIError
: API responded with an error (checkerror
anderror_description
)BitrixAPIExpiredToken
: access token expired; forBitrixToken
B24PySDK can auto-refresh
from b24pysdk.error import BitrixAPIError, BitrixTimeout
try:
request = client.crm.deal.get(bitrix_id=2)
print(request.result)
except BitrixTimeout:
# retry or log
pass
except BitrixAPIError as e:
print(e.error, e.error_description)
Instead of BitrixApp and BitrixToken, you can use their abstract class versions with frameworks and ORM libraries. When using these abstract classes, the programmer is responsible for declaring the instance attributes and storing them.
Examples of the available abstract classes are AbstractBitrixApp
, AbstractBitrixAppLocal
, AbstractBitrixToken
and AbstractBitrixTokenLocal
.
You can add any Bitrix24 entity like CRM deals, user records, etc. Example: Adding a new deal in CRM
deal_data = {
"TITLE":"New Deal #1",
"TYPE_ID":"COMPLEX",
"CATEGORY_ID":0,
"STAGE_ID":"PREPARATION",
"IS_RECURRING":"N",
"IS_RETURN_CUSTOMER":"Y",
"IS_REPEATED_APPROACH":"Y",
"PROBABILITY":99,
"CURRENCY_ID":"EUR",
"OPPORTUNITY":1000000,
"IS_MANUAL_OPPORTUNITY":"Y",
"TAX_VALUE":0.10,
"COMPANY_ID":9,
"CONTACT_IDS":[84,83],
"OPENED":"Y",
"CLOSED":"N",
"COMMENTS":"Example comment",
"SOURCE_ID":"CALLBACK",
"SOURCE_DESCRIPTION":"Additional information about the source",
"ADDITIONAL_INFO":"Additional information",
"UTM_SOURCE":"google",
"UTM_MEDIUM":"CPC",
"PARENT_ID_1220":22,
"UF_CRM_1721244482250":"Hello world!"
}
request = client.crm.deal.add(fields=deal_data)
print("Id: ", request.result)
With get method you can fetch details for a specific entity by ID or unique key and get its field values. Example: Retrieve specific deal details
request = client.crm.deal.get(bitrix_id=5)
deal_info = request.result
print(deal_info["TITLE"], deal_info["STAGE_ID"])
There is a method .fields() that provides fields of entities. Example: Get a lable of the userfield.
request = client.crm.deal.fields()
fields = request.result
print(fields["UF_CRM_1758877091066"]["listLabel"])
Modify details of a specific entity by ID. Example: Update a deal's title and move to another stage
update_data = {"TITLE":"New deal title!", "STAGE_ID":"WON",}
request = client.crm.deal.update(bitrix_id=5, fields=update_data)
if request.result:
print("Deal updated successfully.")
To remove an entity permanently from the records you can use method .delete(). Example: Delete a particular deal
request = client.crm.deal.delete(bitrix_id=5)
if request.result:
print("Deal deleted successfully.")
Retrieve up to 50 deals with optional filters. Example: Obtain a list of CRM deals on
select = ["ID","TITLE","TYPE_ID","CATEGORY_ID","STAGE_ID","OPPORTUNITY","IS_MANUAL_OPPORTUNITY","ASSIGNED_BY_ID","DATE_CREATE"]
filter = {
"=%TITLE":"%a","CATEGORY_ID":1,
"TYPE_ID":"COMPLEX",
"STAGE_ID":"C1:NEW",">OPPORTUNITY":10000,
"<=OPPORTUNITY":20000,
"IS_MANUAL_OPPORTUNITY":"Y"
}
order = {
"TITLE":"ASC",
"OPPORTUNITY":"ASC"
}
request = client.crm.deal.list(select=select, filter=filter, order=order)
deals = request.result
print(deals)
Retrieve all pages of a list request. Example: Retrieve more than 50 deals.
request = client.crm.deal.list()
all_deals = request.as_list().result
for deal in all_deals:
print(deal["TITLE"])
Optimized retrieval for very large datasets that returns generator for working with the result. Example: Efficiently retrieve a large dataset of deals.
request = client.crm.deal.list()
deal_iterator = request.as_list_fast().result
for deal in deal_iterator:
print(deal["TITLE"])