MagStore
MagStore API
HTTP · JSON · email + token

MagStore API

REST-подобный интерфейс поверх одного эндпойнта /resale/api. Работает через GET (query-строка) и POST (JSON) — как в стандарте API.md. Все ответы — JSON с единой оболочкой { success, message, data, timestamp, datetime }, либо text/plain для скачивания карточек товара.

Base URL
https://shooac.top/resale/api
Content-Type (POST)
application/json

Авторизация

Все запросы к API требуют пары email + token. Токен выдаётся администратором вручную и уникален для каждого клиента. Компрометацию токена сообщите администратору — он выпустит новый и мгновенно отзовёт старый.

Способы передачи:

  • GET-параметры: ?email=...&token=...
  • JSON-поля тела POST-запроса: {"email":"...","token":"..."}
  • Заголовок: Authorization: Bearer <token>
Не публикуйте токен в исходном коде фронтенда. Запросы к MagStore API должны идти с вашего backend-а.

Формат ответа

Любой JSON-ответ обёрнут одинаково — можно распарсить одним типом:

// success
{
  "success": true,
  "message": "ok",
  "data": { /* payload */ },
  "timestamp": 1753900000,
  "datetime": "2026-07-30T18:26:40.000Z"
}

// error (HTTP 4xx/5xx)
{
  "success": false,
  "message": "insufficient_funds",
  "data": null,
  "timestamp": 1753900000,
  "datetime": "2026-07-30T18:26:40.000Z"
}

Все суммы — целое число «центов»: 1 USD = 10 000 единиц (total_cents / 10000 === USD).

GET

Баланс

Возвращает текущий баланс и персональную скидку.

GET /resale/api?action=balance&email={email}&token={token}
Пример ответа
{
  "success": true,
  "data": {
    "user_id": 42,
    "login": "acme",
    "balance_cents": 12500000,   // $1250.00
    "discount_percent": 10
  }
}
GET

Список товаров

Только товары, включённые администратором в канал MagStore. Цены уже уменьшены на вашу персональную скидку.

GET /resale/api?action=list&email={email}&token={token}
Пример ответа
{
  "success": true,
  "data": [
    {
      "id": 1,
      "code": "INST_2FA",
      "name": "Long-Live Instagram Gmail",
      "description": "...",
      "discount_percent": 0,
      "price_cents": 7000,        // cheapest enabled tier (with discount)
      "list_price_cents": 7000,   // cheapest tier, undiscounted
      "available": 16903,      // total across enabled tiers
      "tiers": [
        {
          "key": "t0_3",           // pass this as tier_key on purchase
          "label": "0–3 дня",
          "price_cents": 7000,      // $0.70 per unit (with discount)
          "list_price_cents": 7000,
          "available": 9021
        },
        {
          "key": "t21",
          "label": "21 день+",
          "price_cents": 14500,
          "list_price_cents": 14500,
          "available": 7882
        }
      ]
    }
  ]
}

Каждый товар делится на возрастные интервалы (tiers) со своей ценой: t0_3 (0–3 дня), t4_14 (4–14 дней), t15_20 (15–20 дней), t21 (21 день+). В ответе только включённые интервалы; поле key нужно передавать как tier_key при покупке.

GET

Один товар

Возвращает объект того же формата, что и элемент list.

# канонический вид
GET /resale/api?action=product&goods_id={id}&email=…&token=…

# API.md-совместимый вид
GET /resale/api?action={id}&email=…&token=…
POST

Покупка (V2)

Двухшаговый flow: шаг 1 — размещение заказа (списывает баланс атомарно), возвращает invoice_id. Шаг 2 — забор содержимого по этому invoice_id (см. следующий раздел).

Обязательное поле tier_key — возрастной интервал из списка товара (t0_3, t4_14, t15_20, t21). Цена и склад берутся именно из этого интервала. Опциональное поле client_order_id — ваш идемпотентный ключ: повтор запроса с тем же ключом никогда не создаст второй заказ (см. раздел Идемпотентность).
Пример запроса
POST /resale/api
Content-Type: application/json

