Перейти к содержимому
Socialift
Интеграция с CRM

Интеграция Instagram, Lead Ads и Telegram с amoCRM и Bitrix24

Чтобы заявки из Instagram Lead Ads или Telegram автоматически попадали в amoCRM или Bitrix24, между платформой и CRM ставится ваш бэкенд. Он принимает вебхук, проверяет подпись, получает данные лида, приводит телефон к формату +998 и пишет в API CRM. Готового коннектора для этих CRM в Socialift нет: SDK закрывает сторону платформы, вызовы CRM — в вашем коде.

Обновлено:

Как подключить Instagram к amoCRM или Bitrix24?

Есть два пути. Первый — встроенные канальные интеграции CRM (например, открытые линии Bitrix24): удобно для переписки. Второй — собственный бэкенд: вебхук Meta → проверка подписи → получение лида → нормализация → API CRM. Если нужны атрибуция рекламы, свои правила дублей и маршрутизация, второй путь даёт полный контроль.

В справке Bitrix24 среди каналов открытых линий перечислены Instagram и Telegram. У amoCRM есть Chats API для интеграторов. Эти решения приводят переписку в CRM, но записать ID кампании, объявления и формы Lead Ads в нужные поля обычно можно только своим кодом.

Готового коннектора для amoCRM, Bitrix24 или другой CRM в Socialift нет. Socialift — это Python SDK: он проверяет подпись вебхука, разбирает события, получает лид из Graph API и нормализует ответы формы. Ниже — те 20–40 строк, которые пишут данные в CRM.

Архитектура: от вебхука до записи в CRM за 6 шагов

Каждый шаг независим — если один упал, данные не теряются.

  1. Подключите вебхук

    В Meta App подпишитесь на поле leadgen и подключите каждую Page к приложению (в SDK: fb.subscribe_page(page_id, page_token, fields=["leadgen"])). Для Telegram-бота — set_webhook(url, secret_token=...).

  2. Проверьте подпись

    Запрос Meta приходит с X-Hub-Signature-256: verify_request(app_secret, body, headers). Telegram тело не подписывает — verify_telegram_request(headers, secret_token) сверяет секретную строку в заголовке.

  3. Разберите события и отсейте дубли

    parse_events(payload) превращает payload в поток WebhookEvent. Пишите event.key в уникальную колонку: Meta может повторить доставку.

  4. Получите данные лида

    В вебхуке leadgen нет ответов формы — только leadgen_id, page_id, form_id, ad_id и время. Полная запись: fb.lead(leadgen_id, page_token).

  5. Нормализуйте

    normalize(lead.field_data) приводит поля с любыми названиями к full_name, phone, email. Телефон доведите до E.164 (+998...) сами.

  6. Пишите в CRM через очередь

    Сразу отвечайте вебхуку 200, а вызов CRM отдайте фоновому воркеру: поиск дубля по телефону, затем создание. На 429/503 — повтор с задержкой.

Приёмник вебхука (aiohttp)

Обработчик только проверяет, отсеивает дубли и ставит в очередь — тяжёлая работа позже.

webhook.py
import json, os
from aiohttp import web
from socialift.webhooks import verify_request, parse_events

APP_SECRET = os.environ["META_APP_SECRET"]

async def meta_webhook(request: web.Request) -> web.Response:
    body = await request.read()  # сырые байты — подпись считается по ним
    if not verify_request(APP_SECRET, body, request.headers):
        return web.Response(status=403)
    for event in parse_events(json.loads(body)):
        if event.field == "leadgen" and await mark_seen(event.key):
            await queue.put({"leadgen_id": event.leadgen_id, "page_id": event.page_id})
    return web.Response(text="ok")

mark_seen — ваша функция: INSERT ... ON CONFLICT DO NOTHING, возвращает True для новой записи. queue — Redis, RabbitMQ или таблица в базе.

Получение лида и приведение телефона к +998

normalize() из SDK убирает пробелы и дефисы и сохраняет +, но код страны не добавляет.

lead.py
import re
from socialift import Facebook
from socialift.leads import normalize

def to_e164_uz(raw: str | None) -> str | None:
    digits = re.sub(r"\D", "", raw or "")
    if digits.startswith("00"):
        digits = digits[2:]
    if len(digits) == 12 and digits.startswith("998"):
        return "+" + digits
    if len(digits) == 9:  # 90 123 45 67
        return "+998" + digits
    return None  # на ручную проверку

async def load_lead(fb: Facebook, leadgen_id: str, page_token: str) -> dict:
    lead = await fb.lead(leadgen_id, page_token)
    person = normalize(lead.field_data)
    return {"lead_id": lead.id, "name": person.full_name, "email": person.email,
            "phone": to_e164_uz(person.phone), "phone_raw": person.phone,
            "form_id": lead.form_id, "ad_id": lead.ad_id,
            "campaign": lead.campaign_name, "organic": lead.is_organic}

