SOROKA Документация API

Справочник

Все пути API этой версии — из /v1/openapi.json. У каждого: право ключа, поля, пример ответа и пример запроса на curl и Python. Ключ в примерах берётся из переменной окружения API_KEY.

Служебное

Проверка ключа и учёт вызовов. Эти пути не тратят кредиты.

GET /v1/me

Мой ключ

любой ключ ответ 200

Что может этот ключ: права, лимиты, расход за сегодня, тариф и остаток кредитов. Удобно проверять ключ: вызов не тратит ни лимит в минуту, ни кредиты.

billing — null, если расход не тарифицируется.

curl
curl -s "https://soroka.tools/v1/me" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/me", headers=headers, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "key": "reports",
  "org": "acme",
  "scopes": [
    "jobs",
    "tg:read",
    "tg:stream"
  ],
  "pools": [],
  "rate_per_min": 600,
  "daily_quota": null,
  "expires_at": null,
  "usage_today": {
    "calls": 120,
    "items": 5311
  },
  "rate_remaining": 598,
  "billing": {
    "plan": "api.start",
    "status": "active",
    "credits": {
      "included": 30000,
      "used": 1250.5,
      "left": 28749.5,
      "percent": 4
    }
  }
}
GET /v1/usage

Учёт ключа

любой ключ ответ 200

Вызовы, ошибки и отданные записи по дням или по методам. Период — не длиннее 93 суток, по умолчанию последние 7.

полегдетипсмысл
from запрос string начало периода, ГГГГ-ММ-ДД (UTC)
to запрос string конец периода включительно, ГГГГ-ММ-ДД (UTC)
group_by запрос string day или method · по умолчанию day
curl
curl -s "https://soroka.tools/v1/usage?from=2026-09-16&to=2026-09-22&group_by=day" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/usage",
    headers=headers,
    params={"from": "2026-09-16", "to": "2026-09-22", "group_by": "day"},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "from": "2026-09-16",
  "to": "2026-09-22",
  "group_by": "day",
  "items": [
    {
      "day": "2026-09-22",
      "calls": 1200,
      "ok": 1180,
      "errors": {
        "too_often": 12
      },
      "items": 50311
    }
  ]
}

Telegram: чтение

Карточки, посты и сообщения публичных каналов и чатов, медиа из них.

POST /v1/tg/resolve

Карточка канала или чата

tg:read ответ 200

Узнать, что стоит за ссылкой: вид, peer_id, название, число подписчиков, описание. Свежие карточки отдаются из нашего каталога сразу.

source: catalog — из каталога, иначе — только что из Telegram. fresh: true — всегда из Telegram (для сверки, а не на каждый запрос).

полегдетипсмысл
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
ref* тело string | integer канал, чат или сообщество: @name, ссылка t.me/… или peer_id
fresh тело boolean true — не брать из нашего каталога, спросить Telegram заново · по умолчанию false
curl
curl -s "https://soroka.tools/v1/tg/resolve" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ref": "@telegram"}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(f"{API}/v1/tg/resolve", headers=headers, json={"ref": "@telegram"}, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "kind": "channel",
  "peer_id": -1005678901234,
  "username": "telegram",
  "title": "Telegram News",
  "participants_count": 9800000,
  "about": "…",
  "linked_chat_id": null,
  "is_public": true,
  "source": "catalog"
}
POST /v1/tg/full

Полная карточка

tg:read ответ 200

Сущность и полная карточка канала или чата: описание, связанный чат обсуждений, закреплённое сообщение, счётчики.

полегдетипсмысл
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
ref* тело string | integer канал, чат или сообщество: @name, ссылка t.me/… или peer_id
curl
curl -s "https://soroka.tools/v1/tg/full" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ref": "@telegram"}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(f"{API}/v1/tg/full", headers=headers, json={"ref": "@telegram"}, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "entity": {
    "_": "Channel",
    "id": 5678901234,
    "title": "Telegram News"
  },
  "result": {
    "_": "ChatFull",
    "full_chat": {
      "about": "…",
      "participants_count": 9800000
    }
  }
}
POST /v1/tg/messages

Сообщения

tg:read ответ 200

Сообщения канала или чата, от новых к старым (reverse: true — наоборот). До 1 000 за вызов; больше — листать offset_id или потоком.

Поток: ?stream=1 — строка на сообщение, последняя — {"done": true, "count": n, "cursor": {…}}.

полегдетипсмысл
stream запрос integer true или ?stream=1 — отдавать NDJSON-потоком, по записи на строку (нужно право tg:stream) · по умолчанию 0
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
chat* тело string | integer канал или чат: @name, https://t.me/name или peer_id числом
limit тело integer сколько записей вернуть · 1…1000 · по умолчанию 100
min_id тело integer только записи с id больше этого
max_id тело integer только записи с id меньше этого
offset_id тело integer начать со записи до этого id (листать назад)
offset_date тело string начать с записей до этой даты (ISO-8601)
reverse тело boolean от старых к новым
ids тело array of integer конкретные id записей · до 1000 элементов
stream тело boolean true или ?stream=1 — отдавать NDJSON-потоком, по записи на строку (нужно право tg:stream) · по умолчанию false
curl
curl -s "https://soroka.tools/v1/tg/messages" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chat": "@telegram", "limit": 50}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/messages",
    headers=headers,
    json={"chat": "@telegram", "limit": 50},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "items": [
    {
      "id": 512,
      "date": "2026-09-23T09:15:00+00:00",
      "text": "…",
      "views": 18400,
      "forwards": 52,
      "sender_id": null,
      "reply_to": null,
      "media": null
    }
  ]
}
POST /v1/tg/posts

Посты канала

tg:read ответ 200

Как «Сообщения», но альбом приходит одним постом: подпись и все части в media[]. Для каналов это удобнее всего.

