How to sign an OKEx POST API request?

Viewed 514

The below is a result of this question How to sign an OKEx API request? and some of the answers:

import hmac
import base64
import requests
import datetime
import json

from config import KEY, SECRET, PASS, ROOT_URL


def get_time():
    now = datetime.datetime.utcnow()
    t = now.isoformat("T", "milliseconds")
    return t + "Z"


def signature(timestamp, request_type, endpoint, body, secret):
    if body != '':
        body = json.dumps(body)
    message = str(timestamp) + str.upper(request_type) + endpoint + body
    print(message)
    mac = hmac.new(bytes(secret, encoding='utf-8'), bytes(message, encoding='utf-8'), digestmod='sha256')
    d = mac.digest()
    return base64.b64encode(d)


def get_header(request_type, endpoint, body):
    time = get_time()
    header = dict()
    header['CONTENT-TYPE'] = 'application/json'
    header['OK-ACCESS-KEY'] = KEY
    header['OK-ACCESS-SIGN'] = signature(time, request_type, endpoint, body, SECRET)
    header['OK-ACCESS-TIMESTAMP'] = str(time)
    header['OK-ACCESS-PASSPHRASE'] = PASS
    return header


def get(endpoint, body=''):
    url = ROOT_URL + endpoint
    header = get_header('GET', endpoint, body)
    return requests.get(url, headers=header)


def post(endpoint, body=''):
    url = ROOT_URL + endpoint
    header = get_header('POST', endpoint, body)
    return requests.post(url, headers=header)

where KEY, SECRET, PASS are the API key, secret key, and pass phrase respectively; The ROOT_URL is 'https://www.okex.com'.

The Problem

GET requests work absolutely fine, so when I run the following, there are no issues:

ENDPOINT = '/api/v5/account/balance'
BODY = ''

response = get(ENDPOINT)
response.json()

However, when I try to place an order via a POST request, like so:

ENDPOINT = '/api/v5/trade/order'
BODY = {"instId":"BTC-USDT",
        "tdMode":"cash",
        "side":"buy",
        "ordType":"market",
        "sz":"1"}

response = post(ENDPOINT, body=BODY)
response.json()

I get the following output, i.e. it won't accept the signature:

{'msg': 'Invalid Sign', 'code': '50113'}

Related Questions

In this one Can't figure out how to send a signed POST request to OKEx an answer was provided, but it does not work for me as I was already using the suggested URL. More or less the same question was asked here Unable to send a post requests OKEX Invalid Signature, but no activity likely due to the format, so I thought I would repost and elaborate.

OKEX Docs

The docs simply specify that The API endpoints of Trade require authentication (https://www.okex.com/docs-v5/en/?python#rest-api-authentication-signature). But they make no reference to there being any difference between the two methods. Away from that, I am including all required parameters in the body of the post request as far as I can see.

I would appreciate any input on this.

Many thanks!

2 Answers

I ran into the same POST problem and figured it out. I used new domain name okex.com. Here is my code.

def set_userinfo(self):
    position_path = "/api/v5/account/set-position-mode"
    try:
        self.get_header("POST", position_path, {"posMode":"net_mode"})
        resp = requests.post(url=self.base_url+position_path, headers=self.headers, json={"posMode":"long_short_mode"}).json()
    except Exception as e:
        log.error("OK set_userinfo error={} type={}".format(f'{e}', f'{type(e)}'))

def get_header(self, request_type, endpoint, body=''):
    timestamp = self.get_time()
    self.headers["OK-ACCESS-TIMESTAMP"] = timestamp
    self.headers["OK-ACCESS-SIGN"] = self.signature(timestamp, request_type, endpoint, body)

def signature(self, timestamp, request_type, endpoint, body):
    if body != '':
        body = json.dumps(body)
    message = str(timestamp) + str.upper(request_type) + endpoint + body
    mac = hmac.new(bytes(self.secret_key, encoding='utf-8'), bytes(message, encoding='utf-8'), digestmod='sha256').digest()
    return base64.b64encode(mac)

I have fix the same problem. Both of the 'body' in signature() and in get_header() should be json. So you should add following code:

if str(body) == '{}' or str(body) == 'None':
    body = ''
else:
    body = json.dumps(body)
Related