uCheckeruChecker
Блог/Верификация
Для разработчиков6 апреля 202613 мин чтения

Интеграция email-валидации с CRM-системами: Bitrix24, amoCRM, HubSpot

Webhook при создании контакта, bulk-проверка перед рассылкой, автоматическая сегментация по результатам. Рабочие примеры на PHP, Python и Node.js.

CRM-система хранит контакты. Email-валидатор проверяет адреса. По отдельности каждый инструмент работает нормально. Вместе - закрывают дыру, через которую в базу попадают несуществующие адреса, спам-ловушки и одноразовые ящики.

В этой статье - конкретные интеграции: Bitrix24, amoCRM, HubSpot. Для каждой CRM - архитектура, код, подводные камни. Без абстрактных диаграмм, только то, что можно взять и внедрить.

Зачем проверять email внутри CRM

Стандартный сценарий без валидации: менеджер вбивает контакт в CRM, через неделю маркетинг отправляет рассылку, письмо уходит на несуществующий адрес, ESP фиксирует hard bounce. Двадцать таких адресов - и репутация домена начинает проседать. Пятьдесят - и письма уходят в спам у всех получателей, включая живых.

Проблема усиливается, когда контакты приходят из нескольких источников: форма на сайте, импорт из Excel, ручной ввод менеджером, парсинг из LinkedIn. Каждый источник добавляет свой процент мусора. Форма - опечатки и одноразовые адреса. Excel - устаревшие контакты. Ручной ввод - банальные ошибки. Без валидации на входе CRM превращается в коллектор невалидных адресов.

Решение - проверять email в момент создания или обновления контакта. Не раз в месяц, не перед рассылкой, а сразу. Это отсекает мусор до того, как он успеет попасть в сегменты и рассылочные списки.

Общая архитектура: CRM + API валидатора

Независимо от конкретной CRM, схема одна и та же. Три точки интеграции покрывают все сценарии:

1.

Webhook при создании контакта

CRM отправляет событие на ваш сервер. Сервер вызывает API валидатора, получает результат, записывает статус обратно в CRM. Задержка - 2-5 секунд.

2.

Bulk-проверка существующей базы

Выгружаете контакты через API CRM, отправляете списком на bulk-валидацию, по готовности обновляете статусы в CRM. Для первичной очистки.

3.

Регулярная переproверка по расписанию

Cron-задача раз в месяц: берёт контакты, которые не проверялись дольше 30 дней, отправляет на валидацию. Ящики умирают - адрес, валидный в январе, может не существовать в марте.

Для хранения результатов создайте в CRM пользовательское поле - например, email_validation_status с вариантами: valid, invalid, risky, unknown. Отдельное поле email_validated_at с датой последней проверки. Это позволяет строить сегменты: «только валидные адреса» для рассылок, «risky» для ручной проверки менеджером.

Bitrix24: входящий webhook + REST API

Bitrix24 поддерживает исходящие вебхуки на события CRM. Нас интересует событие ONCRMCONTACTADD - срабатывает при создании нового контакта. Для обновления есть ONCRMCONTACTUPDATE.

Предварительно создайте пользовательские поля в Bitrix24: зайдите в CRM → Настройки → Пользовательские поля, добавьте UF_EMAIL_VALID (список) и UF_EMAIL_CHECKED (дата). Запомните ID полей - они понадобятся в коде.

Обработчик webhook-а на PHP

Bitrix24 отправляет POST-запрос с ID контакта. Ваш сервер получает ID, забирает email через REST API, отправляет на валидацию, записывает результат обратно.

PHPbitrix24-webhook-handler.php
<?php
// Webhook endpoint: POST /webhooks/bitrix24-contact

$contactId = $_POST['data']['FIELDS']['ID'] ?? null;
if (!$contactId) { http_response_code(400); exit; }

$bitrixWebhook = getenv('BITRIX24_WEBHOOK_URL');
// e.g. https://your-domain.bitrix24.ru/rest/1/abc123xyz/

// 1. Fetch contact email from Bitrix24
$contact = json_decode(file_get_contents(
    $bitrixWebhook . "crm.contact.get?ID=" . $contactId
), true)['result'];

$email = $contact['EMAIL'][0]['VALUE'] ?? null;
if (!$email) exit;

