Code SDK: подключить FlowCastle к боту, который уже написан

Открытая middleware для Telegram-бота, который уже работает в коде. Какой пакет ставить, где взять ключ, минимальное подключение, API для хендлеров, режимы приватности и как проверить, что всё работает.

7 минут чтения·Обновлено: 2026-10-10

01SDK или визуальный редактор

  • Визуальный редактор. Бот собирается в редакторе FlowCastle, токен вы отдаёте FlowCastle, и бот работает на нашей стороне. Код не нужен. Начните с Создайте первого Telegram-бота за 10 минут.
  • Code SDK. Бот уже работает в коде, и вы хотите его оставить. Код, хостинг, polling или webhook остаются у вас. FlowCastle добавляет слой вокруг бота: контакты, живой диалог, рассылки, аналитику.
  • И то и другое. С runtime: { enabled: true } сценарии из редактора работают через вашего бота. Апдейт, который совпал с опубликованным триггером FlowCastle, обрабатывает сценарий, и до ваших хендлеров он не доходит. Двойных ответов не бывает. Всё остальное идёт в ваш код как раньше. Подробнее о триггерах: Триггеры: как запускается ваш бот.
  • Другой фреймворк или язык. Адаптера пока нет.

02Какой пакет ставить

ФреймворкСредаУстановкаИмпорт
grammY ≥ 1.20Node.js ≥ 18npm i @flowcastle/grammy @flowcastle/sdk-runtimeimport { flowcastle } from '@flowcastle/grammy'
Telegraf ≥ 4.16Node.js ≥ 18npm i @flowcastle/telegraf @flowcastle/sdk-runtimeimport { flowcastle } from '@flowcastle/telegraf'
aiogram 3.xPython ≥ 3.10pip install 'flowcastle[aiogram]'from flowcastle.adapters.aiogram import AiogramAdapter
python-telegram-bot 21–22Python ≥ 3.10pip install 'flowcastle[python-telegram-bot]'from flowcastle.adapters.python_telegram_bot import PythonTelegramBotAdapter

Оба Node-пакета требуют @flowcastle/sdk-runtime как peer-зависимость. npm 7 и новее ставит её сам, но надёжнее указать явно. Других зависимостей у Node-пакетов нет. Python-ядро использует только стандартную библиотеку, а фреймворк ставится как extra.

03Ключ

  1. Войдите в панель. Бесплатный тариф, карта не нужна.
  2. Откройте приложение (или создайте новое) и нажмите Добавить бота.
  3. Выберите Code SDK.

Окно «Добавить бота» в FlowCastle с вариантом Code SDK: подключите бота, который уже написан на grammY, Telegraf, aiogram или python-telegram-bot

Токен Telegram здесь не спрашивают. Назовите подключение и создайте его. Вы получите ключ fc_sdk_… и инструкцию под выбранную библиотеку.

SDK-бот создан: API-ключ, переключатель библиотек с выбранным grammY, команда установки и сниппет из трёх строк

Положите ключ в окружение рядом с BOT_TOKEN под именем FLOWCASTLE_API_KEY. Это секрет, в коде его не храните. BOT_TOKEN в FlowCastle не передавайте никогда.

04Минимальное подключение

Два правила порядка, одинаковые для всех библиотек:

  • Подключайте FlowCastle раньше остальных хендлеров, чтобы он видел каждый апдейт.
  • Вызывайте ready() до запуска polling или webhook. Этот вызов загружает триггеры опубликованных сценариев. Без него первый подходящий апдейт может уйти в ваш хендлер.

grammY:

import { Bot, Context } from 'grammy';
import { flowcastle, FlowCastleFlavor } from '@flowcastle/grammy';

type BotContext = FlowCastleFlavor<Context>;           // adds ctx.flowcastle
const bot = new Bot<BotContext>(process.env.BOT_TOKEN!);

const fc = flowcastle<BotContext>({
  apiKey: process.env.FLOWCASTLE_API_KEY!,
  privacy: {},                                          // see Privacy below
  runtime: { enabled: true },                           // only if no-code flows should run through this bot
  onError: (e) => console.error('[flowcastle]', e),
});
bot.use(fc);                                            // BEFORE other handlers

// ...existing handlers unchanged...

await fc.ready();
bot.start();
// on shutdown: await bot.stop(); await fc.flush(); fc.destroy();

aiogram 3:

import asyncio
import os

from aiogram import Bot, Dispatcher
from aiogram.filters import CommandStart
from aiogram.types import Message
from flowcastle import FlowCastleContext, FlowCastleCore, FlowCastleOptions
from flowcastle.adapters.aiogram import AiogramAdapter

core = FlowCastleCore(FlowCastleOptions(
    api_key=os.environ['FLOWCASTLE_API_KEY'],
    privacy={},
    runtime_enabled=True,
))
adapter = AiogramAdapter(core)
dp = Dispatcher()

# handlers receive the context by argument name `flowcastle`:
@dp.message(CommandStart())
async def start(message: Message, flowcastle: FlowCastleContext) -> None:
    await flowcastle.identify({'displayName': message.from_user.full_name})