Узбекский номер — это 9 цифр после +998. Не выбрасывайте номер, который не подошёл под формат: запишите phone_raw в примечание, менеджер разберётся.

API amoCRM и Bitrix24: чем писать

API amoCRM и Bitrix24: чем писать — Таблица возможностей по платформам
amoCRM (API v4)Bitrix24 (REST)
ДоступOAuth 2.0; для приватной интеграции — долгосрочный токенВходящий вебхук (секрет в URL) или OAuth-приложение
Срок токеновВ примере ответа expires_in 86400 (24 часа); refresh token — 3 месяца, обменивается один разOAuth: access — 1 час, refresh — 180 дней; вебхук работает с правами создавшего сотрудника
Создание лидаPOST /api/v4/leads/complex — сделка + контакт + компания одним запросом, до 50 штукcrm.item.add (entityTypeId: 1); crm.lead.add работает, но его развитие остановлено
Телефонcustom_fields_values: field_code PHONE, enum_code WORK/MOBfm: typeId PHONE, valueType WORK/MOBILE
Поиск дублейGET /api/v4/contacts?query=...; контроль дублей в complex (если включён для интеграции)crm.duplicate.findbycomm — PHONE/EMAIL, до 20 значений за запрос
Лимиты7 запросов/с на интеграцию, 50 запросов/с на аккаунт; превышение — 429, систематическое — блокировка с 403Leaky bucket: 2 запроса/с, блок на 50 (Enterprise: 5/с, 250); 503 QUERY_LIMIT_EXCEEDED
Ошибки401 — не авторизован, 400 — некорректные данныеВ теле error и error_description; неверный вебхук — 401 INVALID_CREDENTIALS

Значения — из официальной документации amoCRM и Bitrix24 на 2026-09-17. Лимиты меняются — перепроверьте перед запуском.

amoCRM: сделка и контакт одним запросом

leads/complex создаёт сделку, контакт и телефон вместе. request_id возвращается в ответе — свяжите его с ID лида.

amocrm.py
import os, aiohttp

AMO = f"https://{os.environ['AMO_SUBDOMAIN']}.amocrm.ru/api/v4"
HEADERS = {"Authorization": f"Bearer {os.environ['AMO_ACCESS_TOKEN']}"}

async def amo_create(session: aiohttp.ClientSession, lead: dict) -> dict:
    payload = [{
        "name": f"Lead Ads: {lead['campaign'] or lead['form_id']}",
        "request_id": lead["lead_id"],
        "_embedded": {
            "tags": [{"name": "instagram-lead-ads"}],
            "contacts": [{
                "first_name": lead["name"] or "Lead",
                "custom_fields_values": [{"field_code": "PHONE",
                    "values": [{"enum_code": "MOB", "value": lead["phone"]}]}],
            }],
        },
    }]
    async with session.post(f"{AMO}/leads/complex", json=payload, headers=HEADERS) as r:
        if r.status == 429:
            raise RetryLater(r.status)
        r.raise_for_status()
        return (await r.json())[0]  # id, contact_id, merged

merged: true в ответе означает, что контроль дублей amoCRM нашёл существующий контакт и объединил. Если контроль выключен, сначала ищите через GET /api/v4/contacts?query=<телефон>.

Атрибуцию удобно писать примечанием: POST /api/v4/leads/{id}/notes с note_type: "common" и текстом в params.text — форма, объявление, кампания.

Bitrix24: входящий вебхук и crm.item.add

URL вебхука — это и есть ключ: храните его в переменной окружения и никогда не кладите во фронтенд.

bitrix24.py
import os, aiohttp

B24 = os.environ["B24_WEBHOOK_URL"]  # https://<portal>/rest/<user_id>/<secret>/

async def b24(session: aiohttp.ClientSession, method: str, params: dict):
    async with session.post(f"{B24}{method}.json", json=params) as r:
        data = await r.json()
    if "error" in data:  # QUERY_LIMIT_EXCEEDED -> повторить позже
        raise B24Error(data["error"], data.get("error_description"))
    return data["result"]

async def b24_create(session: aiohttp.ClientSession, lead: dict) -> int:
    dup = await b24(session, "crm.duplicate.findbycomm",
                    {"entity_type": "LEAD", "type": "PHONE", "values": [lead["phone"]]})
    if isinstance(dup, dict) and dup.get("LEAD"):
        return dup["LEAD"][0]
    res = await b24(session, "crm.item.add", {"entityTypeId": 1, "fields": {
        "title": f"Lead Ads: {lead['campaign'] or lead['form_id']}",
        "name": lead["name"],
        "utmCampaign": lead["campaign"],
        "sourceDescription": f"form={lead['form_id']} ad={lead['ad_id']}",
        "fm": [{"typeId": "PHONE", "valueType": "MOBILE", "value": lead["phone"]}],
    }})
    return res["item"]["id"]

