-
Notifications
You must be signed in to change notification settings - Fork 5
API Reference
Полная документация по REST API AI Secretary System с примерами запросов и ответов.
POST /admin/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "admin"
}Ответ:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 86400
}При логине создаётся серверная сессия с записью IP-адреса и User-Agent. Токен содержит jti (уникальный ID сессии), который проверяется при каждом запросе.
Пароли хешируются bcrypt. Старые SHA-256 хеши автоматически перехешируются при успешном входе (lazy-rehash).
Добавьте JWT токен в заголовок Authorization для всех защищённых эндпоинтов:
GET /admin/auth/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...| Метод | Эндпоинт | Описание |
|---|---|---|
| POST | /admin/auth/login |
Вход (получение JWT + создание сессии) |
| GET | /admin/auth/me |
Текущий пользователь |
| GET | /admin/auth/status |
Статус аутентификации |
| GET | /admin/auth/profile |
Профиль пользователя |
| PUT | /admin/auth/profile |
Обновление профиля |
| POST | /admin/auth/change-password |
Смена пароля (отзыв всех сессий + новый токен, rate-limit) |
| GET | /admin/auth/sessions |
Список активных сессий текущего пользователя |
| DELETE | /admin/auth/sessions/{jti} |
Отзыв конкретной сессии |
| GET | /admin/auth/permissions |
Эффективные права текущего пользователя |
Каждый вход создаёт серверную сессию. Сессии можно просматривать и отзывать (revoke). При отзыве сессии токен мгновенно становится недействительным.
GET /admin/auth/sessions
Authorization: Bearer <token>Ответ:
[
{
"token_jti": "550e8400-e29b-41d4-a716-446655440000",
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0 ...",
"created_at": "2026-02-22T03:00:00",
"expires_at": "2026-02-23T03:00:00",
"revoked_at": null
}
]DELETE /admin/auth/sessions/{jti}
Authorization: Bearer <token>- Обычные пользователи могут отзывать только свои сессии
- Пользователи с
users:manageмогут отзывать любые сессии - После отзыва токен возвращает 401
Ответ: {"message": "Session revoked"}
Требует settings:edit. Rate-limit: RATE_LIMIT_AUTH (по умолчанию 10/minute).
POST /admin/auth/change-password
Authorization: Bearer <token>
Content-Type: application/json
{
"old_password": "current",
"new_password": "new_secure_password"
}Ответ: Все существующие сессии отзываются, возвращается новый токен:
{
"message": "Password updated successfully",
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 86400
}Все активные сессии пользователя автоматически отзываются при:
- Смене пароля (
POST /admin/auth/change-password) - Смене роли (через
manage_users.py set-role) - Деактивации аккаунта (через
manage_users.py disable)
Для интеграции с OpenWebUI и другими клиентами, поддерживающими OpenAI API.
GET /v1/models
Authorization: Bearer <token>Ответ:
{
"data": [
{
"id": "anna-secretary-vllm",
"object": "model",
"created": 1234567890,
"owned_by": "system"
},
{
"id": "marina-secretary-gemini",
"object": "model",
"created": 1234567890,
"owned_by": "system"
}
]
}Формат ID: {persona}-secretary-{backend} (например, anna-secretary-vllm, marina-secretary-cloud_1)
GET /v1/voices
Authorization: Bearer <token>Ответ:
{
"voices": [
{"id": "anna_ru", "name": "Анна (Russian)"},
{"id": "marina_ru", "name": "Марина (Russian)"}
]
}POST /v1/audio/speech
Authorization: Bearer <token>
Content-Type: application/json
{
"model": "tts-1",
"input": "Привет, это Анна",
"voice": "anna_ru"
}Ответ: WAV аудиофайл (audio/wav)
Особенности:
- Поддержка streaming cache optimization
- Автоматическое кеширование аудио
POST /v1/chat/completions
Authorization: Bearer <token>
Content-Type: application/json
{
"model": "anna-secretary-vllm",
"messages": [
{"role": "user", "content": "Привет"}
],
"stream": true
}Ответ (SSE):
data: {"choices":[{"delta":{"content":"Привет"}}]}
data: {"choices":[{"delta":{"content":"!"}}]}
data: [DONE]
Особенности:
- Background TTS synthesis (аудио генерируется параллельно)
- Non-streaming режим (stream: false) возвращает полный JSON
POST /tts
Content-Type: application/json
{
"text": "Привет, это Анна",
"voice_id": "anna_ru"
}Ответ: WAV аудиофайл
POST /stt
Content-Type: multipart/form-data
file: <audio.wav>Ответ:
{
"text": "Привет, это Анна"
}POST /chat
Content-Type: application/json
{
"message": "Привет",
"persona": "anna"
}Ответ:
{
"response": "Здравствуйте! Чем могу помочь?"
}POST /process_call
Content-Type: multipart/form-data
audio: <call.wav>Ответ:
{
"transcription": "Текст звонка",
"response": "Ответ секретаря",
"audio_url": "/path/to/response.wav"
}POST /reset_conversationОтвет:
{
"status": "ok",
"message": "Контекст сброшен"
}GET /healthОтвет:
{
"status": "healthy",
"services": {
"tts": "running",
"stt": "running",
"llm": "running"
},
"database": "connected",
"llm_backend": "vllm"
}| Метод | Эндпоинт | Описание | Доступ |
|---|---|---|---|
| GET | /admin/kanban/projects |
Список всех проектов | kanban:view |
| POST | /admin/kanban/projects |
Создать проект (GitHub-привязка) | kanban:manage |
| PATCH | /admin/kanban/projects/{id} |
Обновить проект | kanban:manage |
| DELETE | /admin/kanban/projects/{id} |
Удалить проект | kanban:manage |
| POST | /admin/kanban/projects/{id}/sync |
Полная синхронизация GitHub issues | kanban:edit |
| Метод | Эндпоинт | Описание | Доступ |
|---|---|---|---|
| GET | /admin/kanban/tasks?project_id=N |
Список задач проекта (null = локальные) | kanban:view |
| POST | /admin/kanban/tasks |
Создать задачу (всегда draft + private) | kanban:edit |
| PATCH | /admin/kanban/tasks/{id} |
Обновить задачу (+ push на GitHub) | kanban:edit |
| DELETE | /admin/kanban/tasks/{id} |
Удалить задачу | kanban:manage |
| POST | /admin/kanban/reorder |
Изменить статус и позицию (+ push на GitHub) | kanban:edit |
| Метод | Эндпоинт | Описание | Доступ |
|---|---|---|---|
| POST | /admin/kanban/dependencies |
Добавить зависимость (409 при цикле) | kanban:edit |
| DELETE | /admin/kanban/dependencies?blocker_id=X&dependent_id=Y |
Удалить зависимость | kanban:edit |
| Метод | Эндпоинт | Описание | Доступ |
|---|---|---|---|
| POST | /admin/kanban/tasks/{id}/checklist |
Добавить пункт чеклиста | kanban:edit |
| PATCH | /admin/kanban/checklist/{item_id}/toggle |
Переключить выполнение | kanban:edit |
| DELETE | /admin/kanban/checklist/{item_id} |
Удалить пункт | kanban:edit |
POST /admin/kanban/projects
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "AI Secretary",
"github_owner": "ShaerWare",
"github_repo": "AI_Secretary_System",
"github_token": "ghp_xxx...",
"webhook_secret": "my-secret",
"label_mapping": {"todo": "status:todo", "in_progress": "status:in_progress", "review": "status:review"},
"sync_enabled": true
}Ответ: {"project": {...}} (токен не возвращается, только has_token: true/false)
POST /admin/kanban/projects/1/sync
Authorization: Bearer <token>Ответ: {"created": 15, "updated": 3, "total": 18}
POST /admin/kanban/tasks
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "Настроить интеграцию",
"description": "Подключить API",
"assignee": "admin",
"due_date": "2026-03-01",
"tags": ["интеграция", "api"]
}Ответ:
{
"task": {
"id": 1,
"title": "Настроить интеграцию",
"description": "Подключить API",
"status": "draft",
"is_private": true,
"assignee": "admin",
"created_by": "admin",
"owner_id": 1,
"start_date": null,
"due_date": "2026-03-01",
"position": 0,
"tags": ["интеграция", "api"],
"project_id": null,
"github_issue_number": null,
"checklist": [],
"blockers": [],
"dependents": [],
"created": "2026-02-21T00:00:00",
"updated": "2026-02-21T00:00:00"
}
}PATCH /admin/kanban/tasks/1
Authorization: Bearer <token>
Content-Type: application/json
{
"status": "in_progress",
"assignee": "admin"
}При смене статуса с draft на любой другой — задача автоматически становится публичной (is_private: false). Для GitHub-привязанных задач статус также обновляется на GitHub (лейблы + open/close).
С PR #424 задачи используют owner_id (INT FK → users.id) для контроля доступа:
-
Локальные задачи:
owner_id= ID создателя,created_by= username (аудит) -
GitHub-задачи:
owner_id = null,created_by= GitHub username -
Видимость: non-admin видит задачи с
owner_id == user.id+ публичные не-draft -
Редактирование: non-admin может редактировать только задачи с
owner_id == user.id -
Зависимости: нельзя зависеть от приватной задачи другого пользователя (проверка по
owner_id)
POST /admin/kanban/dependencies
Authorization: Bearer <token>
Content-Type: application/json
{
"blocker_id": 1,
"dependent_id": 2
}Возвращает 409 если зависимость создаёт цикл или целевая задача приватная.
Вызываются виджетами, Telegram-ботами, внешними клиентами. Пути без /admin/ (PR #420).
| Метод | Эндпоинт | Описание |
|---|---|---|
| GET | /privacy-policy?lang=ru |
Страница политики конфиденциальности (HTML) |
| GET | /terms?lang=ru |
Страница условий использования (HTML) |
| GET | /consent-types |
Список типов согласий |
| POST | /legal/consents/grant |
Дать согласие (user_id, user_type, consent_type) |
| POST | /legal/consents/grant-bulk |
Дать несколько согласий (consent_types[]) |
| POST | /legal/consents/grant-required |
Дать все обязательные согласия |
| Метод | Эндпоинт | Доступ | Описание |
|---|---|---|---|
| GET | /admin/legal/consents/{user_id} |
settings:manage |
Все согласия пользователя |
| GET | /admin/legal/consents/check/{user_id} |
settings:view |
Проверка обязательных согласий |
| POST | /admin/legal/consents/revoke |
settings:manage |
Отозвать согласие |
| GET | /admin/legal/stats |
settings:manage |
Статистика согласий |
| POST | /admin/legal/gdpr/delete |
settings:manage |
Удаление данных пользователя (GDPR) |
Полный каскад удаления/анонимизации данных пользователя. Два режима:
Режим 1 — Admin user (по user_id):
POST /admin/legal/gdpr/delete
Authorization: Bearer <token>
{
"user_id": 42,
"confirm": true
}Режим 2 — External contact (по provider + provider_uid):
POST /admin/legal/gdpr/delete
Authorization: Bearer <token>
{
"provider": "telegram",
"provider_uid": "123456789",
"confirm": true
}Ответ:
{
"status": "deleted",
"report": {
"user_sessions": 3,
"chat_sessions": 12,
"claude_code_sessions": 1,
"user_consents": 2,
"bot_instances_nullified": 1,
"widget_instances_nullified": 2,
"audit_log_anonymized": 45,
"usage_log_anonymized": 128
}
}Валидация:
-
confirm: trueобязателен - Нельзя удалить данные текущего пользователя (403)
- Указать
user_idилиprovider+provider_uid, не оба (400) -
providerдопустимые значения:telegram,whatsapp,widget
Действия по режимам:
- Admin: DELETE сессии/чаты, SET NULL ownership ресурсов, ANONYMIZE логи
- Contact: DELETE профили/подписки/события/сессии, ANONYMIZE платежи/логи
| Паттерн | Описание | Пример |
|---|---|---|
GET /admin/{resource} |
Список всех | /admin/chat/sessions |
POST /admin/{resource} |
Создать новый | /admin/telegram/bots |
GET /admin/{resource}/{id} |
Получить один | /admin/telegram/bots/123 |
PUT /admin/{resource}/{id} |
Обновить | /admin/telegram/bots/123 |
DELETE /admin/{resource}/{id} |
Удалить | /admin/telegram/bots/123 |
| Паттерн | Описание | Пример |
|---|---|---|
POST /admin/{resource}/{id}/action |
Выполнить действие | /admin/telegram/bots/123/start |
Примеры действий:
-
/admin/telegram/bots/{id}/start— запустить бота -
/admin/telegram/bots/{id}/stop— остановить бота -
/admin/telegram/bots/{id}/test— тестовое сообщение
| Паттерн | Описание | Пример |
|---|---|---|
GET /admin/{resource}/stream |
Server-Sent Events | /admin/monitor/gpu/stream |
Формат SSE:
data: {"message": "chunk"}\n\n
data: [DONE]\n\n
Все SSE-эндпоинты требуют JWT-авторизацию (PR #420). Фронтенд использует fetch + ReadableStream вместо EventSource, чтобы передавать Authorization: Bearer заголовок. Эндпоинты:
| Эндпоинт | Доступ | Описание |
|---|---|---|
GET /admin/monitor/gpu/stream |
system:view |
GPU-метрики (SSE) |
GET /admin/logs/stream/{logfile} |
system:view |
Стриминг логов |
GET /admin/finetune/train/log |
system:view |
Стриминг лога обучения |
POST /admin/chat/stream |
chat:edit |
Стриминг чата (отдельный flow) |
| Паттерн | Описание | Пример |
|---|---|---|
POST /webhooks/{service} |
Внешние вебхуки | /webhooks/amocrm |
Доступные вебхуки:
-
/webhooks/amocrm— amoCRM webhook -
/webhooks/yoomoney— YooMoney payments -
/webhooks/github— GitHub PR events + Issues (kanban sync)
Middleware SecurityHeadersMiddleware (app/security_headers.py) добавляет защитные заголовки ко всем HTTP-ответам.
| Заголовок | Значение | Назначение |
|---|---|---|
Content-Security-Policy |
default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self' |
Блокирует XSS-инъекции скриптов (PR #422) |
X-Content-Type-Options |
nosniff |
Блокирует MIME-sniffing |
X-Frame-Options |
DENY |
Предотвращает clickjacking |
X-XSS-Protection |
1; mode=block |
Legacy XSS-защита |
Referrer-Policy |
strict-origin-when-cross-origin |
Контроль Referer |
Permissions-Policy |
geolocation=() |
Ограничение browser API |
Конфигурация (env vars):
-
SECURITY_HEADERS_ENABLED— включить все заголовки (default:true) -
CSP_ENABLED— включить CSP отдельно (default:true) -
X_FRAME_OPTIONS— значение X-Frame-Options (default:DENY)
Эндпоинт мониторинга: GET /admin/monitor/security (system:view) — возвращает текущие заголовки и статус.
Все роутеры мигрированы на RBAC. Legacy guard-функции (require_admin, require_not_guest, verify_ownership) удалены в PR #358.
| Dependency | Описание | Применение |
|---|---|---|
require_permission(module, level) |
Проверяет уровень прав по модулю | Эндпоинт-уровень (все роутеры) |
user_has_level(user, module, level) |
Inline-проверка внутри эндпоинта | Дополнительная логика (owner/manage) |
get_current_user |
Аутентификация без RBAC-проверки | Self-service (auth.py) |
Мигрированные роутеры (20): chat.py (21), llm.py (42), telegram.py (23), whatsapp.py (10), widget.py (7), bot_sales.py (43), amocrm.py (26), faq.py (8), wiki_rag.py (15), stt.py (4), services.py (6), monitor.py (9), backup.py (8), gsm.py (14), tts.py (14), kanban.py (15), audit.py (4), usage.py (8), claude_code.py (4), legal.py (4), roles.py (5). Инфраструктурный: auth.py (self-service + inline RBAC checks).
| Роль | RBAC маппинг | Права | Ограничения |
|---|---|---|---|
| admin | admin (manage all) | Полный доступ | Видит все ресурсы всех пользователей |
| user | operator (edit) | Read + Write своих ресурсов | Полный доступ к админ-панели |
| web | operator (edit) | Как user, но упрощённый UI | Скрыты: Dashboard, Services, vLLM, Models |
| guest | viewer (view) | Read-only (demo) | Только просмотр, без изменений |
Матрица прав: 16 модулей × 3 уровня (view/edit/manage). Legacy роли автоматически маппятся на RBAC через get_role_for_legacy().
Подробнее: RBAC
GET /admin/auth/permissions
Authorization: Bearer <token>Ответ: {"dashboard": "manage", "chat": "manage", ...}
В облачном режиме (DEPLOYMENT_MODE=cloud) модули speech и gsm исключаются. Модуль system остаётся доступным (логи, finetune). Фильтрация происходит в get_user_permissions() и распространяется на require_permission() (PR #428).
| Метод | Эндпоинт | Описание |
|---|---|---|
| GET | /admin/roles |
Список всех ролей с правами |
| POST | /admin/roles |
Создать пользовательскую роль |
| GET | /admin/roles/{id} |
Получить роль по ID |
| PUT | /admin/roles/{id} |
Обновить роль |
| DELETE | /admin/roles/{id} |
Удалить роль (только пользовательские) |
Двухуровневая фильтрация: owner_id (кто создал) + workspace_id (какому workspace принадлежит):
from auth_manager import workspace_context
owner_id, workspace_id = workspace_context(user, "chat")
# owner_id = None для manage-level (видит все ресурсы workspace)
# workspace_id = всегда из JWT (user.workspace_id)
sessions = await manager.list_sessions(owner_id=owner_id, workspace_id=workspace_id)Ресурсы с owner_id + workspace_id: ChatSession, BotInstance, WidgetInstance, WhatsAppInstance, CloudLLMProvider, TTSPreset, KnowledgeDocument, ClaudeCodeSession и др. (13 таблиц).
Workspace — контейнер всех ресурсов. Default workspace (id=1) создаётся автоматически. JWT содержит workspace_id. Репозитории фильтруют через BaseRepository._apply_workspace_filter().
Статус: workspace_id колонки добавлены на 13 таблиц, фильтрация полностью реализована. Модули с workspace-фильтрацией: Chat (PR #385), Channels — Telegram, WhatsApp, Widget (PR #387), AI/LLM — Cloud LLM Providers, TTS Presets (PR #389), Knowledge/FAQ — Knowledge Documents, Collections, FAQ Entries (PR #391), System/Kanban/amoCRM — Kanban Tasks & Projects, Claude Code Sessions, amoCRM Config (PR #393), Финализация — gate-check на мутациях всех модулей (PR #395). Audit excluded (no workspace_id).
| Метод | Путь | Доступ | Описание |
|---|---|---|---|
GET |
/admin/workspace |
users:view |
Информация о workspace (name, slug, owner_id, member_count, created_at) |
GET |
/admin/workspace/members |
users:view |
Список участников с user details (username, display_name, email, is_active, last_login) |
PUT |
/admin/workspace/members/{user_id}/role |
users:manage |
Смена роли. Body: {"role_name": "operator"}. Нельзя менять себе и owner |
DELETE |
/admin/workspace/members/{user_id} |
users:manage |
Удаление участника. Нельзя удалить себя и owner. Ревокация сессий удалённого |
| Метод | Путь | Доступ | Описание |
|---|---|---|---|
POST |
/admin/workspace/invites |
users:manage |
Создать инвайт. Body: {role_name, email?, max_uses?, expires_hours?}. Нельзя инвайтить на роль "owner" |
GET |
/admin/workspace/invites |
users:manage |
Список инвайтов текущего workspace |
DELETE |
/admin/workspace/invites/{id} |
users:manage |
Удалить инвайт |
GET |
/admin/workspace/invites/{code}/info |
Public | Информация для страницы принятия (workspace_name, role_name, expires_at) |
POST |
/admin/workspace/invites/accept |
Public + rate limit | Регистрация по инвайту. Body: {invite_code, username, password, display_name?}. Возвращает JWT (auto-login) |
Чат-сессии (admin source) могут быть расшарены другим пользователям с уровнями доступа read или write.
При read-доступе пользователь может просматривать чат, но не может отправлять/редактировать/удалять сообщения. При write — полный доступ, аналогичный владельцу (кроме удаления сессии и управления шарами).
| Метод | Эндпоинт | Описание | Доступ |
|---|---|---|---|
| GET | /admin/chat/sessions/{id}/shares |
Список шар сессии |
chat:edit + owner/manage |
| POST | /admin/chat/sessions/{id}/shares |
Расшарить сессию |
chat:edit + owner/manage |
| PUT | /admin/chat/sessions/{id}/shares/{user_id} |
Изменить permission |
chat:edit + owner/manage |
| DELETE | /admin/chat/sessions/{id}/shares/{user_id} |
Удалить шар |
chat:edit + owner/manage |
| POST | /admin/chat/sessions/{id}/fork |
Форк сессии (глубокое копирование) | chat:edit |
| GET | /admin/chat/shareable-users |
Список пользователей для шаринга | chat:view |
POST /admin/chat/sessions/{id}/shares
Content-Type: application/json
Authorization: Bearer <token>
{
"user_id": 2,
"permission": "read"
}Ответ:
{
"share": {
"id": 1,
"session_id": "chat_123",
"user_id": 2,
"permission": "read",
"shared_by": 1,
"shared_at": "2026-02-19T12:00:00"
}
}При получении сессии добавляются поля шаринга:
{
"session": {
"id": "chat_123",
"owner_id": 1,
"is_shared_with_me": true,
"share_permission": "read",
"share_count": 2
}
}POST /admin/chat/sessions/{id}/fork
Content-Type: application/json
Authorization: Bearer <token>
{
"title": "Мой форк"
}Создаёт глубокую копию всех активных сообщений с новым owner_id.
Все ошибки возвращаются в единообразном JSON формате:
{
"detail": "Описание ошибки"
}| Код | Описание |
|---|---|
| 200 | Успех |
| 201 | Создано |
| 400 | Некорректный запрос |
| 401 | Требуется аутентификация |
| 403 | Доступ запрещён |
| 404 | Не найдено |
| 422 | Ошибка валидации |
| 500 | Внутренняя ошибка сервера |
# Получить токен
TOKEN=$(curl -s -X POST http://localhost:8002/admin/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | jq -r .access_token)
# Запрос к API
curl -X GET http://localhost:8002/v1/models \
-H "Authorization: Bearer $TOKEN"import requests
# Аутентификация
response = requests.post(
"http://localhost:8002/admin/auth/login",
json={"username": "admin", "password": "admin"}
)
token = response.json()["access_token"]
# Запрос с токеном
headers = {"Authorization": f"Bearer {token}"}
response = requests.get("http://localhost:8002/v1/models", headers=headers)
print(response.json())← Personas | Troubleshooting →