API v1 — YTMarket

REST API для оптовых клиентов: каталог, заказы, баланс, webhook.

Base URL: https://ytmarket.pro/api/v1

⚡ Quick Start — от ключа до первого заказа за 5 минут

Минимальная цепочка чтобы начать пользоваться API:

  1. Напиши в Telegram поддержку — получи `X-API-Key` + (опционально) HMAC `secret`. Cохрани в password manager.
  2. Попробуй `GET /v1/health` с этим ключом — должен вернуть 200.
  3. Посмотри каталог: `GET /v1/products?min_qty=10&max_price=2` — увидишь все товары + поле `min_quantity` (минимальная партия).
  4. Пополни баланс: `POST /v1/balance/topup` → отправь USDT на возвращённый адрес. Через 5-10 сек после prizn confirmations баланс обновится автоматически.
  5. Сделай заказ: `POST /v1/orders` с `payment_method:"balance"`. Получи `order_id` + `status: "processing"`.
  6. Опрашивай `GET /v1/orders/{id}` каждые 5 сек, пока `status` не станет `completed` (тогда в `items[]` придут данные аккаунтов) или `failed` (баланс автоматически вернётся).
  7. Опционально: передай `webhook_url` в POST /orders, чтобы получать push-уведомления вместо polling.

1. Получение API-ключа

Ключ выдаётся только админом — нет self-signup. Напишите в Telegram поддержку с темой "API ключ" + укажите ваш email/проект. Лимит: 60 запросов в минуту на ключ (rate-limit, при превышении HTTP 429). Ключ + HMAC secret выдаются вместе и показываются один раз — сохрани сразу. поддержку.

2. Аутентификация

X-API-Key: YOUR_KEY_HERE

Каждый запрос требует header. Без ключа или с invalid — HTTP 401 Unauthorized.

3. Каталог (READ-ONLY)

GET /v1/health

Проверка ключа + uptime probe.

curl -H "X-API-Key: $KEY" https://ytmarket.pro/api/v1/health
# {"status":"ok","timestamp":1779497200}

GET /v1/products

Каталог с фильтрами. Query params:

  • category, sku
  • min_price, max_price (float, USDT)
  • min_qty (default 1), page (default 1), page_size (default 50, max 200)
curl -H "X-API-Key: $KEY" \
  "https://ytmarket.pro/api/v1/products?min_price=1&page=1&page_size=50"

GET /v1/products/{id}

Детали одного товара по ID.

GET /v1/categories

Список категорий с количеством товаров + минимальной ценой.

4. Баланс и пополнение

GET /v1/balance

Текущий баланс ключа + сумма потрачено/пополнено/возвращено.

curl -H "X-API-Key: $KEY" https://ytmarket.pro/api/v1/balance
# {"balance_usdt": 50.0, "total_spent_usdt": 12.5,
#  "total_topup_usdt": 62.5, "total_refunded_usdt": 1.2,
#  "currency": "USDT"}

POST /v1/balance/topup

Создать заявку на пополнение → получить USDT-адрес для перевода. Сумма + сеть выбирает клиент. Body:

curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"amount_usdt": 100, "network": "usdt_trc_20"}' \
  https://ytmarket.pro/api/v1/balance/topup

# {"topup_id": "abc123...", "payment_address": "TYz...",
#  "payment_network": "usdt_trc_20", "amount_usdt": 100.0,
#  "expires_at": 1779500800}

После перевода USDT на этот адрес — баланс автоматически кредитуется (cron сканирует приходящие TX каждые 5 сек). Адреса единые с website-покупками (один master-кошелёк на сеть), различаются заявки по сумме.

Полный цикл пополнения

  1. T+0:00 — клиент: POST /v1/balance/topup {amount_usdt: 100, network: "usdt_trc_20"}
  2. T+0:00 — API создаёт `topup_id`, возвращает `payment_address` (твой мастер) + `amount_usdt: 100` + `expires_at: now+1h`
  3. T+0:30 — клиент со своего кошелька шлёт 100 USDT (TRC-20) на этот адрес
  4. T+0:55 — TRC-20 подтверждается (~20 сек / 3-5 блоков)
  5. T+1:00 — backend (каждые 5s) видит входящую TX, ищет совпадение по сумме среди ожидающих заявок
  6. T+1:05 — backend матчит депозит по amount ±$0.01 с твоей заявкой → BAL +100, status=credited_auto
  7. T+1:05 — клиент: GET /v1/balance → balance_usdt: 100.0 ✓

