Документация разработчика

Zenith API

Рабочие методы текущего API: инвойс, checkout, вебхук, кабинет, вывод и свап. Ниже — контракты, подпись и ответы, без чужих SDK.

Старт

API-ключи

Кабинет — это аккаунт. Мерчант (магазин/бот) получает отдельную пару ключей при создании. HMAC и вебхук считаются секретом этого мерчанта. Ключ кабинета после регистрации не используйте для приёма платежей разных проектов.

Ключ: страница мерчанта в кабинете. Secret показывается один раз (создание или «Сменить ключ»). Ротация: POST /api/v1/shops/{id}/rotate-keys с Bearer JWT.

Создать мерчанта
POST /api/v1/shops
Authorization: Bearer <jwt>
Content-Type: application/json

{ "name": "Shop One", "kind": "website", "project_url": "https://shop.example" }

# 201
{
  "id": "…",
  "name": "Shop One",
  "status": "pending",
  "api_key": "pk_…",
  "api_secret": "sk_…",
  "webhook_url": null
}
  • Платежи: X-Api-Key = pk_ мерчанта. shop_id в теле не нужен — инвойс сам привяжется.
  • Вебхук: PATCH /api/v1/shops/{id} { "webhook_url": "https://…" }.
  • Логин кабинета: POST /api/v1/merchants/login → access_token.
  • Telegram Login: POST /api/v1/merchants/telegram-login.
Старт

Формат запроса

Подпись обязательна, если REQUIRE_API_SIGNATURE=true или вы уже передали X-Signature. Тело в HMAC — сырые байты запроса, не пересобранный JSON.

  • X-Api-Key — публичный ключ pk_…
  • X-Timestamp — unix time, допуск signature_ttl_seconds (по умолчанию 300).
  • X-Signature — hex HMAC-SHA256(secret, timestamp + "\n" + METHOD + "\n" + path + "\n" + body).
  • path — полный путь, например /api/v1/invoice/create, без query.
  • GET: body пустая строка.
  • Кабинет: Authorization: Bearer <jwt> — HMAC не нужен.
bash + openssl
BODY='{"amount_usd":"10.00","order_id":"ORD-1042","network":"TRC20"}'
TS=$(date +%s)
PATH='/api/v1/invoice/create'
SIG=$(printf '%s\nPOST\n%s\n%s' "$TS" "$PATH" "$BODY" | openssl dgst -sha256 -hmac "$API_SECRET" | awk '{print $2}')
curl -sS -X POST "https://api.example.com$PATH" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $API_KEY" \
  -H "X-Timestamp: $TS" \
  -H "X-Signature: $SIG" \
  -d "$BODY"
Python
import hashlib, hmac, json, time, urllib.request

body = json.dumps({"amount_usd": "10.00", "order_id": "ORD-1042", "network": "TRC20"}, separators=(",", ":"))
path = "/api/v1/invoice/create"
ts = str(int(time.time()))
msg = f"{ts}\nPOST\n{path}\n{body}"
sig = hmac.new(api_secret.encode(), msg.encode(), hashlib.sha256).hexdigest()
req = urllib.request.Request(
    "https://api.example.com" + path,
    data=body.encode(),
    headers={"Content-Type": "application/json", "X-Api-Key": api_key, "X-Timestamp": ts, "X-Signature": sig},
    method="POST",
)
print(urllib.request.urlopen(req).read().decode())
Node.js
const crypto = require("crypto");
const body = JSON.stringify({ amount_usd: "10.00", order_id: "ORD-1042", network: "TRC20" });
const path = "/api/v1/invoice/create";
const ts = String(Math.floor(Date.now() / 1000));
const sig = crypto.createHmac("sha256", apiSecret).update(`${ts}\nPOST\n${path}\n${body}`).digest("hex");
const res = await fetch("https://api.example.com" + path, {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-Api-Key": apiKey, "X-Timestamp": ts, "X-Signature": sig },
  body,
});

Лимит создания инвойсов: 30 запросов в минуту на IP. Ошибки: 401 подпись/ключ, 409 email занят, 422 валидация, 429 лимит.

Интеграция

Payform

  • Бэкенд создаёт инвойс.
  • Покупатель открывает checkout_url.
  • Платит USDT по QR/адресу.
  • Вы получаете вебхук invoice.paid и/или polling статуса.

Покупатель не регистрируется. Таймер жизни инвойса — 30 минут.

Интеграция

Host-to-host

Тот же POST /invoice/create. Не открывайте checkout_url — покажите deposit_address, amount_crypto, asset, network, payment_memo (если есть), expires_at. QR соберите сами (данные = адрес или адрес|сумма).

  • Статус: GET /api/v1/invoice/{id} с HMAC или публичный GET /api/v1/pay/{token}/status.
  • token — хвост checkout_url после /pay/.
  • Итог оплаты дублируйте вебхуком, не только polling.
Интеграция

Виджет

Инвойс всё равно создаётся на вашем бэкенде. На страницу отдайте только checkout_url. Скрипт: GET /widget.js (проксируется с API).

HTML
<div id="zenith-pay"></div>
<script src="https://ваш-домен/widget.js"
  data-checkout="CHECKOUT_URL"
  data-target="#zenith-pay"
  data-height="640"></script>
Платежи

Создание инвойса

ПолеТипОписание
amount_usdstring decimal > 0Сумма в USD, до 2 знаков
order_idstring 1–128Ваш id заказа, уникален на мерчанта
networkTRC20 | TONСеть USDT, по умолчанию TRC20
return_urlurl?Куда вернуть покупателя после оплаты
shop_iduuid?Не нужен, если X-Api-Key — ключ мерчанта. Иначе привязка к одобренному магазину

