Авторизация
Подпись запросов к API — заголовок x-public-token, HMAC-SHA256 по параметрам, примеры на Node.js, Python, PHP, Go.
Для доступа к API каждый запрос должен быть подписан.
1. Какие параметры нужны
| Где | Поле | Тип | Обязательное | Описание |
|---|---|---|---|---|
| Header | x-public-token | string | да | Публичный токен магазина (идентификатор) |
| Query / Body | signature | string | да | HMAC-SHA256 подпись параметров запроса (hex) |
Где передаётся signature
- GET — в query string (например
...?message=OK&signature=...) - POST / PUT / PATCH / DELETE — в JSON body (полеsignature)
2. Откуда берётся секрет (private token)
private_token — это секретный ключ магазина (shared secret), который выдаётся вам при подключении. Подпись signature вычисляется на стороне мерчанта из параметров запроса и private_token.
Безопасность
Не передавайте private_token в запросах и не публикуйте его. Используйте его только для вычисления подписи на
своей стороне.
3. Что именно подписывается (нормализация payload)
Подпись считается по нормализованным параметрам вашего запроса.
3.1 Источник payload
- GET → параметры query string
- POST/PUT/PATCH/DELETE → JSON body
Запросы по URL с идентификатором транзакции
Для методов вида GET/DELETE/PATCH/POST /api/v1/payin/{transactionId} (и аналогов для payout) подпись считается по payload с тем же transactionId, что в URL.
- GET — в query передайте
transactionId(из URL) иsignature. Подпись от строкиtransactionId=<значение>. - DELETE / PATCH / POST — в body передайте
transactionId(из URL) иsignature. Подпись от{ "transactionId": "<значение из URL>" }.
Итог: подписывается один ключ transactionId с идентификатором из пути.
3.3 Очистка (strip)
Перед подписью удаляются:
- поле
signature - пустые строки
"" - строки из одних пробелов (после
trim())
Если значения нет — не включайте поле в запрос. Не отправляйте null.
3.4 Сортировка (sort)
Ключи сортируются по алфавиту (ASC).
3.5 Формирование строки для подписи
Из очищенного payload собирается строка:
k1=v1&k2=v2&...
Правила для значений:
- строки подписываются как есть (пробелы в начале/конце участвуют в подписи; удаляются только полностью пустые/пробельные строки)
- объект/массив → JSON-строка без форматирования (аналог
JSON.stringify(value)) - иначе → строковое представление (аналог
String(value))
Подробнее: порядок ключей и кодирование
Ключи в строке для подписи идут в алфавитном порядке (ASC). Значения не URL-кодируются — в message попадают «как есть» после приведения к строке. Сравнение подписи на сервере — по криптостойкому сравнению hex-строк (timing-safe).
4. Алгоритм подписи
signature = HMAC_SHA256_HEX(message, private_token)
где message — строка из пункта 3.5.
5. Ошибки авторизации (HTTP 401)
Ответ 401
При любой из перечисленных ниже причин сервер вернёт HTTP 401 и поле message в теле ответа.
message | Когда |
|---|---|
ERROR_PUBLIC_TOKEN_REQUIRED | Нет x-public-token |
ERROR_SIGNATURE_REQUIRED | Нет signature в payload |
ERROR_PUBLIC_TOKEN_INVALID | x-public-token не найден или запись невалидна |
ERROR_SIGNATURE_INVALID | Подпись не совпала |
6. Примеры payload (что подписывать)
В зависимости от метода запроса payload для подписи выглядит так:
| Сценарий | GET (query) | POST/PATCH/DELETE (body) | Строка для подписи (пример) |
|---|---|---|---|
| Произвольный запрос (например баланс, создание платежа) | Параметры запроса + signature | Поля тела (amount, gate, clientId и т.д.) + signature | amount=100&clientId=1&gate=... или message=OK |
Запрос по transactionId (GET/DELETE/PATCH/POST по /api/v1/payin/{transactionId}) | transactionId (тот же, что в URL) + signature | transactionId (тот же, что в URL) + signature | transactionId=5e8b0d5b-6c56-4f4f-9c70-6b8a1a1b2c3d |
Примеры payload в виде объекта (перед подписью поле signature исключается):
- Произвольный:
{ "message": "OK" }или{ "amount": 100, "clientId": 1, "gate": "default" }— подпись от оставшихся после очистки полей. - Только transactionId:
{ "transactionId": "5e8b0d5b-6c56-4f4f-9c70-6b8a1a1b2c3d" }— подпись от одной парыtransactionId=<uuid>.
7. Пример генерации подписи (Node.js)
import crypto from "node:crypto"
const stripAndSortPayload = (obj) => {
const out = {}
const keys = Object.keys(obj).sort((a, b) => a.localeCompare(b))
for (const k of keys) {
const v = obj[k]
if (k === "signature") continue
if (v === undefined || v === "" || (typeof v === "string" && v.trim() === "")) continue
out[k] = v
}
return out
}
const stringifyPayloadValue = (v) => (typeof v === "object" && v != null ? JSON.stringify(v) : String(v))
const buildSignature = (payload, secret) => {
const keys = Object.keys(payload).sort((a, b) => a.localeCompare(b))
const parts = []
for (const k of keys) {
const v = payload[k]
if (v === undefined || v === "") continue
parts.push(`${k}=${stringifyPayloadValue(v)}`)
}
const message = parts.join("&")
return crypto.createHmac("sha256", secret).update(message).digest("hex")
}
const privateToken = "<PRIVATE_TOKEN>"
const basePayload = { message: "OK", signature: "will-be-removed" }
const payload = stripAndSortPayload(basePayload)
const signature = buildSignature(payload, privateToken)
console.log("Произвольный payload:", signature)
const transactionId = "5e8b0d5b-6c56-4f4f-9c70-6b8a1a1b2c3d"
const txPayload = stripAndSortPayload({ transactionId, signature: "" })
const txSignature = buildSignature(txPayload, privateToken)
console.log("По transactionId:", txSignature)Примеры на Python, PHP, Go — аналогичная логика: нормализация payload, сборка строки, HMAC-SHA256 hex. См. спецификацию выше.