# SP Configurator API

This document describes how your shop communicates securely with the
SP Configurator platform.

## Authentication

All requests to the SP Configurator API must be authenticated.

Set the `Authorization` header using the following format:

```
Authorization: <token>
```

Example:

```
Authorization: aaabbbccc
```

You can obtain (or rotate) your Shop token in the Control Panel.
https://stream-promotion.ru/index.php?route=account/smm

Treat the token as a secret and never expose it in client-side code or logs.

If the header is missing or invalid the API will respond with an
authentication error.

## API Endpoints

### Base URL
```
https://stream-promotion.ru/configurator/
```

### Data format

```typescript
type Geo = {
	id: integer;
	label: string;
};

type KickQuality = {
	id: integer;
	label: string;
};

type Platform = {
	id: integer;
	label: string;
};

type Referrer = {
	id: integer;
	label: string;
};

type FilterOrderRequest = {
	filter: {
        type: "twitch" | "trovo" | "kick" | "youtube" | "vk" | null;
        status: "on" | "off" | null;
		order_id: order_id[] | null;
        is_freez: boolean | null;
        is_stop: boolean | null;
        is_subscribe: boolean | null;
        date_from:  string | null; // example 2026-04-08
        date_to: string | null; // example 2026-04-08
    },
    last_id: string | null;
    limit: integer | null;
	order: "asc" | "desc" | null;
};

type OrderRequest = 
	| {
		type: "twitch.viewers",
		viewers: {
			spread_percent: integer;
			spread_delay: integer;
			auth_percent: integer;
			is_collect_points: boolean;
		},
		views: {
			views_per_viewers: integer;
			unique_viewers_percent: integer;
			retention: integer;
			geo: integer;
		},
		raid: {
			count: integer;
			time: integer;
			viewers_percent: integer;
		},
		is_casino: boolean;
		channels: [
			{
				channel: string;
				viewers: {
					maximum: integer;
					interval: double;
				}
			}
		],
		total_time: string; // timespan examples: 30.00:00:00 or 02:00:00 or 00:15:00
		is_subscribe: boolean;
	  }
	| {
		type: "kick.viewers";
		quality: 0 | 1 | 2;
		channels: [
			{
				channel: string;
				viewers: {
					maximum: integer;
					interval: double;
				}
			}
		],
		views: {
			views_per_viewers: integer;
			geo: integer;
		},
		total_time: string;
		is_subscribe: boolean;
	  }
	| {
		type: "youtube.viewers";
		channels: [
			{
				channel: string;
				viewers: {
					maximum: integer;
					interval: double;
				}
			}
		],
		total_time: string;
		is_subscribe: boolean;
	  }
	| {
		type: "trovo.viewers";
		channels: [
			{
				channel: string;
				viewers: {
					maximum: integer;
					interval: double;
				}
			}
		],
		total_time: string;
		is_subscribe: boolean;
	  }
	| {
		type: "vk.viewers";
		viewers: {
			auth_percent: integer;
		},
		channels: [
			{
				channel: string;
				viewers: {
					maximum: integer;
					interval: double;
				}
			}
		],
		total_time: string;
		is_subscribe: boolean;
	  };
```

### User Info

`GET /api/user/info` возвращает информацию о текущем пользователе

```http
GET /api/user/info
Authorization: 111:aaabbbccc
```

```json
{
    "balance": 176.00,
    "currency": "USD",
    "language": "ru-ru"
}
```

### Helper

`GET /api/helper/geo` возвращает информацию о локациях. Список локаций отсортирован по популярности

```http
GET /api/helper/geo
Authorization: 111:aaabbbccc
```

```json
[
    {
        "id": 7,
        "label": "Russia"
    },
    {
        "id": 1,
        "label": "SNG"
    },
	{
        "id": 1000,
        "label": "SNG PRO"
    }
]
```

`GET /api/helper/kick/quality` возвращает информацию о качестве зритилей Kick

```http
GET /api/helper/kick/quality
Authorization: 111:aaabbbccc
```

```json
[
    {
        "id": 0,
        "label": "MQ"
    },
    {
        "id": 1,
        "label": "HQ"
    },
    {
        "id": 2,
        "label": "UHQ"
    }
]
```

`GET /api/helper/platforms` возвращает информацию о платформах для просмотров

```http
GET /api/helper/platforms
Authorization: 111:aaabbbccc
```

```json
[
    {
        "id": 1,
        "label": "Web"
    },
    {
        "id": 2,
        "label": "iOS"
    },
    {
        "id": 3,
        "label": "Android"
    }
]
```

`GET /api/helper/referrers` возвращает информацию о реферрерах для просмотров

```http
GET /api/helper/referrers
Authorization: 111:aaabbbccc
```

```json
[
    {
        "id": 1,
        "label": "Following"
    },
    {
        "id": 2,
        "label": "Notification on site"
    },
    {
        "id": 3,
        "label": "Other Recommendation"
    }
]
```