полегдетипсмысл
stream запрос integer true или ?stream=1 — отдавать NDJSON-потоком, по записи на строку (нужно право tg:stream) · по умолчанию 0
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
chat* тело string | integer канал или чат: @name, https://t.me/name или peer_id числом
limit тело integer сколько записей вернуть · 1…1000 · по умолчанию 100
min_id тело integer только записи с id больше этого
max_id тело integer только записи с id меньше этого
offset_id тело integer начать со записи до этого id (листать назад)
offset_date тело string начать с записей до этой даты (ISO-8601)
reverse тело boolean от старых к новым
ids тело array of integer конкретные id записей · до 1000 элементов
stream тело boolean true или ?stream=1 — отдавать NDJSON-потоком, по записи на строку (нужно право tg:stream) · по умолчанию false
curl
curl -s "https://soroka.tools/v1/tg/posts" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chat": "@telegram", "limit": 20}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/posts",
    headers=headers,
    json={"chat": "@telegram", "limit": 20},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "items": [
    {
      "id": 512,
      "peer_id": -1005678901234,
      "date": "2026-09-23T09:15:00+00:00",
      "text": "Текст поста",
      "views": 18400,
      "forwards": 52,
      "media": [],
      "ids": [
        512
      ]
    }
  ]
}
POST /v1/tg/media

Медиа сообщения

tg:media ответ 200

Ссылка на файл из сообщения (живёт 15 минут, только этому ключу). С Accept: application/octet-stream — сразу байты файла.

Нет медиа — 404 no_data, code=no_media; больше max_bytes — 400 caller_error, code=too_large.

полегдетипсмысл
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
chat* тело string | integer канал или чат: @name, https://t.me/name или peer_id числом
msg_id* тело integer id сообщения с медиа · 1……
index тело integer номер части альбома, начиная с 0 · 0…9
max_bytes тело integer не больше стольких байт (по умолчанию 20 МБ) · 1…209 715 200
curl
curl -s "https://soroka.tools/v1/tg/media" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chat": "@telegram", "msg_id": 512}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/media",
    headers=headers,
    json={"chat": "@telegram", "msg_id": 512},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "url": "/v1/tg/media/Zm9vYmFyLmpwZw",
  "size": 482133,
  "mime": "image/jpeg",
  "expires_at": "2026-09-23T10:15:00+00:00"
}
GET /v1/tg/media/{token}

Файл медиа по ссылке

tg:media ответ 200

Скачать файл по ссылке из POST /v1/tg/media. Картинки, видео и звук отдаются для показа, всё прочее — вложением.

полегдетипсмысл
token* путь string метка из ссылки, которую вернул POST /v1/tg/media
curl
curl -s "https://soroka.tools/v1/tg/media/Zm9vYmFyLmpwZw" \
  -H "Authorization: Bearer $API_KEY" \
  -o media.jpg
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/tg/media/Zm9vYmFyLmpwZw", headers=headers, timeout=60)
r.raise_for_status()
with open("media.jpg", "wb") as f:
    f.write(r.content)

Telegram: подписки на события

Новые посты и сообщения из списка каналов — потоком, страницами или вебхуком.

GET /v1/tg/subscriptions

Список подписок

tg:stream ответ 200

Подписки ключа, от новых к старым, страницами по курсору.

полегдетипсмысл
limit запрос integer сколько записей вернуть · по умолчанию 50
cursor запрос string курсор следующей страницы из next_cursor прошлого ответа
curl
curl -s "https://soroka.tools/v1/tg/subscriptions?limit=50" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/tg/subscriptions", headers=headers, params={"limit": 50}, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "items": [
    {
      "subscription_id": "5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
      "name": "brand-watch",
      "delivery": "webhook",
      "events": [
        "post"
      ],
      "chats_total": 2,
      "chats_active": 2,
      "chats_waiting": 0,
      "last_event_at": "2026-09-23T09:15:02+00:00",
      "created_at": "2026-09-20T08:00:00+00:00",
      "ended_at": null
    }
  ],
  "next_cursor": null
}
POST /v1/tg/subscriptions

Создать подписку

tg:streamIdempotency-Key рекомендуется ответ 201

Подписка — список каналов и способ доставки. Новые посты приходят потоком SSE, страницами или вебхуком; какой способ выбрать — в «Основах».

webhook_secret — только при delivery: webhook, показывается один раз.

Статус чата: resolving → active; no_data — канала нет или он закрыт.

полегдетипсмысл
name тело string имя для себя · до 100 симв.
chats* тело array of string | integer | object до 5 000 каналов и чатов: строка-ссылка или объект {ref, priority, backfill} · до 5000 элементов
events тело array of new | edit | delete | action | post new, edit, delete, action, post; по умолчанию ["new"]
delivery тело stream | pull | webhook stream (SSE, по умолчанию), pull (страницами) или webhook · по умолчанию stream
webhook_url тело string https-адрес, куда присылать события (для delivery: webhook) · до 2000 симв.
format тело json | tl | both json (по умолчанию) · по умолчанию json
curl
curl -s "https://soroka.tools/v1/tg/subscriptions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name": "brand-watch", "chats": ["@telegram", {"ref": "@tginfo", "backfill": 20}], "events": ["post"], "delivery": "webhook", "webhook_url": "https://example.ru/hooks/tg"}'
Python
import os
import uuid

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
headers["Idempotency-Key"] = str(uuid.uuid4())  # тот же ключ при повторе того же запроса

r = httpx.post(
    f"{API}/v1/tg/subscriptions",
    headers=headers,
    json={
        "name": "brand-watch",
        "chats": [
            "@telegram",
            {
                "ref": "@tginfo",
                "backfill": 20
            }
        ],
        "events": [
            "post"
        ],
        "delivery": "webhook",
        "webhook_url": "https://example.ru/hooks/tg"
    },
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 201
{
  "subscription_id": "5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
  "webhook_secret": "whs_…",
  "chats": [
    {
      "ref": "@telegram",
      "peer_id": -1005678901234,
      "status": "active",
      "mode": "poll"
    }
  ]
}
GET /v1/tg/subscriptions/{sub_id}

Подписка целиком

tg:stream ответ 200

Подписка с чатами и их статусами. Больше 500 чатов — листать chats_cursor.

полегдетипсмысл
sub_id* путь string subscription_id подписки
chats_cursor запрос string курсор следующей страницы чатов подписки
curl
curl -s "https://soroka.tools/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "subscription_id": "5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
  "status": "active",
  "chats": [
    {
      "ref": "@telegram",
      "peer_id": -1005678901234,
      "status": "active",
      "priority": 0
    }
  ],
  "chats_cursor": null
}
PATCH /v1/tg/subscriptions/{sub_id}

Изменить подписку

tg:stream ответ 200