{
  "email": "you@example.com",
  "token": "…",
  "action": "purchase_v2",
  "goods_id": 1,
  "tier_key": "t0_3",
  "quantity": 10,
  "client_order_id": "my-cart-abc123",  // опционально
  "format": 1                     // опционально: 1 = разделитель '|' вместо ':'
}
Пример ответа
{
  "success": true,
  "data": {
    "invoice_id": "29BF50fC037d14d",
    "client_order_id": "my-cart-abc123",
    "goods_id": 1,
    "tier_key": "t0_3",
    "quantity": 10,
    "unit_price_cents": 7000,
    "total_cents": 70000,
    "list_price_cents": 7000,
    "discount_percent": 0,
    "status": "delivered",
    "idempotent": false,   // true = повтор того же client_order_id
    "card_content": "login|pass|cookie\nlogin|pass|cookie\n…"  // при format=1 разделитель '|'
  }
}
format — необязательный параметр разделителя полей в выдаче: format=1 заменяет структурные : на |. Двоеточия внутри cookie-значений Instagram (блок начинается с двойного ||: login:pass:2fa||…rur=…:…;Bearer IGT:2:…;sessionid=…%3A…) сохраняются — пайпятся только поля до ||. У форматов без cookie-блока (Twitter, TikTok, Threads и т.п.) вся строка становится |-разделённой, включая токены (напр. Twitter: login|pass|email|empass|токен_почты|uuid|2fa|твит1|твит2). format=0 или отсутствие параметра — формат без изменений. Ответ purchase_v2 теперь всегда содержит card_content с уже доставленными аккаунтами (кроме идемпотентного повтора — там пусто, заберите через query_card).
curl
curl -s https://shooac.top/resale/api \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","token":"…","action":"purchase_v2","goods_id":1,"tier_key":"t0_3","quantity":10}'
GET

Содержимое заказа

Забирает карточки по invoice_id. Можно вызвать несколько раз — контент неизменен. Через 24 часа после доставки контент удаляется — придёт 410 Gone / content_expired.

Если ответ на purchase_v2 был потерян (таймаут / сетевой сбой), передайте client_order_id вместо invoice_id — заказ найдётся по вашему ключу. Указывать нужно ровно одно из двух полей.

JSON
# поиск по invoice_id
GET /resale/api?action=query_card&invoice_id={id}&email=…&token=…

# или поиск по вашему client_order_id
GET /resale/api?action=query_card&client_order_id=my-cart-abc123&email=…&token=…
{
  "success": true,
  "data": {
    "invoice_id": "29BF50fC037d14d",
    "client_order_id": "my-cart-abc123",
    "goods_id": 1,
    "tier_key": "t0_3",
    "quantity": 10,
    "total_cents": 70000,
    "unit_price_cents": 7000,
    "discount_percent": 0,
    "status": "delivered",
    "created_at":   "2026-08-31T12:00:00.000Z",
    "delivered_at": "2026-08-31T12:00:00.100Z",
    "card_content": "login:pass:cookie\nlogin:pass:cookie\n…",
    "expired": false
  }
}
JSON с разделителем | (аккаунты + реквизиты заказа)
# JSON (по умолчанию) + card_content на '|' + статус/номер/товар/кол-во/стоимость
GET /resale/api?action=query_card&invoice_id={id}&pipe=1&email=…&token=…

# работает и по client_order_id
GET /resale/api?action=query_card&client_order_id=my-cart-abc123&pipe=1&email=…&token=…
Сырой TXT (для скачивания файлом)
# обычный разделитель ':'
GET /resale/api?action=query_card&invoice_id={id}&format=txt&email=…&token=…

# разделитель '|' (TXT)
GET /resale/api?action=query_card&invoice_id={id}&format=1&email=…&token=…
Два независимых параметра:
  • format — контейнер ответа: json (по умолчанию) или txt.
  • pipe — разделитель: pipe=1 → поля через |; без него — :. Меняются только разделители, сами данные и cookie не изменяются.
Их можно комбинировать: pipe=1 без format вернёт JSON с реквизитами заказа (статус, invoice_id, товар, количество, стоимость) и card_content через | — как раз для восстановления заказа, когда ответ на покупку не дошёл.
Легаси: format=1 = TXT с | (по-прежнему работает), format=0 = TXT с :.

Идемпотентность (client_order_id)