📋 Поля ответа — что значит каждое

topup_idUUID заявки (хранится 24h в Redis). Используй для GET статуса или audit.
payment_addressТвой master-кошелёк выбранной сети. Тот же что для website-покупок. Не создаётся новый адрес на каждый топап.
payment_networkЭхо: usdt_trc_20 / usdt_bep_20 / usdt_polygon / usdt_arbitrum / usdt_ton / usdt_solana.
amount_usdtКлючевая метка для матчинга. Backend ищет входящую TX ровно на эту сумму (±$0.01).
expires_atUnix epoch +1h. Если клиент не пришлёт TX за час → заявка expired; депозит ждёт ручного зачисления через поддержку.

⚠️ Edge cases — что если что-то не так

Просил $100, прислал $100.00
✅ Авто-credit за 5-10 сек
Просил $100, прислал $99.99
✅ Зачтётся (tolerance ±$0.01)
Просил $100, прислал $98
❌ Не сматчится автоматически. Напиши в поддержку — зачислят фактическую сумму вручную.
Просил $100, прислал $200
❌ Не сматчится (превышение tolerance), нужно вручную
Просил $100, прислал через 2ч (expired)
❌ Заявка истекла; депозит ждёт ручного зачисления через поддержку.
Сумма совпадает с website-заказом в 15-мин окне
✅ Защита: dynamic pricing +1%/hit делает суммы уникальными. Вероятность коллизии < 1%. Заказы сайта имеют приоритет.
Клиент послал TX не в той сети (usdt_bep_20 вместо usdt_trc_20)
❌ Депозит придёт на EVM-адрес, но заявка ждёт TRC-20 → не сматчится. Вручную credit + поговорить с клиентом.

5. Заказы (balance-debit)

POST /v1/orders

Создать заказ + auto-debit balance + обработка системой. При failed/expired/cancelled — баланс автоматически возвращается (поле `refunded` в ответе и webhook).

curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"product_id": 12345, "quantity": 10,
       "payment_method": "balance",
       "webhook_url": "https://your.app/api-cb"}' \
  https://ytmarket.pro/api/v1/orders

# {"order_id": 789, "status": "processing",
#  "price_usdt": 12.34, "quantity": 10, "refunded": false,
#  "created_at": 1779497200, "updated_at": 1779497200}

Если баланс < price → HTTP 402 Payment Required + сообщение с инструкцией topup.

⚠️ Минимальная партия для каждого товара указана в поле `min_quantity`. Если запрошенное `quantity` меньше — HTTP 400 с подсказкой минимально допустимого количества.

GET /v1/orders/{id}

Статус заказа + items[] с credentials когда completed. Доступен только владельцу ключа (key-scoped, 404 если чужой).

curl -H "X-API-Key: $KEY" https://ytmarket.pro/api/v1/orders/789

# {"order_id": 789, "status": "completed", "refunded": false,
#  "price_usdt": 12.34, "quantity": 10,
#  "items": [{"login": "...", "password": "...", ...}],
#  "created_at": 1779497200, "updated_at": 1779497500}

6. Webhook уведомления

В POST /v1/orders передайте `webhook_url` — мы POST'нем JSON туда при изменении статуса (completed/partial/failed/expired/cancelled/refunded).

POST $YOUR_WEBHOOK_URL
Content-Type: application/json

{
  "order_id": 789,
  "status": "completed",
  "price_usdt": 12.34,
  "quantity": 10,
  "product_id": 12345,
  "items": [{"login": "...", "password": "...", ...}],
  "error_message": null,
  "refunded": false,
  "fired_at": 1779497200
}

Сервис ожидает HTTP 2xx ответ. На 5xx/timeout — retry до 5 раз с exp-backoff. После 5 неудач webhook помечается как fired.

7. Метрики usage

GET /v1/usage

