Вы принимаете интеграцию онлайн-школы в Алматы с CRM. Создаёте тестовый контакт C7 и две независимые покупки, D101 и D102, по 25 000 ₸. В отчёт попадает только 25 000 ₸. Разработчик убирал повторы по ID клиента и решил, что вторая покупка уже учтена. Цифры и записи условные, цена курса та же, что в плане измерения заявки.
Данные при этом везде правильные: в CRM две сделки, в учёте две оплаты, а после загрузки осталась одна. Ошибка сидит в том, как интеграция их склеивает. Чтобы её найти, разведите три вещи: человека, заявку и платёж, и для каждой опишите, как она проходит через интеграцию.
Контакт C7: две независимые покупки
Сделка D101
Платёж P501: 25 000 ₸
E801 пришло дважды, а платёж P501 один.
Сделка D102
Платёж P502: 25 000 ₸
Другая покупка того же контакта C7
В отчёте должны быть P501 и P502, всего 50 000 ₸. Повтор узнают по ключу оплаты, а не по ID клиента.
Что связываем с чем
Контакт - это человек. Сделка - одна возможность продажи со своим этапом и итогом. У сделки бывает несколько платежей, а об одном платеже может прийти несколько уведомлений. Стоит смешать эти уровни, и получится ровно ошибка из начала урока.
Нарисуйте для теста такую таблицу, а потом найдите для каждой строки поле в своей CRM:
| Объект | Записи в примере | Что по ним узнаём |
|---|---|---|
| Контакт | C7 | Кто покупает |
| Сделка | D101, D102 | Какую из двух продаж ведёт менеджер |
| Платёж | P501, P502 | Какие две операции подтвердил учёт |
| Уведомление | E801, E802 | Какие сообщения принял обработчик |
P501 относится к D101, P502 к D102, и оба платежа ведут к C7. Если уведомление E801 пришло дважды, платёж P501 всё равно один. Если после него пришёл P502, это вторая оплата, хотя клиент тот же.
ID без источника мало что значит. Сделка с номером 101 в двух аккаунтах CRM может оказаться двумя разными сделками. Поэтому в реестре интеграции у записи хранят систему, аккаунт и ID, а когда менеджер объединяет контакты, ещё и то, какой старый ID стал каким новым.
Как заявка с сайта попадает в CRM
Таблица заявок держится на том, что менеджер переносит заявки руками. Когда сервер сайта сам создаёт контакт и сделку через API, ручной перенос уходит. Принимая этот участок, ищите три результата: заявка сохранена, у неё есть ID в CRM, рекламные метки лежат в этой же заявке.
Сначала сервер получает доступ. В amoCRM интеграция авторизуется по OAuth 2.0: access token действует сутки (OAuth в amoCRM), refresh token - три месяца, и обменять его на новую пару можно только один раз (пошаговая авторизация amoCRM). Поэтому новую пару сохраняйте сразу после обмена: потеряете её - интеграцию придётся подключать заново. Для внешней или приватной интеграции amoCRM с февраля 2024 года позволяет выпустить долгосрочный токен сроком от одного дня до пяти лет, без refresh token. В Битрикс24 свой сервер можно подключить входящим вебхуком, о его адресе и правах ниже.
В amoCRM сделку вместе с контактом создают одним запросом POST /api/v4/leads/complex. За раз можно передать до 50 сделок, у каждой не больше одного контакта и одной компании (методы сделок amoCRM). Дубли метод ищет только среди уже созданных записей и только если для интеграции включён контроль дублей, так что целиком на него не полагайтесь. В Битрикс24 сделку создают методом crm.item.add: развитие старого метода crm.deal.add остановлено. Этапы и поля вроде «Оплачено» и «Программа курса» в вашем проекте могут быть настройками аккаунта. Разработчику нужны их настоящие идентификаторы из этой CRM, номера из чужого примера не подойдут.
Разработчик хранит пару: локальный ID заявки и ID сделки в CRM. Если запрос пришлось повторить после тайм-аута, интеграция находит уже созданную сделку и продолжает с ней. Если же она на каждый повтор создаёт новую, менеджер получит две карточки одного обращения и может позвонить человеку дважды.
Повтор формы через пару минут и новое обращение выпускника через полгода - разные случаи. В первом менеджеру нужна одна актуальная заявка, во втором может понадобиться новая сделка у прежнего контакта. Правило согласуйте с отделом продаж и прогоните на тестовой форме. По одному совпадению телефона отбрасывать все будущие заявки нельзя: выпускник, который вернулся за вторым курсом, просто пропадёт из воронки.
Источник заявки сохраняется у сделки
Школа размечает рекламу по общей схеме UTM, кампания course_start. Метки, которые есть в адресе, форма отправляет вместе с заявкой, а интеграция кладёт их в сделку. В Битрикс24 для них у сделки есть стандартные поля utmSource, utmMedium, utmCampaign, utmContent и utmTerm (поля сделки в crm.item.add), в старом методе они называются UTM_SOURCE, UTM_MEDIUM, UTM_CAMPAIGN, UTM_CONTENT и UTM_TERM. Если не сохранить метки сразу, их потеряет первый же переход на другую страницу или перенос контакта менеджером, и продажа останется без рекламного контекста.
У одного человека может быть история «впервые пришёл из Instagram», а новое обращение - по другой кампании. Поэтому источник первого контакта и источник заявки храните в разных полях, а модель атрибуции применяйте к ним в отчёте. Когда интеграция обновляет поле в контакте, прежние сделки этого человека меняться не должны.
Если метки не дошли, источник остаётся неизвестным, так его и записывают. Интеграция не ставит «Instagram» всем, кто написал в WhatsApp, и не требует рекламный click ID у органической заявки. Чтобы передавать оплаты в Google Ads или другой кабинет, нужные идентификаторы и условия передачи описывают в ТЗ своим пунктом. Полную карточку клиента в рекламное событие не кладут, только поля, которые требует кабинет.
Какой статус считается оплатой
До настройки обмена владелец школы и тот, кто отвечает за оплаты, договариваются, откуда берётся подтверждение денег. Этап «Успешно реализовано» (в amoCRM это системный статус 142) менеджер мог поставить сразу после подписания договора. Для отчёта об оплатах этого мало: нужен подтверждённый платёж с суммой, валютой, временем и номером операции.
В тесте это P501 и P502 по 25 000 ₸. Интеграция берёт факты оплаты из учёта и привязывает их к сделкам. В поле «Бюджет сделки» может стоять цена, которую менеджер только ожидает получить, поэтому автоматически считать её полученными деньгами нельзя.
Повторное открытие D101 не создаёт новый P501. Если клиент вносит по той же сделке второй платёж, у него будет свой номер операции. Возврат тоже записывается своей операцией и меняет итог по правилу, которое вы зафиксировали заранее. Поэтому в ТЗ нужны примеры полной оплаты, частичной оплаты, возврата и ошибочной смены этапа, даже если в первом тесте всего две покупки.
Что приходит по API и по webhook
Через API ваш сервис сам обращается к CRM: читает или меняет запись. Webhook работает в обратную сторону: CRM сама сообщает, что у неё что-то изменилось. В интеграции нужны оба. Уведомление говорит, что запись изменилась, а запрос дочитывает данные, чтобы это изменение обработать.
amoCRM публикует методы управления вебхуками и события подписки. Подписывайтесь на то, что нужно задаче: смена этапа сделки и подтверждённый платёж - разные события. В формате уведомлений amoCRM нет собственного ID события смены статуса, поэтому номер вроде E801 обработчик присваивает сам. А оплату узнают по устойчивому ключу самого платежа, в тесте это P501.
В Битрикс24 вебхуки названы по направлению относительно CRM:
| Механизм | Кто начинает запрос | Для чего нужен в нашей схеме |
|---|---|---|
| Входящий вебхук, incoming webhook | Наш сервис обращается к Битрикс24 | Вызвать REST API с выданным доступом |
| Исходящий вебхук, outgoing webhook | Битрикс24 обращается к нашему обработчику | Сообщить, что запись изменилась |
Описание локальных вебхуков Битрикс24 задаёт адрес входящего вебхука: https://<портал>/rest/<ID сотрудника>/<секретный код>/<метод>.json. Запросы по нему выполняются с правами сотрудника, который создал вебхук, и только в тех разрешениях, которые для вебхука выбрали. Секретный код в адресе работает как пароль: кто знает адрес, тот работает с CRM от имени этого сотрудника. Держите адрес на сервере и не пускайте его в браузерный код, обычные логи и скриншоты для клиента.
Уведомление может содержать только ID сделки, так что нужные поля обработчик дочитывает через API. Подлинность уведомления в двух CRM проверяют по-разному. Исходящий вебхук Битрикс24 несёт auth[application_token], и его сравнивают с токеном из настроек вебхука. В описании вебхуков amoCRM подписи нет, поэтому уведомлению на слово не верят: сделку перечитывают через API и только потом сохраняют результат.
Доставка сообщения и учёт оплаты
Обработчик уведомлений из CRM принимает их так же, как любой приёмник вебхуков, с одной поправкой: повтор узнают по ключу оплаты P501, а не по ID клиента C7. Иначе вторая покупка пропадёт, как в начале урока.
Есть и вторая ловушка. Если обработчик записывает служебное поле обратно в CRM, эта запись сама может вызвать webhook, и обмен пойдёт по кругу. Поэтому в правилах подписки и обработки изменения менеджера отличают от технических записей самой интеграции.
Как найти пропуск после сбоя
Уведомления нужны, чтобы реагировать быстро, а пропуски находит сверка по расписанию. Читая список записей, разработчик проходит все страницы ответа и отмечает, какой диапазон обработан успешно. Границы по времени, перекрытие интервалов и глубину доступной истории он берёт из документации API. Число строк на первой странице ответа о них ничего не говорит.
Текущий статус и история отвечают на разные вопросы. Сделка стала оплаченной в 10:00 и отменённой в 11:00, а запрос в 12:00 может показать только отмену. Чтобы восстановить обе операции, нужен журнал оплат и возвратов или история изменений. Если журнала не вели, запрос текущего состояния его не заменит.
В протоколе сверки сравнивают ID и суммы, итога мало. Потеря D102 на 25 000 ₸ и лишняя копия D101 на те же 25 000 ₸ дадут правильную общую сумму при двух ошибках. Поэтому в отчёте сверки нужны списки пропущенных, лишних и расходящихся записей, и у каждого расхождения есть ответственный.
Ошибку доступа выводят своим сигналом. Если сотрудник, выдавший доступ, уволился или у него отозвали права, отчёт придёт пустым, и выглядеть как день без продаж он не должен. На приёмке отказ доступа воспроизводят специально, а для рабочего обмена назначают человека, который получит сигнал и восстановит подключение.
Задание: протокол приёмки интеграции
Возьмите форму и CRM своего проекта. Понадобится тестовый доступ, в котором разрешено создавать и менять записи: в рабочем аккаунте клиента тестовые сделки окажутся в воронке и отчётах отдела продаж, пока их не удалят.
Выполнено 0 из 6
Для C7 протокол должен показать P501 и P502, всего 50 000 ₸. Два уведомления о P501 - это две доставки, но один платёж. Новая покупка C7 остаётся в отчёте, потому что у неё свой факт оплаты. Если сумма сошлась, а номера операций нет, интеграцию не принимают: совпавший итог может прятать две ошибки, как в примере с лишней D101 и потерянной D102.
Клиенту вы сдаёте связку записей, которую можно пройти от формы до денег, и инструкцию на случай сбоя. Список подключённых сервисов без такой проверки не поможет, когда в понедельник из отчёта пропадёт продажа и вас спросят, куда она делась.
Видео: пример интеграции amoCRM
Пример подключения к amoCRM на Python. Обратите внимание, где автор хранит access и refresh token и что делает код, когда access token через сутки истекает.