﻿# Yoto Files API (v1)

Публичный API для интеграции заданий Yoto Files в ваше приложение, бота или
сайт: получайте список заданий для пользователя и проверяйте их выполнение.

База: `https://yotofiles.com/api/v1`
Онлайн-версия: https://yotofiles.com/api/docs

## Методы

| Метод | Назначение |
|-------|------------|
| `GET  /api/v1/get_tasks`  | Получение списка заданий для пользователя |
| `POST /api/v1/check_task` | Проверка выполнения заданий |
| `GET  /api/v1/ping`       | Доступность API (без авторизации) |
| `GET  /api/v1/me`         | Информация о текущем ключе и его статистике |

Алиасы: `GET /api/v1/tasks`, `POST /api/v1/tasks/check`.

Ответ `/api/v1/me` — сам ключ и его счётчики (те же, что видно в боте):

```json
{
  "ok": true,
  "key_id": 12,
  "owner_id": 987654321,
  "name": "Мой бот",
  "key_prefix": "yf_AbCdEfGh…",
  "created_at": "2026-07-16T10:00:00+00:00",
  "requests_total": 1024,
  "tasks_issued": 380,
  "tasks_completed": 205,
  "earned_total": "12.40"
}
```

## Авторизация

Все запросы (кроме `/ping`) требуют личный API-ключ. Ключ создаётся в боте
Yoto Files (@YotoFilesBot): меню → **API** → «Создать ключ».

Можно создать **до 5 ключей** — каждому задаётся необязательное название, у
каждого своя статистика (запросы, выданные и выполненные задания, заработок),
доступная в мини-аппе в боте. Ключ всегда можно посмотреть в боте (он показан
скрытым — нажмите, чтобы раскрыть) и настроить для него ссылку возврата после
капчи.

Передавайте ключ в заголовке `X-Api-Key` (поддерживается и `Authorization: Bearer`).
Копируйте команду **одной строкой**:

```
curl -H "X-Api-Key: yf_ВАШ_КЛЮЧ" "https://yotofiles.com/api/v1/get_tasks?user_id=123456789"
```

> Если разбивать команду знаком `\`, не оставляйте пробел после `\` — иначе curl
> вернёт `curl: (3) URL rejected: Malformed input to a URL function`.

> Храните ключ в секрете. Если ключ скомпрометирован — сбросьте/удалите его в
> боте: он перестанет работать сразу.

## Капча

Задания выдаются только пользователям, прошедшим проверку «я не робот» в
Yoto Files. Это то же самое окно, что видят пользователи бота: мини-апп с
галочкой, где Telegram спрашивает разрешение отправлять сообщения. Именно
это разрешение и нужно провайдерам заданий, чтобы человека стало видно.

`/get_tasks` и `/check_task` вернут `status: "captcha_required"`, когда:

* пользователь ещё не проходил проверку;
* проверка перестала действовать — провайдер сообщил, что больше не видит
  пользователя (заблокировал бота, удалил аккаунт). Тогда `captcha_required`
  придёт и тому, кто раньше получал задания.

```json
{
  "ok": true,
  "status": "captcha_required",
  "message": "Требуется проверка «я не робот».",
  "user_id": 123456789,
  "captcha": {
    "link": "https://t.me/YotoFilesBot/captcha?startapp=api12",
    "status": "not_passed"
  },
  "tasks": []
}
```

Покажите пользователю окно капчи: текст `message`, кнопку «Пройти проверку»
со ссылкой `captcha.link` и кнопку «Готово», по которой вы повторяете запрос.
Ссылка открывает мини-апп внутри Telegram — из бота выходить не нужно, и
нажимать «Start» тоже.

**Возврат в ваше приложение.** В настройках ключа (бот → API → ключ →
⚙️ Настройки) можно указать ссылку возврата. Тогда после проверки мини-апп
покажет кнопку **«Вернуться в приложение»** на этот адрес. Id ключа
автоматически вшивается в `captcha.link` (`startapp=api<id>`) — отдельно
ничего передавать не нужно.

## GET /api/v1/get_tasks

Получение списка заданий — **тот же набор**, что бот показывает при получении
материалов. Типы: `external` — задания платформы, `personal` — ваши личные
каналы-задания. Поле `provider` уточняет источник внешнего задания: `op` —
ваши собственные задания; `YotoFiles` — задания платформы.

Задания платформы (`provider: "YotoFiles"`) показываются, только если включена
монетизация и настройка «Использовать внешние задания». За их выполнение
(подтверждённое через `/check_task`) вам начисляется вознаграждение — как в боте.

Параметры query:

| Параметр  | Тип                | Описание |
|-----------|--------------------|----------|
| `user_id` | int, обязателен    | Telegram ID пользователя |
| `limit`   | int, 1–10          | Максимум внешних заданий (личные включаются всегда). По умолчанию 5 |

Что подставить:

```
Key    : yf_ВАШ_КЛЮЧ    -> заголовок X-Api-Key (обязательно)
UserID : 123456789      -> параметр user_id  (обязательно)
limit  : 5              -> параметр limit    (необязательно, 1-10)
```

Пример запроса (одной строкой):

```
curl -H "X-Api-Key: yf_ВАШ_КЛЮЧ" "https://yotofiles.com/api/v1/get_tasks?user_id=123456789&limit=5"
```

```python
import requests