`POST /api/helper/calculator` возвращает информацию о предварительной стоимости заказа

```http
POST /api/helper/calculator
Authorization: 111:aaabbbccc
Content-Type: application/json

{
    "type": "twitch.viewers",
    "viewers": {
        "spread_percent": 0,
        "spread_delay": 0,
        "auth_percent": 0,
        "is_collect_points": false
    },
    "views": {
        "views_per_viewers": 0,
        "unique_viewers_percent": 0,
        "retention": 0,
        "geo": 0
    },
    "raid": {
        "count": 0,
        "time": 0,
        "viewers_percent": 0
    },
    "is_casino": false,
    "channels": [
        {
            "channel": "foobar",
            "viewers": {
                "maximum": 335,
                "interval": 1
            }
        }
    ],
    "total_time": "10.00:00:00",
    "is_subscribe": false
}
```

```json
{
    "total_amount": 17.50,
    "total_base": 19.44,
    "currency": "USD"
}
```

### Orders

`POST /api/orders` возвращает информацию о заказах пользователя

```http
POST /api/orders
Authorization: 111:aaabbbccc
Content-Type: application/json

{
    "filter": {
        "type": "twitch",
        "status": "on",
		"order_id": [
			123
		],
        "is_freez": false,
        "is_stop": false,
        "is_subscribe": false,
        "date_from": "2026-04-01",
        "date_to": "2026-04-08"
    },
    "last_id": null,
    "limit": 20
}
```

```json
{
    "items": [
        {
            "uuid": "uuid",
            "order_id": 0,
            "type": "twitch.viewers",
            "viewers": {
                "count": 120,
                "interval": 2
            },
            "channels": [
                "foobar"
            ],
            "total_time": "0.12:00:00",
            "free_time": "0.00:00:00",
            "is_subscribe": false,
            "is_stop": false,
            "is_freez": false,
            "status": "on",
            "actions": [
				"edit",
				"pause",
				"stop"
			],
            "added_at": "2026-04-01T00:39:11+03:00"
        }
	],
	"last_id": "Mjk4OTA0",
    "has_next": true
}
```

`POST /api/order` создает заказ пользователя

```http
POST /api/order
Authorization: 111:aaabbbccc
Content-Type: application/json

{
    "type": "kick.viewers",
	"quality": 1,
    "views": {
        "views_per_viewers": 0,
        "geo": 0,
        "referrers": [
            {
                "id": 1,
                "min": 5,
                "max": 15
            },
            {
                "id": 11,
                "min": 5,
                "max": 15,
                "value": "foobar"
            }
        ],
        "platforms": [
            {
                "id": 1,
                "min": 20,
                "max": 20
            }
        ]
    },
    "channels": [
        {
            "channel": "foobar",
            "viewers": {
                "maximum": 335,
                "interval": 1
            }
        }
    ],
    "total_time": "10.00:00:00",
    "is_subscribe": false
}
```

```json
{
    "uuid": "uuid",
    "order_id": 0
}
```

`GET /api/order/<uuid>` возвращает подробную информацию о заказе

```http
GET /api/order/<uuid>
Authorization: 111:aaabbbccc
```

```json
{
    "uuid": "uuid",
    "order_id": 0,
    "type": "twitch.viewers",
    "viewers": {
        "count": 18,
        "interval": 1,
        "spread_percent": 0,
        "spread_delay": 0,
        "auth_percent": 0,
        "is_collect_points": false
    },
    "views": {
        "views_per_viewers": 0,
        "unique_viewers_percent": 0,
        "retention": 0,
        "geo": 0
    },
    "raid": {
        "count": 0,
        "time": 0,
        "viewers_percent": 0
    },
    "is_casino": false,
    "channels": [
        {
            "channel": "foobar1",
            "priority": 0,
            "viewers": {
                "maximum": 18,
                "interval": 1,
                "spread_percent": 0,
                "spread_delay": 0,
                "auth_percent": 0,
                "is_collect_points": false
            },
            "views": {
                "views_per_viewers": 0,
                "unique_viewers_percent": 0,
                "retention": 0,
                "geo": 0,
                "platforms": [
                    {
                        "id": 1,
                        "min": 5,
                        "max": 15
                    }
                ],
                "referrers": []
            },
            "raid": {
                "count": 0,
                "time": 0,
                "viewers_percent": 0
            }
        },
		{
            "channel": "foobar2",
            "priority": 0,
            "viewers": {
                "maximum": 18,
                "interval": 1,
                "spread_percent": 0,
                "spread_delay": 0,
                "auth_percent": 0,
                "is_collect_points": false
            },
            "views": {
                "views_per_viewers": 0,
                "unique_viewers_percent": 0,
                "retention": 0,
                "geo": 0
            },
            "raid": {
                "count": 0,
                "time": 0,
                "viewers_percent": 0
            }
        }
    ],
    "total_time": "30.00:00:00",
    "free_time": "23.01:44:10",
    "is_subscribe": true,
    "is_stop": false,
    "is_freez": false,
    "status": "on",
    "actions": [
        "edit",
        "stop",
        "pause"
    ],
    "added_at": "2026-04-01T22:03:16+03:00"
}
```