Имя, события, способ доставки, адрес вебхука, пауза, новый секрет вебхука. Сутки после смены секрета пачки подписываются обоими секретами.

Паузу, которую поставили мы (ключ отозван, тариф) снять нельзя — 409 conflict, code=paused_by_owner.

полегдетипсмысл
sub_id* путь string subscription_id подписки
name тело string имя для себя · до 100 симв.
events тело array of new | edit | delete | action | post new, edit, delete, action, post; по умолчанию ["new"]
format тело json | tl | both json (по умолчанию)
delivery тело stream | pull | webhook stream (SSE, по умолчанию), pull (страницами) или webhook
webhook_url тело string https-адрес, куда присылать события (для delivery: webhook) · до 2000 симв.
active тело boolean false — пауза подписки, true — снять свою паузу и заново включить вебхук
rotate_webhook_secret тело boolean true — выпустить новый секрет вебхука (придёт в ответе один раз) · по умолчанию false
curl
curl -s -X PATCH "https://soroka.tools/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"active": false}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.patch(
    f"{API}/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
    headers=headers,
    json={"active": False},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "subscription_id": "5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
  "status": "paused"
}
DELETE /v1/tg/subscriptions/{sub_id}

Закончить подписку

tg:stream ответ 200

События больше не копятся. Повтор — тоже 200.

полегдетипсмысл
sub_id* путь string subscription_id подписки
curl
curl -s -X DELETE "https://soroka.tools/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.delete(
    f"{API}/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "subscription_id": "5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13",
  "status": "ended",
  "ended_at": "2026-09-23T12:00:00+00:00"
}
POST /v1/tg/subscriptions/{sub_id}/chats

Добавить каналы

tg:stream ответ 200

Добавить каналы в подписку; уже подписанные остаются как были.

полегдетипсмысл
sub_id* путь string subscription_id подписки
chats* тело array of string | integer | object до 5 000 каналов и чатов: строка-ссылка или объект {ref, priority, backfill} · до 5000 элементов
curl
curl -s "https://soroka.tools/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/chats" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chats": ["@telegram"]}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/chats",
    headers=headers,
    json={"chats": ["@telegram"]},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "chats": [
    {
      "ref": "@telegram",
      "peer_id": -1005678901234,
      "status": "active"
    }
  ]
}
DELETE /v1/tg/subscriptions/{sub_id}/chats/{ref}

Убрать канал

tg:stream ответ 200

Снять канал с подписки по peer_id или ссылке.

Канала в подписке нет — 404 not_found.

полегдетипсмысл
sub_id* путь string subscription_id подписки
ref* путь string peer_id или ссылка канала в подписке
curl
curl -s -X DELETE "https://soroka.tools/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/chats/-1005678901234" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.delete(
    f"{API}/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/chats/-1005678901234",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "removed": 1
}
GET /v1/tg/subscriptions/{sub_id}/stream

Поток событий (SSE)

tg:stream ответ 200

События подписки потоком text/event-stream. При обрыве — переподключиться с Last-Event-ID: пропусков не будет (события хранятся 7 дней). Раз в 15 секунд приходит : ping.

Один поток на подписку: второй — 409 conflict, code=stream_busy.

полегдетипсмысл
sub_id* путь string subscription_id подписки
after запрос integer id последнего полученного события
Last-Event-ID заголовок string id последнего полученного события — продолжить с него
curl
curl -sN "https://soroka.tools/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/stream" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: text/event-stream"
Python
import os
import json

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
headers["Accept"] = "text/event-stream"

with httpx.stream("GET", f"{API}/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/stream", headers=headers, timeout=None) as r:
    r.raise_for_status()
    for line in r.iter_lines():          # при обрыве — снова с заголовком Last-Event-ID
        if line.startswith("data:"):
            event = json.loads(line[5:])
            print(event["id"], event["kind"])
Ответ 200
id: 18446
event: post
data: {"id": "18446", "kind": "post", "chat": {…}, "message": {…}, "received_at": "2026-09-23T09:15:02Z"}
GET /v1/tg/subscriptions/{sub_id}/events

События страницами

tg:stream ответ 200

Забрать события после after. wait — подождать до N секунд, если событий пока нет; ack=1 — отметить, докуда обработано.

полегдетипсмысл
sub_id* путь string subscription_id подписки
after запрос integer id последнего полученного события · по умолчанию 0
limit запрос integer сколько записей вернуть · по умолчанию 500
wait запрос integer сколько секунд ждать событий, если их пока нет (long-poll) · по умолчанию 0
ack запрос integer 1 — запомнить after как подтверждённый · по умолчанию 0
curl
curl -s "https://soroka.tools/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/events?after=18400&limit=500&wait=25" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/tg/subscriptions/5b0c7e1a-3c2f-4e8a-9d61-0f2b7a4c9e13/events",
    headers=headers,
    params={"after": 18400, "limit": 500, "wait": 25},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "items": [
    {
      "id": "18446",
      "kind": "post",
      "chat": {
        "peer_id": -1005678901234,
        "username": "telegram"
      },
      "message": {
        "id": 512,
        "peer_id": -1005678901234,
        "date": "2026-09-23T09:15:00+00:00",
        "text": "Текст поста",
        "views": 18400,
        "forwards": 52,
        "media": [],
        "ids": [
          512
        ]
      },
      "source": "poll",
      "received_at": "2026-09-23T09:15:02Z"
    }
  ],
  "next_after": "18446"
}

ВКонтакте

Методы API ВКонтакте на чтение и страницы vk.com: ответ как у самого ВКонтакте.

POST /v1/vk/batch

Несколько методов разом

vk:read ответ 200

До 25 методов одним вызовом. Ответ — по результату на вызов, в том же порядке.

полегдетипсмысл
calls* тело до 25 объектов {method, params}
curl
curl -s "https://soroka.tools/v1/vk/batch" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"calls": [{"method": "wall.get", "params": {"owner_id": -1, "count": 5}}, {"method": "groups.getById", "params": {"group_id": 1}}]}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/vk/batch",
    headers=headers,
    json={
        "calls": [
            {
                "method": "wall.get",
                "params": {
                    "owner_id": -1,
                    "count": 5
                }
            },
            {
                "method": "groups.getById",
                "params": {
                    "group_id": 1
                }
            }
        ]
    },
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "results": [
    {
      "response": {
        "count": 3120,
        "items": [
          "…"
        ]
      }
    },
    {
      "response": {
        "groups": [
          {
            "id": 1,
            "name": "…"
          }
        ]
      }
    }
  ]
}
GET /v1/vk/page

