FAQ: Signature for this request is not valid.

For new users to API, one of the most common questions is how to work out the signature.

It’s hard to replicate this on our end to help out because it requires using an API key/secret key combination.

There are some of the reasons why the signature is invalid:

  • The secret key is not set
  • The secret key is not matching to API key
  • The parameter sending to server has no value.
    • /api/v3/order?orderId=&timestamp=xxxxx&signature=xxxx can give this error
  • The signature is signed by different Hash algo, it has to be SHA256

This repository https://github.com/binance-exchange/binance-signature-examples has the hashing method in many languages.

Q: How do I debug to find the issue?
A: Some users are working with API endpoint by SDK/library, and it adds extra complexity for this issue. Please make sure you can print out the raw HTTP request URL or the post body sending to the API server. That could be different from what you thought.

GET /fapi/v1/income?symbol=BTCUSDT&timestamp=1589747537229&signature=57cf6e89721e8fa12b11bd  HTTP/1.1
Content-Type: application/json
X-MBX-APIKEY: xxxxxxxxxxxxxxxxx
User-Agent: PostmanRuntime/7.24.1
Accept: */*
Cache-Control: no-cache
Postman-Token: xxxxxxxxxxxxxxx
Host: testnet.binancefuture.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive


HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Date: Tue, 18 May 2020 00:19:00 GMT
Server: Bengine
Vary: Accept-Encoding
X-MBX-USED-WEIGHT-1M: 4
x-response-time: 2928ms
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: *
Content-Encoding: gzip
X-Cache: Miss from cloudfront
Via: 1.1 xxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: xxxxxx
X-Amz-Cf-Id: xxxxxxxxxxxxxxxxxxxxx==

While you can have this request text with headers, it’s can be easier to check:

  • If the X-MBX-APIKEY is set correctly
  • If the parameters are correct.
  • If the signature is appended.

Q: How can I be sure that the signature is valid?

A: The API documentation has the details about how to sign the parameters for reference.
https://binance-docs.github.io/apidocs/spot/en/#signed-trade-user_data-and-margin-endpoint-security

It’s recommend to start with a simple endpoint, my favourite is getting the account information.

# https://binance-docs.github.io/apidocs/spot/en/#account-information-user_data
GET /api/v3/account

As it only requires timestamp, we only need to work out the SHA256 value of the string:

# timestamp should be 13 number of  UTC  time in milliseconds
# it's a mock timestamp for validation, you should use current time in production.
timestamp=1589747537229

with secret
NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j

the signature should be
d84e6641b1e328e7b418fff030caed655c266299c9355e36ce801ed14631eed4

Sample Code

Here are the code snippet that hash the query string in different languages. Please be advised that:

  • timestamp should be your current time in production
  • The secret key used here is for sample purposes. Should you decide to use this code then please replace with your own secret key.

In Javascript:

const crypto = require('crypto');

const query_string = 'timestamp=1578963600000';
const apiSecret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j';

const signature = crypto
.createHmac('sha256', apiSecret)
.update(query_string)
.digest('hex')

In Ruby

require 'openssl'

query_string = 'timestamp=1578963600000'
secret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j'

signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, query_string)

In Python

import hmac
import hashlib

query_string = 'timestamp=1578963600000'
secret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j'

signature = hmac.new(secret.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256).hexdigest()

In PHP

$query_string = 'timestamp=1578963600000';
$secret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j';

$signature = hash_hmac('sha256', $query_string, $secret);

They are collected in this repo: