ДОКУМЕНТАЦИЯ
Разработка на SMetaGateway.
Всё, что нужно, чтобы создавать счета USDT TRC20 с сервера, направлять покупателей на страницу оплаты и подтверждать платежи подписанными вебхуками.
Обзор
SMetaGateway — некастодиальный слой выставления счетов для USDT в сети TRON. Продавцы регистрируют публичный адрес, покупатели платят на него напрямую. Шлюз назначает каждому счёту уникальную точную сумму, отслеживает статус, ведёт учёт и уведомляет ваш сервер.
Все эндпоинты находятся под /api/v1 на том же домене, что и этот сайт. Суммы всегда передаются десятичными строками с не более чем шестью знаками после запятой — никогда числами с плавающей точкой.
- Ваш сервер → SMetaGateway1POST /api/v1/invoices с Idempotency-Key
- SMetaGateway → Ваш сервер2Счёт с payable_amount и checkout_url
- Ваш сервер → Покупатель3Перенаправление покупателя на checkout_url
- Покупатель → SMetaGateway4Покупатель открывает страницу оплаты и сканирует QR-код
- Покупатель → Ваш кошелёк TRON5Покупатель отправляет точную сумму USDT на ваш адрес
- SMetaGateway6Шлюз находит точную сумму в блокчейне и подтверждает счёт
- SMetaGateway → Ваш сервер7Подписанный вебхук invoice.confirmed
- Ваш сервер → SMetaGateway8GET /api/v1/invoices/{id} для проверки, затем выполнение заказа
Путь данныхПуть денег
Быстрый старт
1. Создайте рабочее пространство и добавьте адрес получения TRON. Скопируйте ID кошелька.
2. Откройте «Разработчики → API-ключи» и создайте ключ со сроком действия. Секрет начинается с smg_ и показывается только один раз, поэтому сохраните его в надёжном месте.
3. Создайте счёт с сервера запросом ниже. Сохраните ID счёта и точное значение payable_amount.
4. Перенаправьте покупателя на checkout_url. Отмечайте заказ оплаченным только после проверки вебхука invoice.confirmed и серверного запроса счёта.
curl -X POST "https://smg.sabco24.com/api/v1/invoices" \
-H "Authorization: Bearer $SMETA_API_KEY" \
-H "Idempotency-Key: order-1001" \
-H "Content-Type: application/json" \
-d '{"merchant_order_id":"1001","amount":"49.95","wallet_id":"WALLET_ID","description":"Example order","expires_in_minutes":20}'Аутентификация
Серверные интеграции аутентифицируются bearer-ключом API: Authorization: Bearer smg_…. Ключи имеют права invoices:read, invoices:write и ledger:read и могут истекать через 30, 90 или 365 дней. Истёкший ключ возвращает 401 api_key_expired; перевыпустите его в панели, чтобы получить новый секрет. Храните ключи на сервере и никогда не встраивайте их в браузер или мобильное приложение.
Панель управления использует HttpOnly cookie сессии. Управление аккаунтом, кошельками, ключами API и вебхуками требует сессии владельца и недоступно по ключу API.
curl "https://smg.sabco24.com/api/v1/invoices/INVOICE_ID" \
-H "Authorization: Bearer $SMETA_API_KEY"Суммы и идентификация
Передайте базовую цену десятичной строкой, например "49.95". Шлюз добавит положительную надбавку — от 0.000001 до 0.009999 USDT ниже 100 USDT или от 0.000001 до 0.999999 USDT от 100 USDT — и вернёт base_amount, adjustment и payable_amount отдельно.
Точная сумма резервируется на 90 дней для одной и той же сети, токена и адреса среди всех продавцов. Предпочитаются неиспользованные суммы; повторно использованная сумма переводит счёт в review вместо автоматического подтверждения.
Резервируется на 90 дней для сети, токена и адреса получения
{
"base_amount": "49.950000",
"adjustment": "0.003821",
"payable_amount": "49.953821"
}Счета и идемпотентность
POST /api/v1/invoices требует заголовок Idempotency-Key. Повтор того же запроса с тем же ключом вернёт исходный счёт с idempotent_replay: true; повтор ключа с другими данными вернёт 409 idempotency_conflict.
Для каждого merchant_order_id существует один счёт. Сохраните ID счёта и payable_amount вместе с заказом и сверяйте их при получении вебхука.
POST /invoices + Idempotency-Key- Новый ключ201 — создан новый счёт
- Тот же ключ, то же телоИсходный счёт, idempotent_replay: true
- Тот же ключ, другое тело409 idempotency_conflict
{
"invoice": {
"id": "6f1c…",
"merchant_order_id": "1001",
"base_amount": "49.950000",
"adjustment": "0.003821",
"payable_amount": "49.953821",
"status": "pending",
"mode": "live",
"checkout_url": "https://smg.sabco24.com/checkout/…",
"expires_at": "2026-10-21T12:20:00.000Z",
"reserved_until": "2027-01-19T12:00:00.000Z"
},
"idempotent_replay": false
}Страница оплаты и статус счёта
checkout_url — ссылка-доступ: любой её владелец видит безопасные для плательщика данные, поэтому храните её конфиденциально. Страница показывает имя продавца, разбивку суммы, адрес, QR-код и срок действия, но не ваши метаданные или внутренние ID.
Статус счёта: pending, confirmed, expired или review. Страница оплаты истекает через expires_in_minutes (по умолчанию 20, максимум 1440); резерв суммы действует 90 дней независимо.
pending- Получена точная сумма
confirmed - Время оплаты истекло
expired - Сумма повторно использована или нужна ручная проверка
review
Подписанные вебхуки
Зарегистрируйте публичный HTTPS-эндпоинт (порт 443) в панели. Секрет подписи показывается один раз. События: invoice.created, invoice.confirmed, invoice.expired, invoice.review и webhook.test. Доставка повторяется до восьми раз, возможен ручной повтор.
Каждый запрос содержит заголовки X-SMeta-Event-Id, X-SMeta-Timestamp и X-SMeta-Signature. Вычислите HMAC-SHA256 от timestamp + "." + сырое тело, сравните за постоянное время, отклоняйте метки старше пяти минут и только затем разбирайте JSON. Обрабатывайте каждый ID события один раз.
- 1Прочитайте исходное тело и заголовки X-SMeta-*
- 2Метка времени не старше 5 минут?Отклонить (4xx)
- 3HMAC-SHA256(timestamp + "." + body)
- 4Сравнение за постоянное время с X-SMeta-SignatureОтклонить (4xx)
- 5Этот ID события уже обработан?Вернуть 2xx, пропустить
- 6Обновите заказ и верните 2xx
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(rawBody: Buffer, headers: Record<string, string>, secret: string) {
const timestamp = headers['x-smeta-timestamp'];
const signature = headers['x-smeta-signature'] ?? '';
if (!/^\d+$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return null;
const expected = 'sha256=' + createHmac('sha256', secret)
.update(timestamp + '.').update(rawBody).digest('hex');
const a = Buffer.from(expected), b = Buffer.from(signature);
if (a.length !== b.length || !timingSafeEqual(a, b)) return null;
const event = JSON.parse(rawBody.toString('utf8'));
return event.id === headers['x-smeta-event-id'] ? event : null;
}Ошибки и лимиты
Ошибки возвращают JSON с error.code и error.message. Типичные статусы: 400 валидация, 401 аутентификация, 403 права или источник, 404 не найдено, 409 конфликт или проверка, 429 превышен лимит.
Создание счетов ограничено 120 запросами в минуту на продавца. Повторяйте ответы 429 и 5xx с нарастающей задержкой и тем же Idempotency-Key.
{
"error": {
"code": "idempotency_conflict",
"message": "This idempotency key was used with different invoice details."
},
"mode": "live"
}Интеграции
В панели есть 32 готовых рецепта для Node.js, NestJS, PHP, Laravel, Python, Django, Go, Java, C#, Ruby, React, Next.js, Vue и e-commerce платформ, таких как WooCommerce, Magento и Shopware. Загружаемый плагин WooCommerce — предварительная версия и пока не принимает рабочие API-ключи.
Рецепты — это примеры, а не опубликованные SDK. Фронтенд-примеры обращаются к вашему бэкенду, который хранит ключ API.
Подтверждение платежей
Шлюз читает основную сеть TRON через TronGrid, находя подтверждённые переводы USDT TRC20 на каждый адрес получения с открытым счётом, и перепроверяет каждый перевод по успешной финализированной квитанции. Перевод точной суммы payable_amount между созданием и истечением счёта подтверждает его, а хеш транзакции сохраняется в tx_hash.
Перевод, пришедший после истечения срока, совпадающий с ранее использованной суммой или относящийся к счёту на проверке, переводит статус в review и никогда не подтверждается автоматически. Обнаружение обычно занимает несколько минут. Нулевая комиссия и некастодиальная модель сами по себе не означают налогового освобождения или регуляторного разрешения.