Страница vk.com

vk:read ответ 200

HTML страницы vk.com (для разбора того, чего нет в API). Только https://vk.com/… и https://m.vk.com/….

полегдетипсмысл
url запрос string адрес страницы
account запрос string auto (по умолчанию) или метка аккаунта · по умолчанию auto
curl
curl -s "https://soroka.tools/v1/vk/page?url=https%3A%2F%2Fvk.com%2Fclub1" \
  -H "Authorization: Bearer $API_KEY" \
  -o page.html
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/vk/page",
    headers=headers,
    params={"url": "https://vk.com/club1"},
    timeout=60,
)
r.raise_for_status()
with open("page.html", "wb") as f:
    f.write(r.content)
POST /v1/vk/{method}

Метод ВКонтакте

vk:read ответ 200

Метод API ВКонтакте на чтение: тело — параметры метода. Ответ — как у ВКонтакте ({"response": …}), ошибка ВКонтакте — ошибкой API с полем vk_error и code=vk_<номер>.

Токен и версию API подставляем мы. Списки в параметрах уходят через запятую, true/false — 1/0.

полегдетипсмысл
method* путь string метод API ВКонтакте: раздел.метод, например wall.get, groups.getById, newsfeed.search
curl
curl -s "https://soroka.tools/v1/vk/wall.get" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"owner_id": -1, "count": 100}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/vk/wall.get",
    headers=headers,
    json={"owner_id": -1, "count": 100},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "response": {
    "count": 3120,
    "items": [
      {
        "id": 28516,
        "text": "…",
        "likes": {
          "count": 120
        }
      }
    ]
  }
}

Задачи

Долгий сбор целиком: поставить задачу, узнать цену заранее, дождаться, скачать файл.

GET /v1/jobs

Список задач

jobs ответ 200

Задачи организации, от новых к старым, страницами по курсору; status — фильтр.

полегдетипсмысл
limit запрос integer сколько записей вернуть · по умолчанию 50
cursor запрос string курсор следующей страницы из next_cursor прошлого ответа
status запрос string queued, running, done, failed или cancelled
curl
curl -s "https://soroka.tools/v1/jobs?status=done&limit=50" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/jobs", headers=headers, params={"status": "done", "limit": 50}, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "items": [
    {
      "job_id": "3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74",
      "kind": "parser.preset",
      "status": "done",
      "progress": {
        "done": 300,
        "total": 300,
        "percent": 100,
        "note": null
      },
      "result_summary": {
        "rows": 300,
        "credits": 150
      },
      "error": null,
      "created_at": "2026-09-23T10:00:00+00:00",
      "started_at": "2026-09-23T10:00:02+00:00",
      "finished_at": "2026-09-23T10:01:10+00:00"
    }
  ],
  "next_cursor": null
}
POST /v1/jobs

Поставить задачу

jobsIdempotency-Key рекомендуется ответ 202

Долгий сбор целиком: посты канала за период, поиск, карточки. Ответ приходит сразу, задача идёт в очереди; готовый результат — файлом. Список видов сбора — в «Основах».

Нужно ещё право источника: tg:read для Telegram, vk:read для ВКонтакте. В ref — до 20 каналов через пробел или запятую.

Ещё виды: tg.history ({chat, since?, until?, media?, limit?}) и tg.participants ({chat, limit?}, нужно tg:people).

полегдетипсмысл
kind* тело string parser.preset — сбор по готовому шаблону · до 40 симв.
params тело object {preset, params: {ref, query, period_from, period_to, limit, media, with_comments}}
priority тело integer 0 обычный, 1 важный, 2 срочный · 0…2 · по умолчанию 0
curl
curl -s "https://soroka.tools/v1/jobs" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"kind": "parser.preset", "params": {"preset": "tg.channel_posts", "params": {"ref": "@telegram", "period_from": "2026-09-01", "limit": 300}}}'
Python
import os
import uuid

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
headers["Idempotency-Key"] = str(uuid.uuid4())  # тот же ключ при повторе того же запроса

r = httpx.post(
    f"{API}/v1/jobs",
    headers=headers,
    json={
        "kind": "parser.preset",
        "params": {
            "preset": "tg.channel_posts",
            "params": {
                "ref": "@telegram",
                "period_from": "2026-09-01",
                "limit": 300
            }
        }
    },
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 202
{
  "job_id": "3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74",
  "status": "queued"
}
POST /v1/jobs/estimate

Оценить задачу

jobs ответ 200

Сколько кредитов задача может стоить, «от–до», без постановки. Тело — как у POST /v1/jobs. Работает и при нуле кредитов.

полегдетипсмысл
kind* тело string вид задачи · до 40 симв.
params тело object параметры задачи (ниже)
priority тело integer 0 обычный, 1 важный, 2 срочный · 0…2 · по умолчанию 0
curl
curl -s "https://soroka.tools/v1/jobs/estimate" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "parser.preset", "params": {"preset": "tg.channel_posts", "params": {"ref": "@telegram", "period_from": "2026-09-01", "limit": 300}}}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/jobs/estimate",
    headers=headers,
    json={
        "kind": "parser.preset",
        "params": {
            "preset": "tg.channel_posts",
            "params": {
                "ref": "@telegram",
                "period_from": "2026-09-01",
                "limit": 300
            }
        }
    },
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "unit": "tg_post",
  "unit_title": "пост канала",
  "credits_per_unit": 0.5,
  "records": {
    "min": 0,
    "max": 300
  },
  "credits": {
    "min": 0,
    "max": 150
  },
  "balance": 28749.5,
  "enough": true,
  "note": "пустой результат и наши ошибки не списываются"
}
GET /v1/jobs/{job_id}

Карточка задачи

jobs ответ 200

Статус и ход задачи: queued → running → done (или failed, cancelled). В result_summary.credits — сколько кредитов списано (числом, может быть дробным: 1.5).

