# TGEX Backend API v2 ## Аутентификация **JWT Bearer Token** в заголовке `Authorization: Bearer ` ### Получение токена через Telegram Bot Логика точно такая же как и раньше ### Эндпоинты | Метод | Эндпоинт | Описание | Auth | |-------|----------|----------|------| | `GET` | `/auth/complete` | Обмен временного токена на JWT | ❌ | | `GET` | `/auth/me` | Получить текущего пользователя | ✅ | **Response** `/auth/me`: ```json { "id": "uuid", "telegram_id": 123456789, "username": "string | null" } ``` --- ## Workspaces (Рабочие пространства) Воркспейсы - изолированные пространства для команд. У пользователя может быть несколько воркспейсов. | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces` | Список воркспейсов пользователя (пагинация) | | `POST` | `/workspaces` | Создать воркспейс | | `PATCH` | `/workspaces/{workspace_id}` | Обновить название | | `DELETE` | `/workspaces/{workspace_id}` | Удалить воркспейс | **Body** `POST /workspaces`: ```json { "name": "string" } ``` **Response**: ```json { "id": "uuid", "name": "string" } ``` --- ## Workspace Members (Участники воркспейса) | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces/{workspace_id}/members` | Список участников (пагинация) | | `PUT` | `/workspaces/{workspace_id}/members/{user_id}/permissions` | Обновить права участника | **Права доступа** (`PermissionKey`): - `admin_full` - полный доступ - `projects_read` - чтение проектов - `projects_write` - запись проектов - `placements_read` - чтение размещений - `placements_write` - запись размещений - `analytics_read` - чтение аналитики **Scope types**: `project` (ограничение прав на конкретный проект) **Body** `PUT permissions`: ```json { "permissions": [ { "key": "admin_full" }, { "key": "projects_write", "scopes": [ {"type": "project", "id": "project-uuid"} ] } ] } ``` --- ## Workspace Invites (Приглашения) | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces/{workspace_id}/invites` | Список приглашений (пагинация) | | `POST` | `/workspaces/{workspace_id}/invites` | Создать приглашение | **Body** `POST /invites`: ```json { "username": "telegram_username" // без @ } ``` **Статусы приглашения**: `PENDING`, `ACCEPTED`, `REJECTED` --- ## Projects (Проекты / Целевые каналы) Проекты = целевые Telegram каналы, которые продвигаются. Создаются через Telegram бота. | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces/{workspace_id}/projects` | Список проектов (пагинация) | **Response**: ```json { "id": "uuid", "telegram_id": -1001234567890, "title": "string", "username": "string | null", "status": "ACTIVE | INACTIVE | ARCHIVED" } ``` **Управление проектами**: через Telegram бота (добавить/удалить канал) --- ## Channels (Каналы для размещений) Каталог Telegram каналов, где можно размещать рекламу. | Метод | Эндпоинт | Описание | Фильтры | |-------|----------|----------|---------| | `GET` | `/channels` | Список каналов (пагинация) | `?username=...` | **Response**: ```json { "id": "uuid", "telegram_id": -1002345678901, "title": "string", "username": "string | null", "description": "string | null", "subscribers_count": 15000 } ``` --- ## Purchase Plan (План закупа) План закупа - список каналов для покупки рекламы в рамках проекта. | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels` | Список каналов плана (пагинация) | | `POST` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels` | Добавить канал в план | | `PATCH` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels/{id}` | Обновить параметры канала | | `DELETE` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels/{id}` | Удалить из плана | **Body** `POST`: ```json { "channel_id": "uuid", "planned_date": "2025-01-15T12:00:00Z", // optional "price": 5000.50, // optional "comment": "string" // optional } ``` **Body** `PATCH`: ```json { "planned_date": "2025-01-15T12:00:00Z", // optional "price": 5000.50, // optional "comment": "string" // optional } ``` **Response**: ```json { "id": "uuid", "status": "PLANNED | COMPLETED | CANCELLED", "planned_date": "2025-01-15T12:00:00Z | null", "price": 5000.50, "comment": "string | null", "channel": { "id": "uuid", "title": "string", "username": "string | null", "subscribers_count": 15000 } } ``` --- ## Creatives (Креативы) Креативы = рекламные материалы (текст с пригласительной ссылкой). | Метод | Эндпоинт | Описание | Фильтры | |-------|----------|----------|---------| | `GET` | `/workspaces/{ws}/creatives` | Список креативов (пагинация) | `?project_id=...&include_archived=false` | | `GET` | `/workspaces/{ws}/creatives/{id}` | Один креатив | | | `POST` | `/workspaces/{ws}/creatives?project_id=...` | Создать креатив | | | `PATCH` | `/workspaces/{ws}/creatives/{id}` | Обновить креатив | | | `DELETE` | `/workspaces/{ws}/creatives/{id}` | Удалить (архивировать) | | **Body** `POST/PATCH`: ```json { "name": "string", "text": "Текст с {invite_link} тегом" } ``` **Response**: ```json { "id": "uuid", "name": "string", "text": "string", "status": "ACTIVE | ARCHIVED", "placements_count": 5 } ``` **Важно**: `{invite_link}` в тексте заменяется на уникальную ссылку при создании размещения. --- ## Placements (Размещения) Размещения = факт размещения креатива в канале. | Метод | Эндпоинт | Описание | Фильтры | |-------|----------|----------|---------| | `GET` | `/workspaces/{ws}/placements` | Список размещений (пагинация) | `?project_id=...&placement_channel_id=...&creative_id=...&include_archived=false` | | `GET` | `/workspaces/{ws}/placements/{id}` | Одно размещение | | | `POST` | `/workspaces/{ws}/placements` | Создать размещение | | | `PATCH` | `/workspaces/{ws}/placements/{id}` | Обновить размещение | | | `DELETE` | `/workspaces/{ws}/placements/{id}` | Удалить (архивировать) | | **Body** `POST`: ```json { "project_id": "uuid", "placement_channel_id": "uuid", "creative_id": "uuid", "placement_date": "2025-01-15T12:00:00Z", "cost": 5000.50, // optional "comment": "string", // optional "ad_post_url": "https://t.me/channel/123", // optional "invite_link_type": "PUBLIC | APPROVAL" } ``` **Body** `PATCH`: ```json { "placement_date": "2025-01-15T12:00:00Z", // optional "cost": 5000.50, // optional "comment": "string", // optional "ad_post_url": "https://t.me/channel/123" // optional } ``` **Response**: ```json { "id": "uuid", "placement_date": "2025-01-15T12:00:00Z", "cost": 5000.50, "comment": "string | null", "ad_post_url": "string | null", "invite_link_type": "PUBLIC | APPROVAL", "invite_link": "https://t.me/+UniqueCode", "status": "ACTIVE | ARCHIVED", "subscriptions_count": 42, "views_count": 1850, "views_availability": "UNKNOWN | AVAILABLE | UNAVAILABLE | MANUAL", "last_views_fetch_at": "2025-01-15T14:30:00Z", "project": { "id": "uuid", "title": "string", "username": "string | null" }, "placement_channel": { "id": "uuid", "title": "string", "username": "string | null", "subscribers_count": 15000 }, "creative": { "id": "uuid", "name": "string" } } ``` **Типы пригласительных ссылок**: - `PUBLIC` - открытая ссылка - `APPROVAL` - с одобрением через бота **Статус просмотров**: - `UNKNOWN` - еще не проверялось - `AVAILABLE` - просмотры доступны (автообновление) - `UNAVAILABLE` - нет доступа к просмотрам - `MANUAL` - ручной ввод --- ## Views History (История просмотров) | Метод | Эндпоинт | Описание | Фильтры | |-------|----------|----------|---------| | `GET` | `/workspaces/{ws}/placements/{id}/views/history` | История просмотров (пагинация) | `?from_date=...&to_date=...` | **Response**: ```json { "id": "uuid", "views_count": 1850, "fetched_at": "2025-01-15T14:30:00Z" } ``` --- ## Analytics (Аналитика) Все эндпоинты поддерживают фильтр `?project_id=...` для конкретного проекта. ### Аналитика размещений | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces/{ws}/analytics/placements` | Аналитика по размещениям (пагинация) | **Response**: ```json { "placement_id": "uuid", "placement_channel_title": "string", "placement_channel_username": "string | null", "creative_name": "string", "placement_date": "2025-01-15T12:00:00Z", "cost": 5000.50, "subscriptions_count": 42, "views_count": 1850, "cps": 119.05, // cost per subscription "cpm": 2702.70 // cost per mille views } ``` ### Аналитика креативов | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces/{ws}/analytics/creatives` | Аналитика по креативам (пагинация) | **Response**: ```json { "creative_id": "uuid", "creative_name": "string", "placements_count": 5, "total_cost": 25000.00, "total_subscriptions": 210, "total_views": 9250, "avg_cps": 119.05, "avg_cpm": 2702.70 } ``` ### Аналитика каналов | Метод | Эндпоинт | Описание | |-------|----------|----------| | `GET` | `/workspaces/{ws}/analytics/channels` | Аналитика по каналам (пагинация) | **Response**: ```json { "channel_id": "uuid", "channel_title": "string", "channel_username": "string | null", "placements_count": 3, "total_cost": 15000.00, "total_subscriptions": 126, "total_views": 5550, "avg_cps": 119.05, "avg_cpm": 2702.70 } ``` ### Аналитика расходов | Метод | Эндпоинт | Описание | Фильтры | |-------|----------|----------|---------| | `GET` | `/workspaces/{ws}/analytics/spending` | Динамика расходов | `?date_from=...&date_to=...&grouping=DAY\|WEEK\|MONTH` | **Response**: ```json { "items": [ { "date": "2025-01-15", "cost": 5000.50, "subscriptions": 42, "views": 1850 } ], "total_cost": 25000.00, "total_subscriptions": 210, "total_views": 9250 } ``` **Группировка** (`DateGrouping`): `DAY`, `WEEK`, `MONTH` --- ## Пагинация Все эндпоинты с пагинацией возвращают: ```json { "items": [...], "total": 42, "page": 1, "size": 50, "pages": 1 } ``` **Query параметры**: `?page=1&size=50` --- ## Статусы и Enum ### WorkspaceUserStatus - `ACTIVE` - активный участник - `INVITED` - приглашён, но не принял ### WorkspaceInviteStatus - `PENDING` - ожидает принятия - `ACCEPTED` - принято - `REJECTED` - отклонено ### ProjectStatus / ChannelStatus - `ACTIVE` - активен - `INACTIVE` - неактивен - `ARCHIVED` - архивирован ### CreativeStatus / PlacementStatus - `ACTIVE` - активен - `ARCHIVED` - архивирован ### PurchasePlanStatus - `PLANNED` - запланирован - `COMPLETED` - завершён - `CANCELLED` - отменён ### InviteLinkType - `PUBLIC` - открытая ссылка - `APPROVAL` - с одобрением бота ### PostViewsAvailability - `UNKNOWN` - неизвестно (ещё не проверялось) - `AVAILABLE` - доступны (автообновление) - `UNAVAILABLE` - недоступны - `MANUAL` - ручной ввод --- ## Коды ошибок HTTP - `200` - OK - `201` - Created - `204` - No Content (успешное удаление) - `400` - Bad Request (валидация) - `401` - Unauthorized (нет токена) - `403` - Forbidden (нет прав) - `404` - Not Found - `500` - Internal Server Error **Формат ошибки**: ```json { "detail": "Error message" } ``` --- ## Особенности 1. **Все UUID в формате**: `xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx` 2. **Даты в ISO 8601**: `2025-01-15T12:00:00Z` (UTC) 3. **Метрики автообновляются**: просмотры обновляются воркером каждые 60 секунд (если `views_availability = AVAILABLE`) 4. **Подписки отслеживаются**: через Telegram бота при присоединении по invite_link 5. **Права проверяются**: все эндпоинты под воркспейсами требуют соответствующих прав 6. **Soft delete**: удаление = архивирование (статус `ARCHIVED`) --- ## Telegram Bot Integration - Создание проектов (добавление целевых каналов) - Создание креативов через диалог - Приглашения в воркспейсы - Отслеживание подписок через invite links - Начальная аутентификация (`/start` → временный токен)