async def main() -> None:
    bot = Bot(os.environ['BOT_TOKEN'])
    await adapter.ready()
    adapter.install(dp)                                 # registers an outer middleware on dp.update
    dp.shutdown.register(adapter.stop)                  # final flush
    await dp.start_polling(bot)

asyncio.run(main())

Для Telegraf и python-telegram-bot всё устроено так же. В Telegraf добавляется fc.wrapTelegram(bot.telegram), чтобы SDK видел вызовы bot.telegram.* вне middleware. В python-telegram-bot adapter.install(application) вызывается до всех add_handler. Полные примеры: README для Telegraf и README для Python. У пакета для grammY тоже есть свой README.

С webhook всё работает так же.

Бот не ждёт FlowCastle. Событие попадает в очередь в памяти, хендлер выполняется сразу. Очередь ограничена 500 событиями, при переполнении самые старые вытесняются. Отправка идёт пачками раз в три секунды, при ошибке одна повторная попытка. Если FlowCastle недоступен, вы теряете часть аналитики, а пользователи ничего не замечают.

05Что вызывать из хендлеров

В контексте появляется небольшой API: ctx.flowcastle в Node, аргумент flowcastle в aiogram, context.flowcastle в python-telegram-bot.

ЗадачаNode (ctx.flowcastle.)Python (flowcastle. / context.flowcastle.)
Отметить цель (конверсию или шаг воронки)goal(key, props?)await goal(key, props=None)
Записать свойства контакта для CRMidentify(props)await identify(props)
Передать чат оператору в живой диалогrequestLiveAgent({ note? })await request_live_agent(note=None)
Ведёт ли сейчас чат человек?isLiveAgentActive (только Node)нет
Запустить сценарий из редактораawait runFlow(flowKey, { inputs? })await run_flow(flow_key, inputs=None)

Что важно знать:

  • goal, identify и requestLiveAgent ставятся в очередь и хендлер не тормозят. Им нужен отправитель апдейта. Если его нет, вызов пропускается, а ошибка уходит в onError.
  • Имена целей ваши: lead_qualified, order_paid, из чего у вас состоит воронка. Свойства передаются плоским JSON-объектом. Передайте числовое value, и в аналитике появится выручка.
  • Свойства из identify не проходят через фильтр приватности. Не кладите туда сырой текст сообщений.
  • isLiveAgentActive даёт подсказку, а не точный ответ: это окно на 30 минут, которое открывает запрос и продлевает каждый ответ оператора. Пока оно открыто, автоответы можно отключить: if (ctx.flowcastle.isLiveAgentActive) return;. В Python SDK этого поля нет, там проверку пропустите.
  • runFlow ждёт ответа сервера и возвращает id запуска. Без включённого runtime он выбрасывает ошибку. Сценарий должен быть опубликован и отмечен в панели как доступный из SDK. Оборачивайте вызов в try/catch.

Ответ оператора из живого диалога уходит пользователю через процесс вашего бота. Список методов Bot API, которые сервер может попросить выполнить, короткий и зашит в SDK. Всё, что касается токена, webhook и polling, отклоняется всегда.

06Приватность

Фильтрация идёт внутри вашего процесса, до того как что-то попадёт в очередь или уйдёт наружу.

  • privacy: {} включает режим по умолчанию, только маршрутизацию. Команды и id нажатых кнопок передаются, текст сообщений нет. У контакта будет только id в Telegram.
  • contactFields задаёт поля профиля, которые можно передавать, например contactFields: ['username', 'languageCode']. Тогда контакты в CRM можно узнать по имени.
  • messageContent: 'full' включает передачу текста. Нужно, если сценарии FlowCastle читают, что пишут люди: ИИ-ответы, триггеры по ключевым словам, ожидание ответа.
  • В transformText вы передаёте свою функцию, которая вычищает текст ещё в вашем процессе, например почту или номера карт. Упала или не уложилась в таймаут (по умолчанию 1 секунда), поле не уйдёт вовсе.

В Python те же параметры называются contact_fields, message_content и transform_text.

Передавайте privacy всегда. Если параметр не указан, SDK работает по-старому и отправляет текст сообщений целиком.

07Как проверить

  1. Код проходит проверку типов или импортируется: tsc --noEmit или python -c "import bot".
  2. Выводите ошибки через onError и запустите бота. Если за 10 секунд нет ошибок [flowcastle], ключ принят. Неверный ключ даёт 401 примерно через 3 секунды после первого апдейта.
  3. Напишите боту /start. Через несколько секунд пользователь появится в Контактах, а SDK-бот будет отмечен как подключённый.
  4. Если добавили goal, вызовите его. Цель должна появиться в карточке контакта и в аналитике целей.
  5. Если включили runtime, опубликуйте сценарий с триггером на /команду, которой нет в вашем коде. Отправьте её: ответит FlowCastle, а команды из кода продолжат работать.
  6. Остановите процесс через SIGINT (Ctrl+C). Он должен завершиться чисто, без зависания.

08Что почитать дальше

Попробуйте в своём боте

Соберите это на бесплатном тарифе, пока шаги свежи в памяти. Карта не нужна.

SDK на GitHub