AI integration in Bitrix24 via webhooks and API
A new lead in Bitrix24 fires a webhook, your server asks the model, and a hint for the manager appears as a comment on the lead card.
5 min · · бизнес · автоматизация
Bitrix24 receives leads every day from the website, forms, and messengers, and a manager spends time reading each request to judge how urgent it is. Integrating Bitrix24 with an AI model removes that routine: when a lead appears, your server sends its description to the model, and the answer — a priority and a tip for the manager — shows up as a comment on the card. Below are a webhook-based setup, a PHP handler, a Python version, and a cost estimate.
How the integration works
Bitrix24 has two kinds of webhooks, and you need both:
- Inbound webhook — a secret URL your code uses to call the portal's REST API methods (read a lead, add a comment).
- Outbound webhook — Bitrix24 sends a POST request to your URL when an event happens, such as a lead being created.
The chain looks like this:
- A lead is created → the outbound webhook sends your handler an
ONCRMLEADADDevent with the lead ID. - The handler fetches the lead data through the inbound webhook with
crm.item.get. - The handler sends the request description to the model via Zukko.
- The model's answer is written to the lead's timeline with
crm.timeline.comment.add.
An important detail: the outbound webhook sends only the object ID, not all lead fields. That's why step 2 is required.
Step 1: inbound webhook
Webhooks are created in the developer section of the Applications menu (Applications → Developer resources → Other in the Bitrix24 docs). Item names depend on the interface version.
- Choose "Inbound webhook".
- In access permissions, select CRM (scope
crm). - Save and copy the URL, which looks like
https://your-portal.bitrix24.com/rest/1/xxxxxxxx/. Here1is the ID of the employee the requests run as, andxxxxxxxxis the secret code.
This URL grants CRM access with that employee's permissions — treat it like a password and keep it only in server environment variables.
Step 2: outbound webhook
- In the same section, choose "Outbound webhook".
- Enter your handler URL, for example
https://your-server.com/b24-handler.php. It must be reachable from the internet over HTTPS;localhostand self-signed certificates won't work. - Select the lead creation event (
ONCRMLEADADD). - Save the token Bitrix24 shows: the handler uses it to verify that a request really came from your portal.
Step 3: a PHP handler
Bitrix24 sends data as a regular form (application/x-www-form-urlencoded), so PHP has already parsed it into $_REQUEST: event, data[FIELDS][ID], auth[application_token].
<?php
// b24-handler.php — Bitrix24 outbound webhook handler
$expectedToken = (string) getenv('B24_OUTGOING_TOKEN');
$event = $_REQUEST['event'] ?? '';
$token = (string) ($_REQUEST['auth']['application_token'] ?? '');
$leadId = (int) ($_REQUEST['data']['FIELDS']['ID'] ?? 0);
if ($expectedToken === '' || !hash_equals($expectedToken, $token)) {
http_response_code(403);
exit;
}
// Respond right away and call the model after the response (works under PHP-FPM)What matters here:
- Token check.
hash_equalscompares the token in the request with the one Bitrix24 issued. Without this check, anyone who learns the handler URL can trigger it and spend your balance. - Fast response. Bitrix24 shouldn't wait for the model.
fastcgi_finish_request()sends the response immediately and keeps working in the background. If PHP doesn't run under FPM, move the processing to a queue or cron. - REST methods.
crm.item.getwithentityTypeId = 1is the universal method for reading a CRM item (the oldercrm.lead.getis marked deprecated in the docs).crm.timeline.comment.addtakes its parameters under a lowercasefieldskey. - Personal data. Only the title, source, and comment go to the model. Phone and email aren't needed to judge priority.
Environment variables: ZUKKO_API_KEY, B24_WEBHOOK_URL (the inbound webhook URL), and B24_OUTGOING_TOKEN (the outbound webhook token).
Step 4: testing
Send the handler a test event with the ID of an existing lead:
curl -X POST https://your-server.com/b24-handler.php \
-d 'event=ONCRMLEADADD' \
-d 'data[FIELDS][ID]=123' \
-d 'auth[application_token]=your_token'Within a few seconds a comment should appear in lead 123's timeline. If it doesn't, check error_log: it will show Zukko status codes (401 — invalid key, 402 — balance ran out, 429 — too many requests) or Bitrix24 REST errors.
A Python version
The same handler in Flask. We answer Bitrix24 right away and run the model work in a separate thread:
import hmac
import os
import threading
import requests
from flask import Flask, request
app = Flask(__name__)
B24_URL = os.environ["B24_WEBHOOK_URL"].rstrip("/")
B24_TOKEN = os.environ["B24_OUTGOING_TOKEN"]
def b24(method: str, params: dict) -> dict:
return requests.post(f"{B24_URL}/{method}.json", json=params, timeout=15).json()A thread is fine for a light stream of leads. With hundreds of events per hour, use a task queue (Celery, RQ, and the like) so jobs aren't lost when the server restarts.
What it costs
Example: 200 leads a day, about 300 input and 150 output tokens each. Per day that's 200 × 300 = 60,000 input and 200 × 150 = 30,000 output tokens, 0.09M in total.
| Model | Price in/out per 1M | Per day | Per 30 days |
|---|---|---|---|
glm-5.3-flash | $0.04 / $0.04 | 0.09 × 0.04 = $0.0036 | $0.108 |
gpt-5.6-luna | $0.1 / $0.1 | 0.09 × 0.1 = $0.009 | $0.27 |
claude-sonnet-5 | $0.3 / $0.3 | 0.09 × 0.3 = $0.027 | $0.81 |
Real token counts are in the response's usage field and in the spending history in the dashboard. How well a model assesses your particular leads is something to test on a sample: take 30–50 past leads with a known outcome and compare the assessments of two or three models. Request parameters are in the Chat Completions docs.
FAQ
The comment doesn't appear — what should I check?
- Whether the request reaches the handler: check the web server logs. The URL must be reachable from the internet over HTTPS.
- Whether the
auth[application_token]token matches the outbound webhook token. - Whether the inbound webhook has the CRM permission and the employee has access to the lead.
- What Zukko returned: the status code and error text go to
error_log.
How do I handle more than new leads?
Add other events to the outbound webhook, such as lead updates (ONCRMLEADUPDATE) or deal creation, and branch on the event field. For deals, use entityTypeId = 2 and ENTITY_TYPE = deal. Make sure your own comment doesn't trigger processing again.
Can I do without my own server?
You need any public HTTPS endpoint that can accept a webhook and make two HTTP requests: PHP hosting, a cloud function, or an automation service that supports webhooks. The code itself is small, as the examples above show.
Where do I get a key, and how do I cap spending?
Create a separate key for Bitrix24 in the Zukko dashboard, give it a daily limit, and allow only the model you need. If something goes wrong — say, the handler loops — the limit stops the spending. More in the key limits section.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- AI for testers: test cases, checklists and bug reportsHow a QA engineer can use a model for test cases, checklists and bug reports, check coverage, and avoid requirements the model made up.
- Anonymizing data before sending it to a neural network: a practical wayYou do not have to send personal data to a model for it to process a document. How to replace it with labels, restore it in the answer and check that nothing leaked.
- A neural network for HR: job posts, candidate emails and resume reviewA model can draft job posts and emails and do a first-pass resume review. What to hand over, how to treat candidates' personal data and how to prevent biased decisions.
- Generating an FAQ with a neural network from tickets and a knowledge baseA good FAQ is built on what customers really ask. A pipeline: group the tickets, answer from the knowledge base with a source reference, and verify the result.