Signature
Requests to Mercuryo and callbacks from Mercuryo are signed with the same algorithm:
- Take your Sign Key from the Mercuryo Dashboard under Widgets → select your widget. Use the Sign Key of the widget associated with your
Sdk-Partner-Token, and make sure the key is stored securely on your backend and never exposed on the frontend. - Take the JSON body string:
- request — the body serialized to compact JSON: no whitespace,
/and non-ASCII characters not escaped; - callback — the raw body exactly as received.
- request — the body serialized to compact JSON: no whitespace,
- Compute HMAC-SHA256 of this string with the Sign Key and hex-encode the result.
- Use the signature:
- request — send it in the
X-Signatureheader, and send exactly the same string as the body; - callback — compare it with the
X-Signatureheader and reject the callback if they differ.
- request — send it in the
Code Examples
JavaScript
const crypto = require('crypto');
const sign = (body, signKey) => crypto.createHmac('sha256', signKey).update(body, 'utf8').digest('hex');
// Request: send `body` as the request body and `sign(body, SIGN_KEY)` in X-Signature
const body = JSON.stringify(payload);
// Callback: compare with the X-Signature header
const isValid = sign(rawBody, SIGN_KEY) === signatureHeader;
Python
import hashlib
import hmac
import json
def sign(body: str, sign_key: str) -> str:
return hmac.new(sign_key.encode(), body.encode('utf-8'), hashlib.sha256).hexdigest()
# Request: send body.encode('utf-8') as the request body and sign(body, SIGN_KEY) in X-Signature
body = json.dumps(payload, separators=(',', ':'), ensure_ascii=False)
# Callback: compare with the X-Signature header
is_valid = hmac.compare_digest(sign(raw_body, SIGN_KEY), signature_header)
Go
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
)
func sign(body []byte, signKey string) string {
h := hmac.New(sha256.New, []byte(signKey))
h.Write(body)
return hex.EncodeToString(h.Sum(nil))
}
// Request: compact JSON without escaping, send body and sign(body, signKey) in X-Signature
func requestBody(payload any) ([]byte, error) {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
if err := enc.Encode(payload); err != nil {
return nil, err
}
return bytes.TrimRight(buf.Bytes(), "\n"), nil
}
// Callback: hmac.Equal([]byte(sign(rawBody, signKey)), []byte(signatureHeader))
PHP
$sign = fn(string $body, string $signKey): string => hash_hmac('sha256', $body, $signKey);
// Request: send $body as the request body and $sign($body, $signKey) in X-Signature
$body = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
// Callback: compare with the X-Signature header
$isValid = hash_equals($sign($rawBody, $signKey), $signatureHeader);
Try It: Signature Calculator
Paste a JSON body and your Sign Key to check your implementation:
- Request — paste the exact compact JSON string you send as the request body, and compare the result with the
X-Signatureyou send. - Callback — paste the raw callback body exactly as received, and compare the result with the
X-Signatureheader of the callback.
Note: The hash is computed locally using your browser.