#Аутентификация и права
Статус: Доступно — ключи, области, права, список IP. Планируется — тестовые ключи и песочница.
Назначение: как устроены интеграции и ключи, что означают области, как вычисляются фактические права запроса, как ротировать и отзывать ключи и что делать при утечке.
#Модель: арендатор → интеграция → ключи
Арендатор
└── Интеграция «Моя CRM» (служебная учётная запись, без входа в кабинет)
├── роль интеграции (набор прав)
├── Ключ A (области, срок, список IP, режим)
└── Ключ B (выпущен при ротации; Ключ A доживает до 24 ч)
- Интеграция — служебная учётная запись арендатора. В неё нельзя войти в кабинет; она не попадает в выбор операторов, рассылки и учёт мест. У неё своя роль и доступ ко всем диалогам арендатора.
- Ключи принадлежат интеграции. Ротация ключа не меняет идентификатор интеграции: ваши журналы и аудит остаются сквозными.
- За каждой интеграцией закреплён сотрудник-владелец — тот, кто её создал. От его текущих прав зависят права интеграции (см. ниже).
- На арендатора можно выпустить не более 20 активных ключей.
- Создавать интеграции и ключи может сотрудник с правом
integrations.manage(по умолчанию — владелец и менеджер). Это право отдельное от управления ключами внешних поставщиков, которые платформа использует сама.
#Формат ключа
sap_<ячейка>_<режим>_<идентификатор>_<секрет>
| Часть | Значения | Смысл |
|---|---|---|
sap | постоянно | Префикс. По нему сканеры секретов находят утёкшие ключи. |
ячейка | ru, en, id | Ячейка, в которой ключ действует. |
режим | live, test | Боевой или тестовый (песочница — Планируется). |
идентификатор | 12 знаков base32 | Публичный идентификатор ключа (key_id). Виден в кабинете и журналах. |
секрет | около 43 знаков base62 | Секретная часть: 32 случайных байта. |
Пример (заведомо ненастоящий):
sap_ru_test_EXAMPLE0KEYID_EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLEX
На стороне платформы хранится только необратимый хеш секрета с серверным «перцем» ячейки. Утечка базы без перца не раскрывает ключи.
#Как передавать ключ
Только в заголовке Authorization, только по TLS:
GET /api/public/v1/me HTTP/1.1
Host: formula-cream.pro
Authorization: Bearer sap_ru_live_EXAMPLE0KEYID_…
- Ключ нельзя передавать в адресе (
?key=…), теле запроса или в cookie. - В версии v1 подпись каждого запроса не требуется и не поддерживается: защита построена на Bearer-ключе по TLS. Усиленный режим на открытом ключе клиента (Ed25519) в v1 не поддерживается. Код
signature_invalidзарезервирован для него и в v1 не возвращается. - Браузер и мобильное приложение ключ получать не должны: используйте клиентские интерфейсы (Введение).
#Жизненный цикл ключа
| Событие | Как работает |
|---|---|
| Выпуск | Кабинет: Настройки → API. Ключ показывается один раз; сохраните его немедленно. Событие записывается в аудит, владельцу арендатора уходит уведомление. |
| Хранение | Ответственность клиента: хранилище секретов или переменные окружения. Не в репозитории, не во фронтенде, не в логах. |
| Срок | По умолчанию 365 суток, больше 365 задать нельзя. Срок виден в GET /me (key.expires_at). За 30 и за 7 суток до истечения приходит событие вебхука api_key.expiring. Ключ с истёкшим сроком получает тот же ответ, что и несуществующий: 401 invalid_api_key. |
| Ротация | Выпустите новый ключ интеграции, переключите свои системы, затем отзовите старый. Старый ключ при ротации продолжает работать до 24 часов, чтобы переключение не было мгновенным. |
| Отзыв | Кабинет → ключ → «Отозвать». Действует не позже чем через 60 секунд (результат проверки кэшируется до минуты, при отзыве кэш сбрасывается). Отзыв необратим. |
| Учёт | Для каждого ключа в кабинете видны время и (в хешированном виде) адрес последнего использования. |
#Пошаговая ротация без простоя
- Выпустите новый ключ той же интеграции с теми же областями.
- Разверните новый ключ в хранилище секретов и перезапустите сервисы.
- Убедитесь по «Использованию API» в кабинете, что старый ключ больше не вызывается.
- Отзовите старый ключ. Если забыли — он погаснет сам по окончании окна перекрытия.
#Области (scopes)
Область — право, которое вы даёте ключу. Выдавайте минимально необходимые. Колонка «Платно» — списывается ли плата с кошелька арендатора. Колонка «ПДн» — попадают ли в ответы персональные данные клиентов арендатора.
| Область | Что даёт | Платно | ПДн |
|---|---|---|---|
conversations:read | Диалоги и сообщения | нет | да |
conversations:write | Приём сообщения клиента из вашего канала, сообщение оператора, передача, закрытие, перехват и возврат ИИ | нет | да |
ai_seller:invoke | Ответ ИИ-продажника на сообщение клиента из вашего канала | да | да |
leads:read | Лиды и контакты | нет | да |
leads:write | Создание и правка лида, принятие во внешнюю CRM, заметки, задачи, подтверждение запросов действий агента, запись внешней оценки (PUT /leads/{id}/score), карта статусов (PUT /crm/status-map) | нет | да |
leads:score | Оценка лида нашей моделью | да | да |
analytics:read | Агрегаты трафика, источники, воронка, видимость | нет | нет |
analytics:write | Приём событий и офлайн-конверсий; только псевдонимные идентификаторы | нет | нет (см. примечание 2) |
dashboards:read | Готовые срезы «Обзор» и «Пульс» | нет | нет |
articles:read | Статьи, ревизии, статусы публикации | нет | нет |
articles:write | Правка, утверждение, публикация | нет | нет |
articles:generate | Заказ генерации статьи | да | нет |
strategist:read | Отчёты, очередь тем, действия чата | нет | нет (примечание 1) |
strategist:write | Утверждение и отклонение тем, подтверждение и отмена действий стратега | нет | нет |
strategist:chat | Ход разговора со стратегом | да | нет (примечание 1) |
webhooks:manage | Подписки на события, журнал доставок | нет | нет (примечание 6) |
Примечания.
- Стратег работает с агрегатами и не видит персональные данные по построению; это подтверждается при выпуске API.
- Приём событий принимает только псевдонимные идентификаторы:
anonymous_idиuser_id— ваши собственные псевдонимы. Почта, телефон и имя вpropertiesотклоняются ответом422 validation_failed(JSON Pointer указывает поле), поэтому область не относится к ПДн. POST /leads/{id}/scoreплатный и требуетleads:score. Запись собственной оценки внешней CRM (PUT /leads/{id}/score) бесплатна и требуетleads:write.- Утверждение темы стратега и подтверждение его действия дополнительно требуют права на то, что предлагается выполнить, и доступного бюджета. Утверждение темы генерацию статьи не запускает.
GET /me,GET /walletиGET /operations/{id}доступны любому действующему ключу и не требуют области (GET /meиGET /walletработают и при остановленном обмене — Кошелёк); операции видны только той интеграции, которая их создала.- Подписка с
include_pii: trueдополнительно требует у интеграцииleads:readи/илиconversations:read(Вебхуки). - Журнал выдач ПДн виден арендатору в кабинете и по
GET /disclosures(хранится 3 года). Какое право нужно ключу для этого запроса, в v1 не зафиксировано и будет указано в OpenAPI. Подробнее — Ячейки и данные.
#Соответствие областей и конечных точек
| Область | Конечные точки |
|---|---|
conversations:read | GET /conversations, GET /conversations/{id}, GET /conversations/{id}/messages |
conversations:write | POST /conversations, POST /conversations/{id}/messages (приём), POST /conversations/{id}/operator-messages, POST /conversations/{id}/takeover, /release, /close |
ai_seller:invoke | ответ ИИ в POST /conversations/{id}/messages (вместе с conversations:write) |
leads:read | GET /leads, GET /leads/{id}, GET /leads/by-external/{external_id} |
leads:write | POST /leads, PATCH /leads/{id}, POST /leads/{id}/accept, POST /leads/{id}/notes, POST /leads/{id}/tasks, POST /leads/{id}/actions/{action_id}/ack, PUT /leads/{id}/score, PUT /crm/status-map |
leads:score | POST /leads/{id}/score |
analytics:read | GET /analytics/timeseries, /analytics/traffic-sources, /analytics/funnel, /analytics/visibility |
analytics:write | POST /analytics/events, POST /analytics/conversions |
dashboards:read | GET /dashboards/overview, GET /dashboards/pulse |
articles:read | GET /articles, GET /articles/{id}, GET /articles/generation-jobs/{id} |
articles:write | PATCH /articles/{id}, POST /articles/{id}/approve, POST /articles/{id}/publish |
articles:generate | POST /articles/generation-jobs (или generate: true при утверждении темы стратега) |
strategist:read | GET /strategist/reports, GET /strategist/reports/{id}, GET /strategist/topics, GET /strategist/actions, GET /strategist/actions/{id} |
strategist:write | POST /strategist/topics/{id}/approve, POST /strategist/topics/{id}/reject, POST /strategist/actions/{id}/confirm, POST /strategist/actions/{id}/cancel |
strategist:chat | POST /strategist/chat/sessions, POST /strategist/chat/sessions/{id}/turns |
webhooks:manage | GET/POST/PATCH/DELETE /webhooks, POST /webhooks/{id}/test, POST /webhooks/{id}/rotate-secret, GET /webhooks/{id}/deliveries |
| без области | GET /me, GET /wallet, GET /operations/{id} |
#Как вычисляются права запроса
Запрос разрешён, только если каждое из условий выполнено. Фактические права — пересечение:
права запроса = области ключа
∩ роль интеграции
∩ ТЕКУЩИЕ права сотрудника-владельца
∩ лицензия (api_access) и тариф
| Слой | Что означает на практике |
|---|---|
| Области ключа | Задаются при выпуске. Расширить область нельзя — выпускают новый ключ. |
| Роль интеграции | Максимум того, что интеграция вообще может делать в арендаторе. |
| Текущие права владельца | Проверяются в момент запроса, а не при выпуске. Если у сотрудника отобрали право, интеграция тоже его теряет. Если сотрудник деактивирован — ключи его интеграций приостанавливаются, владельцу арендатора приходит тревога. |
| Лицензия и тариф | Признак api_access и ограничения тарифа. Отказ — 403 feature_not_in_plan. |
Помимо этого действует проверка арендатора: арендатор должен быть активен. Идентификатор чужого ресурса даёт 404 not_found.
Следствие для интегратора: ключ, который работал вчера, может сегодня получить scope_missing, если права владельца изменились. Это нормальное поведение; обрабатывайте 403.
#Список разрешённых IP
- Необязательный: список адресов или сетей CIDR, с которых принимаются запросы ключа.
- Запрос с другого адреса —
403 ip_not_allowed. - Для областей с ПДн (
conversations:*,leads:*) в ячейке RU список IP интеграции обязателен; без него ключ с такими областями не выпускается. Дополнительно при подключении указываются страна размещения принимающей системы и основание передачи; если страна не РФ, областиconversations:*,leads:*не выдаются (403 pii_transfer_not_allowed, Ячейки и данные). Текущий список виден вGET /me(key.ip_allowlist). - Если вы запускаете вызовы из облака с плавающими адресами, закрепите исходящий адрес (NAT-шлюз, статический IP).
- Использование ключа с нового адреса или из новой страны вызывает тревогу владельцу арендатора.
#Тестовые ключи
Статус: Планируется.
Ключи с режимом test (sap_<ячейка>_test_…) работают в песочнице ячейки — отдельном арендаторе с вымышленными данными.
| Свойство | Тестовый ключ |
|---|---|
| Данные | вымышленные, ваши боевые данные не затрагиваются |
| Платные операции | не списывают деньги |
| ИИ-продажник | отвечает заготовками |
| Вебхуки | события приходят |
| Тот же код | различие только в ключе и в данных |
Боевой ключ не работает в песочнице, тестовый — в боевом арендаторе.
#Что делать при утечке ключа
- Отзовите ключ в кабинете (Настройки → API). Отзыв действует не позже чем через 60 секунд.
- Выпустите новый ключ и обновите секреты в своих системах.
- Проверьте журнал «Использование API» (хранится 90 суток; в нём метод, маршрут, статус, время, стоимость,
request_id— без тел запросов и ПДн) и аудит: что делал ключ после предполагаемой даты утечки. - Если у ключа были области с ПДн, проверьте журнал выдач ПДн (кабинет или
GET /disclosures, хранится 3 года) и оцените, какие данные могли быть выданы. Обязанности оператора ПДн по уведомлению регуляторов и субъектов определяются законодательством вашей юрисдикции. - Проверьте, не создавались ли новые вебхуки, ключи и интеграции, и отзовите лишнее; при подозрении ротируйте секреты вебхуков.
- Удалите ключ из истории репозитория и из логов; одного коммита-удаления мало.
Профилактика: минимальные области, список IP, срок жизни меньше максимального, отдельные ключи на отдельные системы, хранение в менеджере секретов.
#Ошибки аутентификации
| Код | HTTP | Когда |
|---|---|---|
invalid_api_key | 401 | Ключа нет, он неверен, отозван или истёк. Ответ намеренно одинаков во всех случаях |
wrong_cell | 401 | Ключ другой ячейки; в ответе поле correct_base_url с правильным адресом |
scope_missing | 403 | У ключа нет нужной области или она «срезана» ролью, правами владельца или тарифом |
ip_not_allowed | 403 | Адрес вне списка разрешённых |
feature_not_in_plan | 403 | Тариф или лицензия не включают API/функцию |
pii_transfer_not_allowed | 403 | Ячейка RU: область с ПДн или include_pii запрошены для интеграции со страной размещения вне РФ |
Тело ответа — application/problem+json с type вида https://<домен ячейки>/developers/errors#<code> (Соглашения). Полный каталог — Соглашения.
#Заметки
- Каждая запись через API попадает в аудит арендатора с указанием интеграции и ключа (
key_id), от имени служебной учётки. - Брутфорс: поиск ключа идёт по
key_idс сравнением за постоянное время; частые неудачи с одного адреса ограничиваются. - CORS не поддерживается: прямой вызов API из браузера невозможен и не должен делаться.