HMAC signature generator: debug exchange API signing
Build the exact string an exchange signs, see it byte by byte, get the HMAC in hex and Base64 and compare it with yours. Never paste a live secret into any website, this one included: the tool loads a published sample key. Free, no sign-up required.
Do not paste a live secret here
Do not paste a live API secret into this page or any other website. A secret in a web page is within reach of that page's scripts, your browser extensions and anything recording your screen, and you cannot check those afterward. Use the published sample that loads with the page, a testnet key, or a throwaway key you delete when you finish. If a live secret has already gone into a website, replace the key on the exchange.
- Nothing is sent. The HMAC is computed in your browser with the Web Crypto API (
SubtleCrypto.sign, which browsers offer only on HTTPS pages). The tool makes no network call. - Nothing you type is stored. It goes into no cookie, no
localStorageand no URL parameter. Autocomplete is off on every field, and the values are gone when you close the page.
How to confirm it in the Network tab: open your browser's developer tools (F12, or Cmd+Option+I on a Mac), choose Network, clear the list, then type in the fields and change the preset. No request appears. The requests you see while the page loads are its own files and the Cloudflare Web Analytics beacon described in the privacy notice, which carries page and performance data, not form values; it can report once more when you switch away from the page or close it. You can also read the connect-src part of the page's Content-Security-Policy response header: it allows connections only to this site and to Cloudflare Insights.
How each exchange builds the string it signs
Each exchange signs a different string, and the tool builds the one you pick so you can see every byte.
| Preset | String signed | Secret used as | Hash | Sent as |
|---|---|---|---|---|
| Binance spot REST | query string + body, no separator, non-ASCII characters percent-encoded first | Text | SHA-256 | Hex, signature |
| BtcTurk | public key + nonce | Base64-decoded | SHA-256 | Base64, X-Signature |
| Bybit V5 | timestamp + API key + recv_window + query string or JSON body | Text | SHA-256 | Lowercase hex, X-BAPI-SIGN |
| Kraken spot REST | URI path + SHA-256 of (nonce + POST data) | Base64-decoded | SHA-512 | Base64, API-Sign |
| OKX v5 | timestamp + method + request path + body | Text | SHA-256 | Base64, OK-ACCESS-SIGN |
How far each preset could be tested on 5 November 2026:
- Published key and signature, reproduced: Binance (both samples in
rest-api.md), Kraken (its authentication guide) and the plain HMAC mode (RFC 4231). - Published string reproduced, signature not testable: Bybit prints the string to sign and an example signature but not the secret behind it. The preset rebuilds that string byte for byte and uses the placeholder key from Bybit's demo script, so its result differs from the printed example.
- Recipe only: OKX prints an example secret, timestamp and path, which the preset loads, but no signature made with them. BtcTurk prints code samples with no test values, so its preset uses a made-up key.
Every preset also agrees with a separate Python implementation on random inputs. Coinbase App API keys have no preset: they sign a JWT, not an HMAC. Exchange names here describe their documents only: no affiliation, no referral link, no recommendation, and no statement that Fincode has integrated any of them. For readers in Turkey, Article 99/A of Capital Markets Law No. 6362 treats activity by foreign crypto-asset platforms directed at Turkish residents as unauthorized.
Worked example: Binance's published sample
Published sample, not a live key: these are the values the tool loads, from Binance's rest-api.md. Secret: NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j.
String signed, 110 bytes: symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559
HMAC-SHA-256 in hex, the form Binance takes: c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71. The same bytes in Base64: yNtWglrnHW15RHhJ5hcRX0qSD6Ks3KsrBTxLKDi9a3E=. Pasted as the signature to compare, Binance's printed value gives Match.
The timestamp in the string is 2017-07-12 02:41:59.559 UTC. With a hypothetical server time of 1499827320000, it is 441 ms behind, inside the 5,000 ms window.
Now change one byte. With price=0.10 in place of price=0.1, the HMAC becomes 7f124c213f122930e71386ade5952185fcd4cee18ce97ebc3af221748c75cf81, different from the first character on. Paste that string as the one your code signed, and the tool names the cause: first difference at byte 71, yours is 0x30 (0), this one 0x26 (&).
Why a signature does not match
A different HMAC means a different input, so look at the inputs and not at the signature.
- Stray bytes in the secret: a space or line break copied with the key. The tool warns about this.
- Secret format: Kraken and BtcTurk sign with the Base64-decoded secret; the other presets use the text as it is.
- What you sign is not what you send: reordered parameters, values encoded again by an HTTP library, or JSON serialized twice with different spacing.
- Output format: hex and Base64 of one HMAC look unrelated, so the compare row names that case.
- A line break from the shell:
echowithout-nadds one byte to the message. - Time: a correct signature is still refused when the timestamp falls outside the exchange's window. Type a server time you fetched yourself to see where it falls; this page requests nothing.
What each refusal looks like is in Binance API error codes, and how to keep keys safe is in API key security for trading bots. The whole request is walked through in API signature generation. If you would rather have this part built and tested, see exchange API integration.
The same calculation in Python
This short script gives the same results with the standard library, so you can compare the tool with your own environment.
import base64, hashlib, hmac
secret = "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"
payload = "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559"
mac = hmac.new(secret.encode(), payload.encode(), hashlib.sha256)
print(mac.hexdigest()) # hex: Binance, Bybit
print(base64.b64encode(mac.digest()).decode()) # Base64: BtcTurk, OKX
# Kraken: SHA-256 inside, HMAC-SHA512 outside, secret decoded from Base64
def kraken_sign(secret_b64, path, nonce, post_data):
message = path.encode() + hashlib.sha256((nonce + post_data).encode()).digest()
mac = hmac.new(base64.b64decode(secret_b64), message, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()
Run on Python 3.11 on 5 November 2026, the two print lines show the hex and Base64 values above, and kraken_sign with Kraken's published values returns its printed API-Sign.
Which values to enter
- Exchange preset: picking one loads its sample and shows only the fields that exchange signs. The plain HMAC mode takes any message, with the secret as text, hex or Base64.
- Secret: a sample, testnet or throwaway key only.
- Signature to compare: what your code produced, in hex or Base64.
- String your code signed: log it just before signing and paste it here, the most useful field when the signatures differ.
- Server time: in milliseconds, from the exchange's time endpoint. The tool applies that exchange's documented window. Kraken uses an increasing nonce and BtcTurk's page states no window, so the field hides for them.
Frequently asked questions
Is it safe to paste my API secret into an online HMAC generator?
No, not a live one, on any website, this one included. Use a published sample, a testnet key or a throwaway key, and replace any live key that has been pasted into a web page.
How can I check that this tool sends nothing?
Open your browser's developer tools, choose the Network tab, clear the list and type in the fields. No request appears. The page's Content-Security-Policy header also limits connections to this site and Cloudflare Insights.
Can an HMAC be decoded or decrypted?
No. An HMAC is a one-way keyed digest, not encryption, so neither the key nor the message can be read back from it. RFC 2104 and NIST FIPS 198-1 define it as two nested hash runs with the key mixed in. You check one the way the exchange does: compute it again from the same key and message, then compare. A page that offers to decode an HMAC can only try guesses against it.
Should an HMAC signature be hex or Base64?
The API decides. As read on 5 November 2026, Binance and Bybit take hex, and BtcTurk, Kraken and OKX take Base64. The tool prints both, and they are the same bytes.
What is the difference between HMAC-SHA256 and HMAC-SHA512?
The hash inside. SHA-256 gives a 32-byte result and SHA-512 a 64-byte result, and an API accepts only the one its documents name. Kraken's spot REST uses HMAC-SHA512 over a message that already contains a SHA-256 digest.
Why is my signature different in every character?
An HMAC changes completely when one input byte changes, so the first differing character only helps with a cut or re-encoded copy. To find the cause, paste the string your code signed, and the tool names the first byte that differs.
Sources
- Binance Spot API documentation: REST API, request security and signed examples (read 5 November 2026) (opens in a new tab)
- Binance Spot API changelog, entry of 17 December 2025: payloads not percent-encoded before signing are rejected with -1022 (read 6 November 2026) (opens in a new tab)
- BtcTurk API documentation: Authentication V1 (read 5 November 2026) (opens in a new tab)
- Bybit V5: Integration guidance, authentication (read 5 November 2026) (opens in a new tab)
- Bybit API usage examples: HMAC demo script (opens in a new tab)
- Kraken: Spot REST authentication (read 5 November 2026) (opens in a new tab)
- OKX API v5: REST authentication (read 5 November 2026) (opens in a new tab)
- Coinbase App API key authentication (JWT, read 5 November 2026) (opens in a new tab)
- RFC 2104: HMAC, keyed-hashing for message authentication (opens in a new tab)
- RFC 4231: Test vectors for HMAC-SHA-224, 256, 384 and 512 (opens in a new tab)
- NIST FIPS 198-1: The Keyed-Hash Message Authentication Code (opens in a new tab)
- MDN: SubtleCrypto.sign(), HMAC, secure contexts only (opens in a new tab)
- Capital Markets Law No. 6362, consolidated text, Article 99/A (Turkish) (opens in a new tab)
This calculator is general information, not tax, legal or investment advice. Results depend on the values you enter; fees, margin rules and tax rules differ by exchange and country and change over time, so check the official source and ask a licensed adviser about your own situation. Sources, checks and corrections: see the editorial policy.
Related guides
Send a short project brief
The form or an email is enough. You do not need to share your rules yet.
- The exchange or platform you use
- What the software should do
- Your target timeline
- Project briefs and business inquiriesinfo@fincodelabs.com
- WhatsApp (messages only)+90 545 697 41 15 (opens in a new tab)