Files
tgex-frontend/FRONTEND_API.md
2025-11-19 12:56:04 +03:00

18 KiB
Raw Permalink Blame History

API Документация для Frontend

Базовая информация

  • Base URL: /api/v1 (для всех эндпоинтов)
  • Формат данных: JSON
  • Аутентификация: JWT Bearer Token (в заголовке Authorization: Bearer <token>)

Авторизация

Процесс авторизации через Telegram

  1. Пользователь запускает Telegram бота командой /start с параметром login
  2. Бот создает одноразовый токен (живет 10 минут) и отправляет ссылку на веб-приложение
  3. Фронтенд получает token из URL параметра (/auth/complete?token=...)
  4. Фронтенд отправляет запрос на GET /api/v1/auth/complete?token=<token>
  5. Бэкенд возвращает 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 username
  • exp - время истечения токена (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 ID
  • username (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

Обновить связи внешнего канала с целевыми каналами.

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 - просмотры доступны через API
  • unavailable - нет доступа к просмотрам
  • 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.


Примечания

  1. Soft delete: При удалении сущностей (креативы, размещения, внешние каналы) они помечаются как удаленные (deleted_at), но не удаляются физически из БД.

  2. Отслеживание подписчиков: Работает только для размещений с invite_link_type: "approval". Бот автоматически одобряет запросы на вступление и увеличивает счетчик подписок.

  3. Автоматическое обновление просмотров: Фоновый worker периодически обновляет просмотры для активных размещений. Можно также запросить обновление вручную через /api/v1/placements/{id}/views/fetch.

  4. Целевые каналы подключаются только через Telegram бота: Нельзя создать целевой канал через API. Нужно добавить бота в канал как администратора, и он автоматически зарегистрирует канал в системе.