AVOdigital
ГлавнаяМатериал AVOdigital

Интеграция amoCRM с сайтом: автопередача заявок по API

Экспертная статья: как настроить интеграцию amoCRM с сайтом через REST API. Пошаговая инструкция по вебхукам, передаче UTM-меток, склеиванию лидов и распределению сделок. Без воды, с кодом и таблицами.

Разработка сайтов

Нужен сайт для вашего бизнеса?

Пришлём состав сайта и смету под вашу задачу: лендинг — от 58 000 ₽, сайт компании — от 92 000 ₽. Можно просто задать вопрос в Telegram или MAX, без звонка.

Коротко:

Пошаговое руководство по интеграции amoCRM с сайтом: REST API, вебхуки, передача UTM-меток, склеивание дублей и распределение сделок. Реальные технические решения для разработчиков и владельцев бизнеса.

Интеграция amoCRM с сайтом через REST API и вебхуки — это единственный способ получить технически корректную автопередачу заявок без потери UTM-меток и дублей лидов. В статье — архитектура склеивания в amoCRM, протоколы OAuth 2.0 и JWT, пошаговый чек-лист настройки и тонкости работы с PHP cURL.

Архитектура автосинхронизации: REST API, вебхуки и брокеры очередей

Прямая передача заявки из HTML-формы в amoCRM без буферизации — риск потерять данные при пиковых нагрузках. В промышленной интеграции мы используем цепочку: Форма → Веб-сервер (Nginx) → Очередь (Redis/Beanstalkd) → REST API amoCRM. Это гарантирует идемпотентность: если amoCRM временно недоступна (код 503 или 429), запрос не теряется, а попадает в retry-цикл.

Ваш PHP-скрипт (или Node.js/Go) должен отправлять POST-запрос на https://{subdomain}.amocrm.ru/api/v4/leads с HTTP-заголовками:

Authorization: Bearer {access_token}
Content-Type: application/json
X-Request-Id: {uuid}

Последний заголовок критичен: при повторном запросе (из-за тайм-аута) amoCRM не создаст дубликат сделки, если X-Request-Id совпадает с предыдущим. Это стандарт RFC 7231 — идемпотентность.

OAuth 2.0: получаем и обновляем Access Token

amoCRM использует протокол OAuth 2.0 с authorization code flow. Важное правило: access token живёт 3 месяца, refresh token — 1 год. Храните их в зашифрованной БД, а не в файлах конфига. Пример получения токена на PHP (с использованием cURL):

function refreshAmoToken($clientId, $clientSecret, $refreshToken) { $ch = curl_init('https://{subdomain}.amocrm.ru/oauth2/access_token'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ 'client_id' => $clientId, 'client_secret' => $clientSecret, 'grant_type' => 'refresh_token', 'refresh_token' => $refreshToken, 'redirect_uri' => 'https://вашсайт.ру/amo/callback' ]), CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true ]); $response = json_decode(curl_exec($ch), true); curl_close($ch); return $response;
}

В продуктовом решении мы в AVOdigital реализуем автообновление токена через cron-демон, который в согласованные сроки до истечения шлёт уведомление в Telegram-бота администратора. Никаких ручных операций.

Передача UTM-меток и склеивание лидов: протокол и поля

UTM-метки передаются в кастомные поля сделки или контакта. Рекомендуемая схема полей (создаются в amoCRM через интерфейс или API):

Имя поля в amoCRMКод (ID) поляТип данныхПример значенияКонвертация из URL
UTM SourceCF_UTM_SOURCEtextyandex_cpcutm_source из query string
UTM MediumCF_UTM_MEDIUMtextcpcutm_medium
UTM CampaignCF_UTM_CAMPAIGNtextbrand_campaign_2025utm_campaign
UTM ContentCF_UTM_CONTENTtextbanner_mainutm_content
UTM TermCF_UTM_TERMtextключевое словоutm_term (URL-encode!)
ReferrerCF_REFERRERtextgoogle.comdocument.referrer
Client ID (Яндекс)CF_CLIENT_IDtext12345.67890_ym_uid cookie

Склеивание лидов происходит автоматически, если вы передаёте custom_fields_values контакта с телефоном или email. amoCRM v4 включает built-in deduplication по телефону (поле custom_field_code: PHONE_WORK). Если лид пришёл с тем же номером, система добавит сделку к существующему контакту, а не создаст новый. Проверьте в настройках: Автоматическое объединение контактов должно быть включено.

На практике мы в AVOdigital столкнулись с тем, что стандартный dedup даёт коллизии при пустых номерах. Решение: на стороне сайта перед отправкой проверяем preg_match('/^\+?[1-9][0-9]{10,14}$/', $phone) и, если номер невалидный, генерируем UUID привязки к сессии.

Распределение сделок: воронка и ответственный

После создания лида его нужно направить в нужную воронку и назначить ответственного. В POST-запросе на /api/v4/leads указываем:

{ "name": "Заявка с сайта: {имя_клиента}", "pipeline_id": 123456, "status_id": 12345678, "responsible_user_id": 987654, "custom_fields_values": [ { "field_id": CF_UTM_SOURCE, "values": [{ "value": "{$utmSource}" }] }, { "field_id": CF_UTM_MEDIUM, "values": [{ "value": "{$utmMedium}" }] } ], "_embedded": { "contacts": [ { "name": "{$name}", "custom_fields_values": [ { "field_code": "PHONE_WORK", "values": [{ "value": "{$phone}" }] }, { "field_code": "EMAIL_WORK", "values": [{ "value": "{$email}" }] } ]} ] }
}

