Обсудить задачу

Kommo + Airtable: синхронизация сделок без Zapier

Синхронизация между Kommo и Airtable работает через прямую связку: webhook Kommo при смене статуса сделки -> ваш middleware -> Airtable REST API (POST/PATCH /v0/{baseId}/{tableIdOrName}/records). Обратное направление - Airtable Automation -> ваш endpoint -> Kommo API PATCH /api/v4/leads/{id}. Нативной двусторонней интеграции между этими платформами нет; no-code мосты вроде Zapier или Albato не дают нужной гибкости при объёме от 500+ сделок в месяц.

Операционная команда ведёт базу проектов в Airtable: там сроки, ответственные, статусы онбординга. Продажи закрывают сделки в Kommo. В какой-то момент данные расходятся: менеджер двигает сделку в «Выиграна» - операционщик не видит, пока кто-то вручную не обновит строчку в Airtable. Или наоборот: клиент подписал акт в Airtable - продавец об этом узнаёт из мессенджера, не из CRM.

В проектах Exceltic.dev этот сценарий встречается стабильно у компаний от 15 человек, где продажи и операционный трек ведутся в разных инструментах. Статья описывает конкретную архитектуру двусторонней синхронизации и реальные параметры API, которые нужно знать до начала разработки.

Почему нативной интеграции нет

Kommo не предлагает встроенного коннектора к Airtable. Airtable Marketplace содержит интеграции с Salesforce и HubSpot, но не с Kommo. Это не случайность: Airtable позиционирует себя как гибкая база данных, а не как CRM-экосистема, поэтому партнёрские интеграции идут в сторону enterprise-стека.

Но главная проблема не в отсутствии коннектора. Проблема в том, что даже если бы он существовал, он не закрывал бы двусторонний сценарий с настраиваемой логикой:

  • Маппинг полей между Kommo (custom_fields_values) и Airtable (fields object) нетривиален: типы данных, enum-значения этапов воронки, мультиселекты - всё это требует преобразования.
  • Zapier и Make передают данные через polling или простой webhook, но не поддерживают идемпотентные upsert-операции по внешнему ключу. При сбое или дублировании события в Airtable создаётся дублирующая запись.
  • Бизнес-логика часто сложнее, чем «поле A -> поле B»: нужно обновить Airtable только при определённых статусах, обогатить запись данными из третьего источника, или не синхронизировать тестовые сделки.

Upsert - операция, которая обновляет запись если она существует, или создаёт новую если нет. В Airtable API это параметр performUpsert с fieldsToMergeOn - ключевое поле для идемпотентности.

Что реализуется

Kommo webhook -> ваш endpoint -> Airtable API upsert по external_id

Kommo отправляет webhook при смене этапа сделки (leads.status в payload). Ваш middleware принимает POST в формате x-www-form-urlencoded, извлекает id сделки, запрашивает полные данные через GET /api/v4/leads/{id}, формирует объект fields для Airtable и вызывает PATCH https://api.airtable.com/v0/{baseId}/{tableIdOrName}/records с параметром performUpsert.

Ключ идемпотентности - kommo_deal_id, хранящийся в Airtable как обычное числовое поле. В запросе:

{
  "records": [
    {
      "fields": {
        "Kommo Deal ID": 123456,
        "Deal Name": "Acme Corp - Enterprise",
        "Stage": "Negotiation",
        "Amount": 15000,
        "Manager": "Ivan Petrov"
      }
    }
  ],
  "performUpsert": {
    "fieldsToMergeOn": ["Kommo Deal ID"]
  }
}

Airtable вернёт в ответе createdRecords или updatedRecords - по этому признаку можно логировать результат. Авторизация: заголовок Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN. Лимит: 5 запросов в секунду на базу, при превышении - HTTP 429, нужен exponential backoff с паузой от 30 секунд.

Kommo webhook настраивается в разделе Settings -> Integrations -> Web hooks. Выбираете событие «Lead stage (status) changed», указываете URL вашего endpoint. Payload приходит в x-www-form-urlencoded, обрабатывать нужно синхронно - ответ в течение 2 секунд, иначе Kommo повторит попытку (до 5 раз).