Per-key статистика: запросы, последняя активность, потрачено, возвращено.

curl -H "X-API-Key: $KEY" https://ytmarket.pro/api/v1/usage
# {"request_count": 1234, "last_used_at": 1779497200,
#  "first_used_at": 1779480000, "last_endpoint": "/api/v1/products",
#  "total_spent_usdt": 125.50}

8. Доставка аккаунтов

Срок выдачи: 30 секунд — 10 минут после `status=processing`. Заказ обрабатывается асинхронно — polling GET /v1/orders/{id} или webhook.

  1. POST /v1/orders → status=processing
  2. Заказ обрабатывается (30s-10min)
  3. Когда готово → status=completed
  4. GET /v1/orders/{id} → items[]
  5. Webhook fired (если зарегистрирован)

9. Сети USDT и комиссии

СетьFeeВремяРекомендация
usdt_trc_20$0.5-11-3 minПо умолчанию
usdt_bep_20$0.2-0.530 sec - 2 minДёшево + быстро
usdt_polygon$0.01-0.051-3 minСамый дешёвый
usdt_arbitrum$0.1-0.330 secЕсли уже на Arbi
usdt_ton$0.05-0.15-15 secБыстрая
usdt_solana$0.01-0.025-30 secДёшево + быстро

10. Лимиты и тарифы

  • Rate-limit: 60 запросов в минуту на ключ (HTTP 429 + Retry-After)
  • Цена через API = такая же как на сайте (без наценки)
  • page_size: 1-200 (по умолчанию 50)
  • quantity в заказе: 1-10000 единиц
  • Топап: 1-100000 USDT
  • Webhook timeout 10s, до 5 retry
  • Auto-refund: баланс возвращается при failed/expired/cancelled (cron каждые 30s)

11. Коды ошибок

  • 401invalid X-API-Key
  • 402insufficient balance
  • 404product/order не найден
  • 409insufficient stock
  • 422invalid request body
  • 429rate-limit (60/min)
  • 501invoice mode не реализован
  • 503Redis down

11.5 Безопасность (HMAC + IP whitelist)

Дополнительные защиты для production ключей. Опционально, по запросу к админу.

HMAC body signing (POST /orders + /topup)

При выдаче ключа админ может выдать HMAC secret одной строкой (показывается один раз). Если у ключа есть secret, POST запросы требуют 2 дополнительных header. Формула:

X-Timestamp = unix epoch seconds (≤5 min drift от server)
X-Signature = hmac_sha256(secret, f"{timestamp}\n{request_body}").hex()
# Python example
import hmac, hashlib, time, json, requests
KEY = "..."; SECRET = "..."
BASE = "https://ytmarket.pro/api/v1"
body = json.dumps({"product_id": 12345, "quantity": 1, "payment_method": "balance"})
ts = str(int(time.time()))
sig = hmac.new(SECRET.encode(), f"{ts}\n{body}".encode(), hashlib.sha256).hexdigest()
r = requests.post(f"{BASE}/orders", data=body, headers={
    "X-API-Key": KEY,
    "Content-Type": "application/json",
    "X-Timestamp": ts,
    "X-Signature": sig,
})
print(r.status_code, r.json())

Защита от: replay attack, MITM tampering, accidental key leak (signature не валидна без secret). Если secret не выдан — backward-compat, signature не требуется.

IP whitelist

По запросу можно добавить разрешённые IP для ключа. Если whitelist пуст — IP не проверяется (default). Если есть хоть один IP — все остальные получают HTTP 403.

Audit log

Все admin-действия (mint/revoke/credit/topup credited/rotate secret/whitelist) записываются в БД таблицу `api_audit_log`. Админ может посмотреть последние 50 через bot команду `/api_audit` или endpoint `GET /api/admin/api-audit`.

🧪 Try it now — интерактивная песочница

Вставь свой X-API-Key ниже и нажми любую кнопку — запрос пойдёт прямо с этой страницы на наш API. Для POST endpoints HMAC-подпись считается в браузере автоматически (если у твоего ключа есть secret).

GET https://ytmarket.pro/api/v1/health
🔒 Запрос отправляется напрямую с твоего браузера на https://ytmarket.pro/api/v1. Ключ нигде не сохраняется на сервере.

