In this article we will dive into details on how to authenticate on our API. For this example we will use Python.

For more information see our full API documentation and our sample codes on GitHub.


The first things you need to connect to our API is your API key and your secret key, they will respectively be referred as api and secret in the rest of the article. You can create your pair of keys here

Your request needs to contain the following headers:

  1. FTX-KEY: Which is your API key.

  2. FTX-TS: Which is the number of milliseconds since Unix epoch.

  3. FTX-SIGN: Which is the SHA256 HMAC of the following four strings, using your API secret, as a hex string: Request timestamp (same as above), HTTP method in uppercase (e.g. GET or POST), Request path, including leading slash and any URL parameters but not including the hostname (e.g. /account), Request body (JSON-encoded) only for POST requests

  4. FTX-SUBACCOUNT (optional): URI-encoded name of the subaccount to use. Omit if not using subaccounts.

This is what the general code would look like:

import time
import hmac
from requests import Request

ts = int(time.time() * 1000)
request = Request('GET', '<api_endpoint>')
prepared = request.prepare()
signature_payload = f'{ts}{prepared.method}{prepared.path_url}'
if prepared.body:
    signature_payload += prepared.body
signature_payload = signature_payload.encode()
signature ='YOUR_API_SECRET'.encode(), signature_payload, 'sha256').hexdigest()

request.headers['FTX-KEY'] = 'YOUR_API_KEY'
request.headers['FTX-SIGN'] = signature
request.headers['FTX-TS'] = str(ts)

# Only include this line if you want to access a subaccount. Remember to URI-encode the subaccount name if it contains special characters!
# request.headers['FTX-SUBACCOUNT'] = urllib.parse.quote('my_subaccount_name')

Get signature example

Let’s dive into more details of what GET /markets request would look like, for the sake of this example we will use the following API keys:

api = "LR0RQT6bKjrUNh38eCw9jYC89VDAbRkCogAc_XAm"
secret = "T4lPid48QtjNxjLUFOcUZghD7CUJ7sTVsfuvQZF2"

We will also use the following timestamp:

ts = 1588591511721
signature_payload = b'1588591511721GET/api/markets'
signature = "dbc62ec300b2624c580611858d94f2332ac636bb86eccfa1167a7777c496ee6f"

POST signature example

In this example we will look at what the POST /orders would look like using the same API keys. Let’s say we want to place a limit buy order of 1BTC on BTC-PERP at $8500

ts = 1588591856950
signature_payload = b'1588591856950POST/api/orders{"market": "BTC-PERP", "side": "buy", "price": 8500, "size": 1, "type": "limit", "reduceOnly": false, "ioc": false, "postOnly": false, "clientId": null}'
signature = "c4fbabaf178658a59d7bbf57678d44c369382f3da29138f04cd46d3d582ba4ba"

Please note that the order of the arguments in the embedded post body in the signature matters: it should match the order of the post body.

Not logged in error

If you ever encounter a Not logged in error it means that authentication failed. In this case make sure that your code is correct by referring to the above example and also check your timestamp against our server’s timestamp using this endpoint

Sam Bankman-Fried