Обратная синхронизация: Airtable Automation -> ваш endpoint -> Kommo API update deal

Airtable поддерживает встроенные Automations: триггер по изменению поля + действие Send HTTP request. Когда операционная команда обновляет статус в Airtable (например, «Onboarding Complete»), срабатывает automation и отправляет JSON на ваш endpoint.

Endpoint принимает данные, маппирует их в Kommo custom fields и вызывает:

PATCH https://{subdomain}.kommo.com/api/v4/leads/{id}

С телом:

[
  {
    "id": 123456,
    "custom_fields_values": [
      {
        "field_id": 789012,
        "values": [{"value": "Onboarding Complete"}]
      }
    ]
  }
]

Kommo API использует OAuth 2.0 или долгоживущий Integration Token. field_id - числовой ID кастомного поля, который нужно получить заранее через GET /api/v4/leads/custom_fields.

Идемпотентность и защита от дублей

Оба направления должны быть идемпотентны: повторный вызов с теми же данными не должен создавать дубль и не должен вызывать ошибку.

Для Airtable это обеспечивает performUpsert - при повторном webhook от Kommo запись просто обновится. Для Kommo PATCH-запрос по существующему id - тоже идемпотентен по природе.

Дополнительная защита: хранить last_event_ts последнего обработанного события и пропускать события со старым timestamp. Это закрывает сценарий, когда Kommo повторно отправляет webhook после таймаута.

Пошаговая схема

  1. Kommo webhook - Settings -> Integrations -> Web hooks -> событие «Lead stage (status) changed» -> URL вашего middleware
  2. Middleware получает payload - парсит x-www-form-urlencoded, извлекает leads[status][0][id] и leads[status][0][status_id]
  3. GET /api/v4/leads/{id} - запрашивает полные данные сделки: название, сумму, ответственного, кастомные поля
  4. Маппинг полей - конвертирует status_id Kommo в строковое значение для Airtable, числовые поля -> числа, текст -> текст
  5. PATCH Airtable - https://api.airtable.com/v0/{baseId}/{tableId}/records с performUpsert по полю Kommo Deal ID. Авторизация через Authorization: Bearer PAT_...
  6. Логирование результата - createdRecords vs updatedRecords в ответе Airtable, retry при HTTP 429
  7. Airtable Automation - триггер по изменению нужного поля -> Send HTTP request -> ваш endpoint
  8. Обратный маппинг - endpoint принимает Airtable payload, формирует custom_fields_values для Kommo
  9. PATCH /api/v4/leads/{id} - обновляет сделку в Kommo по kommo_deal_id из Airtable
  10. Дедупликация - проверка timestamp, игнорирование устаревших событий

Инфраструктура: любой простой HTTP-сервер (Python/FastAPI, Node.js/Express, Go). Хостинг - Railway, Render, или Lambda-функция. Данных немного - 1 запрос на событие, при 100 сделках в день это около 200 API-вызовов суммарно, хорошо в пределах лимитов.

Реальный кейс с цифрами

Компания из 22 человек - продажи работают в Kommo, операционная команда (онбординг, проектное управление) ведёт Airtable. До интеграции: синхронизация вручную занимала 30-45 минут в день у двух сотрудников, задержка передачи данных - от нескольких часов до суток, систематические ошибки в суммах сделок (разные форматы ввода в двух системах).

После запуска кастомной синхронизации через Exceltic.dev:

  • Задержка между сменой статуса в Kommo и обновлением в Airtable - до 5 секунд (время обработки webhook + API-вызов)
  • Ручное время на синхронизацию - 0 (задачу не нужно выполнять)
  • Дублей при тестировании на 2000 событиях за первый месяц - 0, благодаря performUpsert и дедупликации по timestamp
  • Срок разработки и запуска - 3 недели, включая маппинг кастомных полей, настройку Airtable Automations и тестирование

Отдельно решили задачу «фильтрации»: тестовые сделки и сделки с тегом «internal» не синхронизируются в Airtable - это бизнес-логика, которую no-code инструмент не реализует без дополнительных ухищрений.

Для кого актуальна эта интеграция

