Попробовать API
</>
Quickstart, триал-как-sandbox и партнёрские sub-проекты
sdkКейс
14 мин

Quickstart, триал-как-sandbox и партнёрские sub-проекты

TL;DR: первая интеграция BOTIX в реальном агентстве заняла у разработчика 38 минут — мы рассчитывали на 5. За квартал время «регистрация → первый успешный запрос» упало до 4-7 минут. Три решения, которые это дали: quickstart как отдельный артефакт с ключом на первом экране, триал на той же production-инфраструктуре вместо отдельного sandbox, и один partner-key, который превращает пять минут агентства в десятки клиентских проектов.

Коротко

  • Quickstart — не короткая документация, а отдельный артефакт. Ключ выдаётся на той же странице, первый блок кода виден без скролла, snippet с реальными значениями (curl + PHP/Python/Node). Между копированием кода и ответом — ноль промежуточных шагов.
  • Отдельный sandbox не нужен — его роль играет триал на проде. Тот же контур, те же миграции, те же валидаторы и заголовки; отличия только в лимитах (api_rate_per_minute 30 против 2000), флаге api_write_enabled и сроке 14 дней. Класс ошибок «в sandbox работало, в проде нет» исчезает.
  • Партнёрский слой закладывается заранее. Один partner-key + sub-проекты через API: агентство создаёт клиента одним POST за секунды, а не регистрирует 47 аккаунтов вручную. Изоляция — Auth::assertProjectAccess() + WHERE project_id = ? в каждом запросе.

BOTIX — российская SaaS-платформа AI-ассистентов. Public API v1.1.0, база — https://api.botix.pro, эндпоинты под префиксом /public/v1/*, документация на developers.botix.pro, репозитории — github.com/BOTIX-pro. Ниже — не про «купите рекламу, чтобы привести разработчика», а про то, как убрать трение в первые две минуты, чтобы разработчик вернулся сам и рассказал коллегам. Три связанных решения — по одному на каждый узел developer experience: первый запрос, тестовая среда, масштабирование интегратора.

Узкое горлышко: первая встреча с API

Любой публичный API проходит через одно узкое горлышко — первую встречу с разработчиком. У неё нет второго шанса. Если человек тратит больше пяти-десяти минут на первый осмысленный запрос и не видит ответа — он закрывает вкладку. Это не лень, а фокус: он пришёл проверить гипотезу «подходит ли этот API под мою задачу», и каждая лишняя минута увеличивает шанс, что гипотеза не проверится вовсе.

Что дала первая итерация онбординга — та самая, на которой агентство мучилось 38 минут:

  1. Регистрация по email + подтверждение через ссылку. 1-3 минуты, иногда 10 (письмо в спаме).
  2. Логин, мастер настройки бота: выбор ниши, профиль бизнеса, подключение Telegram через token, импорт каталога. 15-25 минут.
  3. Поиск раздела API — он назывался «Интеграции» и был спрятан в третьем уровне меню. 1-2 минуты.
  4. Генерация ключа, копирование, переключение в IDE, первый запрос с подсматриванием в документацию. 5-15 минут.
  5. Первый запрос. Часто INVALID_API_KEY / 401 (не тот формат заголовка). Дополнительные минуты на отладку.

Итого около 38 минут на медиану. Для владельца барбершопа, пришедшего «сделать бота», — нормально: мастер и есть его продукт. Для разработчика, пришедшего проверить «подходит ли API», — катастрофа. Дальше — три раздела, каждый снимает одну из этих точек трения.

Решение 1. Quickstart как отдельный артефакт (тезис 06)

Документация отвечает на вопрос «как устроена система». Quickstart — на «как мне получить первый ответ прямо сейчас». Разные жанры, разная структура. Документацию читают последовательно и возвращаются к ней; quickstart читают один раз, по диагонали. Не увидел блок кода при пролистывании — ушёл.

Признаки правильного quickstart, которые легко проверить визуально:

  • Первый блок кода виден без скролла, на первом экране после заголовка.
  • API-ключ выдаётся прямо на этой же странице. Не «зарегистрируйтесь, подтвердите email, дождитесь письма, создайте проект, найдите вкладку API».
  • Snippet содержит реальные значения, а не плейсхолдеры YOUR_API_KEY или https://api.example.com.
  • Есть переключатель языка: curl и два-три популярных языка с SDK.
  • Между копированием кода и видимым результатом нет промежуточных шагов.

