18 KiB
API Документация для Frontend
Базовая информация
- Base URL:
/api/v1(для всех эндпоинтов) - Формат данных: JSON
- Аутентификация: JWT Bearer Token (в заголовке
Authorization: Bearer <token>)
Авторизация
Процесс авторизации через Telegram
- Пользователь запускает Telegram бота командой
/startс параметромlogin - Бот создает одноразовый токен (живет 10 минут) и отправляет ссылку на веб-приложение
- Фронтенд получает
tokenиз URL параметра (/auth/complete?token=...) - Фронтенд отправляет запрос на
GET /api/v1/auth/complete?token=<token> - Бэкенд возвращает JWT токен, который нужно сохранить и использовать для всех последующих запросов
GET /api/v1/auth/complete
Обмен одноразового токена на JWT access token.
Query параметры:
token(string, обязательный) - одноразовый токен из Telegram бота
Response 200:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
JWT токен содержит:
user_id(UUID) - ID пользователяtelegram_id(integer) - Telegram ID пользователяusername(string | null) - Telegram usernameexp- время истечения токена (7 дней по умолчанию)
Ошибки:
404- токен не найден400- токен уже использован или истек
GET /api/v1/auth/me
Получить информацию о текущем пользователе.
Headers:
Authorization: Bearer <access_token>
Response 200:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"telegram_id": 123456789,
"username": "user_name"
}
Поля:
id(UUID) - ID пользователя в системеtelegram_id(integer) - Telegram IDusername(string | null) - Telegram username (может быть null)
Целевые каналы (Target Channels)
Каналы пользователя, в которых установлен бот.
GET /api/v1/target_channels
Получить список всех целевых каналов пользователя.
Headers:
Authorization: Bearer <access_token>
Response 200:
{
"target_channels": [
{
"id": "uuid",
"telegram_id": 123456789,
"title": "Название канала",
"username": "channel_username",
"is_active": true
}
]
}
DELETE /api/v1/target_channels/{channel_id}
Отключить целевой канал (удалить из системы).
Headers:
Authorization: Bearer <access_token>
Path параметры:
channel_id(UUID) - ID канала
Response 200: пустой ответ
Внешние каналы (External Channels)
Каналы, в которых размещается реклама.
GET /api/v1/external_channels/target/{target_channel_id}
Получить все внешние каналы, связанные с конкретным целевым каналом.
Headers:
Authorization: Bearer <access_token>
Path параметры:
target_channel_id(UUID) - ID целевого канала
Response 200:
{
"external_channels": [
{
"id": "uuid",
"telegram_id": 123456789,
"title": "Внешний канал",
"username": "external_channel",
"description": "Описание канала",
"subscribers_count": 10000
}
]
}
POST /api/v1/external_channels
Создать новый внешний канал.
Headers:
Authorization: Bearer <access_token>
Request body:
{
"telegram_id": 123456789,
"title": "Название канала",
"username": "channel_username",
"description": "Описание",
"subscribers_count": 10000,
"target_channel_ids": ["uuid1", "uuid2"]
}
Поля:
telegram_id(integer, обязательный) - Telegram ID каналаtitle(string, обязательный) - название каналаusername(string, optional) - username канала (без @)description(string, optional) - описание каналаsubscribers_count(integer, optional) - количество подписчиковtarget_channel_ids(array of UUID, обязательный) - список ID целевых каналов для связи
Response 200: объект ExternalChannelOutput
PATCH /api/v1/external_channels/{channel_id}
Обновить информацию о внешнем канале.
Headers:
Authorization: Bearer <access_token>
Path параметры:
channel_id(UUID) - ID канала
Request body:
{
"title": "Новое название",
"username": "new_username",
"description": "Новое описание",
"subscribers_count": 15000
}
Все поля опциональны. Отправляйте только те, которые нужно изменить.
Response 200: объект ExternalChannelOutput
PATCH /api/v1/external_channels/{channel_id}/links
Обновить связи внешнего канала с целевыми каналами.
Headers:
Authorization: Bearer <access_token>
Path параметры:
channel_id(UUID) - ID канала
Request body:
{
"add_target_channel_ids": ["uuid1", "uuid2"],
"remove_target_channel_ids": ["uuid3"]
}
Поля:
add_target_channel_ids(array of UUID, optional, default=[]) - добавить связиremove_target_channel_ids(array of UUID, optional, default=[]) - удалить связи
Response 200: объект ExternalChannelOutput
DELETE /api/v1/external_channels/{channel_id}
Удалить внешний канал.
Headers:
Authorization: Bearer <access_token>
Path параметры:
channel_id(UUID) - ID канала
Response 200: пустой ответ
Креативы (Creatives)
Рекламные сообщения для размещения.
GET /api/v1/creatives
Получить список креативов.
Headers:
Authorization: Bearer <access_token>
Query параметры:
target_channel_id(UUID, optional) - фильтр по целевому каналуinclude_archived(boolean, optional, default=false) - включить архивные
Response 200:
{
"creatives": [
{
"id": "uuid",
"name": "Название креатива",
"text": "Текст рекламного сообщения",
"target_channel_id": "uuid",
"target_channel_title": "Название канала",
"created_at": "2024-01-01T12:00:00Z",
"status": "active",
"placements_count": 5
}
]
}
Статусы креатива:
active- активныйarchived- архивный
GET /api/v1/creatives/{creative_id}
Получить конкретный креатив.
Headers:
Authorization: Bearer <access_token>
Path параметры:
creative_id(UUID) - ID креатива
Response 200: объект CreativeOutput
POST /api/v1/creatives
Создать новый креатив.
Headers:
Authorization: Bearer <access_token>
Request body:
{
"name": "Название креатива",
"text": "Текст рекламного сообщения",
"target_channel_id": "uuid"
}
Поля:
name(string, обязательный) - название креативаtext(string, обязательный) - текст сообщенияtarget_channel_id(UUID, обязательный) - ID целевого канала
Response 200: объект CreativeOutput
PATCH /api/v1/creatives/{creative_id}
Обновить креатив.
Headers:
Authorization: Bearer <access_token>
Path параметры:
creative_id(UUID) - ID креатива
Request body:
{
"name": "Новое название",
"text": "Новый текст",
"status": "archived"
}
Все поля опциональны.
Response 200: объект CreativeOutput
DELETE /api/v1/creatives/{creative_id}
Удалить креатив.
Headers:
Authorization: Bearer <access_token>
Path параметры:
creative_id(UUID) - ID креатива
Response 200: пустой ответ
Размещения (Placements)
Размещения рекламы во внешних каналах.
GET /api/v1/placements
Получить список размещений.
Headers:
Authorization: Bearer <access_token>
Query параметры:
target_channel_id(UUID, optional) - фильтр по целевому каналуexternal_channel_id(UUID, optional) - фильтр по внешнему каналуcreative_id(UUID, optional) - фильтр по креативуinclude_archived(boolean, optional, default=false) - включить архивные
Response 200:
{
"placements": [
{
"id": "uuid",
"target_channel_id": "uuid",
"target_channel_title": "Целевой канал",
"external_channel_id": "uuid",
"external_channel_title": "Внешний канал",
"creative_id": "uuid",
"creative_name": "Название креатива",
"placement_date": "2024-01-01T12:00:00Z",
"cost": 1000.5,
"comment": "Комментарий",
"ad_post_url": "https://t.me/channel/123",
"invite_link_type": "approval",
"invite_link": "https://t.me/+unique_invite_link",
"status": "active",
"subscriptions_count": 42,
"views_count": 1500,
"views_availability": "available",
"last_views_fetch_at": "2024-01-02T10:00:00Z",
"created_at": "2024-01-01T12:00:00Z"
}
]
}
Типы пригласительных ссылок (invite_link_type):
public- обычная открытая ссылкаapproval- ссылка с одобрением бота (отслеживание подписчиков)
Статусы размещения (status):
active- активноеarchived- архивное
Доступность просмотров (views_availability):
unknown- ещё не проверялосьavailable- просмотры доступны через APIunavailable- нет доступа к просмотрамmanual- просмотры вводятся вручную
GET /api/v1/placements/{placement_id}
Получить конкретное размещение.
Headers:
Authorization: Bearer <access_token>
Path параметры:
placement_id(UUID) - ID размещения
Response 200: объект PlacementOutput
POST /api/v1/placements
Создать новое размещение.
Headers:
Authorization: Bearer <access_token>
Request body:
{
"target_channel_id": "uuid",
"external_channel_id": "uuid",
"creative_id": "uuid",
"placement_date": "2024-01-01T12:00:00Z",
"cost": 1000.5,
"comment": "Комментарий",
"ad_post_url": "https://t.me/channel/123",
"invite_link_type": "approval"
}
Поля:
target_channel_id(UUID, обязательный)external_channel_id(UUID, обязательный)creative_id(UUID, обязательный)placement_date(datetime, обязательный) - дата размещенияcost(float, optional) - стоимость размещенияcomment(string, optional) - комментарийad_post_url(string, optional) - ссылка на рекламный постinvite_link_type(enum, optional, default="public") - тип пригласительной ссылки
Response 200: объект PlacementOutput
PATCH /api/v1/placements/{placement_id}
Обновить размещение.
Headers:
Authorization: Bearer <access_token>
Path параметры:
placement_id(UUID) - ID размещения
Request body:
{
"placement_date": "2024-01-02T12:00:00Z",
"cost": 1500.0,
"comment": "Новый комментарий",
"ad_post_url": "https://t.me/channel/124",
"status": "archived"
}
Все поля опциональны.
Response 200: объект PlacementOutput
DELETE /api/v1/placements/{placement_id}
Удалить размещение.
Headers:
Authorization: Bearer <access_token>
Path параметры:
placement_id(UUID) - ID размещения
Response 200: пустой ответ
Просмотры (Views)
Работа с просмотрами рекламных постов.
GET /api/v1/placements/{placement_id}/views/history
Получить историю просмотров размещения.
Headers:
Authorization: Bearer <access_token>
Path параметры:
placement_id(UUID) - ID размещения
Query параметры:
from_date(datetime, optional) - начало периодаto_date(datetime, optional) - конец периода
Response 200:
{
"histories": [
{
"id": "uuid",
"placement_id": "uuid",
"views_count": 1500,
"fetched_at": "2024-01-02T10:00:00Z",
"created_at": "2024-01-02T10:00:00Z"
}
]
}
POST /api/v1/placements/{placement_id}/views/fetch
Получить актуальные просмотры через Telegram API (запросить обновление).
Headers:
Authorization: Bearer <access_token>
Path параметры:
placement_id(UUID) - ID размещения
Response 200:
{
"placement_id": "uuid",
"views_count": 1500,
"views_availability": "available",
"fetched_at": "2024-01-02T10:00:00Z",
"error_message": null
}
При ошибке получения просмотров:
{
"placement_id": "uuid",
"views_count": null,
"views_availability": "unavailable",
"fetched_at": "2024-01-02T10:00:00Z",
"error_message": "Не удалось получить просмотры: нет доступа к каналу"
}
POST /api/v1/placements/{placement_id}/views/manual
Обновить просмотры вручную (когда автоматическое получение недоступно).
Headers:
Authorization: Bearer <access_token>
Path параметры:
placement_id(UUID) - ID размещения
Query параметры:
views_count(integer, обязательный) - количество просмотров
Response 200: объект PlacementOutput (обновленное размещение)
Типы данных и enum
DateTime
Все даты в формате ISO 8601 с timezone (UTC): 2024-01-01T12:00:00Z
UUID
Строковое представление UUID: "550e8400-e29b-41d4-a716-446655440000"
CreativeStatus (enum)
"active"- активный"archived"- архивный
PlacementStatus (enum)
"active"- активное"archived"- архивное
InviteLinkType (enum)
"public"- открытая публичная ссылка"approval"- ссылка с одобрением ботом
PostViewsAvailability (enum)
"unknown"- статус не определен"available"- просмотры доступны через API"unavailable"- просмотры недоступны"manual"- просмотры вводятся вручную
Обработка ошибок
Формат ошибки
Все ошибки возвращаются в стандартном формате FastAPI:
{
"detail": "Описание ошибки"
}
HTTP коды ответов
200- успешный запрос401- не авторизован (невалидный/истекший токен)403- доступ запрещен (нет прав на ресурс)404- ресурс не найден422- ошибка валидации входных данных500- внутренняя ошибка сервера
Авторизация
Для всех защищенных эндпоинтов (все, кроме /api/v1/auth/complete) необходимо передавать JWT токен:
Authorization: Bearer <access_token>
При отсутствии или невалидном токене вернется 401 Unauthorized.
Примечания
-
Soft delete: При удалении сущностей (креативы, размещения, внешние каналы) они помечаются как удаленные (
deleted_at), но не удаляются физически из БД. -
Отслеживание подписчиков: Работает только для размещений с
invite_link_type: "approval". Бот автоматически одобряет запросы на вступление и увеличивает счетчик подписок. -
Автоматическое обновление просмотров: Фоновый worker периодически обновляет просмотры для активных размещений. Можно также запросить обновление вручную через
/api/v1/placements/{id}/views/fetch. -
Целевые каналы подключаются только через Telegram бота: Нельзя создать целевой канал через API. Нужно добавить бота в канал как администратора, и он автоматически зарегистрирует канал в системе.