Повтор с тем же order_id идемпотентен: 200 и старый инвойс, не дубль. Сумма в USDT = USD × (1 + спред курса, по умолчанию 1%). TON: уникальный subwallet без memo, если настроена мнемоника казны; иначе общий адрес + payment_memo.

Ответ 201
{
  "id": "7c2e…",
  "order_id": "ORD-1042",
  "amount_usd": "10.00",
  "amount_crypto": "10.100000",
  "asset": "USDT",
  "network": "TRC20",
  "deposit_address": "T…",
  "payment_memo": null,
  "status": "pending",
  "checkout_url": "https://…/pay/{token}",
  "return_url": null,
  "shop_id": null,
  "expires_at": "2026-09-20T18:10:00+00:00",
  "tx_hash": null,
  "received_crypto": null,
  "confirmations": 0,
  "created_at": "2026-09-20T17:40:00+00:00"
}
Платежи

Статус платежа

  • Список: GET /api/v1/invoice
  • Один: GET /api/v1/invoice/{id}
  • Публично по токену checkout: GET /api/v1/pay/{token}/status
pendingdetectedconfirmingpaidexpiredunderpaidoverpaidfailedreview

Сканер сам ищет перевод по адресу инвойса: USDT/USDC (TRC-20, TON, ERC-20, BEP-20, SOL), BTC, ETH, TON, TRX, BNB, SOL, LTC, DOGE, BCH, DASH, AVAX, POL, DAI, SHIB. Допуск суммы 0.5%. Подтверждения зависят от сети (TRC-20 — 19, TON — 1, BTC — 2, ETH — 12). DEBUG: POST /api/v1/invoice/{id}/simulate-pay.

Платежи

Checkout

Готовая payform. Polling публичного статуса. После paid можно увести на return_url.

Вебхуки

Вебхук оплаты

Событие invoice.paid. 3 попытки, пауза 60 с, пока ответ не 2xx. URL и подпись — у мерчанта (shop), иначе fallback на кабинет.

  • Заголовки: X-Timestamp, X-Signature, X-Event=invoice.paid, X-Event-Id=invoice_id
  • Подпись: HMAC-SHA256(api_secret, timestamp + "." + raw_body) — не та же строка, что у входящих API-запросов.
  • Повтор: POST /api/v1/invoice/{id}/webhook (только paid).
Тело
{
  "event": "invoice.paid",
  "event_id": "7c2e…",
  "invoice_id": "7c2e…",
  "order_id": "ORD-1042",
  "amount_usd": "10.00",
  "amount_crypto": "10.100000",
  "asset": "USDT",
  "network": "TRC20",
  "tx_hash": "…",
  "status": "paid",
  "paid_at": "2026-09-20T17:41:02+00:00"
}
Проверка (Python)
import hmac, hashlib
expected = hmac.new(api_secret.encode(), f"{timestamp}.{body}".encode(), hashlib.sha256).hexdigest()
assert hmac.compare_digest(expected, header_signature)
Кошельки

Пополнение кабинета

Это пополнение личного/бизнес леджера, не инвойс покупателя. Аналог «статического» адреса мерчанта в кабинете.

Адрес
GET /api/v1/dashboard/deposit-address?asset=USDT&network=TRC20
# { "network": "TRC20", "asset": "USDT", "address": "T…", "memo": null }

Список монет и сетей: GET /api/v1/dashboard/coins.

Кошельки

Балансы и история

  • GET /api/v1/dashboard/overview?account=personal|business
  • GET /api/v1/dashboard/history?scope=all|personal|merchants
  • GET /api/v1/dashboard/analytics
  • GET /api/v1/dashboard/treasury — адреса казны для ончейн-выводов
Выплаты

Перевод между счетами

POST /api/v1/dashboard/transfer
{ "from_account": "business", "to_account": "personal", "asset": "USDT", "amount": "50" }

Счета должны отличаться. Списывается баланс выбранного актива на from_account.

Выплаты

Вывод в сеть

POST /api/v1/dashboard/send
{ "asset": "USDT", "network": "TRC20", "address": "T…", "amount": "10.5", "comment": "vendor" }

Сначала бизнес-счёт, если не хватает — личный. ENABLE_ONCHAIN_PAYOUTS=true и USE_MOCK_CHAIN=false: воркер шлёт USDT с казначейства (TRC-20 / TON jetton). Иначе заявка закрывается offchain-хешем. Свип депозитов: ENABLE_DEPOSIT_SWEEP.

Обмен

Конвертация

GET /api/v1/dashboard/quote?from_asset=USDT&to_asset=TON&amount=10
POST /api/v1/dashboard/convert
{ "account": "personal", "from_asset": "USDT", "to_asset": "TON", "amount": "10" }

Курс TON с CoinGecko/Coinbase плюс спред платформы. Это не ончейн DEX.

Обмен

Автосвап депозита

  • GET /api/v1/dashboard/swap-rules
  • POST /api/v1/dashboard/swap-rules { from_asset, to_asset, account, enabled }
  • POST /api/v1/dashboard/swap-rules/{id}/toggle
  • DELETE /api/v1/dashboard/swap-rules/{id}
Справка

Монеты и сети

СимволСети в кабинете
USDTTRC20, TON, ERC20, BEP20
USDCERC20, TRC20, SOL
BTCBTC
ETHERC20
TON / GRAMTON
TRXTRC20
BNBBEP20
SOLSOL
LTC / DOGE / XMR / AVAX / POL / BCH / DAI / DASH / SHIBсвои сети в /dashboard/coins