полегдетипсмысл
job_id* путь string job_id задачи
curl
curl -s "https://soroka.tools/v1/jobs/3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/jobs/3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74", headers=headers, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "job_id": "3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74",
  "kind": "parser.preset",
  "status": "done",
  "progress": {
    "done": 300,
    "total": 300,
    "percent": 100,
    "note": null
  },
  "result_summary": {
    "rows": 300,
    "credits": 150
  },
  "error": null,
  "created_at": "2026-09-23T10:00:00+00:00",
  "started_at": "2026-09-23T10:00:02+00:00",
  "finished_at": "2026-09-23T10:01:10+00:00"
}
POST /v1/jobs/{job_id}/cancel

Отменить задачу

jobs ответ 200

Задача в очереди или в работе становится cancelled, собранное остаётся в файлах. Повтор ничего не меняет.

полегдетипсмысл
job_id* путь string job_id задачи
curl
curl -s -X POST "https://soroka.tools/v1/jobs/3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74/cancel" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/jobs/3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74/cancel",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "job_id": "3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74",
  "kind": "parser.preset",
  "status": "cancelled",
  "progress": {
    "done": 300,
    "total": 300,
    "percent": 100,
    "note": null
  },
  "result_summary": {
    "rows": 300,
    "credits": 150
  },
  "error": null,
  "created_at": "2026-09-23T10:00:00+00:00",
  "started_at": "2026-09-23T10:00:02+00:00",
  "finished_at": "2026-09-23T10:01:10+00:00"
}
GET /v1/jobs/{job_id}/result

Файл результата

jobs ответ 200

Результат готовой задачи: json — данные как есть, csv и xlsx — таблица. Пока задача не done — 404 not_found.

полегдетипсмысл
job_id* путь string job_id задачи
format запрос string json, csv или xlsx · по умолчанию json
curl
curl -s "https://soroka.tools/v1/jobs/3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74/result?format=csv" \
  -H "Authorization: Bearer $API_KEY" \
  -o result.csv
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/jobs/3f1c9a2e-7b4d-4c1e-8a2f-6d5e9b0c1a74/result",
    headers=headers,
    params={"format": "csv"},
    timeout=60,
)
r.raise_for_status()
with open("result.csv", "wb") as f:
    f.write(r.content)

Аренды аккаунтов

Закрепить аккаунт Telegram за ключом для долгой работы.

GET /v1/leases

Мои аренды

tg:read ответ 200

Активные аренды ключа.

curl
curl -s "https://soroka.tools/v1/leases" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/leases", headers=headers, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "items": [
    {
      "lease_id": "8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95",
      "account": {
        "label": "acc_082"
      },
      "purpose": "history",
      "expires_at": "…"
    }
  ]
}
POST /v1/leases

Взять аренду

tg:read ответ 201

Закрепить аккаунт за ключом: все вызовы с lease_id идут в него. Без heartbeat аренда истекает через ttl секунд.

полегдетипсмысл
purpose* тело string зачем аренда (видно владельцу) · до 200 симв.
pool тело string имя пула из пулов ключа · до 100 симв.
ttl тело integer секунд без heartbeat до освобождения · 60…21 600 · по умолчанию 3600
roles тело object {"join": true} — только аккаунт, которому можно вступать
prefer тело string метка желаемого аккаунта · до 64 симв.
chat тело string | integer аренда под чат: только аккаунт-участник
curl
curl -s "https://soroka.tools/v1/leases" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"purpose": "history @telegram", "ttl": 1800}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/leases",
    headers=headers,
    json={"purpose": "history @telegram", "ttl": 1800},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 201
{
  "lease_id": "8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95",
  "account": {
    "label": "acc_082",
    "status": "active",
    "flood_until": null
  },
  "expires_at": "2026-09-23T11:00:00Z"
}
GET /v1/leases/{lease_id}

Аренда

tg:read ответ 200

Одна своя аренда; после конца — с причиной.

полегдетипсмысл
lease_id* путь string lease_id аренды
curl
curl -s "https://soroka.tools/v1/leases/8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/leases/8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95", headers=headers, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "lease_id": "8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95",
  "released_at": null
}
DELETE /v1/leases/{lease_id}

Отпустить аренду

tg:read ответ 200

Вернуть аккаунт в пул. Повтор — тоже 200.

полегдетипсмысл
lease_id* путь string lease_id аренды
curl
curl -s -X DELETE "https://soroka.tools/v1/leases/8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.delete(
    f"{API}/v1/leases/8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "released": true
}
POST /v1/leases/{lease_id}/heartbeat

Продлить аренду

tg:read ответ 200

Продлить аренду ещё на ttl; items — сколько собрано.

полегдетипсмысл
lease_id* путь string lease_id аренды
curl
curl -s "https://soroka.tools/v1/leases/8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95/heartbeat" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items": 1200}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/leases/8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95/heartbeat",
    headers=headers,
    json={"items": 1200},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "expires_at": "2026-09-23T11:30:00Z"
}

Telegram: сырой вызов, участники, запись

Методы Telegram по белому списку, состав чатов, диалоги аренды, приглашения, отправка.

POST /v1/tg/call

Вызов метода Telegram

tg:read ответ 200

Метод TelegramClient или TL-запрос из белого списка. Генераторы iter_* — только потоком.

Пишущий метод (право tg:write) — только с Idempotency-Key.

полегдетипсмысл
method* тело string метод из белого списка или raw · до 64 симв.
args тело array позиционные аргументы
kwargs тело object именованные аргументы
request тело object TL-запрос JSON-ом (для raw)
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
format тело json | tl | both json, tl или both · по умолчанию json
stream тело boolean true или ?stream=1 — отдавать NDJSON-потоком, по записи на строку (нужно право tg:stream) · по умолчанию false
curl
curl -s "https://soroka.tools/v1/tg/call" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"method": "get_messages", "kwargs": {"entity": "@telegram", "limit": 10}}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/call",
    headers=headers,
    json={"method": "get_messages", "kwargs": {"entity": "@telegram", "limit": 10}},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "account": "acc_082",
  "result": {
    "_": "Message",
    "id": 512
  },
  "took_ms": 123
}
POST /v1/tg/participants

Участники чата

tg:people ответ 200

Состав чата; больше 10 000 — потоком.

