/v1/public/* подписывается на вашей стороне ключом api_secret. Платформа
проверяет подпись на сервере — сам api_secret никогда не передаётся по сети после момента
выдачи. Базовый URL индивидуален для вашего инстанса, например https://wallet.your-exchange.com.
В этих примерах используются единые значения во всех разделах документации:
базовый URL
https://wallet.your-exchange.com, X-Api-Id = pk_live_a1b2c3d4,
order_id в формате INV-2026-000042. Подставьте свои реальные значения.Обязательные заголовки
Эти заголовки должны присутствовать в каждом запросе.Публичный идентификатор ключа. Выдаётся в админ-кабинете при создании API-ключа.
Не является секретом — это лишь указатель, по какому ключу проверять подпись.
Unix-время в секундах на момент формирования запроса. Сервер принимает значение
только в пределах ±300 секунд от своего времени. Часть подписываемого сообщения.
HMAC-SHA256 в нижнем регистре hex от сообщения {X-Timestamp}.{raw_body}
с ключом api_secret. Подробности — ниже.Опционально, только для write-операций (создание депозита, выплаты и т. п.). UUID,
который гарантирует, что безопасный повтор того же запроса не создаст дубликат.
См. Идемпотентность.
Как формируется подпись
Сообщение для HMAC — это конкатенация трёх частей: значениеX-Timestamp, символ-разделитель
точка . и сырое тело запроса.
GET, HEAD, DELETE) сырое тело — это пустая строка ""
(именно пустая строка, а не {}). Поэтому сообщение оканчивается на точку:
Соберите тело
Сериализуйте JSON в строку — это и есть
raw_body. Для запросов без тела используйте пустую строку.Полный разбор на конкретных числах
Возьмём заведомо известные входные данные и проверим, что у вас получается тот же результат. Эти значения детерминированы — повторите расчёт у себя и сверьте подпись.| Параметр | Значение |
|---|---|
api_secret | s3cr3t_ApiSecret_ExampleOnly_DoNotUse |
X-Timestamp | 1735680000 |
raw_body | {"assetCode":"USDT_TRC20","orderId":"INV-2026-000042","expectedAmount":"100.50"} |
HMAC-SHA256 в hex:
Если ваша реализация выдаёт ровно
58d7e5946e50f93551ac9d48728b5d66308c5328241044a0e7ef03528f0bc6ed —
алгоритм подписи у вас собран правильно.GET) с тем же секретом и тем же X-Timestamp = 1735680000 сообщение —
1735680000., а подпись:
Готовый запрос
Так выглядит подписанныйPOST /v1/public/deposits с данными из примера выше.
Формат ответа
Все ответы возвращаются в едином envelope.Успех
Ошибка
"100.50"), чтобы исключить потерю точности на
плавающей запятой. Полный справочник кодов — на странице Ошибки.
IP-whitelist
Помимо подписи платформа проверяет IP-адрес вызывающего. Если для сайта задан белый список, запросы принимаются только с перечисленных адресов; иначе —403 IP_NOT_WHITELISTED.
Узнайте исходящий IP
Это адрес, с которого ваш бэкенд CMS обращается к API (а не IP браузера клиента).
Добавьте его в админ-кабинете
Белый список IP сайта управляется оператором в админ-панели платформы.
Если белый список для сайта пуст, проверка IP не применяется. Для боевого окружения мы
рекомендуем всегда настраивать whitelist.
Ротация ключей
api_secret показывается один раз — в момент создания ключа. Сохраните его сразу в
безопасное место (секрет-менеджер). Восстановить его позже нельзя; если секрет утерян или
скомпрометирован — выпустите новый ключ через ротацию.
Выпустите новый ключ
В админ-кабинете создайте новый credential или выполните ротацию существующего. Вы получите
новый
X-Api-Id и новый api_secret (последний — единожды).Переключите интеграцию
Обновите
X-Api-Id и api_secret в своей CMS. Старый ключ при ротации помечается как
rotated и продолжает работать ограниченное время (grace period) — это позволяет выкатить
смену без простоя.Возможные ошибки аутентификации
| HTTP | Код | Когда возникает | Что проверить |
|---|---|---|---|
| 401 | UNAUTHORIZED | Нет X-Api-Id, X-Signature или X-Timestamp; ключ не найден, неактивен, истёк; сайт не активен; X-Timestamp не число | Все три обязательных заголовка на месте; ключ действующий; сайт активен |
| 401 | INVALID_SIGNATURE | Подпись не совпала | Подписаны те же байты, что отправлены; верный секрет; сообщение timestamp + "." + raw_body |
| 401 | TIMESTAMP_SKEW | X-Timestamp вне диапазона ±300 секунд | Синхронизируйте часы сервера по NTP; шлите время в секундах, не миллисекундах |
| 403 | IP_NOT_WHITELISTED | IP вызывающего не в белом списке сайта | Добавьте исходящий IP бэкенда в whitelist |
| 429 | RATE_LIMITED | Превышен лимит запросов для сайта | Снизьте частоту; учитывайте заголовок Retry-After. См. Лимиты |
Частые вопросы
Получаю INVALID_SIGNATURE, хотя секрет верный
Получаю INVALID_SIGNATURE, хотя секрет верный
В 9 случаях из 10 причина — расхождение тела. Подписывайте и отправляйте одну и ту же
строку. Не сериализуйте JSON дважды, не позволяйте HTTP-клиенту повторно кодировать тело,
не добавляйте отступы. Сравните: сообщение для HMAC — это
X-Timestamp, затем точка, затем
байт-в-байт тело запроса.Получаю TIMESTAMP_SKEW
Получаю TIMESTAMP_SKEW
Время сервера расходится с временем платформы более чем на 300 секунд. Включите синхронизацию
по NTP. Также убедитесь, что отправляете Unix-время в секундах:
Math.floor(Date.now() / 1000)
в JS, int(time.time()) в Python.Как подписать GET-запрос?
Как подписать GET-запрос?
Тело пустое, поэтому
raw_body = "", а сообщение — "<timestamp>." (timestamp и точка).
Заголовки X-Api-Id, X-Timestamp, X-Signature всё равно обязательны.Нужно ли передавать X-Api-Key или X-Api-Secret?
Нужно ли передавать X-Api-Key или X-Api-Secret?
Нет. Достаточно
X-Api-Id плюс подпись. api_secret не передаётся по сети ни в каком виде —
он используется только локально для вычисления X-Signature.Заголовки регистрозависимы?
Заголовки регистрозависимы?
Имена HTTP-заголовков нечувствительны к регистру. А вот сама подпись — hex в нижнем
регистре, и сообщение для HMAC чувствительно к каждому байту тела.