Bitrix24 CRM Integration with Website
Bitrix24 is an enterprise platform with built-in CRM, tasks, and communications. Website integration with Bitrix24 comes down to two tasks: sending leads/deals from website forms to CRM and synchronizing data bidirectionally via REST API.
Bitrix24 REST API
Bitrix24 provides REST API based on webhooks or OAuth applications. For external websites, it's easiest to use incoming webhooks:
- In Bitrix24:
Settings → Integrations → Webhooks → Add webhook - Select required permissions (CRM, Tasks)
- Get a URL like
https://your-company.bitrix24.ru/rest/1/abc123xyz/
Creating a Lead from a Form
class Bitrix24Client {
private string $webhookUrl;
public function __construct() {
$this->webhookUrl = config('bitrix24.webhook_url');
}
public function callMethod(string $method, array $params = []): array {
$response = Http::timeout(15)
->post($this->webhookUrl . $method, $params);
if ($response->failed()) {
throw new \RuntimeException('Bitrix24 API error: ' . $response->status());
}
$data = $response->json();
if (!empty($data['error'])) {
throw new \RuntimeException('Bitrix24: ' . $data['error_description']);
}
return $data['result'] ?? [];
}
public function createLead(array $fields): int {
return $this->callMethod('crm.lead.add', [
'fields' => $fields,
'params' => ['REGISTER_SONET_EVENT' => 'Y'],
]);
}
}
Contact form handler:
class ContactFormController extends Controller {
public function submit(ContactFormRequest $request): JsonResponse {
// Save to our database
$contact = ContactRequest::create($request->validated());
// Send to Bitrix24
try {
$bitrix = app(Bitrix24Client::class);
$leadId = $bitrix->createLead([
'TITLE' => 'Request from website: ' . $request->name,
'NAME' => $request->name,
'PHONE' => [['VALUE' => $request->phone, 'VALUE_TYPE' => 'WORK']],
'EMAIL' => [['VALUE' => $request->email, 'VALUE_TYPE' => 'WORK']],
'COMMENTS' => $request->message,
'SOURCE_ID' => 'WEB',
'SOURCE_DESCRIPTION' => 'Form: ' . $request->form_id,
'ASSIGNED_BY_ID' => config('bitrix24.default_responsible_id'),
'UF_CRM_UTM_SOURCE' => session('utm_source'),
'UF_CRM_UTM_MEDIUM' => session('utm_medium'),
'UF_CRM_UTM_CAMPAIGN' => session('utm_campaign'),
]);
$contact->update(['bitrix_lead_id' => $leadId]);
} catch (\Exception $e) {
Log::error('Bitrix24 lead creation failed', ['error' => $e->getMessage()]);
// Don't interrupt flow — request saved in our database
}
return response()->json(['success' => true]);
}
}
Deals Instead of Leads
For e-commerce, deals are often needed instead of leads:
public function createDealFromOrder(Order $order): void {
$bitrix = app(Bitrix24Client::class);
// Find or create contact
$contacts = $bitrix->callMethod('crm.contact.list', [
'filter' => ['PHONE' => $order->customer_phone],
'select' => ['ID', 'NAME'],
]);
$contactId = $contacts[0]['ID'] ?? $bitrix->callMethod('crm.contact.add', [
'fields' => [
'NAME' => $order->customer_name,
'PHONE' => [['VALUE' => $order->customer_phone, 'VALUE_TYPE' => 'WORK']],
'EMAIL' => [['VALUE' => $order->customer_email, 'VALUE_TYPE' => 'WORK']],
],
]);
// Create deal
$dealId = $bitrix->callMethod('crm.deal.add', [
'fields' => [
'TITLE' => 'Order #' . $order->number,
'CONTACT_ID' => $contactId,
'OPPORTUNITY' => $order->total,
'CURRENCY_ID' => 'RUB',
'STAGE_ID' => 'NEW',
'COMMENTS' => $this->buildOrderComment($order),
],
]);
// Attach products to deal
$productRows = $order->items->map(fn($item) => [
'PRODUCT_NAME' => $item->product->name,
'PRICE' => $item->price,
'QUANTITY' => $item->quantity,
'MEASURE_NAME' => 'pc.',
])->toArray();
$bitrix->callMethod('crm.deal.productrows.set', [
'id' => $dealId,
'rows' => $productRows,
]);
$order->update(['bitrix_deal_id' => $dealId]);
}
Incoming Webhook: Status Updates
When a manager changes deal status in Bitrix24, the website should update order status. Configure an outgoing webhook from Bitrix24:
// routes/api.php
Route::post('/webhooks/bitrix24', [Bitrix24WebhookController::class, 'handle'])
->middleware('bitrix24.signature');
class Bitrix24WebhookController extends Controller {
public function handle(Request $request): Response {
$event = $request->input('event');
$data = $request->input('data');
match ($event) {
'ONCRMDEALSTAGEUPDATED' => $this->onDealStageUpdated($data),
'ONCRMLEADADD' => $this->onLeadAdded($data),
default => null,
};
return response('OK');
}
private function onDealStageUpdated(array $data): void {
$dealId = $data['FIELDS']['ID'];
$stageId = $data['FIELDS']['STAGE_ID'];
$order = Order::where('bitrix_deal_id', $dealId)->first();
if (!$order) return;
$statusMap = [
'WON' => 'completed',
'LOSE' => 'cancelled',
'IN_PROCESS' => 'processing',
];
if ($status = $statusMap[$stageId] ?? null) {
$order->update(['status' => $status]);
}
}
}
Signature Verification Middleware
class Bitrix24SignatureMiddleware {
public function handle(Request $request, Closure $next): Response {
// Bitrix24 passes auth[member_id] — check by token
$memberId = $request->input('auth.member_id');
if ($memberId !== config('bitrix24.member_id')) {
abort(403);
}
return $next($request);
}
}
Batch Requests
Bitrix24 limits REST API: 2 requests per second per webhook. For bulk operations, use the batch method:
$batch = [
'get_lead' => 'crm.lead.get?id=' . $leadId,
'get_contact' => 'crm.contact.list?filter[EMAIL]=' . urlencode($email),
];
$results = $bitrix->callMethod('batch', [
'halt' => 0,
'cmd' => $batch,
]);
// $results['result']['get_lead'], $results['result']['get_contact']
One batch call contains up to 50 methods.
Implementation Timeline
Basic integration: leads from forms to Bitrix24, save ID to local database: 1–2 days. Bidirectional synchronization (deals, contacts, incoming webhooks, UTM tags): 3–4 days. Product catalog synchronization + integration with Bitrix24 telephony for callback forms: plus 2–3 days.