12. SDK примеры

Python (requests)

import requests
KEY = "YOUR_API_KEY"
BASE = "https://ytmarket.pro/api/v1"
headers = {"X-API-Key": KEY}

# 1. List products
products = requests.get(f"{BASE}/products", headers=headers,
                         params={"min_price": 1, "page_size": 50}).json()

# 2. Check balance
bal = requests.get(f"{BASE}/balance", headers=headers).json()
print(f"Balance: {bal['balance_usdt']} USDT")

# 3. Create order (balance-debit)
order = requests.post(f"{BASE}/orders", headers=headers, json={
    "product_id": products["items"][0]["id"],
    "quantity": 1,
    "payment_method": "balance",
    "webhook_url": "https://your.app/cb",
}).json()
print(f"Order #{order['order_id']} {order['status']}")

# 4. Poll until final
import time
while True:
    o = requests.get(f"{BASE}/orders/{order['order_id']}", headers=headers).json()
    if o["status"] in ("completed", "failed", "expired", "cancelled"):
        break
    time.sleep(5)
print(f"Final: {o['status']}, items={o.get('items')}, refunded={o.get('refunded')}")

Node.js (axios)

import axios from "axios";

const KEY = process.env.API_KEY;
const api = axios.create({
  baseURL: "https://ytmarket.pro/api/v1",
  headers: { "X-API-Key": KEY },
});

// 1. List products
const { data: products } = await api.get("/products", { params: { min_price: 1 } });

// 2. Create order
const { data: order } = await api.post("/orders", {
  product_id: products.items[0].id,
  quantity: 1,
  payment_method: "balance",
  webhook_url: "https://your.app/cb",
});

// 3. Poll
let o;
while (true) {
  o = (await api.get(`/orders/${order.order_id}`)).data;
  if (["completed", "failed", "expired", "cancelled"].includes(o.status)) break;
  await new Promise(r => setTimeout(r, 5000));
}
console.log("Final:", o.status, "items:", o.items, "refunded:", o.refunded);

Go (net/http)

package main

import (
  "bytes"; "encoding/json"; "fmt"; "io"; "net/http"
)

func main() {
  body, _ := json.Marshal(map[string]any{
    "product_id": 12345, "quantity": 1, "payment_method": "balance",
  })
  req, _ := http.NewRequest("POST", "https://ytmarket.pro/api/v1/orders", bytes.NewReader(body))
  req.Header.Set("X-API-Key", "YOUR_KEY")
  req.Header.Set("Content-Type", "application/json")
  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()
  b, _ := io.ReadAll(resp.Body); fmt.Println(string(b))
}

curl

# Full flow in 4 curls
KEY=YOUR_API_KEY
BASE=https://ytmarket.pro/api/v1

curl -H "X-API-Key: $KEY" "$BASE/products?min_price=1&page_size=5"
curl -H "X-API-Key: $KEY" "$BASE/balance"
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"product_id":12345,"quantity":1,"payment_method":"balance"}' \
  "$BASE/orders"
curl -H "X-API-Key: $KEY" "$BASE/orders/789"

🙋 FAQ — частые вопросы

В чём разница между X-API-Key и HMAC Secret?

X-API-Key — публичный идентификатор клиента, передаётся в каждом запросе в header. Secret — приватный ключ для подписи POST-запросов через HMAC-SHA256, НИКОГДА не передаётся в запросе (используется только для расчёта X-Signature). Если кто-то украдёт только key, он сможет читать каталог/баланс, но не сможет делать POST orders/topup.

Когда мне нужен HMAC Secret?

Если админ выдал тебе secret вместе с ключом (default через бот) — secret обязателен для POST /orders и /topup. Без подписи получишь HTTP 401. Для GET запросов (health/products/balance/etc) secret не нужен — только X-API-Key.

Я потерял secret. Что делать?

Попроси админа сделать `POST /api/admin/api-keys/{fp}/rotate-secret` — выдаст новый secret. Старый сразу инвалидируется. Сам ключ остаётся прежним.

Можно ли пополнить баланс без заказа?