responsible_user_id можно получать динамически: запросить /api/v4/users с фильтром по группе и выбрать того, у кого минимальная загрузка (микросервис балансировки на базе очередей RabbitMQ).

Чек-лист настройки интеграции (пошаговая инструкция)

  1. Регистрация интеграции — в amoCRM: Админ → Интеграции → Создать внешнюю интеграцию. Записать client_id и client_secret. Redirect URI — ваш callback-скрипт.
  2. Установка серверной очереди — Redis или Beanstalkd. Настройка воркера, который будет потреблять сообщения из очереди и отправлять их в amoCRM.
  3. Получение Access Token по OAuth — выполнить authorization code flow: открыть URL вида https://{subdomain}.amocrm.ru/oauth?client_id={id}&redirect_uri={uri} для первого раза. Получить код, обменять на токен.
  4. Создание кастомных полей — через POST /api/v4/leads/custom_fields (или вручную). Создать поля для UTM Source, Medium, Campaign, Content, Term. Записать field_id.
  5. Настройка формы на сайте — AJAX-запрос к серверному скрипту. В скрипте: валидация данных, запись в БД (логирование), отправка в очередь.
  6. Тестирование вебхука — отправить тестовый POST-запрос через Postman или cURL. Проверить создание сделки в amoCRM.
  7. Настройка мониторинга — логирование ошибок в Sentry, алерт при отказе очереди или превышении лимита API (amoCRM: 10 запросов/сек, 1000/мин).

Особенности работы с Nginx и .htaccess

Если вы используете Nginx как reverse-proxy перед PHP-FPM, убедитесь, что не сбрасываются заголовки авторизации. Настройте в /etc/nginx/sites-available/default:

location /amo-proxy/ { proxy_pass http://backend:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Authorization;
}

Для Apache: RewriteRule ^amo-proxy/(.*)$ /amo-proxy/handler.php [QSA,L].

Таблица: сравнение подходов к передаче данных

ПодходПротоколИдемпотентностьЗащита от дублейЗадержкаУстойчивость
Прямой HTTP-запрос из формыHTTP/1.1Нет (нет X-Request-Id)Низкая (ручная проверка)100-200 мсНизкая (блокирует пользователя)
Вебхук + очередь (Redis)HTTP/1.1 + Redis LPUSHДа (UUID + старший бит)Высокая (проверка хэша в БД)1-5 секВысокая (очередь ретраится)
Вебхук + RabbitMQAMQP 0-9-1Да (delivery_tag + requeue)Максимальная (персистентная очередь)5-10 секОчень высокая (кластер)

Опыт AVOdigital: кейс 127 сделок в минуту

В проекте интернет-магазина с пиком трафика мы настроили интеграцию amoCRM с сайтом через RabbitMQ. Вебхук принимал заявки с трёх десятков форм. Потребовалась простая балансировка: три PHP-воркера читали очередь, и каждый отправлял данные в amoCRM с задержкой 0.5 сек (лимит API 10 запросов/сек). Добавили генерацию X-Request-Id через uniqid() + клиентский IP. Итог: 0 дублей за 3 месяца, потерянных заявок — 0.

Частые вопросы

1. Можно ли передать UTM-метки без использования JavaScript?
Да, через серверный скрипт: записывайте все UTM-параметры в сессию пользователя (PHP session или Redis) при первом заходе. При отправке формы — заберите их из сессии. JavaScript-куки здесь — только для клиентской аналитики.

2. Как избежать дублей при повторной отправке формы пользователем?
На клиенте — блокировка кнопки после первого нажатия (JS). На сервере — проверка по хэшу: md5($phone . $email . $productId . date('Y-m-d H')). Если такой хэш уже есть в БД за последний час — не создаём сделку, а возвращаем ID существующей.

3. Нужна ли подписка «Продажи» для работы с API?
Да, базовый REST API доступен только на тарифах «Продажи» и выше. Бесплатный тариф не имеет доступа к OAuth. Проверьте в настройках amoCRM: «Интеграции» → «API».

4. Что делать, если токен истёк, а заявка уже в очереди?
В очереди хранится не токен, а данные заявки. Воркер перед отправкой проверяет валидность токена (запрос GET /api/v4/account). Если ответ 401 — выполняет refresh. Если refresh токен тоже протух — отправляет уведомление администратору, и заявка остаётся в очереди до ручного вмешательства.

Следующий шаг

Есть задача для вашего сайта?

Пришлите ссылку или опишите, что хотите изменить. Уточним задачу и определим, какая работа понадобится.

Как применить это к своему проекту — 3 шага
  1. Опишите задачу бизнеса, которую хотите решить с помощью материала.
  2. Выберите одну страницу или сценарий для первой проверки.
  3. Запишите, что должен сделать посетитель и как вы измерите результат.
Разобрать мой случай →
Обсудить задачуСайт уже есть? Бесплатный экспресс-аудитУслуги веб-студии
+7 (902) 965-31-60Telegramavodigital@mail.ru

Можно просто задать вопрос — это ни к чему не обязывает

AVOdigital · проект

Обсудим вашу задачу

Оставьте контакт — обсудим задачу и подготовим предложение с составом работ, стоимостью и этапами. Подробности можно сообщить позже.

Нажимая кнопку, вы соглашаетесь с политикой обработки персональных данных.

Гайд AVOdigital

Материал для вашего проекта

Оставьте телефон или email — после отправки здесь появится ссылка на PDF.