полегдетипсмысл
stream запрос integer true или ?stream=1 — отдавать NDJSON-потоком, по записи на строку (нужно право tg:stream) · по умолчанию 0
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
chat* тело string | integer канал или чат: @name, https://t.me/name или peer_id числом
search тело string строка поиска по имени · до 64 симв.
limit тело integer сколько записей вернуть · 1…1 000 000 · по умолчанию 1000
stream тело boolean true или ?stream=1 — отдавать NDJSON-потоком, по записи на строку (нужно право tg:stream) · по умолчанию false
curl
curl -s "https://soroka.tools/v1/tg/participants" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chat": "@chat", "limit": 1000}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/participants",
    headers=headers,
    json={"chat": "@chat", "limit": 1000},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "items": [
    {
      "id": 1,
      "username": "…",
      "role": "member"
    }
  ]
}
POST /v1/tg/dialogs

Диалоги аренды

tg:read ответ 200

Где состоит арендованный аккаунт.

полегдетипсмысл
lease_id* тело string lease_id своей аренды
limit тело integer сколько записей вернуть · 1…5000 · по умолчанию 500
curl
curl -s "https://soroka.tools/v1/tg/dialogs" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lease_id": "8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95"}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/dialogs",
    headers=headers,
    json={"lease_id": "8c1e5d2a-6f3b-4a9c-b1e7-2d4f6a8c0e95"},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "items": [
    {
      "peer_id": -100123,
      "title": "…"
    }
  ]
}
POST /v1/tg/invite/check

Проверить приглашение

tg:read ответ 200

Что за чат по ссылке-приглашению, без вступления.

полегдетипсмысл
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
hash* тело string хэш или ссылка t.me/+… · до 200 симв.
curl
curl -s "https://soroka.tools/v1/tg/invite/check" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"hash": "https://t.me/+AbCdEf"}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/tg/invite/check",
    headers=headers,
    json={"hash": "https://t.me/+AbCdEf"},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "invite": {
    "kind": "invite",
    "title": "…"
  }
}
POST /v1/tg/send

Отправить сообщение

tg:writeнужен Idempotency-Key ответ 200

Сообщение от лица аккаунта.

полегдетипсмысл
lease_id тело string выполнить на арендованном аккаунте
account тело string auto (по умолчанию) или метка аккаунта · до 64 симв. · по умолчанию auto
chat* тело string | integer канал или чат: @name, https://t.me/name или peer_id числом
text* тело string текст сообщения · до 4096 симв.
curl
curl -s "https://soroka.tools/v1/tg/send" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"chat": "@SpamBot", "text": "/start"}'
Python
import os
import uuid

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
headers["Idempotency-Key"] = str(uuid.uuid4())  # тот же ключ при повторе того же запроса

r = httpx.post(
    f"{API}/v1/tg/send",
    headers=headers,
    json={"chat": "@SpamBot", "text": "/start"},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true,
  "msg_id": 17
}

Telegram: вступления и членство

Вступление в чаты через очередь и сведения о членстве.

POST /v1/tg/join

Вступить в чат

tg:joinнужен Idempotency-Key ответ 200

Заявка на вступление в очередь; wait — подождать итога до N секунд.

полегдетипсмысл
ref* тело string @name, t.me/name, t.me/+hash · до 300 симв.
priority тело integer 0 обычный, 1 важный, 2 срочный · 0…2 · по умолчанию 0
wait тело integer секунд ждать итога (0 — сразу 202) · 0…30 · по умолчанию 0
curl
curl -s "https://soroka.tools/v1/tg/join" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"ref": "https://t.me/+AbCdEf", "wait": 10}'
Python
import os
import uuid

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
headers["Idempotency-Key"] = str(uuid.uuid4())  # тот же ключ при повторе того же запроса

r = httpx.post(
    f"{API}/v1/tg/join",
    headers=headers,
    json={"ref": "https://t.me/+AbCdEf", "wait": 10},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "join_id": 912,
  "state": "done",
  "already": false,
  "chat": {
    "peer_id": -1001234567890,
    "title": "…",
    "is_public": false
  },
  "account": "acc_017"
}
GET /v1/tg/join/{join_id}

Заявка на вступление

tg:join ответ 200

Состояние своей заявки.

полегдетипсмысл
join_id* путь integer join_id заявки на вступление
curl
curl -s "https://soroka.tools/v1/tg/join/912" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/tg/join/912", headers=headers, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "join_id": 912,
  "state": "queued"
}
POST /v1/tg/leave

Выйти из чата

tg:joinIdempotency-Key рекомендуется ответ 200

Выйти из членств, созданных по заявкам организации.

полегдетипсмысл
chat* тело string | integer канал или чат: @name, https://t.me/name или peer_id числом
curl
curl -s "https://soroka.tools/v1/tg/leave" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"chat": -1001234567890}'
Python
import os
import uuid

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
headers["Idempotency-Key"] = str(uuid.uuid4())  # тот же ключ при повторе того же запроса

r = httpx.post(f"{API}/v1/tg/leave", headers=headers, json={"chat": -1001234567890}, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "left": true,
  "accounts": [
    "acc_017"
  ]
}
GET /v1/tg/membership

Членство в чате

tg:read ответ 200

Есть ли доступ к чату и как он слушается.

полегдетипсмысл
ref* запрос string канал, чат или сообщество: @name, ссылка t.me/… или peer_id
curl
curl -s "https://soroka.tools/v1/tg/membership?ref=%40chat" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/tg/membership", headers=headers, params={"ref": "@chat"}, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "chat": {
    "peer_id": -100123
  },
  "members": 2,
  "join": null
}

Брокер прокси

Прокси для своих HTTP-запросов к целям.

POST /v1/proxy/lease

Взять прокси

proxy:lease ответ 201

Прокси под цель; пароль в ответе живёт дольше аренды.

полегдетипсмысл
target* тело string цель: по ней ведётся отдых пары прокси × цель · до 120 симв.
purpose тело string для учёта · до 200 симв.
ttl тело integer секунд · 60…3600 · по умолчанию 600
exit тело ipv6 | ipv4 | any ipv6, ipv4 или any · по умолчанию any
curl
curl -s "https://soroka.tools/v1/proxy/lease" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target": "sudrf", "ttl": 600, "exit": "ipv6"}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/proxy/lease",
    headers=headers,
    json={"target": "sudrf", "ttl": 600, "exit": "ipv6"},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 201
{
  "lease_id": "…",
  "proxy": {
    "scheme": "http",
    "host": "…",
    "port": 8080,
    "username": "…",
    "password": "…"
  },
  "exit_ip": "…",
  "expires_at": "…"
}
POST /v1/proxy/report

