Signing template
Canonical HMAC-SHA256 signing primitive in bash, Python, and Node. Define once, reuse on every endpoint.
Every authenticated endpoint signs the same way: HMAC-SHA256 over the exact request body bytes, keyed by your apiSecret. Define the primitive once and call it from every endpoint snippet.
The primitive
Define signBody(body, apiSecret) in your language of choice. The function takes the exact bytes you put on the wire and your apiSecret, and returns a lowercase hex digest for X-API-SIGN.
sign_body() {
# Args: $1 = body string (exact bytes to be sent), $2 = apiSecret
printf '%s' "$1" | openssl dgst -sha256 -hmac "$2" | sed 's/^.* //'
}Timestamped signing (recommended)
For a stronger signature, also send an X-API-TIMESTAMP header (Unix seconds, must be recent) and sign `${timestamp}\n${nonce}\n${body}` instead of the body alone. Same key, same endpoints, no new credentials. Body-only signing stays supported, so there is no deadline.
sign_v2() {
# Args: $1 = timestamp (unix seconds), $2 = nonce, $3 = body, $4 = apiSecret
printf '%s\n%s\n%s' "$1" "$2" "$3" | openssl dgst -sha256 -hmac "$4" | sed 's/^.* //'
}
# Usage:
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
SIGN=$(sign_v2 "$TS" "$NONCE" "$BODY" "$APISECRET")
# Send: -H "X-API-TIMESTAMP: $TS" -H "X-API-NONCE: $NONCE" -H "X-API-SIGN: $SIGN"Empty bodies
Two literals come up often, and they are not the same:
""is zero bytes. Used byGET /api/v1/codes(no body)."{}"is two bytes. Used byPOST /api/v1/currenciesandPOST /api/v1/pairswhen sending an explicit empty object.
Sign whichever literal you actually put on the wire. The two digests differ.
Common signing mistakes
- Re-serialising after signing. If your HTTP client pretty-prints, sorts keys, or normalises escapes before transmission, the body on the wire differs from the bytes you signed. Sign exactly what you POST.
- Using
echoin shell.echoappends a newline. Useprintf '%s'for the exact bytes. - Reusing nonces. Generate a fresh random
X-API-NONCE(16..64 chars) on every request, including retries. Reused nonces returncode: 3 AUTH_INVALID. - Mixing keys. Your
X-API-KEYand yourapiSecretare a pair, issued together. The header itself is not part of the HMAC input. Make sure the secret in your signing function matches the key you send.
Where this is used
Every endpoint snippet in this portal (bash, Python, Node) is written against this primitive. Once you adopt it, every authenticated call in your integration shares the same one-line callsite: signBody(body, apiSecret).
See the end-to-end example on the Authentication page, then jump to Quickstart for first signed call, first order, first webhook.