SigmaPay

Авторизация

Подпись запросов к API — заголовок x-public-token, HMAC-SHA256 по параметрам, примеры на Node.js, Python, PHP, Go.

Для доступа к API каждый запрос должен быть подписан.

1. Какие параметры нужны

ГдеПолеТипОбязательноеОписание
Headerx-public-tokenstringдаПубличный токен магазина (идентификатор)
Query / Bodysignaturestringда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_INVALIDx-public-token не найден или запись невалидна
ERROR_SIGNATURE_INVALIDПодпись не совпала

6. Примеры payload (что подписывать)

В зависимости от метода запроса payload для подписи выглядит так:

СценарийGET (query)POST/PATCH/DELETE (body)Строка для подписи (пример)
Произвольный запрос (например баланс, создание платежа)Параметры запроса + signatureПоля тела (amount, gate, clientId и т.д.) + signatureamount=100&clientId=1&gate=... или message=OK
Запрос по transactionId (GET/DELETE/PATCH/POST по /api/v1/payin/{transactionId})transactionId (тот же, что в URL) + signaturetransactionId (тот же, что в URL) + signaturetransactionId=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. См. спецификацию выше.

On this page