В обычном онбординге BOTIX триал начинается с мастера: ниша, профиль бизнеса, Telegram, каталог, приветственный сценарий. Владельцу бизнеса это нужно — его задача увидеть работающего бота под свою нишу. Разработчику это препятствие: он хочет понять форматы запросов и ответов, а не настраивать ассистента. Поэтому после регистрации с пометкой «я разработчик» (флаг is_developer_trial в проекте) система обходит мастер и открывает /developers/quickstart: выданный API-ключ (показанный один раз), четыре snippet-таба для curl, PHP, Python, Node; ссылки на полную документацию и Swagger UI на developers.botix.pro/try-it.

Первый snippet — curl, работает в любом терминале без установки SDK:

bash
curl -X POST https://api.botix.pro/public/v1/contacts \
  -H "Authorization: Bearer XXXXXXXX" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+79991234567","name":"Test"}'

Тот же запрос в Python через SDK:

python
from botix import Client

client = Client(api_key="XXXXXXXX")
contact = client.contacts.create(phone="+79991234567", name="Test")

Никаких предварительных шагов, никакого выбора ниши. Триал должен решать вопрос «совместим ли API с моими нуждами», а не «умеете ли вы пользоваться платформой». То, что оба snippet генерируются из одной спецификации и не расходятся с curl, — отдельная тема: почему SDK лучше генерировать из OpenAPI, а не писать руками.

Одноразовый показ ключа — компромисс. Стандартный паттерн: показать ключ один раз, дальше хранить только хеш. Если база утечёт, восстановить рабочие ключи невозможно (по дизайну — потерянный ключ мы не восстанавливаем, только перевыпускаем). Но для quickstart это трение: скопировал, получил 401, переключил окна, потерял ключ. Компромисс BOTIX: ключ показывается один раз, но рядом кнопка «Перевыпустить» (аннулирует старый и сразу показывает новый). Правило «не хранить ключ в открытом виде в БД» сохранено, трение убрано.

Что должно быть в первом ответе. Первый запрос почти всегда заканчивается одним из четырёх исходов, и каждый требует подсказки:

  • 200 — возвращённый объект с полями (id, время создания, статус), а не голый {"id":123}.
  • 401 — явный код, что не так с ключом: MISSING_API_KEY, INVALID_API_KEY, KEY_REVOKED. Без этого разработчик гадает.
  • 422 — список ошибок валидации по полям с указанием конкретного поля.
  • 5xx — уникальный идентификатор запроса, который можно приложить к обращению в поддержку.

Что отрезали осознанно. В жанре quickstart допустимо не рассказывать про все коды ошибок (отдельная страница developers.botix.pro/error-codes), webhook-подписи (гайд на best-practices), OAuth (developers.botix.pro/oauth), идемпотентность в деталях (на quickstart одна строка: «обязательный заголовок Idempotency-Key, генерируйте UUIDv4; ключ действует 24 часа»), версионирование (developers.botix.pro/versioning). Каждая тема критична для production, но не для первого запроса — иначе страница раздувается и теряет жанр.

Решение 2. Триал на production-инфраструктуре (тезис 08)

Когда у платформы появляется публичный API, почти автоматически принимается решение: «нужен sandbox» — отдельный домен sandbox.api.example.com, база, ключи, панель, CI-пайплайн. Проблема в том, что любой второй контур — не половина прода, а отдельный продукт со своей жизнью, расходящейся с продом. Расходы больше, чем кажется на старте:

  • Дублирование инфраструктуры. Свои серверы БД, очередей, кеша, воркеров. Стоят денег. Экономишь — sandbox отдаёт другие тайминги, тесты становятся ненадёжными.
  • Дублирование миграций и фич. Любая новая фича — в оба контура. Команда забывает. Через полгода в sandbox устаревшие поля, неработающие endpoint'ы, отдельный тикет «синхронизировать sandbox с prod».
  • Дублирование тестовых данных. Тоже устаревают: формат меняется, ссылочная целостность ломается из-за наполовину применённых миграций.
  • Расхождение поведения. Самый болезненный пункт. Sandbox считается «безопасным» — в нём отключают часть проверок: rate-limit послабее, fraud-фильтры выключены, валидация мягче. Интеграция работает в sandbox, переключается на prod — падает на первом запросе. Это не лень разработчика, а архитектурное расхождение, заложенное командой платформы.