Архитектура имеет смысл для компаний, где:

  • Продажи ведутся в Kommo, операционный трек (онбординг, доставка, проектное управление) - в Airtable
  • Объём сделок от 50+ в месяц, при котором ручная синхронизация ощутимо дорога
  • Нужна двусторонняя связь: Kommo должен видеть обновления из Airtable, и наоборот
  • Уже пробовали Zapier или Make, но не устроила стоимость при объёме, или возникали дубли/потери при сбоях

Меньше подходит, если синхронизация нужна только в одну сторону и без сложного маппинга - там Zapier может закрыть задачу дешевле.

Смежные сценарии, которые мы реализовывали: Kommo + Google Sheets с аналогичной логикой upsert, и Kommo + Jira для передачи задач между командами. Общий принцип один и тот же - middleware с идемпотентной записью по внешнему ключу.

Если вы хотите понять, какие инструменты для кастомных интеграций вообще существуют в экосистеме Kommo - читайте обзор кастомных интеграций для Kommo CRM, там описаны паттерны и ограничения.

Термин: Personal Access Token (PAT) - токен авторизации в Airtable API, заменивший старый API Key. Создаётся в разделе airtable.com/account, передаётся в заголовке Authorization: Bearer PAT_..., имеет настраиваемые scopes.

Часто задаваемые вопросы

Нужен ли сервер для этой интеграции?

Да, нужен промежуточный endpoint - ваш middleware. Это не обязательно полноценный сервер: подойдёт Lambda-функция (AWS, Cloudflare Workers) или простое приложение на Railway/Render. Бесплатных tier у этих платформ хватает для 100-300 запросов в день. Полностью serverless-подход работает хорошо: функция запускается только при входящем webhook, стоимость близка к нулю при умеренном объёме.

Что будет, если Kommo отправит webhook, а Airtable не ответит?

Kommo повторяет доставку до 5 раз с нарастающим интервалом. Если ваш endpoint не ответил кодом 200-299 в течение 2 секунд, Kommo попробует ещё раз. Со стороны Airtable: если вы получаете HTTP 429 (превышение лимита 5 req/s), реализуйте exponential backoff - ждите 30+ секунд перед повтором. В типовом проекте достаточно очереди на 10-20 событий и retry-логики на 3 попытки.

Можно ли синхронизировать не все сделки, а только определённые?

Да, это стандартная часть middleware-логики. Webhook от Kommo приходит по всем сделкам в аккаунте, но ваш код фильтрует по pipeline_id, status_id, тегам или кастомным полям. Например, синхронизировать только сделки из воронки «Enterprise» или только при переходе в статусы «Выиграна» и «В работе». Это невозможно настроить на стороне самого Kommo webhook - только на уровне обработчика.

Как получить field_id кастомных полей в Kommo?

Через API: GET https://{subdomain}.kommo.com/api/v4/leads/custom_fields - вернёт список всех кастомных полей с их id, name и type. Это нужно сделать один раз в начале проекта и зафиксировать маппинг. Поля не меняют ID при переименовании, так что маппинг стабилен.

Поддерживает ли Airtable API работу с вложениями и связями между таблицами?

Да. Вложения (attachments) передаются как массив объектов с url. Связи между таблицами (linkedRecord) - как массив record ID из связанной таблицы. Для большинства сценариев синхронизации с Kommo эти типы не нужны: достаточно текстовых полей, чисел и single select. Если нужна связь с таблицей клиентов - синхронизируйте контакт отдельным вызовом и передавайте его record ID в поле сделки.

Что делать дальше

Если у вас сейчас:

  • Операционная команда и продажи работают в разных инструментах и данные расходятся
  • Пробовали Zapier/Make - дорого при объёме или возникали дубли
  • Нужна двусторонняя синхронизация с нестандартной логикой фильтрации

Опишите задачу команде Exceltic.dev. Разберём ваш стек: какие поля нужно синхронизировать, в каких направлениях, какой объём событий. Оценим объём работ и предложим конкретную архитектуру.

Техническая документация, если хотите разобраться самостоятельно: Airtable Web API и Kommo Webhooks.

Ещё статьи

Все →