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:

  1. A lead is created → the outbound webhook sends your handler an ONCRMLEADADD event with the lead ID.
  2. The handler fetches the lead data through the inbound webhook with crm.item.get.
  3. The handler sends the request description to the model via Zukko.
  4. 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.

  1. Choose "Inbound webhook".
  2. In access permissions, select CRM (scope crm).
  3. Save and copy the URL, which looks like https://your-portal.bitrix24.com/rest/1/xxxxxxxx/. Here 1 is the ID of the employee the requests run as, and xxxxxxxx is 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

  1. In the same section, choose "Outbound webhook".
  2. Enter your handler URL, for example https://your-server.com/b24-handler.php. It must be reachable from the internet over HTTPS; localhost and self-signed certificates won't work.
  3. Select the lead creation event (ONCRMLEADADD).
  4. 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].

bash
<?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_equals compares 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.get with entityTypeId = 1 is the universal method for reading a CRM item (the older crm.lead.get is marked deprecated in the docs). crm.timeline.comment.add takes its parameters under a lowercase fields key.
  • 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:

bash
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:

bash
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.

ModelPrice in/out per 1MPer dayPer 30 days
glm-5.3-flash$0.04 / $0.040.09 × 0.04 = $0.0036$0.108
gpt-5.6-luna$0.1 / $0.10.09 × 0.1 = $0.009$0.27
claude-sonnet-5$0.3 / $0.30.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?

  1. Whether the request reaches the handler: check the web server logs. The URL must be reachable from the internet over HTTPS.
  2. Whether the auth[application_token] token matches the outbound webhook token.
  3. Whether the inbound webhook has the CRM permission and the employee has access to the lead.
  4. 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.

Get API keyDocumentation

api.zukko.pro · fetch_*

Bitrix24 AI integration: webhooks, leads, and auto-replies · Zukko