Twenty CRM: self-hosted CRM, яку ми зробили пультом для AI-агентів

Більшість чіпляє AI-агента до CRM як чат-бота збоку. Ми зробили навпаки: CRM стала пультом, а агенти — виконавцями. Розповідаємо, що таке Twenty (open-source, self-hosted, AGPL), як під'єднати до неї агентів через REST/GraphQL і вебхуки, і показуємо на своїх кейсах — збагачення даних, аутріч і внутрішня автоматизація через чергу задач.

Twenty CRM: self-hosted CRM, яку ми зробили пультом для AI-агентів
Зміст статті

Коли кажуть «під'єднати AI до CRM», зазвичай мають на увазі чат-бота, який відповідає на питання поверх бази. Ми пішли іншим шляхом. У нас CRM — це не довідник контактів, а пульт: там лежить канонічний стан кожного процесу й черга задач, а агенти — виконавці, які ці задачі розбирають. Нижче — що таке Twenty, чому саме self-hosted, як під'єднати до неї агентів, і три наші кейси: збагачення даних, аутріч і внутрішня автоматизація.

Що таке Twenty CRM

Twenty — це open-source CRM, яку можна розгорнути на власному сервері. Її позиціонують як відкриту альтернативу Salesforce: та сама модель «компанії — люди — угоди — задачі», але код відкритий, а дані лежать у вашій базі, а не в чужій хмарі. Розгортання — через Docker Compose: сервер, фоновий воркер, PostgreSQL і Redis піднімаються одним стеком.

Технічно це TypeScript-застосунок: бекенд на NestJS із чергами BullMQ, PostgreSQL як сховище, Redis для черг і кешу, фронтенд на React. Для нас це знайомий стек без екзотики — те саме, на чому ми будуємо решту продуктів.

Ключова риса, через яку ми її взяли, — відкрита модель даних. Ви додаєте власні об'єкти й поля не «в обхід», а як першокласні сутності, і вони одразу стають доступні через API нарівні з вбудованими.

Що означає self-hosted — і чому це перевага

Self-hosted означає, що CRM працює на вашому сервері, а не на серверах вендора, і всі дані фізично у вас. Для бізнесу це три конкретні наслідки: дані клієнтів не залишають ваш периметр, немає щомісячної плати за кожного користувача, і ніхто не може підняти вам ціну чи закрити доступ до API за тарифом.

Ліцензія Twenty — GNU AGPL v3. Це та сама «вільна назавжди» ліцензія, що гарантує: код лишається відкритим, навіть коли хтось запускає його як хмарний сервіс. Self-hosted-версію не можна раптом зробити платною заднім числом.

Але тут потрібна точність, якої зазвичай не пишуть в оглядах: Twenty не є на 100% AGPL. Частина файлів позначена міткою @license Enterprise й виведена з-під AGPL під окрему комерційну ліцензію — це функції Enterprise Edition, для яких у продакшені потрібна платна підписка. Ядро відкрите й самодостатнє; але якщо вам потрібні саме enterprise-фічі, це вже не «безкоштовно назавжди». Плануючи впровадження, дивіться, що саме вам треба, а не лише на слово «open source».

Для нашого сценарію — CRM як пульт для агентів — вистачає відкритого ядра. Нам потрібні кастомні поля, кастомні об'єкти й API, а це AGPL-частина.

Який у Twenty API — і чому це головне для агентів

Twenty автоматично генерує REST і GraphQL API з моделі даних вашого воркспейсу — окремого «статичного» API немає, бо кожен воркспейс має власну схему. Додали кастомний об'єкт (скажімо, «Рахунок») — і він миттєво отримує REST- і GraphQL-ендпойнти, ідентичні до вбудованих «Компанія» чи «Людина».

API поділено на дві частини. Core API — це CRUD над записами: люди, компанії, угоди, задачі та ваші кастомні об'єкти, з фільтрами й обходом зв'язків. Metadata API — це керування самою схемою: створення й зміна об'єктів, полів і зв'язків програмно. Тобто агент може не лише читати й писати дані, а й формувати структуру під процес.

Автентифікація — за API-ключем, який ви створюєте в Settings → API & Webhooks. Агент кладе його в заголовок і працює з /rest/ або /graphql/ так само, як будь-який інший клієнт.

І остання деталь, яка робить із CRM саме пульт, а не пасивну базу: вебхуки. Twenty вміє слати повідомлення в реальному часі, коли запис створено чи змінено. Це означає, що агента можна не «опитувати щосекунди», а будити подією — новий лід, змінена стадія, закрита угода.

Наш підхід: CRM — пульт, агенти — виконавці

Ідея проста: стан живе в CRM, робота живе в задачах, а агент — це воркер, який бере задачу, робить її й пише результат назад. CRM стає єдиним джерелом правди, а агенти — взаємозамінними руками. Ось три сутності, на яких усе тримається.

  • Кастомне поле стану на компанії — канонічний статус процесу (наприклад, стадія ліда в аутрічі). Саме за ним іде дедуплікація й вирішується, що робити далі.
  • Нативний об'єкт Task — одиниця роботи: канал, ключ виконавця, статус (у черзі / в роботі / зроблено), час запуску, кількість спроб.
  • Ключ виконавця на задачі — маленьке поле, яке каже контролеру, якому саме агенту-скілу віддати цю задачу.