resp = requests.get(
    "https://yotofiles.com/api/v1/get_tasks",
    headers={"X-Api-Key": "yf_ВАШ_КЛЮЧ"},
    params={"user_id": 123456789, "limit": 5},
)
print(resp.json())
```

Ответ:

```json
{
  "ok": true,
  "status": "ok",
  "user_id": 123456789,
  "tasks": [
    {
      "id": "ext_42",
      "number": 1,
      "type": "external",
      "title": "Подписаться на канал",
      "link": "https://t.me/example_channel",
      "date": "2026-07-01T12:00:00+00:00",
      "status": "not_completed",
      "action": "subscribe"
    },
    {
      "id": "pers_7",
      "number": 2,
      "type": "personal",
      "title": "Мой канал",
      "link": "https://t.me/my_channel",
      "date": "2026-06-20T18:05:00+00:00",
      "status": "completed",
      "action": "subscribe"
    }
  ],
  "count": 2,
  "all_completed": false
}
```

Поля задания:

| Поле     | Описание |
|----------|----------|
| `id`     | ID для `/check_task`. Передавайте как есть, без разбора префикса |
| `number` | Номер задания в блоке (с 1) |
| `type`   | `personal` (ваш канал) или `external` (задание платформы) |
| `provider` | Источник внешнего задания: `op` — ваши собственные задания; `YotoFiles` — задания платформы (личные каналы — `null`) |
| `title`  | Название задания |
| `link`   | Ссылка для пользователя |
| `date`   | Дата создания (ISO 8601) |
| `status` | `completed` / `not_completed` (зачёт — в `/check_task`) |
| `action` | `subscribe` или `join_request` |

## POST /api/v1/check_task

Проверка выполнения заданий. Можно одно (`task_id`) или несколько (`task_ids`).

Что подставить:

```
Key     : yf_ВАШ_КЛЮЧ           -> заголовок X-Api-Key (обязательно)
UserID  : 123456789             -> поле user_id       (обязательно)
task_id : ext_42                -> одно задание, ИЛИ
task_ids: ["ext_42","pers_7"]   -> несколько заданий
```

Тело (application/json):

```json
{ "user_id": 123456789, "task_ids": ["ext_42", "pers_7"] }
```

```json
{ "user_id": 123456789, "task_id": "ext_42" }
```

Пример запроса (одной строкой):

```
curl -X POST "https://yotofiles.com/api/v1/check_task" -H "X-Api-Key: yf_ВАШ_КЛЮЧ" -H "Content-Type: application/json" -d "{\"user_id\": 123456789, \"task_id\": \"ext_42\"}"
```

Ответ:

```json
{
  "ok": true,
  "status": "ok",
  "user_id": 123456789,
  "results": [
    { "id": "ext_42", "completed": true,  "state": "completed" },
    { "id": "pers_7", "completed": false, "state": "not_completed" }
  ],
  "all_completed": false
}
```

`state`: `completed` | `not_completed` | `unknown` (временная ошибка, повторить)
| `not_found`. Не более 20 заданий за запрос.

`/check_task` тоже может вернуть `status: "captcha_required"` вместо
`results` — по тем же правилам, что `/get_tasks`.

## Ошибки и лимиты

Единый формат ошибки:

```json
{ "ok": false, "error": { "code": "unauthorized", "message": "…" } }
```

| HTTP | code            | Описание |
|------|-----------------|----------|
| 400  | `bad_request`   | Некорректные параметры/JSON |
| 401  | `unauthorized`  | Ключ не передан/неверен/отозван |
| 429  | `rate_limited`  | Превышен лимит (см. `error.retry_after` и заголовок `Retry-After`) |
| 500  | `internal_error`| Внутренняя ошибка |
| 503  | `unavailable`   | Сервис временно недоступен — повторите запрос |
| 503  | `provider_unavailable` | Провайдер заданий не отвечает — повторите позже |

Базовый лимит — **300 запросов в секунду** на ключ (всплески до 600). Нужен
больший — напишите в поддержку: https://t.me/YotoNews?direct

## Рекомендуемый сценарий

1. Пользователь запрашивает контент в вашем приложении.
2. Вызовите `GET /api/v1/get_tasks?user_id=…`.
3. Если `status = "captcha_required"` — покажите кнопку «Пройти проверку»
   (`captcha.link`) и «Готово», по которой повторяете шаг 2. Этот же ответ
   может прийти и позже, у пользователя с историей: значит, проверку надо
   пройти заново.
4. Покажите задания (кнопка с `title` и `link` + «Проверить»).
5. По «Проверить» вызовите `POST /api/v1/check_task` со списком `task_ids`.
6. Когда `all_completed = true` — выдайте контент.

Поддержка: https://t.me/YotoNews?direct · Новости: @YotoNews
