Files
tgex-frontend/API_DOCUMENTATION.md
2025-11-10 12:07:24 +03:00

740 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API Документация
## Базовый URL
```
https://api.tgex.app/v1
```
## Аутентификация
Все запросы (кроме `/auth/*`) требуют JWT токен в заголовке:
```
Authorization: Bearer <token>
```
---
## 1. Аутентификация
### POST `/auth/init`
Инициализация процесса авторизации через Telegram
**Response:**
```typescript
{
bot_username: string;
start_param: string; // "login"
}
```
### POST `/auth/complete`
Завершение авторизации с одноразовым токеном
**Request:**
```typescript
{
token: string; // one-time token from bot
}
```
**Response:**
```typescript
{
access_token: string;
refresh_token: string;
user: User;
}
```
### POST `/auth/refresh`
Обновление access токена
**Request:**
```typescript
{
refresh_token: string;
}
```
**Response:**
```typescript
{
access_token: string;
}
```
### GET `/auth/me`
Получение информации о текущем пользователе
**Response:**
```typescript
User;
```
---
## 2. Типы данных
### User
```typescript
{
id: string;
telegram_id: number;
username: string | null;
first_name: string;
last_name: string | null;
created_at: string; // ISO 8601
}
```
### TargetChannel
```typescript
{
id: string;
telegram_id: number;
title: string;
username: string | null; // @channel_name
description: string | null;
is_active: boolean;
created_at: string;
updated_at: string;
// Stats
total_purchases: number;
total_subscriptions: number;
avg_cpf: number | null; // Average Cost Per Follower
}
```
### ExternalChannel
```typescript
{
id: string;
telegram_id: number | null;
title: string;
username: string | null;
link: string; // t.me link or custom
subscribers_count: number | null;
description: string | null;
created_at: string;
updated_at: string;
// Relations
target_channels: string[]; // IDs of target channels
// Stats
total_purchases: number;
avg_cpf: number | null;
avg_cpm: number | null;
}
```
### Creative
```typescript
{
id: string;
name: string;
text: string; // Template with {link} placeholder
target_channel_id: string;
is_archived: boolean;
created_at: string;
updated_at: string;
// Relations
target_channel: TargetChannel;
// Stats
total_purchases: number;
total_subscriptions: number;
avg_cpf: number | null;
}
```
### Purchase
```typescript
{
id: string;
target_channel_id: string;
external_channel_id: string;
creative_id: string;
// Purchase details
scheduled_date: string | null; // ISO 8601
actual_date: string | null;
cost: number | null; // in rubles
comment: string | null;
post_link: string | null; // Link to ad post in external channel
invite_link: string; // Generated invite link
invite_link_type: "public" | "private"; // with bot approval or not
is_archived: boolean;
created_at: string;
updated_at: string;
// Relations
target_channel: TargetChannel;
external_channel: ExternalChannel;
creative: Creative;
// Stats
subscriptions_count: number;
views_count: number | null;
cpf: number | null; // Cost Per Follower
cpm: number | null; // Cost Per Mile (1000 views)
conversion_rate: number | null; // subscriptions / views * 100
}
```
### Subscription
```typescript
{
id: string;
purchase_id: string;
telegram_user_id: number;
username: string | null;
joined_at: string; // ISO 8601
event_type: "chat_member" | "join_request";
}
```
### ViewsSnapshot
```typescript
{
id: string;
purchase_id: string;
views: number;
fetched_at: string; // ISO 8601
}
```
---
## 3. Целевые каналы
### GET `/target-channels`
Получение списка целевых каналов
**Query params:**
- `is_active?: boolean` - фильтр по активности
**Response:**
```typescript
{
data: TargetChannel[];
total: number;
}
```
### GET `/target-channels/:id`
Получение детальной информации о канале
**Response:**
```typescript
TargetChannel & {
recent_purchases: Purchase[]; // last 5
stats_by_period: {
period: 'day' | 'week' | 'month';
subscriptions: number;
cost: number;
cpf: number;
}[];
}
```
### PATCH `/target-channels/:id`
Обновление канала (только is_active)
**Request:**
```typescript
{
is_active: boolean;
}
```
**Response:**
```typescript
TargetChannel;
```
### DELETE `/target-channels/:id`
Отключение канала (soft delete)
**Response:**
```typescript
{
success: true;
}
```
---
## 4. Внешние каналы
### GET `/external-channels`
Получение списка внешних каналов
**Query params:**
- `target_channel_id?: string` - фильтр по целевому каналу
- `search?: string` - поиск по названию/username
**Response:**
```typescript
{
data: ExternalChannel[];
total: number;
}
```
### GET `/external-channels/:id`
Получение детальной информации
**Response:**
```typescript
ExternalChannel & {
purchases: Purchase[];
}
```
### POST `/external-channels`
Создание нового внешнего канала
**Request:**
```typescript
{
title: string;
username?: string;
link: string;
subscribers_count?: number;
description?: string;
target_channel_ids: string[]; // Привязка к целевым каналам
}
```
**Response:**
```typescript
ExternalChannel;
```
### PATCH `/external-channels/:id`
Обновление внешнего канала
**Request:**
```typescript
Partial<{
title: string;
username: string;
link: string;
subscribers_count: number;
description: string;
target_channel_ids: string[];
}>;
```
**Response:**
```typescript
ExternalChannel;
```
### DELETE `/external-channels/:id`
Удаление внешнего канала
**Response:**
```typescript
{
success: true;
}
```
### POST `/external-channels/import`
Импорт из Excel (Tgstat)
**Request:**
```
Content-Type: multipart/form-data
file: File (Excel)
target_channel_id: string
```
**Response:**
```typescript
{
imported: number;
skipped: number;
errors: string[];
channels: ExternalChannel[];
}
```
---
## 5. Креативы
### GET `/creatives`
Получение списка креативов
**Query params:**
- `target_channel_id?: string` - фильтр по целевому каналу
- `is_archived?: boolean` - фильтр по архивности
**Response:**
```typescript
{
data: Creative[];
total: number;
}
```
### GET `/creatives/:id`
Получение детальной информации
**Response:**
```typescript
Creative & {
purchases: Purchase[];
}
```
### POST `/creatives`
Создание нового креатива
**Request:**
```typescript
{
name: string;
text: string; // Must contain {link} placeholder
target_channel_id: string;
}
```
**Response:**
```typescript
Creative;
```
### PATCH `/creatives/:id`
Обновление креатива
**Request:**
```typescript
Partial<{
name: string;
text: string;
is_archived: boolean;
}>;
```
**Response:**
```typescript
Creative;
```
### DELETE `/creatives/:id`
Удаление креатива (только если нет активных закупов)
**Response:**
```typescript
{
success: true;
}
```
---
## 6. Закупы
### GET `/purchases`
Получение списка закупов
**Query params:**
- `target_channel_id?: string`
- `external_channel_id?: string`
- `creative_id?: string`
- `is_archived?: boolean`
- `date_from?: string` (ISO 8601)
- `date_to?: string` (ISO 8601)
- `sort?: 'date' | 'cost' | 'cpf' | 'subscriptions'`
- `order?: 'asc' | 'desc'`
**Response:**
```typescript
{
data: Purchase[];
total: number;
}
```
### GET `/purchases/:id`
Получение детальной информации о закупе
**Response:**
```typescript
Purchase & {
subscriptions: Subscription[];
views_history: ViewsSnapshot[];
}
```
### POST `/purchases`
Создание нового закупа
**Request:**
```typescript
{
target_channel_id: string;
external_channel_id: string;
creative_id: string;
scheduled_date?: string;
actual_date?: string;
cost?: number;
comment?: string;
post_link?: string;
invite_link_type: 'public' | 'private';
}
```
**Response:**
```typescript
Purchase & {
formatted_message: string; // Creative text with invite_link inserted
}
```
### PATCH `/purchases/:id`
Обновление закупа
**Request:**
```typescript
Partial<{
scheduled_date: string;
actual_date: string;
cost: number;
comment: string;
post_link: string;
is_archived: boolean;
}>;
```
**Response:**
```typescript
Purchase;
```
### DELETE `/purchases/:id`
Удаление закупа
**Response:**
```typescript
{
success: true;
}
```
### POST `/purchases/:id/refresh-views`
Принудительное обновление просмотров
**Response:**
```typescript
{
views: number;
fetched_at: string;
}
```
---
## 7. Аналитика
### GET `/analytics/overview`
Общая статистика
**Query params:**
- `target_channel_id?: string`
- `date_from?: string`
- `date_to?: string`
**Response:**
```typescript
{
total_purchases: number;
total_cost: number;
total_subscriptions: number;
avg_cpf: number;
avg_cpm: number;
avg_conversion_rate: number;
}
```
### GET `/analytics/costs`
Данные для графика затрат
**Query params:**
- `target_channel_id?: string`
- `date_from: string` (required)
- `date_to: string` (required)
- `group_by: 'day' | 'week' | 'month' | 'quarter' | 'year'`
**Response:**
```typescript
{
data: {
period: string; // ISO 8601 date (start of period)
cost: number;
purchases_count: number;
subscriptions: number;
}
[];
}
```
### GET `/analytics/channels`
Аналитика по каналам
**Query params:**
- `target_channel_id?: string`
- `date_from?: string`
- `date_to?: string`
- `type: 'external' | 'target'`
**Response:**
```typescript
{
data: {
channel_id: string;
channel_name: string;
purchases_count: number;
total_cost: number;
total_subscriptions: number;
avg_cpf: number;
avg_cpm: number;
}
[];
}
```
### GET `/analytics/creatives`
Аналитика по креативам
**Query params:**
- `target_channel_id?: string`
- `date_from?: string`
- `date_to?: string`
**Response:**
```typescript
{
data: {
creative_id: string;
creative_name: string;
purchases_count: number;
total_cost: number;
total_subscriptions: number;
avg_cpf: number;
conversion_rate: number;
}
[];
}
```
---
## 8. Коды ошибок
```typescript
{
error: {
code: string;
message: string;
details?: any;
}
}
```
Основные коды:
- `UNAUTHORIZED` - 401
- `FORBIDDEN` - 403
- `NOT_FOUND` - 404
- `VALIDATION_ERROR` - 422
- `INTERNAL_ERROR` - 500
- `CHANNEL_NOT_FOUND` - 404
- `CHANNEL_ALREADY_EXISTS` - 409
- `INSUFFICIENT_PERMISSIONS` - 403
- `CREATIVE_IN_USE` - 409
- `INVALID_INVITE_LINK` - 422