`PATCH /api/order/<uuid>` изменяет информацию о заказе

```http
PATCH /api/order/<uuid>
Authorization: 111:aaabbbccc
Content-Type: application/json

{
    "channels": [
        {
            "channel": "foobar3",
            "priority": 0,
            "viewers": {
                "maximum": 18,
                "interval": 1,
                "spread_percent": 0,
                "spread_delay": 0,
                "auth_percent": 0,
                "is_collect_points": false
            }
        },
		{
            "channel": "foobar4",
            "priority": 0,
            "viewers": {
                "maximum": 18,
                "interval": 1,
                "spread_percent": 0,
                "spread_delay": 0,
                "auth_percent": 0,
                "is_collect_points": false
            },
			"views": {
                "views_per_viewers": 0,
				"unique_viewers_percent": 0,
				"retention": 0,
				"geo": 0,
                "platforms": [
                    {
                        "id": 1,
                        "min": 5,
                        "max": 15
                    }
                ],
                "referrers": []
            },
			"raid": {
                "time": 0,
        		"viewers_percent": 0
            }
        }
    ],
    "is_stop": false,
    "is_freez": false
}
```

```json
{
	"updated": true
}
```

`PUT /api/order/<uuid>/renew` продление заказа. Если текущий заказ продлить невозможно, то будет создан новый - признак is_new в ответе

```http
PUT /api/order/<uuid>/renew
Authorization: 111:aaabbbccc
```

```json
{
	"uuid": "uuid",
	"order_id": 0,
	"is_new": true
}
```

#### Order type

| Field          | Description                                                              |
| -------------- | ------------------------------------------------------------------------ |
| `uuid`         | Уникальный айди заказа                                                   |
| `order_id`     | Айди заказа на витрине платформы                                         |
| `type`         | Тип заказа                                                               |
| `quality`      | Качество зрителей для Kick                                               |
| `is_casino`    | Признак специфики канала - казино                                        |
| `total_time`   | Общее время заказа                                                       |
| `free_time`    | Оставшееся время заказа                                                  |
| `is_subscribe` | Признак подписки                                                         |
| `is_stop`      | Заказ остановлен                                                     	|
| `is_freez`     | Заказ на паузе                                                           |
| `status`       | Статус заказа                                                            |
| `actions`      | Доступные действия с заказом                                             |
| `added_at`     | Дата создания заказа                                                     |

#### Order.channels[$i]

| Field value | Description                                      |
| ----------- | ------------------------------------------------ |
| `channel`   | Название канала                                  |
| `priority`  | Приоритет канала в списке подписки               |

#### Order.channels[$i].viewers

| Field value         | Description                                      |
| ------------------- | ------------------------------------------------ |
| `maximum`           | Количество зрителей на канал                     |
| `interval`          | Интервал для зрителей, секунды 0.1-300           |
| `spread_percent`    | Процент плавающих зрителей, 1-50                |
| `spread_delay`      | Пауза разброса зрителей, секунды 120-900         |
| `auth_percent`      | Процент авторизации зрителей, 1-100              |
| `is_collect_points` | Сбор баллов для Twitch                           |


#### Order.channels[$i].views

| Field value              | Description                                      |
| ------------------------ | ------------------------------------------------ |
| `views_per_viewers`      | Просмотры в час, от одного зрителя, 1-50         |
| `unique_viewers_percent` | Процент уникальных зрителей, 1-100               |
| `retention`              | Удержание, секунды 60-900                        |
| `geo`                    | Локация просмотров                               |
| `platforms`              | Платформы просмотров                             |
| `referrers`              | Источники просмотров                             |

#### Order.channels[$i].views.platforms[$i]

| Field value       | Description                                      |
| ----------------- | ------------------------------------------------ |
| `id`              | Идентификатор платформы из справочника           |
| `min`             | Минимальный % просмотров                         |
| `max`             | Максимальный % просмотров                        |

#### Order.channels[$i].views.referrers[$i]

| Field value       | Description                                      |
| ----------------- | ------------------------------------------------ |
| `id`              | Идентификатор источника из справочника           |
| `min`             | Минимальный % просмотров                         |
| `max`             | Максимальный % просмотров                        |
| `value`           | Имя канала для Twitch                            |

#### Order.channels[$i].raid

| Field value       | Description                                      |
| ----------------- | ------------------------------------------------ |
| `count`           | Количество рейдов                                |
| `time`            | Время рейда, секунды 60-43200                    |
| `viewers_percent` | Процент зрителей в рейде, 1-100                  |

### Security Best Practices

- Enforce HTTPS and reject plain HTTP.
- Validate `Content-Type` is `application/json`.
- Rate-limit the endpoint to mitigate abuse.
- Store only required fields; avoid persisting entire raw payloads unless
  needed for audit.
