I am trying to send a simple post request to the bybit api and I keep getting the 10004 sign error. Here is the response:
{"ret_code":10004,"ret_msg":"error sign! origin_string[api_key=(my api key)\u0026symbol=BTCUSDT\u0026timestamp=1635967650768]","ext_code":"","ext_info":"","result":null,"time_now":"1635967651.397800"}
This is the code I am using to send the request.
public async static Task<string> cancelAllOrders()
{
string ts = await GenerateTimeStamp();
string paramString = "api_key=" + apiKey + "&symbol=BTCUSDT" + "timestamp=" + ts;
string sign = CreateSignature(secretKey, paramString);
CancelOrderContent co = new CancelOrderContent(apiKey, "BTCUSDT", ts, sign);
var client = new RestClient(ApiUrl + "/v2/private/order/cancelAll");
var request = new RestRequest();
request.AddJsonBody(co);
var response = client.Post(request);
Trace.WriteLine(response.StatusCode.ToString() + " " + response);
return "";
}
Here is the class I am Serializing to JSON for the body of the request.
public class CancelOrderContent
{
public string api_key;
public string sign;
public string symbol;
public string timestamp;
public CancelOrderContent(string api_key, string symbol, string timestamp,string sign)
{
this.api_key = api_key;
this.symbol = symbol;
this.timestamp = timestamp;
this.sign = sign;
}
}
Here is the code I am using to create signatures:
public static string CreateSignature(string secret, string message)
{
var signatureBytes = Hmacsha256(Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes(message));
return ByteArrayToString(signatureBytes);
}
private static byte[] Hmacsha256(byte[] keyByte, byte[] messageBytes)
{
using (var hash = new HMACSHA256(keyByte))
{
return hash.ComputeHash(messageBytes);
}
}
I've tried al kinds of methods to fix this but I can't seem to get rid of it.I've tried mutliple endpoints and I still get the same error.
2022/01/17 this still works.
Hey @Vexatious I ran into a similar issue with the bybit-api trying to submit orders and I kept receiving a Key denied, insufficient permissions error even though I knew I was setting up my keys properly.
Maybe ByBit changed something? Lib outdated? Who Knows.
One major thing that I noticed is that they require you to Order the params alphabetically before appending the signature to the body of the request.
Edit: Updated because I recognized GET Requests can be equally as confusing. Scroll down to view the example POST Request.
GET and POST requests are handled differently
SIGNATURE
For Both: You must alphabetically arrange the params before generating the signature.
ex: "aParam=foo&bParam=bar",
That's your sign parameter dealt with.
GET REQUESTS: Append the sign parameter to the end of the QueryString and send'er, might need to use a header
// Might still need {'Content-Type': 'application/x-www-form-urlencoded'}
// header depending on what request lib you're using.
const url = "https://api-testnet.bybit.com/GET?aParam=foo&bParam=bar&sign=" + sign
POST REQUESTS: it is required that the object is sent as request data (still, in the form of a QueryString like above) and not a fully built out Http string similar to the GET Request. Add the sign parameter to the end of the QueryString you generated the signature with, assign that to your request handlers data parameter and fire away!
I did come up with a minimal working version that successfully posted a Spot Order on their testnet, here is the jest test.
./bybit.test.ts
test("WORKING BYBIT TRADE.", async () => {
const serverTime:number = (await axios.get(`https://api-testnet.bybit.com/spot/v1/time`)).data
// These need to be within 1000ms of eachother (I'm pree sure, their formula is kinda confusing)
console.log(`Their Timestamp`, serverTime)
console.log(`Our Timestamp`, Date.now())
const queryParams = {
// Alphabetically ordered
// (Sign generation function should deal with unordered params using .sort())
'api_key': bybitApiKey,
qty:10,
recvWindow: 10000,
side:"BUY",
symbol:"ETHUSDT",
timestamp: Date.now(),
type:"MARKET",
}
const queryString = querystring.stringify(queryParams)
const sign = "&sign=" + getSignature(queryParams, bybitSecret)
const fullQuery = queryString + sign
console.log(`FullQuery example`, fullQuery)
// api_key=...&qty=10&recvWindow=10000&side=BUY&symbol=ETHUSDT×tamp=1638371037593&type=MARKET&sign=...
let result = await axios(`https://api-testnet.bybit.com/spot/v1/order`, {
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: "POST",
data: fullQuery,
})
console.log(`Post Status`, result.status)
console.log(`Post Body`, result.data)
})
/**
Post Status 200
Post Body {
ret_code: 0,
ret_msg: '',
ext_code: null,
ext_info: null,
result: {
accountId: '...',
symbol: 'ETHUSDT',
symbolName: 'ETHUSDT',
orderLinkId: '...',
orderId: '...',
transactTime: '...',
price: '0',
origQty: '10',
executedQty: '0',
status: 'FILLED',
timeInForce: 'GTC',
type: 'MARKET',
side: 'BUY'
}
*/
}
./sign.ts
import crypto from 'crypto'
export function getSignature(parameters: any, secret: string) {
var orderedParams = "";
Object.keys(parameters).sort().forEach(function(key) {
orderedParams += key + "=" + parameters[key] + "&";
});
orderedParams = orderedParams.substring(0, orderedParams.length - 1);
return crypto.createHmac('sha256', secret).update(orderedParams).digest('hex');
}
Hopefully this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With