Да, это два независимых процесса. `POST /v1/balance/topup` → получаешь адрес → шлёшь USDT → баланс растёт. Заказы тут не участвуют. Можешь пополнить раз и пользоваться месяцами.

Что если я отправлю TX не на ту сумму?

Если разница ≤ $0.01 — зачтётся автоматически. Если больше — пиши в поддержку, зачислят фактическую сумму вручную. См. таблицу edge cases в секции 4.

Адреса для топапа — общие с website?

Да. Один кошелёк на сеть (TRC-20/EVM/TON/Solana) обслуживает и API клиентов, и обычных покупателей сайта. Заявки различаются по точной сумме. Заказы сайта имеют приоритет.

Почему минимальная партия не 1 шт?

Бизнес-правило marketplace: каждый товар имеет `min_quantity` поле + действует общий минимум на сумму заказа (~600₽). Это отсекает «пилотные» заказы которые не покрывают комиссии сети. Цена через API такая же как на сайте (без наценки).

Как узнать что заказ обработался?

Два способа: (1) polling `GET /v1/orders/{id}` каждые 5 сек, пока status не станет `completed`/`failed`/`expired`/`cancelled` — `items[]` появятся в completed; (2) webhook — передай `webhook_url` в POST /orders, получишь POST с тем же JSON на свой URL.

Что если заказ failed?

Баланс **автоматически возвращается** (`refunded: true` в /orders/{id} + webhook). Refund-cron сканирует каждые 30 сек. Можешь повторить заказ позже или попробовать другой `product_id` той же категории.

Где посмотреть свои недавние запросы / траты?

`GET /v1/usage` показывает request_count, last_used_at, total_spent_usdt. `GET /v1/balance` показывает total_spent_usdt + total_topup_usdt + total_refunded_usdt.

Cross-platform dynamic pricing — как работает?

Если в 15-мин окне уже был заказ на ту же сумму (на любом проекте FBM/IM/TM/VKM + через API), следующий заказ +1% к цене (cap +10%). Цель — гарантировать уникальность сумм для матчинга депозитов. Видно в response: `raw_data.dp_hits`.

Webhook подписан ли?

Да, если у твоего ключа есть HMAC secret — webhook payload подписывается тем же secret. Headers: `X-Webhook-Timestamp`, `X-Webhook-Signature`, `X-Webhook-Algorithm: HMAC-SHA256`. Получи и проверь: `hmac_sha256(secret, f"{ts}\n{request.body}").hex() == X-Webhook-Signature` + drift ≤ 5 мин.

Что если мой webhook URL не отвечает?

Backend retry до 5 раз с exp-backoff (timeout 10s каждый). После 5 неудач webhook помечается как fired (не повторяется). Лучше сделать receiver idempotent (по order_id + status).

Можно ли отменить заказ?

Сейчас нет user-facing cancel. Заказ либо успевает completed, либо provider-side выкидывает failed/expired (тогда auto-refund). Если очень нужно отменить — пиши в саппорт, админ может вручную пометить cancelled (тогда тоже refund).

13. Postman / Changelog / Поддержка

Postman коллекция

Скачать готовую Postman коллекцию для всех endpoints: Скачать .postman_collection.json

Changelog

  • v1.4 (2026-05-23) — Min-purchase enforcement (per-product min_quantity + 600₽ floor); cron auto-credit топапов 120s→5s; cross-platform dynamic pricing +1%/15min применяется и через API; webhook HMAC signing (X-Webhook-Signature header); Try-it playground в /api/docs.
  • v1.3 (2026-05-23) — Auto-refund на failed/expired/cancelled, `refunded` field, status maps paid→processing, `created_at`/`updated_at` в ответе.
  • v1.2 (2026-05-23) — Balance system, POST /orders с balance-debit, webhook cron.
  • v1.1 (2026-05-23) — Rate-limit 60/min/key, per-key metrics.
  • v1.0 (2026-05-23) — Read-only catalog endpoints (products/categories/health).

Поддержка

Вопросы по API: Telegram поддержка. SLA: 30 минут в рабочее время (8:00-22:00 МСК). Telegram.

YTMarket API v1 • ytmarket.pro