Найважливіший принцип: «задача виконана» — це не «успіх». Статус задачі каже лише, що її обробили; чи вдалося — записано у поле стану компанії. Це рятує від класичної пастки, коли «бот відпрацював» плутають з «результат досягнуто».

Практичний бонус такої схеми — розширюваність без переписування. Додати новий канал (скажімо, email поряд із месенджером) означає написати новий скіл-виконавець і новий ключ; контролер, який роздає задачі, не змінюється взагалі. Він лише дивиться на ключ і віддає задачу відповідному воркеру.

Кейс 1: задачі на збагачення даних

Збагачення — це коли агент бере записи з порожнім полем, знаходить значення й дописує назад, не чіпаючи вже заповнені. Класична рутина, яку вручну роблять місяцями, а вона все одно застаріває. У нашому воркспейсі так дозаповнюються контактні канали компаній.

Механіка проста й ідемпотентна: агент запитує через Core API компанії, де потрібне поле порожнє, обробляє їх пачками, а знайдене одразу пише в CRM. Якщо процес перервали — наступний запуск просто знову бере ті, що досі порожні. Стан у CRM, тому повторний запуск нічого не ламає й не дублює.

Конкретна цифра з нашого власного воркспейсу (база ~480 компаній): за один прохід збагачення ми підняли покриття одного контактного каналу приблизно з 34% до 50% записів. Це не куплена база — це дозаповнення того, що вже було, руками агента замість людини.

Кейс 2: аутріч через чергу задач

Аутріч у нас — це не скрипт, що «шле всім підряд», а контролер поверх черги задач у Twenty. Він працює у двох режимах: один будує чергу (створює задачі з робочого списку лідів, ідемпотентно — вже оброблені пропускає), другий її розбирає (бере задачі в статусі «у черзі» й віддає кожну виконавцю за ключем каналу).

Сам контролер не спілкується ні з ким — він лише читає й пише CRM і роздає задачі. Уся логіка конкретного каналу живе в окремому скілі-виконавці. Тому додати канал — це новий скіл, а не переробка контролера.

Дедуплікація йде за полем стану ліда, а не за фактом відправки: якщо стадія вже не «в черзі», задача просто закривається без дії. Є денний ліміт на холодні повідомлення, лічильник спроб і принцип «спершу переконайся, потім запиши» — стан оновлюється тільки після підтвердженої дії. А коли лід відповідає щось, у чому агент не впевнений, — задача не вигадує відповідь, а ескалюється до людини.

Головне тут — не автоматизація заради автоматизації, а те, що весь стан прозорий і живе в CRM. У будь-який момент видно, кому написали, хто відповів, що ескальовано й на якій стадії кожен лід. Це не «чорна скринька бота», а черга, яку можна відкрити й прочитати.

Як це узагальнюється на будь-яку внутрішню автоматизацію

Той самий каркас лягає майже на будь-який повторюваний внутрішній процес, а не лише на аутріч чи збагачення. Рецепт один: кастомне поле під стан, нативна задача під одиницю роботи, агент як виконавець і вебхук або розклад як тригер.

Під цю схему добре лягають онбординг нових клієнтів (стадії як поле, кроки як задачі), кваліфікація вхідних лідів, підготовка даних до дзвінка чи зустрічі, нагадування й перевірки статусів, синхронізація з іншими системами. Скрізь, де є «взяти щось у стані А, зробити дію, перевести в стан Б», CRM стає пультом, а агент — рукою.

Виграш не в тому, що «робот працює замість людини». Виграш у тому, що процес перестає бути невидимим. Стан не розсипаний по головах, чатах і табличках — він в одному місці, машиночитний, з історією. Людина в цій схемі не зникає: вона розбирає саме те, що агент позначив як «не впевнений» і ескалював.

Межі підходу: коли Twenty як пульт — зайве

Ця схема не безкоштовна в підтримці, і є випадки, коли вона надлишкова. Self-hosted означає, що сервер, бекапи й оновлення — на вас; якщо у вас немає кому це тримати, керована SaaS-CRM буде дешевшою за сумою зусиль. Якщо процесів мало й вони рідкісні, чергу задач будувати ні до чого — простий скрипт чи навіть ручна робота обійдуться дешевше.

Enterprise-функції Twenty, як ми зазначили вище, вимагають платної підписки — тож перед впровадженням варто звірити, чи не потрапляє щось із потрібного вам у цю частину. І сам підхід «CRM як пульт» окупається тоді, коли процесів багато й вони повторювані; на одному-двох він додає складності без відповідної віддачі.

Ми будуємо це там, де обсяг рутини реальний і зростає. На малих обсягах розумніша порада — почати з простого й ускладнювати, лише коли ручної роботи стане справді багато.