Чтобы сетевой сбой или повтор запроса не привели к двойной покупке, передавайте на purchase_v2 ваш собственный уникальный ключ в поле client_order_id. Правила:

  • Ключ уникален в пределах одного пользователя (email/token). Формат: от 1 до 64 символов из A–Z a–z 0–9 . _ : @ / + = - (без пробелов, юникода и управляющих символов). Хороший выбор — UUID / ULID или ваш внутренний ID заказа.
  • Повтор с теми же параметрами (goods_id, tier_key, quantity) → 200 OK, тот же invoice_id, в ответе "idempotent": true. Баланс списывается ровно один раз.
  • Повтор с другими параметрами → 409 client_order_id_conflict. В details вернём existing_invoice_id, existing_goods_id, existing_tier_key, existing_quantity. Выберите новый ключ или используйте existing_invoice_id.
  • Ответ потерян — вызовите query_card с тем же client_order_id: получите invoice_id и содержимое.
Пример 409-конфликта
{
  "success": false,
  "message": "client_order_id_conflict",
  "details": {
    "client_order_id":     "my-cart-abc123",
    "existing_invoice_id": "29BF50fC037d14d",
    "existing_goods_id":   1,
    "existing_tier_key":   "t0_3",
    "existing_quantity":   10
  }
}

Статусы заказа и правила возврата

Покупка — атомарная транзакция «всё или ничего»: за один вызов purchase_v2 либо резервируется склад, списывается баланс и создаётся заказ, либо не меняется ничего. Возможные состояния:

status Смысл Баланс / склад
delivered Успех. Заказ создан, карточки доступны через query_card. Списан total_cents, забронировано quantity позиций.
refunded Возврат средств за уже доставленный заказ (только вручную администратором в редких случаях, например брак). Возвращена сумма, зафиксировано в балансовом логе.

Правила возврата при ошибке. Если purchase_v2 вернул любой код 4xx / 5xx — заказ не создан, баланс не списан, склад не изменён. Отдельный «refund» инициировать не нужно. Наиболее частые случаи:

  • 402 insufficient_funds — на балансе меньше total_cents. Пополните баланс и повторите (можно с тем же client_order_id).
  • 409 out_of_stock — на складе меньше quantity в выбранном интервале. Уменьшите количество или выберите другой tier_key.
  • 409 tier_unavailable / 409 product_unavailable — интервал/товар отключены. Проверьте list.
  • 5xx server_error — временный сбой. Безопасно повторить с тем же client_order_id: если предыдущая попытка всё же прошла, вы получите тот же invoice_id, а не второе списание.

Проверить фактический результат после сбоя: query_card с вашим client_order_id. Если заказ не найден (404 not_found) — покупки не было; можно повторить purchase_v2.

Ошибки

HTTP message Значение
401unauthorizedНеверный email/token или пользователь выключен.
400unknown_actionЗначение action не поддерживается.
400missing_fieldsНе указан goods_id, tier_key или quantity.
400bad_tierНеизвестный tier_key.
400bad_quantityКоличество вне диапазона (1…5000).
400bad_client_order_idclient_order_id не соответствует формату (1–64 символа A–Z a–z 0–9 . _ : @ / + = -).
400missing_lookupВ query_card не указан ни invoice_id, ни client_order_id.
400ambiguous_lookupВ query_card указаны и invoice_id, и client_order_id — выберите одно.
404not_foundЗаказ с таким invoice_id/client_order_id у этого пользователя не найден.
409client_order_id_conflictТот же client_order_id уже использован с другими goods_id/tier_key/quantity. См. details.
404product_not_foundТовар не существует / не в канале.
409product_unavailableТовар выключен администратором.
409tier_unavailableИнтервал выключен / не задан для товара.
409out_of_stockНедостаточно единиц на складе.
402insufficient_fundsНе хватает средств на балансе.
410content_expiredКонтент карточек уже удалён (>24 ч).
429rate_limitedПревышен лимит запросов.
500server_errorВнутренняя ошибка — повторите позже.

Лимиты

  • Rate-limit API: до 120 запросов в минуту с одного IP.
  • Максимальное количество в одной покупке: 5000 единиц.
  • Тело POST-запроса: не более 64 КБ.
  • Токен — один активный на пользователя; ротация мгновенная.

Вопросы, ошибки, ротация токена — пишите администратору.