Подход BOTIX иной. Отдельного sandbox нет. Триальный кабинет физически живёт на том же production-контуре, но с жёсткими лимитами и флагами, ограничивающими побочные эффекты:

  • Триальный проект пишет в ту же базу, что и платный.
  • Запросы идут через те же FPM-воркеры, FastAPI-сервисы, Redis-очередь.
  • Те же миграции, фичи, логика обработки ошибок.
  • Те же rate-limit-лимиты (просто значения ниже), те же коды ошибок, те же заголовки в ответе.

Различия только в трёх местах:

  1. Лимиты тарифа. api_rate_per_minute для триала — 30/мин, для бизнеса — 2000/мин; api_rate_per_day — от 1000 до 1000000. Логика одна: тот же механизм rate-limit, что увидят пользователи на проде, просто с более жёстким порогом. Лимиты хранятся в JSON limits каждого тарифа (config/plans.php + btx_plans.limits), читаются через PlanService::getLimit().
  2. Toggle on-write операций. У триала api_write_enabled = false — все POST/PUT/DELETE возвращают 403 TRIAL_READ_ONLY. Удобно для смоук-тестов: прогнать чтение без риска что-то изменить. Тот же тогл доступен и платным клиентам.
  3. Срок жизни. Триал — 14 дней. После — read-only до оплаты. Не успел протестировать — заводишь второй триал или оплачиваешь минимальный тариф.

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

  • «Поле было в sandbox, в проде нет» — невозможно, контур один.
  • «В sandbox 200, в проде 422» — невозможно, валидаторы те же.
  • «Webhook в sandbox отправляется, в проде нет» — невозможно, код обработчика тот же.
  • «Заголовок rate-limit другого формата» — невозможно, middleware один.

Граница между триалом и продом — не в инфраструктуре, а в данных и правах. Триальный проект — просто запись в btx_projects с флагом is_developer_trial = true и тарифом «триал» со своими значениями в JSON limits. API-ключ триала видит только данные своего проекта. Чужие данные защищены той же логикой Auth::assertProjectAccess(), что и у платных клиентов. Идея «безопасной среды» реализуется не через изоляцию инфраструктуры, а через изоляцию проекта — и это правильный уровень. Где ещё встают решения этого класса (хранение ключей, polling или webhook), разбирается отдельно: архитектура интеграции без второго контура.

Сравнение по затратам команды:

Затратаdev/staging/prodТриал-как-sandbox
Серверых2-х3х1
МиграцииКаждую применить дваждыОдин раз
Тестовые данныеПоддерживать отдельноНе нужны
Документация«Различия между sandbox и prod»Не нужна
Тикеты «в sandbox работает, в prod нет»РегулярноНе возникают

Где подход неприменим. Отдельный sandbox оправдан для: финансовых операций с реальным движением денег (тестовые карты или test_mode флаг на уровне ключа), действий с побочными эффектами на третьих лиц (SMS, push, email на боевые номера), тяжёлых операций с физическим миром (промышленное оборудование, доставка грузов). У нас все три обходятся флагами в модулях: у bot-preview есть $context['preview']=true — пишет в лог, но не отправляет реальное сообщение в Telegram. Это снимает риск побочных эффектов без второго контура.

Решение 3. Партнёрские sub-проекты — масштабирование интегратора (тезис 19)

Третий уровень DX, который мало кто делает заранее. Сценарий: агентство пробует API в триале, делает первый запрос за пять минут, видит, что работает. Дальше задача — масштабировать на 47 клиентов. Если нужно зарегистрировать 47 отдельных аккаунтов — это 5 минут × 47 ≈ 4 часа скучной работы, и половина агентств в этой точке отваливается.

У прямого клиента контур простой: один аккаунт, один проект, несколько ключей, один webhook. У партнёра — многоуровневый: сам партнёр имеет аккаунт у поставщика, внутри него десятки или сотни конечных клиентов, у каждого свой логический проект со своими данными, биллингом, webhook'ом. Пытаться удовлетворить это тем же API, что и обычных клиентов, — путь к ошибкам: обычный ключ работает в контексте одного проекта, партнёрский должен работать в контексте партнёрского аккаунта и переключаться между конечными.

Альтернатива вместо четырёх часов ручной регистрации — партнёрский аккаунт + sub-проекты. У агентства один аккаунт BOTIX, в нём отдельный тип ключа (partner-key) с правом создавать sub-проекты через API. Для каждого нового клиента — один POST:

bash
curl -X POST https://api.botix.pro/public/v1/partner/projects \
  -H "Authorization: Bearer XXXXXXXX" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name":"Барбершоп на Тверской","plan":"start"}'

В ответе — новый project_id, новый API-ключ, готовый webhook-секрет. 5 секунд вместо 5 минут на каждого клиента.

Минимальный набор возможностей, без которого партнёрская модель не собирается:

  • Партнёрский уровень аутентификации. Отдельный тип ключа (partner-key) с более высокими привилегиями, чем у обычного project-key: создавать проекты, перечислять существующие, получать ключи. Обращение к партнёрским эндпоинтам обычным ключом возвращает 403 INSUFFICIENT_SCOPE.
  • Sub-проекты под одним аккаунтом. Иерархия: партнёр сверху, набор конечных проектов снизу, у каждого свои данные, webhook, биллинг.
  • Сырые usage-данные через API. Партнёр биллит конечных клиентов по своей модели: ему нужны количество запросов, сообщений, активных контактов по каждому sub-проекту за период — отдельным эндпоинтом или webhook-событием в конце расчётного периода.
  • Audit-логи на партнёрском уровне. Когда конечный клиент пишет «не работает», партнёр диагностирует сам, не привлекая поставщика; доступ к журналу по sub-проектам регулируется тем же partner-ключом.

Изоляция данных — критическая граница. Внутри одного партнёрского аккаунта могут быть sub-проекты конкурирующих компаний. Защита на трёх уровнях: на уровне БД — WHERE project_id = ? в каждом запросе; на уровне API — явный project_id в каждом запросе и проверка, что он принадлежит партнёрскому аккаунту, выпустившему ключ; на уровне ключей — нельзя получить ответ по одному sub-проекту, передав ключ другого. В BOTIX Auth::assertProjectAccess($projectId) вызывается в начале каждого эндпоинта, работающего с проектом; партнёрский слой добавляет проверку, что sub-проект принадлежит выпустившему ключ аккаунту.

Чего не делать. Не навешивать партнёрские возможности на обычные эндпоинты через флаги «если ты партнёр, можешь передать ещё этот параметр» — запутанная семантика; лучше отдельный префикс. Не делать партнёрский API «по запросу» только избранным по NDA — работает, пока партнёров три; на двадцати начинаются разные SLA и теневая документация. Не ставить высокий минимальный объём для входа — из маленьких команд вырастают крупные.

Метрика, которая отвечает «работает ли quickstart»

Единственный полезный показатель — медианное время от просмотра quickstart до первого успешного API-запроса с того же ключа. У нас это поле time_to_first_api_call в таблице btx_developer_funnel. Текущая медиана — 4-7 минут (было 38). Меньше пяти — quickstart работает. Больше — трение, ищется через сессионные логи. Другие метрики (просмотры, время на странице, прокрутка) вторичны: quickstart нужен не для того, чтобы его читали, а для того, чтобы после него был работающий запрос.

Что отвергли по дороге

  • Sandbox-окружение с отдельной БД — отказались в пользу триала на проде.
  • Регистрация через подтверждение email до выдачи ключа. Для триала с is_developer_trial подтверждение отложено: ключ выдаётся сразу, email подтверждается фоном до конца триала. Не подтверждён за 14 дней — триал замораживается.
  • API-ключ только через настройки кабинета. На quickstart ключ выдан сразу; разделы «Настройки → API» доступны позже для управления списком ключей.
  • Один уровень тарифа в триале с урезанными фичами — создаёт расхождение «работает в триале, не в проде». В триале доступны все фичи (bulk-endpoints, OAuth, webhook), просто с жёсткими лимитами. Флаги is_trial / write_enabled — не специальные исключения, а часть общей механики тарифов, работающей у всех клиентов одинаково.

Тенденция в индустрии

Stripe в 2010-х задал стандарт quickstart за 60 секунд. Триал на production-инфраструктуре — следующая волна: Vercel, Render, Supabase делают именно так. Партнёрская модель с sub-проектами через API — стандарт Stripe Connect, GitHub Apps, Shopify Partners; на российском рынке пока редкость. Открытые SDK как канал доверия и снижения интеграционного трения — та же логика: зачем компании open-source-ить SDK.