CFGCLOUD API
Базовый URL: https://api.cfg.ceo
Аутентификация
Все запросы требуют API-ключ в заголовке X-API-Key. Ключ выдаётся через бота cfgcloud.
curl -H "X-API-Key: YOUR_KEY" https://api.cfg.ceo/stats
Формат ответов
Все ответы — JSON. Ошибки возвращаются на русском.
{"success": true, ...данные...}
{"success": false, "error": "Текст ошибки."}
Эндпоинты
Статистика аккаунтов
{
"success": true,
"stats": {"free": 42, "busy": 108, "total": 150}
}
Информация о владельце API ключа
{
"success": true,
"user": {"user_id": 5770559689, "username": "cfg"}
}
Взять аккаунт. Тело запроса не требуется — пользователь определяется по API ключу.
curl -X POST -H "X-API-Key: YOUR_KEY" https://api.cfg.ceo/accounts/issue
{
"success": true,
"tag": "TAG123",
"account": {
"email": "[email protected]",
"password": "password123",
"time": "2026-01-20 20:00:00",
"lifetime_minutes": 60
}
}
403: Вы заблокированы в системе
403: Для получения доступа необходимо сделать хотя бы 1 лок
409: У вас уже есть активный аккаунт: {tag}
429: Вы достигли лимита аккаунтов. Отмените один из активных
503: Нет доступных аккаунтов
Отменить аккаунт. Только владелец может отменить свой аккаунт.
| Поле | Тип | Описание |
|---|---|---|
| tag | string | Тег аккаунта обязательно |
| nickname | string | Никнейм обязательно |
{"success": true, "tag": "TAG123"}
404: Аккаунт не найден
Сгенерировать ссылку для сервиса
| Поле | Тип | Описание |
|---|---|---|
| service | string | rave | ozon обязательно |
{
"success": true,
"tag": "TAG123",
"url": "https://rave.ink/abc123/",
"service": "rave",
"account": {"email": "[email protected]", "password": "password123"},
"lifetime_minutes": 60
}
403: Нет доступа к этому сервису
503: Нет доступных аккаунтов
500: Ошибка генерации ссылки
Оставшееся время аккаунта в минутах. Доступно только холдеру или админу.
| Параметр | Тип | Описание |
|---|---|---|
| tag | string | Тег аккаунта (путь) обязательно |
{"success": true, "minutes_left": 45}
Проверить наличие успешного лока. Доступно холдеру, пользователям из истории холдеров и админам.
| Параметр | Тип | Описание |
|---|---|---|
| tag | string | Тег аккаунта (путь) обязательно |
{"success": true, "tag": "TAG123", "has_lock": true}
has_lock: true — для аккаунта был совершен успешный лок
Проверка IMEI — возвращает модель устройства, маску email и статус.
| Параметр | Тип | Описание |
|---|---|---|
| imei | string | IMEI устройства (15 цифр) обязательно |
{
"success": true,
"found": true,
"device": "iPhone 17 Pro",
"imei": "350344890446295",
"email": "s•••••@icloud.com",
"status": "жив"
}
{"success": true, "found": false}
жив — аккаунт активен ·
деактивирован — аккаунт мёртв ·
уточнить — заблокирован или ограничен, требуется проверка
Логи рабочих процессов из кольцевого буфера (2000 записей, TTL 24 часа). Поддерживает инкрементальный поллинг.
| Параметр | Тип | Описание |
|---|---|---|
| after | int | Записи с id > after по умолчанию 0 |
| limit | int | Максимум записей, 1-500 по умолчанию 200 |
{
"logs": [
{"id": 1723891200001, "tag": "#CL123", "message": "БАМ! Зверь повержен!", "level": "SUCCESS", "time": 1723891200001},
{"id": 1723891200002, "tag": "#CL124", "message": "Поиск устройств...", "level": "INFO", "time": 1723891200002}
],
"last_id": 1723891200002
}
last_id и передавайте как after в следующем запросе для инкрементального поллинга. Авторизация: X-API-Key или X-Monitor-Secret (localhost — без авторизации).
Примеры
# Статистика
curl -H "X-API-Key: YOUR_KEY" https://api.cfg.ceo/stats
# Взять аккаунт
curl -X POST -H "X-API-Key: YOUR_KEY" https://api.cfg.ceo/accounts/issue
# Сгенерировать ссылку (rave)
curl -X POST \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"service":"rave"}' \
https://api.cfg.ceo/accounts/link
# Отменить аккаунт
curl -X POST \
-H "X-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"tag":"TAG123","nickname":"cfg"}' \
https://api.cfg.ceo/accounts/cancel
# Время / лок / IMEI / логи
curl -H "X-API-Key: YOUR_KEY" https://api.cfg.ceo/accounts/TAG123/time
curl -H "X-API-Key: YOUR_KEY" https://api.cfg.ceo/accounts/TAG123/locks
curl -H "X-API-Key: YOUR_KEY" https://api.cfg.ceo/services/imei/350344890446295
curl -H "X-API-Key: YOUR_KEY" "https://api.cfg.ceo/work/logs?after=0&limit=100"
import aiohttp
API = "https://api.cfg.ceo"
KEY = "YOUR_API_KEY"
H = {"X-API-Key": KEY}
async def stats():
async with aiohttp.ClientSession() as s:
async with s.get(f"{API}/stats", headers=H) as r:
return await r.json()
async def issue():
async with aiohttp.ClientSession() as s:
async with s.post(f"{API}/accounts/issue", headers=H) as r:
return await r.json()
async def link(service, service_type=None):
body = {"service": service}
if service_type:
body["service_type"] = service_type
async with aiohttp.ClientSession() as s:
async with s.post(f"{API}/accounts/link",
headers={**H, "Content-Type": "application/json"},
json=body) as r:
return await r.json()
const API = "https://api.cfg.ceo";
const KEY = "YOUR_API_KEY";
const h = {"X-API-Key": KEY};
async function stats() {
return (await fetch(`${API}/stats`, {headers: h})).json();
}
async function issue() {
return (await fetch(`${API}/accounts/issue`, {method: "POST", headers: h})).json();
}
async function link(service, serviceType) {
const body = {service};
if (serviceType) body.service_type = serviceType;
return (await fetch(`${API}/accounts/link`, {
method: "POST",
headers: {...h, "Content-Type": "application/json"},
body: JSON.stringify(body)
})).json();
}
Свой бот
При загрузке собственного бота через Сервисы доступен встроенный клиент для работы с аккаунтами. Авторизация подключается автоматически — указывать ключ не нужно.
import cfgcloud_module as client
Доступные функции
Выдать аккаунт пользователю. Возвращает True / False.
| Параметр | Тип | Описание |
|---|---|---|
| tag | str | Пустая строка "" — сервер выберет сам |
| user_id | int | Telegram ID пользователя |
| username | str | Никнейм пользователя |
| lifetime_minutes | int | Время жизни аккаунта 60 |
Возвращает (tag, data) последнего выданного аккаунта. Вызывать сразу после issue_account.
tag, data = client.get_last_issued()
email = data["email"]
password = data["login_password"]
Обновить поля аккаунта или вернуть его.
# Привязать message_id к аккаунту
client.update_acc_fields(tag, bot_message_id=msg.message_id, client_chat_id=user_id)
# Вернуть аккаунт
client.update_acc_fields(tag, status="free", holder_name=username)
Загрузить все активные аккаунты. Возвращает dict — {tag: {email, minutes_left, ...}}.
Получить данные конкретного аккаунта с актуальным minutes_left.
Пример бота
import asyncio
from aiogram import Bot, Dispatcher, Router, types, F
from aiogram.filters import Command
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import InlineKeyboardMarkup as IKM, InlineKeyboardButton as IKB
import cfgcloud_module as client
BOT_TOKEN = "СЮДА_ТОКЕН"
bot = Bot(token=BOT_TOKEN)
dp = Dispatcher(storage=MemoryStorage())
router = Router()
dp.include_router(router)
_extended = set()
def acc_kb(tag, extended=False):
rows = [[IKB(text="Время ⏳", callback_data=f"time:{tag}")]]
if not extended:
rows[0].append(IKB(text="Продлить 🔄", callback_data=f"ext:{tag}"))
rows.append([IKB(text="Отменить аккаунт", callback_data=f"free:{tag}")])
return IKM(inline_keyboard=rows)
def ext_kb(tag):
return IKM(inline_keyboard=[
[IKB(text="15 мин", callback_data=f"ext15:{tag}"),
IKB(text="30 мин", callback_data=f"ext30:{tag}"),
IKB(text="60 мин", callback_data=f"ext60:{tag}")]
])
@router.message(Command("start"))
async def cmd_start(msg: types.Message):
kb = IKM(inline_keyboard=[[IKB(text="Получить аккаунт", callback_data="get_acc")]])
await msg.answer("Нажми кнопку чтобы получить аккаунт.", reply_markup=kb)
@router.callback_query(F.data == "get_acc")
async def get_account(cb: types.CallbackQuery):
ok = client.issue_account("", cb.from_user.id, cb.from_user.username or "", 60)
if not ok:
return await cb.answer("Нет свободных аккаунтов", show_alert=True)
tag, data = client.get_last_issued()
msg = await cb.message.answer(
f"Аккаунт: {tag}\nEmail: <code>{data['email']}</code>\n"
f"Пароль: <code>{data['login_password']}</code>",
parse_mode="HTML", reply_markup=acc_kb(tag))
client.update_acc_fields(tag, bot_message_id=msg.message_id,
client_chat_id=cb.from_user.id)
await cb.answer()
@router.callback_query(F.data.startswith("time:"))
async def show_time(cb: types.CallbackQuery):
acc = client.get_acc(cb.data.split(":", 1)[1])
await cb.answer(f"Осталось: {acc.get('minutes_left', 0)} мин." if acc
else "Аккаунт не найден", show_alert=True)
@router.callback_query(F.data.startswith("ext:"))
async def extend_menu(cb: types.CallbackQuery):
tag = cb.data.split(":", 1)[1]
if tag in _extended:
return await cb.answer("Уже продлено", show_alert=True)
await cb.message.edit_reply_markup(reply_markup=ext_kb(tag))
await cb.answer()
@router.callback_query(F.data.regexp(r"^ext(15|30|60):"))
async def extend_do(cb: types.CallbackQuery):
parts = cb.data.split(":", 1)
mins, tag = int(parts[0][3:]), parts[1]
if tag in _extended:
return await cb.answer("Уже продлено", show_alert=True)
acc = client.get_acc(tag)
if not acc or acc.get("minutes_left", 0) <= 0:
return await cb.answer("Аккаунт не найден или истёк", show_alert=True)
client.update_acc_fields(tag, lifetime_minutes=acc["minutes_left"] + mins)
_extended.add(tag)
await cb.message.edit_reply_markup(reply_markup=acc_kb(tag, extended=True))
await cb.answer(f"+{mins} мин.", show_alert=True)
@router.callback_query(F.data.startswith("free:"))
async def free_account(cb: types.CallbackQuery):
tag = cb.data.split(":", 1)[1]
client.update_acc_fields(tag, status="free", holder_name=cb.from_user.username or "user")
_extended.discard(tag)
try: await cb.message.delete()
except: pass
note = await cb.message.answer(f"Аккаунт {tag} отменен")
await cb.answer()
await asyncio.sleep(3)
try: await note.delete()
except: pass
if __name__ == "__main__":
dp.run_polling(bot, skip_updates=True)
Ограничения и безопасность
Rate Limiting
- 180 запросов в минуту на ключ
- Превышение:
429
Безопасность
- Только HTTPS
- Не передавайте ключи третьим лицам
- Перевыпуск ключей через бота cfgcloud