AllXBTUSD2322.1+10.47%XBTM172417.4+11.03%ETHM170.07893+5.68%XBJM17299000+7.67%XRPM170.00013992+1.86%LTCM170.01422+13.22%XMRM170.023601+21.30%ETC7D0.005200+24.16%ZECM170.112000+16.65%DASHM170.071574+15.45%GNOM170.098414+4.70%REP7D0.013250+47.22%FCTM170.006555+11.38%XBCM1715500.0+0.03%B_SEGWITZ1740.00-20.00%B_BLOCKSZ1740.00+0.00%.BXBT2308.19+9.85%.XBTCNY15639.87+5.97%.XBTJPY296589.99+7.79%.ETHXBT0.07400+1.65%.ZECXBT0.1126980+17.69%.BVOL24H4.35-37.23%Funding: @ -0.0249%Time:
API Keys Usage

Below we outline the technical and usage details of an API Key.

If you are logged in, please follow this link to manage your active keys.

API Key Permissions

By default, API Keys can only read basic user data, such as positions, margin, orders, and executions. They cannot submit orders or withdraw.

If you wish to execute orders with your API Key, you must add the "order" permission upon creation.

Withdrawals are also possible with the "withdraw" permission. Withdrawals done via API Key are not confirmed via email. Use this permission with caution.

API Keys cannot be used to create other API Keys or modify user authentication.

Authenticating with an API Key

Authentication is done by sending the following HTTP headers:

api-nonce: A constantly increasing 53-bit integer. Each nonce can only be used once. Commonly, API consumers will start with 1 and increment per request, or use something simpler that is constantly increasing, like the current microsecond time.

Note: Because of limitations in the JavaScript Number type, the effective upper bound of the nonce is 253, not 264. Please keep this in mind when choosing a nonce scheme. Generally, we use consumers using microseconds or Ticks (100 nanoseconds) after January 1, 2015, which will continue to work for at least 25 years.

api-key: Your public API key. This the id param returned when you create an API Key via the API.

api-signature: A signature of the request you are making. It is calculated as hex(HMAC_SHA256(apiSecret, verb + path + nonce + data)). See the example calculations below.

Our reference market maker bot features a working implementation of our API key authentication.

The ‘data’ param

The data part of the HMAC construction should be exactly equal to the raw body you send to the server. You can send JSON or form encoding, just ensure you use the exact same body string in the HMAC. Generally you will want to prepare the request in your language of choice, then use the same raw body string for the HMAC construction as in the request body.

Handling colliding nonces

When multiple processes are using the same API key, requests may be received out of order and the nonce will not look like it’s increasing from the server-side. In that case, you may send the header api-expires set to a UNIX timestamp in the future. The call, if replayed, will not be accepted if the current time is past the value in api-expires.

This could potentially open you up to replay attacks for a short time if HTTPS were somehow broken, so choose a very small time in the future. We recommend less than a minute.

If using api-expires, substitute the expires value for nonce in the HMAC construction above. The api-nonce value becomes optional and may be omitted. It will be ignored if provided.

Full sample calculation

Use these calculations as test cases in your code.

apiKey = 'LAqUlngMIQkIUjXMUreyu3qn'
apiSecret = 'chNOOS4KvNXR_Xq4k4c9qsfoKWvnDecLATCRlcBwyKDYnWgO'

# Simple GET with querystring
verb = 'GET'
# Note url-encoding on querystring - this is '/api/v1/instrument?filter={"symbol": "XBTM15"}'
path = '/api/v1/instrument?filter=%7B%22symbol%22%3A+%22XBTM15%22%7D'
nonce = 1429631577690
data = ''

# HEX(HMAC_SHA256(apiSecret, 'GET/api/v1/instrument?filter=%7B%22symbol%22%3A+%22XBTM15%22%7D1429631577690'))
# Result is:
# '9f1753e2db64711e39d111bc2ecace3dc9e7f026e6f65b65c4f53d3d14a60e5f'
signature = HEX(HMAC_SHA256(apiSecret, verb + path + str(nonce) + data))

verb = 'POST'
path = '/api/v1/order'
nonce = 1429631577995
data = '{"symbol":"XBTM15","price":219.0,"clOrdID":"mm_bitmex_1a/oemUeQ4CAJZgP3fjHsA","orderQty":98}'

# HEX(HMAC_SHA256(apiSecret, 'POST/api/v1/order1429631577995{"symbol":"XBTM15","price":219.0,"clOrdID":"mm_bitmex_1a/oemUeQ4CAJZgP3fjHsA","orderQty":98}'))
# Result is:
# '93912e048daa5387759505a76c28d6e92c6a0d782504fc9980f4fb8adfc13e25'
signature = HEX(HMAC_SHA256(apiSecret, verb + path + str(nonce) + data))


If you are receiving "Signature Not Valid" messages, check the following:

  • Check that your signatures match the sample signatures above.
  • If there is a request body, make sure your Content-Length and Content-Type are valid.
  • Ensure your request body is being properly sent. Try a few sample requests against httpbin.
  • Ensure you are signing the exact string that is being sent to the server. Certain JSON serializers have unstable key ordering, so serialize to a string first, sign that string, and then send the same string in the request body.

Sample Code

We have created several example connectors that implement the above authentication:

A Python snippet:

def bitmex_signature(apiSecret, verb, url, nonce, postdict):

    # Generate data string. Blank if not present.
    data = ''
    if postdict:
        data = json.dumps(postdict)

    # Generate path. Path is the relative url including querystring, such as /api/v1/instrument?symbol=XBTUSD
    # We run it through urlparse here to strip out the absolute parts (
    parsedURL = urlparse.urlparse(url)
    path = parsedURL.path
    if parsedURL.query:
        # This is url-encoded
        path = path + '?' + parsedURL.query

    # The message to sign is the concatenation of the verb, path, nonce, and data.
    message = bytes(verb + path + str(nonce) + data).encode('utf-8')

    signature =, message, digestmod=hashlib.sha256).hexdigest()
    return signature