// 2. Validate via uChecker API
$ch = curl_init('https://api.uchecker.net/api/v1/validate/single');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'x-api-key: ' . getenv('UCHECKER_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['email' => $email]),
    CURLOPT_RETURNTRANSFER => true,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);

$taskId = $result['task_id'];

// 3. Poll for result (in production use webhook_url instead)
sleep(5);
$ch = curl_init("https://api.uchecker.net/api/v1/tasks/$taskId");
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'x-api-key: ' . getenv('UCHECKER_API_KEY'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$task = json_decode(curl_exec($ch), true);
curl_close($ch);

$status = $task['result']['status'] ?? 'unknown';
// Map to your custom field values
$statusMap = [
    'deliverable'   => 'valid',
    'undeliverable' => 'invalid',
    'risky'         => 'risky',
    'unknown'       => 'unknown',
];

// 4. Write result back to Bitrix24
file_get_contents($bitrixWebhook . "crm.contact.update?" . http_build_query([
    'ID'     => $contactId,
    'FIELDS' => [
        'UF_EMAIL_VALID'   => $statusMap[$status] ?? 'unknown',
        'UF_EMAIL_CHECKED' => date('Y-m-d'),
    ],
]));
!

В production-коде замените sleep(5) на обработку через webhook_url. Передайте параметр webhook_url в запросе валидации - uChecker отправит результат на указанный URL, как только проверка завершится. Это избавляет от polling и блокировки потока.

Для Bitrix24 on-premise (коробка) логика та же, только webhook URL будет другим. Облачная версия и коробка используют одинаковый REST API. Если у вас несколько порталов, храните webhook URL каждого в конфигурации и выбирайте по source-параметру в запросе.

amoCRM: Digital Pipeline + webhook

В amoCRM события по контактам доступны через вебхуки. Настройка: Настройки → Интеграции → создать интеграцию с типом «Внешний обработчик», указать URL вашего сервера. amoCRM пришлёт POST-запрос при добавлении или обновлении контакта.

Особенность amoCRM - авторизация через OAuth 2.0. Для серверной интеграции вам нужен long-lived токен через client_credentials flow или периодическое обновление через refresh_token. Храните токены в базе, обновляйте автоматически.

Обработчик на Python

Pythonamocrm_webhook.py
import os, requests
from flask import Flask, request, jsonify

app = Flask(__name__)

UCHECKER_KEY = os.environ["UCHECKER_API_KEY"]
AMO_TOKEN    = os.environ["AMOCRM_ACCESS_TOKEN"]
AMO_DOMAIN   = os.environ["AMOCRM_DOMAIN"]  # e.g. mycompany

def validate_email(email: str) -> dict:
    """Send email to uChecker, return validation result."""
    resp = requests.post(
        "https://api.uchecker.net/api/v1/validate/single",
        headers={"x-api-key": UCHECKER_KEY},
        json={"email": email},
    )
    task_id = resp.json()["task_id"]

    # Poll until done (use webhook_url in production)
    import time
    for _ in range(10):
        time.sleep(3)
        r = requests.get(
            f"https://api.uchecker.net/api/v1/tasks/{task_id}",
            headers={"x-api-key": UCHECKER_KEY},
        )
        data = r.json()
        if data.get("status") == "completed":
            return data["result"]
    return {"status": "unknown"}

def update_amo_contact(contact_id: int, validation_status: str):
    """Write validation result back to amoCRM custom field."""
    requests.patch(
        f"https://{AMO_DOMAIN}.amocrm.ru/api/v4/contacts/{contact_id}",
        headers={
            "Authorization": f"Bearer {AMO_TOKEN}",
            "Content-Type": "application/json",
        },
        json={
            "custom_fields_values": [
                {
                    "field_id": 123456,  # your custom field ID
                    "values": [{"value": validation_status}],
                }
            ]
        },
    )

@app.route("/webhooks/amocrm", methods=["POST"])
def handle_amocrm_webhook():
    payload = request.json or {}
    contacts = payload.get("contacts", {}).get("add", [])
    contacts += payload.get("contacts", {}).get("update", [])

    for contact in contacts:
        contact_id = contact["id"]
        # Fetch full contact to get email
        r = requests.get(
            f"https://{AMO_DOMAIN}.amocrm.ru/api/v4/contacts/{contact_id}",
            headers={"Authorization": f"Bearer {AMO_TOKEN}"},
        )
        fields = r.json().get("custom_fields_values", [])
        email = None
        for f in fields:
            if f["field_code"] == "EMAIL":
                email = f["values"][0]["value"]
                break

        if not email:
            continue

        result = validate_email(email)
        status = result.get("status", "unknown")
        update_amo_contact(contact_id, status)

    return jsonify({"ok": True})

Обратите внимание на field_id: в amoCRM у каждого кастомного поля есть числовой ID. Его можно получить через GET /api/v4/contacts/custom_fields. Подставьте реальный ID вместо 123456.

Если контактов много и webhook-и идут потоком, вынесите валидацию в очередь задач - Celery, RQ или любой другой менеджер. Webhook-обработчик должен отвечать за 200-300 миллисекунд, иначе amoCRM перестанет отправлять события.

HubSpot: Workflows + custom coded action

HubSpot предлагает два пути. Первый - Workflows с custom coded action (Operations Hub Professional). Второй - webhook-подписка через API. Для большинства команд Workflows удобнее: настройка через интерфейс, логирование из коробки, повторные попытки при ошибках.

Создайте workflow с триггером «Contact is created». Добавьте шаг «Custom coded action». Внутри - Node.js-скрипт, который вызывает uChecker API и записывает результат в свойство контакта.

Custom coded action (Node.js)

Node.jshubspot-workflow-action.js
// HubSpot Custom Coded Action
// Input: contact email (configured in workflow)
// Secrets: UCHECKER_API_KEY (add in workflow settings)

const hubspot = require("@hubspot/api-client");
const axios = require("axios");

exports.main = async (event, callback) => {
  const email = event.inputFields["email"];
  if (!email) return callback({ outputFields: {} });

  const apiKey = process.env.UCHECKER_API_KEY;

  // 1. Submit for validation
  const { data: task } = await axios.post(
    "https://api.uchecker.net/api/v1/validate/single",
    { email },
    { headers: { "x-api-key": apiKey } }
  );

  // 2. Poll for result
  let result = null;
  for (let i = 0; i < 10; i++) {
    await new Promise((r) => setTimeout(r, 3000));
    const { data } = await axios.get(
      `https://api.uchecker.net/api/v1/tasks/${task.task_id}`,
      { headers: { "x-api-key": apiKey } }
    );
    if (data.status === "completed") {
      result = data.result;
      break;
    }
  }

  const status = result?.status || "unknown";

  // 3. Update contact property
  const hsClient = new hubspot.Client({
    accessToken: process.env.HUBSPOT_TOKEN,
  });

  await hsClient.crm.contacts.basicApi.update(
    event.object.objectId,
    {
      properties: {
        email_validation_status: status,
        email_validated_date: new Date().toISOString().split("T")[0],
      },
    }
  );

  callback({ outputFields: { validation_status: status } });
};

Перед запуском создайте свойства контакта в HubSpot: Settings → Properties → Create property. Тип - Single-line text для email_validation_status и Date для email_validated_date. Internal name должен совпадать с тем, что в коде.

Альтернатива без Operations Hub: внешний сервер + HubSpot webhook subscription API. Подписываетесь на событие contact.creation, обрабатываете аналогично Bitrix24 и amoCRM. Webhook subscription требует верификации через challenge-запрос - HubSpot отправляет GET с параметром, ваш сервер должен вернуть его в ответе.

Bulk-очистка существующей базы

Webhook-интеграция закрывает новые контакты. Но что делать с теми тысячами адресов, которые уже в CRM? Нужна разовая bulk-проверка.

Алгоритм для любой CRM: выгрузите контакты через API, соберите email-адреса в список, отправьте на bulk-валидацию, дождитесь результата, обновите статусы обратно. Вот универсальный скрипт.

Pythonbulk_validate_crm.py
import os, time, requests

API_KEY = os.environ["UCHECKER_API_KEY"]
BASE    = "https://api.uchecker.net"
HEADERS = {"x-api-key": API_KEY, "Content-Type": "application/json"}

def bulk_validate(emails: list[str]) -> dict:
    """Submit bulk validation and wait for results."""
    # 1. Create bulk task
    resp = requests.post(
        f"{BASE}/api/v1/validate/bulk",
        headers=HEADERS,
        json={"emails": emails},
    )
    task_id = resp.json()["task_id"]
    print(f"Bulk task created: {task_id}, emails: {len(emails)}")

    # 2. Poll until complete
    while True:
        time.sleep(10)
        r = requests.get(f"{BASE}/api/v1/tasks/{task_id}", headers=HEADERS)
        data = r.json()
        if data["status"] == "completed":
            return data["results"]  # {email: status, ...}
        if data["status"] == "failed":
            raise RuntimeError(f"Task {task_id} failed")
        print(f"  status: {data['status']}, progress: {data.get('progress', '?')}")

# Usage example:
# contacts = fetch_contacts_from_crm()
# emails = [c["email"] for c in contacts if c.get("email")]
# results = bulk_validate(emails)
# for contact in contacts:
#     status = results.get(contact["email"], "unknown")
#     update_crm_contact(contact["id"], status)

Для больших баз (больше 10 000 адресов) разбивайте на пакеты. uChecker bulk API принимает до 50 000 адресов за запрос, но обновление CRM лучше делать батчами по 100-500 контактов - это снижает нагрузку на API CRM и уменьшает риск rate limiting.

Результат bulk-проверки можно использовать для сегментации. Контакты со статусом invalid - удалить или поставить флаг «не отправлять». Статус risky - отправлять только критически важные письма. Valid - полноценная работа.

Обработка ошибок и граничные случаи

Интеграция двух систем - это всегда борьба с нештатными ситуациями. Вот что ломается на практике и как с этим справляться.

Таймаут API валидатора

uChecker отвечает за 2-5 секунд на single-валидацию. Если ответа нет 15 секунд - ставьте статус unknown и добавляйте контакт в очередь повторной проверки. Не блокируйте создание контакта в CRM.

Rate limiting CRM API

Bitrix24 - 2 запроса в секунду на webhook. amoCRM - 7 запросов в секунду. HubSpot - 100 запросов за 10 секунд (private app). При bulk-обновлении используйте batch-эндпоинты, где они есть, и добавляйте задержку между запросами.

Дубликаты контактов

Один email может быть у нескольких контактов. Кэшируйте результат валидации на стороне вашего сервера (Redis, SQLite) на 24 часа. Если тот же адрес приходит повторно - берите из кэша, не тратьте кредиты.

Контакт без email

Не все контакты в CRM имеют email. Проверяйте наличие поля перед отправкой на валидацию. Это очевидно, но каждый второй обработчик падает именно на этом.

Хорошая практика - логировать каждый вызов: входящий webhook, запрос к API валидатора, результат, обновление CRM. При отладке интеграции двух систем логи экономят часы. Храните логи минимум 7 дней.

Чек-лист внедрения

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

1.Создать пользовательские поля в CRM: validation_status и validated_at
2.Получить API-ключ uChecker на app.uchecker.net
3.Развернуть webhook-обработчик на сервере (PHP, Python, Node.js)
4.Настроить исходящий webhook в CRM на событие создания контакта
5.Протестировать на 5-10 контактах: создать вручную, проверить, что статус записывается
6.Добавить обработку ошибок: таймауты, retry, кэширование
7.Запустить bulk-проверку существующей базы
8.Настроить cron-задачу для ежемесячной переproверки
9.Создать сегмент в CRM: только контакты со статусом valid
10.Настроить мониторинг: alert, если webhook-обработчик не отвечает

Весь процесс - от получения API-ключа до работающего webhook-а - занимает 2-4 часа для опытного разработчика. Bulk-очистка базы в 10 000 контактов - ещё 30-40 минут, включая обновление статусов в CRM.

Валидация email в CRM - не разовая акция. Это процесс: проверка на входе, регулярная переproверка, сегментация по статусу. Адреса устаревают, и результат трёхмесячной давности ничего не гарантирует.

Результат интеграции измеряется просто: bounce rate рассылок до и после. Если до внедрения было 5-8%, а после стало меньше 2% - интеграция работает. Если bounce rate растёт через 2-3 месяца - сломалась регулярная переproверка. Метрика одна, и она не врёт.

Подключите валидацию к вашей CRM

Зарегистрируйтесь в uChecker, получите API-ключ и 30 бесплатных проверок для тестирования интеграции. Документация API - в руководстве для разработчиков.

Попробовать бесплатно
валидация email CRMинтеграция проверки emailBitrix24 email валидацияamoCRM проверка emailHubSpot email validationwebhook CRMbulk email validationAPI email валидации