Request signature
The signature proves request authenticity. Two algorithm versions are supported: 3 (login-based) and 4 (bound to the request body).
Common steps
JSON API v3
Inner hash
innerHash = lowercase(hmac_sha256(password, timestamp))password— merchant secret key, stored in the project settings on the platform side.login— theX-Loginheader value.timestamp— theX-Timestampheader value.
password is a secret. It is never sent in the request, never logged and must not end up in client code: compute the signature only on the merchant server.
Version 3 — login-based
signature = lowercase(hmac_sha256(password, login + innerHash))Example
password = "password"
login = "login"
timestamp = "2025-02-10T17:56:37Z"
innerHash = lowercase(hmac_sha256("password", "2025-02-10T17:56:37Z"))
signature = lowercase(hmac_sha256("password", "login" + innerHash))
→ "5f9e4f4a7a805b898cac96a6c3e7a81dd0e06e200c291d51663e6f250b10853f"Signature v3 implementation
Sandbox
curl
LOGIN=demo_login
PASSWORD=demo_password
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
INNER=$(printf '%s' "$TS" \
| openssl dgst -sha256 -hmac "$PASSWORD" | awk '{print $NF}')
SIG=$(printf '%s%s' "$LOGIN" "$INNER" \
| openssl dgst -sha256 -hmac "$PASSWORD" | awk '{print $NF}')For version 4, requestPayload is added to the message — same function, but requestPayload + login + innerHash is signed.
Version 4 — bound to the request body
signature = lowercase(hmac_sha256(password, requestPayload + login + innerHash))requestPayload is a deterministic concatenation of the significant request fields without separators:
| Method and path | Payload |
|---|---|
POST /invoices | {order.merchant_order_id}{customerPayload}{order.price.amount}{order.price.currency}{contract.merchant_contract_id}{client_ip} |
POST /invoices/{id}/authorize | {invoice_id}{pin_code}{client_ip} |
POST /invoices/{id}/cancel | {invoice_id}{client_ip} |
POST /invoices/{id}/refund | {invoice_id}{client_ip} |
GET /invoices/{id} | {invoice_id} |
GET /invoices?merchant_order_id=... | {merchant_order_id} |
POST /contracts | {merchant_contract_id}{customerPayload}{pin_code}{client_ip} |
POST /contracts/{id}/authorize | {contract_id}{merchant_contract_id}{pin_code}{client_ip} |
POST /contracts/{id}/cancel | {contract_id}{merchant_contract_id}{client_ip} |
POST /billing/check | {customerPayload} |
customerPayload depends on customer.:
| Type | Payload |
|---|---|
mobile_phone | {msisdn} |
undefined_bank_card, bank_card | {source}{country}{merchant_customer_id}{email} |
| (other / none) | (empty string) |
Any missing field is substituted as an empty string. The invoice or contract ID is taken from the URL path.