Bitrix24 советует определять ошибку по полю error в теле, а не по HTTP-статусу: ошибки внутри batch приходят со статусом 200.

Если портал в простом режиме CRM, лидов нет: созданный лид сразу превращается в сделку. Режим проверяется через crm.settings.mode.get. Допустимые значения sourceId — в crm.status.list (ENTITY_ID = SOURCE).

Атрибуция: куда класть поля Lead Ads в CRM

Объект Lead из SDK возвращает ID формы и рекламы. Не теряйте их — иначе не понять, какая кампания принесла продажу.

Атрибуция: куда класть поля Lead Ads в CRM — Таблица возможностей по платформам
Поле лидаamoCRMBitrix24
form_idТег или доп. поле; в примечанииsourceDescription
ad_id, ad_nameДоп. поле или примечаниеutmContent или comments
campaign_id, campaign_nameНазвание сделки и тегutmCampaign
is_organicТег (organic / paid)sourceId (источник, настроенный в портале)
lead.idrequest_id и примечаниеcomments или доп. поле

Если нужны группа объявлений, цель кампании и таргетинг — fb.ad_context(ad_id, token). Без разрешения ads_management метод вернёт пустой словарь и не остановит поток лидов.

Как передавать обращения из Telegram-бота в CRM?

Вебхук Telegram-бота не подписывается: строка, переданная в set_webhook(url, secret_token=...), возвращается в каждом запросе в заголовке X-Telegram-Bot-Api-Secret-Token. Проверяйте её через verify_telegram_request(headers, secret_token).

Официальный способ запросить номер — кнопка request_contact: по нажатию номер пользователя приходит сообщением contact (только в личном чате). Приведите contact.phone_number к +998 так же, как для Lead Ads, и передайте в ту же amo_create или b24_create.

Ключ дедупликации — update_id или пара ID чата + ID сообщения. Если клиент пишет боту несколько раз, обычно правильнее добавить примечание к существующему лиду, чем создавать новый.

Дубли, повторы и надёжность

  • Двухуровневая дедупликация: event.key на уровне вебхука (уникальная колонка), поиск по телефону на уровне CRM.
  • 429 в amoCRM и QUERY_LIMIT_EXCEEDED в Bitrix24 — временные: повторяйте с экспоненциальной задержкой и jitter.
  • При систематическом превышении лимитов amoCRM блокирует аккаунт (403) — ограничьте число воркеров, на 403 останавливайтесь и шлите алерт.
  • Refresh token amoCRM одноразовый: сохраняйте новую пару access/refresh в одной транзакции.
  • Для пропущенного вебхуком периода делайте backfill: fb.leads(form_id, page_token, since=...).
  • Не пишите в логи телефоны, email и токены; URL вебхука Bitrix24 храните как секрет.
  • Не выбрасывайте ненормализуемый номер — сохраните сырое значение в примечании для менеджера.

← Назад в блог

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

Есть ли в Socialift готовый коннектор к amoCRM или Bitrix24?

Нет. Socialift — это Python SDK и кабинет для разработчиков. Он закрывает сторону Instagram, Facebook, Telegram и других платформ, а код записи в API CRM вы пишете в своём бэкенде. Примеры из этой статьи — основа такого кода.

Приходит ли телефон клиента в вебхуке Lead Ads?

Нет. Вебхук leadgen присылает только идентификаторы: leadgen_id, page_id, form_id, ad_id и время. Ответы формы получают отдельным запросом к Graph API — в SDK это fb.lead(leadgen_id, page_token).

В Bitrix24 использовать crm.lead.add или crm.item.add?

Для новой интеграции — crm.item.add с entityTypeId: 1. В документации Bitrix24 сказано, что развитие crm.lead.add остановлено и рекомендуется crm.item.add. Телефон в crm.item.add передаётся через массив fm.

Какие лимиты у API amoCRM?

По документации — не более 7 запросов в секунду на интеграцию и до 50 запросов в секунду на весь аккаунт. При превышении возвращается 429, при систематических нарушениях аккаунт блокируется и отвечает 403. За один запрос рекомендуется передавать не более 50 сделок.

Что значит ошибка QUERY_LIMIT_EXCEEDED в Bitrix24?

Это лимит интенсивности запросов: когда счётчик превышает порог, Bitrix24 отвечает 503 с кодом QUERY_LIMIT_EXCEEDED. На обычных тарифах счётчик уменьшается на 2 в секунду и блокирует на 50, на Enterprise — 5 и 250. Решение — очередь и повтор с небольшой задержкой.

Источники

  1. amoCRM — Сделки, комплексное добавление
  2. amoCRM — Рекомендации и ограничения API
  3. amoCRM — OAuth 2.0 пошагово
  4. Bitrix24 — crm.item.add
  5. Bitrix24 — лимиты REST API
  6. Meta — Retrieving Leads

Связанные страницы