Итог запроса

proxy:lease ответ 200

429/403 — пара прокси × цель отдыхает.

полегдетипсмысл
lease_id* тело string выполнить на арендованном аккаунте
status* тело integer | timeout | ok HTTP-код, timeout или ok
note тело string заметка · до 500 симв.
curl
curl -s "https://soroka.tools/v1/proxy/report" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lease_id": "…", "status": 429}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/proxy/report",
    headers=headers,
    json={"lease_id": "…", "status": 429},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true
}
DELETE /v1/proxy/lease/{lease_id}

Вернуть прокси

proxy:lease ответ 200

Повтор — тоже 200.

полегдетипсмысл
lease_id* путь string lease_id аренды прокси
curl
curl -s -X DELETE "https://soroka.tools/v1/proxy/lease/…" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.delete(f"{API}/v1/proxy/lease/…", headers=headers, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true
}
GET /v1/proxy/pool

Сводка пула

proxy:lease ответ 200

Сколько прокси видно ключу и сколько отдыхает у цели.

полегдетипсмысл
target запрос string цель
curl
curl -s "https://soroka.tools/v1/proxy/pool?target=sudrf" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/proxy/pool", headers=headers, params={"target": "sudrf"}, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "alive": 40,
  "cooldown": 3,
  "total": 44
}

Вебхуки событий

Адреса, на которые приходят события организации: задачи, расход кредитов, счета, совпадения мониторингов, сроки ключей. Эти пути не тратят кредиты.

GET /v1/webhooks

Адреса вебхуков

webhooks ответ 200

Все живые адреса организации, от новых к старым. Секрета в ответе нет никогда.

status: active — работает, failing — последние попытки неудачны, disabled — выключен (disabled_reason: failures — после неудач подряд, user — вручную).

curl
curl -s "https://soroka.tools/v1/webhooks" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(f"{API}/v1/webhooks", headers=headers, timeout=60)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "items": [
    {
      "id": "8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93",
      "url": "https://example.ru/hooks/events",
      "description": "отчёты",
      "events": [
        "task.done",
        "task.failed"
      ],
      "enabled": true,
      "status": "active",
      "disabled_reason": null,
      "fail_count": 0,
      "last_code": 200,
      "last_success_at": "2026-09-23T10:01:11+00:00",
      "last_failure_at": null,
      "disabled_at": null,
      "created_at": "2026-09-23T09:00:00+00:00"
    }
  ],
  "next_cursor": null
}
POST /v1/webhooks

Добавить адрес

webhooks ответ 201

Новый адрес для событий организации. Секрет whs_… для проверки подписи приходит в ответе один раз — сохраните его сразу. Idempotency-Key здесь не действует: повтор создаёт второй адрес.

Ошибки: 400 с code bad_args, unknown_event или webhook_url_forbidden; 409 с code=webhook_limit, если живых адресов у организации уже 10.

полегдетипсмысл
url* тело string https-адрес вашего сервера, куда присылать события · до 2000 симв.
events* тело array of string события: task.done, task.partial, task.failed, quota.threshold, invoice.issued, monitor.hit, key.expiring или ["*"] — все, включая будущие · до 50 элементов
description тело string подпись для себя, до 200 символов · до 200 симв.
enabled тело boolean false — выключить адрес, true — включить (счётчик неудач обнуляется) · по умолчанию true
curl
curl -s "https://soroka.tools/v1/webhooks" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.ru/hooks/events", "events": ["task.done", "task.failed"], "description": "отчёты"}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/webhooks",
    headers=headers,
    json={
        "url": "https://example.ru/hooks/events",
        "events": [
            "task.done",
            "task.failed"
        ],
        "description": "отчёты"
    },
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 201
{
  "id": "8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93",
  "url": "https://example.ru/hooks/events",
  "description": "отчёты",
  "events": [
    "task.done",
    "task.failed"
  ],
  "enabled": true,
  "status": "active",
  "disabled_reason": null,
  "fail_count": 0,
  "last_code": 200,
  "last_success_at": "2026-09-23T10:01:11+00:00",
  "last_failure_at": null,
  "disabled_at": null,
  "created_at": "2026-09-23T09:00:00+00:00",
  "secret": "whs_…"
}
GET /v1/webhooks/{webhook_id}

Адрес вебхука

webhooks ответ 200

Карточка адреса: статус, неудачи подряд, последний код ответа.

полегдетипсмысл
webhook_id* путь string id адреса вебхука
curl
curl -s "https://soroka.tools/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "id": "8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93",
  "url": "https://example.ru/hooks/events",
  "description": "отчёты",
  "events": [
    "task.done",
    "task.failed"
  ],
  "enabled": true,
  "status": "active",
  "disabled_reason": null,
  "fail_count": 0,
  "last_code": 200,
  "last_success_at": "2026-09-23T10:01:11+00:00",
  "last_failure_at": null,
  "disabled_at": null,
  "created_at": "2026-09-23T09:00:00+00:00"
}
PATCH /v1/webhooks/{webhook_id}

Изменить адрес

webhooks ответ 200

Любые из полей url, events, description, enabled; rotate_secret: true — новый секрет (в ответе один раз, сутки события подписываются обоими секретами).

полегдетипсмысл
webhook_id* путь string id адреса вебхука
url тело string https-адрес вашего сервера, куда присылать события · до 2000 симв.
events тело array of string события: task.done, task.partial, task.failed, quota.threshold, invoice.issued, monitor.hit, key.expiring или ["*"] — все, включая будущие · до 50 элементов
description тело string подпись для себя, до 200 символов · до 200 симв.
enabled тело boolean false — выключить адрес, true — включить (счётчик неудач обнуляется)
rotate_secret тело boolean true — выпустить новый секрет (придёт в ответе один раз) · по умолчанию false
curl
curl -s -X PATCH "https://soroka.tools/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.patch(
    f"{API}/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93",
    headers=headers,
    json={"enabled": True},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "id": "8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93",
  "url": "https://example.ru/hooks/events",
  "description": "отчёты",
  "events": [
    "task.done",
    "task.failed"
  ],
  "enabled": true,
  "status": "active",
  "disabled_reason": null,
  "fail_count": 0,
  "last_code": 200,
  "last_success_at": "2026-09-23T10:01:11+00:00",
  "last_failure_at": null,
  "disabled_at": null,
  "created_at": "2026-09-23T09:00:00+00:00"
}
DELETE /v1/webhooks/{webhook_id}

