Authentication of requests is done by sending the following HTTP headers:
RBT-SIGNATURE: Signature of the request generated with your secret key. It is calculated as hex(HMAC_SHA256(secret, payload)). Example given below.
RBT-API-KEY: Your API key.
RBT-TS: A UNIX (in seconds) timestamp after which the request is no longer valid. This is to prevent replay attacks. Only accepts integers.
EID: "bfx"
Note: UNIX timestamps are in seconds. For example, 2018-02-08T04:30:37Z is 1518064237.
Example: Generating RBT-SIGNATURE
PAYLOAD_KEY_METHOD ='method'PAYLOAD_KEY_PATH ='path'REQUIRED_KEYS = [PAYLOAD_KEY_METHOD, PAYLOAD_KEY_PATH]api_key ='<YOUR API KEY>'api_secret ='<YOUR API SECRET>'defhex2bytes(value:str) ->bytes:if value.startswith('0x'): value = value[2:]returnbytes.fromhex(value)classPayload: timestamp:int data: dict[str,str]def__init__(self,timestamp:int,data: dict[str,str]): self.timestamp = timestamp self.data = datafor k in REQUIRED_KEYS:if k in data:continueraiseKeyError@propertydefhash(self) ->bytes:''' Returns the hash of the payload where the params are sorted in alphabetical order. ''' keys =list(self.data.keys()) keys.sort() message = [f'{k}={str(self.data[k]).lower()}' if type(self.data[k]) == bool else f'{k}={self.data[k]}' for k in keys]
message.append(str(self.timestamp)) message =''.join(message) h = hashlib.sha256() h.update(message.encode())return h.digest()defsign(self,secret:str) ->str:''' Returns HMAC-SHA256 signature after signing payload hash with user secret. ''' secret_bytes =hex2bytes(secret)return'0x'+ hmac.new(secret_bytes, self.hash, hashlib.sha256).hexdigest()defverify(self,signature:str,secret:str) ->bool: expected_signature = self.sign(secret)if expected_signature != signature:returnFalse current_timestamp =int(datetime.now().timestamp())if current_timestamp >= self.timestamp:returnFalsereturnTrue
If you would like to onboard with your wallet private key and generate a set of API key and secrets programmatically instead of from the frontend, you can retrieve your account API key and secret by calling the onboarding endpoint and signing a message with your wallet private key. However, note that this method is generally not recommended. Github example here.
Your wallet private key is used to onboard and retrieve a set of API key and secrets.
First call the /onboarding endpoint such as in the example below. Save the response API key and secret to be used for signing private endpoint requests.
expires must be less than or equal to 600 seconds.
from eth_account.messages import encode_defunctfrom hexbytes import HexBytesfrom web3.auto import w3from datetime import datetimeimport requestsonboarding_message = 'Welcome to Bfx!\n\nClick to sign in and on-board your wallet for trading perpetuals.\n\nThis request will not trigger a blockchain transaction or cost any gas fees. This signature only proves you are the true owner of this wallet.\n\nBy signing this message you agree to the terms and conditions of the exchange.'
url ='https://api.bfx.trade'private_key ='<YOUR WALLET PRIVATE KEY>'wallet ='<YOUR WALLET ADDRESS>'expires =600session = requests.Session()def_expiration_timestamp():returnint(datetime.now().timestamp() + expires)def_header() ->dict: expiration_timestamp =_expiration_timestamp()return{'RBT-TS':str(expiration_timestamp),'EID':'bfx'}defhex2bytes(value:str) ->bytes:if value.startswith('0x'): value = value[2:]returnbytes.fromhex(value)defmetamask_sign(message,timestamp:int,private_key:str): private_key =hex2bytes(private_key) metamask_message =f'{message}\n{timestamp}' message =encode_defunct(metamask_message.encode()) signed_message = w3.eth.account.sign_message(message, private_key=private_key)return signed_message.signature.hex()def_prepare_signature(private_key) ->str: expiration_timestamp =_expiration_timestamp() signature =metamask_sign(onboarding_message, expiration_timestamp, private_key) signature =bytearray(hex2bytes(signature)) signature[-1]= signature[-1]%27return'0x'+ signature.hex()defonboard(private_key:str) ->dict: signature =_prepare_signature(private_key) data =dict(wallet=wallet, signature=signature, isClient=False) resp = session.post(f'{url}/onboarding', json=data, headers=_header()).json()return respif__name__=='__main__': onboarding_resp =onboard(private_key) api_secret = onboarding_resp['result'][0]['apiSecret']['Secret']
Note: onboarding message
Welcome to Bfx!\n\nClick to sign in and on-board your wallet for trading perpetuals.\n\nThis request will not trigger a blockchain transaction or cost any gas fees. This signature only proves you are the true owner of this wallet.\n\nBy signing this message you agree to the terms and conditions of the exchange.