Публичный API и интеграции¶
Помимо встроенного интерфейса, Synth предоставляет публичный API — контракт для внешних сервисов, скриптов и интеграций с ограниченным машинным доступом.
Service-ключи¶
Service-ключ — это ключ инстанса для внешних сервисов. Он не привязан к конкретному чату (в отличие от ключа привязки событий) и даёт ровно тот набор прав, который вы выдали.
- Аутентификация:
Authorization: Bearer synth_svc_…. - Секрет показывается один раз при создании; в списке виден только префикс.
- Метка
labelобязательна и уникальна по инстансу. - Управление: раздел «Сервисные ключи» или API
/api/v2/service-keys(в серверном режиме — толькоADMIN).
Права ключа¶
| Поле | Назначение |
|---|---|
roles |
Роль синтетического пользователя (по умолчанию USER) |
scopes |
Точечные разрешения на операции (см. ниже) |
allowedProjects |
Ограничение доступа указанными проектами |
rateLimitPerMinute |
Лимит запросов в минуту |
expiresAt |
Срок действия ключа |
Scopes — это узкие разрешения на группы операций. Примеры:
| Scope | Разрешает |
|---|---|
events:ingest |
Приём внешних событий |
events:watch |
Чтение потока событий |
sessions:create / sessions:read / sessions:prompt |
Создание сессий, чтение, отправку сообщений |
schedules:read / schedules:write |
Чтение и управление расписаниями |
bindings:read / bindings:write |
Чтение и управление привязками событий |
keys:read / keys:write |
Управление API-ключами привязок |
routes:read / routes:write |
Управление правилами маршрутизации |
llm:chat |
Прямые вызовы LLM |
users:read |
Чтение пользователей и идентичностей |
Есть и «семейные» варианты (events:*), но глобального «всё разрешено» нет.
Если задан allowedProjects, запрос к чужому проекту отклоняется. Если у ключа
не хватает scope или доступа к проекту, сервер отвечает 403.
# Создание ключа (ADMIN). Секрет придёт один раз в поле "key".
curl -X POST http://localhost:5000/api/v2/service-keys \
-H 'Authorization: Bearer <api-key>' -H 'Content-Type: application/json' \
-d '{"label":"telegram-gw","roles":["USER"],"scopes":["events:ingest","sessions:create"]}'
Публичный OpenAPI и SDK¶
Публичный контракт описан декларативно и отдаётся ручкой GET /api/v2/openapi.json
(OpenAPI 3.1). В него входит интеграционное ядро — события, сессии, расписания и
LLM (28 операций).
Потребить контракт удобнее через типизированный клиент:
import { createSynthClient, SynthApiError } from '@itphx/synth-sdk';
const synth = createSynthClient({
baseUrl: 'http://localhost:5000', // без /api/v2
serviceKey: 'synth_svc_…',
});
const { sessionId } = await synth.events.ingest({ source: 'tg', type: 'message' });
const jobs = await synth.schedules.jobs('<schedule-id>');
- Namespaces:
events(ingest/journal/bindings/keys/routes),sessions(CRUD + prompt/messages/status),schedules(CRUD + run/jobs),llm(chatCompletions). - Аутентификация: приоритет
serviceKey→apiKey→token. - Ошибки:
SynthApiError({status, code, message, body?}) с единым форматом ответа об ошибке; сетевой сбой даётstatus: 0.
Исходящие webhooks¶
Webhooks — обратный контур: Synth сам отправляет события вашим подписчикам HTTP-запросом.
- Подписка задаёт адрес получателя (
url, толькоhttps), метку и список событий-паттернов (точный типstream.doneили префиксsession.*). - Запросы к приватным и локальным адресам по умолчанию запрещены (защита от SSRF).
- Signing-секрет
whsec_…выдаётся один раз при создании и ротации. - Доставка устойчива к сбоям: повторы с задержкой, дедупликация, журнал доставок.
- Можно провести тестовую доставку и посмотреть журнал по конкретной подписке.
Проверка подписи¶
Каждый запрос несёт заголовок X-Synth-Signature вида t=<unix>,v1=<hex>, где
v1 — HMAC-SHA256 от строки <t>.<тело запроса> на вашем секрете. Тело берётся
сырым, до разбора JSON; расхождение по времени более 5 минут считается
недействительным.
const { createHmac, timingSafeEqual } = require('node:crypto');
function verify(rawBody, header, secret, nowSec = Math.floor(Date.now() / 1000)) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=').map((s) => s.trim())));
const t = Number.parseInt(parts.t, 10);
if (!Number.isFinite(t) || Math.abs(nowSec - t) > 300) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1);
return a.length === b.length && timingSafeEqual(a, b);
}
Webhooks включаются мастер-выключателем: пока он выключен, создание подписок и
тестовая доставка отвечают 503, но список и журнал читаются.
Что дальше¶
- События и автоматизация — приём событий и привязки.
- Интеграция с Telegram — пример внешнего сервиса.
- Аутентификация и роли — роли и вход.
- Конфигурация — секции
events,webhooks,scheduler,decision.