Удалить адрес

webhooks ответ 200

Доставка прекращается, адрес пропадает из списка.

полегдетипсмысл
webhook_id* путь string id адреса вебхука
curl
curl -s -X DELETE "https://soroka.tools/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.delete(
    f"{API}/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "ok": true
}
POST /v1/webhooks/{webhook_id}/test

Тестовое событие

webhooks ответ 200

Отправляет webhook.test сразу — и на выключенный адрес, чтобы проверить его перед включением. В ответе — доставка с итогом попытки. Неудача теста адрес не выключает.

полегдетипсмысл
webhook_id* путь string id адреса вебхука
curl
curl -s -X POST "https://soroka.tools/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/test" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/test",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "id": "48213",
  "event": "webhook.test",
  "event_id": "evt_5f1c…",
  "status": "delivered",
  "attempts": 1,
  "last_code": 200,
  "last_error": null,
  "duration_ms": 184,
  "created_at": "2026-09-23T10:01:10+00:00",
  "last_attempt_at": "2026-09-23T10:01:11+00:00",
  "next_attempt_at": null,
  "delivered_at": "2026-09-23T10:01:11+00:00",
  "request": {
    "headers": {
      "X-Webhook-Id": "evt_5f1c…",
      "X-Webhook-Event": "task.done"
    },
    "body": "{\"id\": \"evt_5f1c…\", \"type\": \"task.done\", …}"
  },
  "response": {
    "code": 200,
    "body": "ok"
  },
  "attempts_log": [
    {
      "at": "2026-09-23T10:01:11+00:00",
      "code": 200,
      "error": null,
      "duration_ms": 184,
      "manual": false
    }
  ]
}
GET /v1/webhooks/{webhook_id}/deliveries

Журнал доставок

webhooks ответ 200

Доставки адреса от новых к старым; хранятся 30 дней.

полегдетипсмысл
webhook_id* путь string id адреса вебхука
limit запрос integer сколько записей вернуть · по умолчанию 50
cursor запрос string курсор следующей страницы из next_cursor прошлого ответа
status запрос string pending, delivered или failed
event запрос string фильтр по событию, например task.done
curl
curl -s "https://soroka.tools/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/deliveries?status=failed&limit=50" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/deliveries",
    headers=headers,
    params={"status": "failed", "limit": 50},
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "items": [
    {
      "id": "48213",
      "event": "task.done",
      "event_id": "evt_5f1c…",
      "status": "failed",
      "attempts": 10,
      "last_code": 500,
      "last_error": null,
      "duration_ms": 184,
      "created_at": "2026-09-23T10:01:10+00:00",
      "last_attempt_at": "2026-09-23T10:01:11+00:00",
      "next_attempt_at": null,
      "delivered_at": null
    }
  ],
  "next_cursor": null
}
GET /v1/webhooks/{webhook_id}/deliveries/{delivery_id}

Доставка

webhooks ответ 200

Доставка целиком: тело запроса как отправлено, код и начало ответа вашего сервера, последние попытки.

полегдетипсмысл
webhook_id* путь string id адреса вебхука
delivery_id* путь string id доставки из журнала
curl
curl -s "https://soroka.tools/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/deliveries/48213" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.get(
    f"{API}/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/deliveries/48213",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "id": "48213",
  "event": "task.done",
  "event_id": "evt_5f1c…",
  "status": "delivered",
  "attempts": 1,
  "last_code": 200,
  "last_error": null,
  "duration_ms": 184,
  "created_at": "2026-09-23T10:01:10+00:00",
  "last_attempt_at": "2026-09-23T10:01:11+00:00",
  "next_attempt_at": null,
  "delivered_at": "2026-09-23T10:01:11+00:00",
  "request": {
    "headers": {
      "X-Webhook-Id": "evt_5f1c…",
      "X-Webhook-Event": "task.done"
    },
    "body": "{\"id\": \"evt_5f1c…\", \"type\": \"task.done\", …}"
  },
  "response": {
    "code": 200,
    "body": "ok"
  },
  "attempts_log": [
    {
      "at": "2026-09-23T10:01:11+00:00",
      "code": 200,
      "error": null,
      "duration_ms": 184,
      "manual": false
    }
  ]
}
POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/retry

Повторить доставку

webhooks ответ 200

Ещё одна попытка сейчас: тот же X-Webhook-Id и тело, новые отметка времени и подпись. Уже доставленное событие отправится ещё раз — отсеивайте повторы по id. Выключенный адрес — 409, code=webhook_disabled.

полегдетипсмысл
webhook_id* путь string id адреса вебхука
delivery_id* путь string id доставки из журнала
curl
curl -s -X POST "https://soroka.tools/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/deliveries/48213/retry" \
  -H "Authorization: Bearer $API_KEY"
Python
import os

import httpx

API = "https://soroka.tools"
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}

r = httpx.post(
    f"{API}/v1/webhooks/8d2e4f1a-6b3c-4a7e-9f10-2c5d8e7b1a93/deliveries/48213/retry",
    headers=headers,
    timeout=60,
)
r.raise_for_status()
print(r.json())
Ответ 200
{
  "id": "48213",
  "event": "task.done",
  "event_id": "evt_5f1c…",
  "status": "delivered",
  "attempts": 1,
  "last_code": 200,
  "last_error": null,
  "duration_ms": 184,
  "created_at": "2026-09-23T10:01:10+00:00",
  "last_attempt_at": "2026-09-23T10:01:11+00:00",
  "next_attempt_at": null,
  "delivered_at": "2026-09-23T10:01:11+00:00",
  "request": {
    "headers": {
      "X-Webhook-Id": "evt_5f1c…",
      "X-Webhook-Event": "task.done"
    },
    "body": "{\"id\": \"evt_5f1c…\", \"type\": \"task.done\", …}"
  },
  "response": {
    "code": 200,
    "body": "ok"
  },
  "attempts_log": [
    {
      "at": "2026-09-23T10:01:11+00:00",
      "code": 200,
      "error": null,
      "duration_ms": 184,
      "manual": false
    }
  ]
}