When posting to https://bpay.binanceapi.com/binancepay/openapi/v3/order I receive response: {"status":"FAIL","code":"400002","errorMessage":"Signature for this request is not valid."} Check whether the signature parameter and method comply with signature algorithm requirements.
These are the methods I use to build the requests to BinancePay API in C# It should match the API specification in https://developers.binance.com/docs/binance-pay/api-order-create-v3 I think I have good signature based on requirements in https://developers.binance.com/docs/binance-pay/api-common
private (string, string, string) GetData()
{
var nonce = GetBinanceNonce();
var request = new StartDepositData
{
env = new StartDepositData.Env
{
TerminalType = TerminalType
},
orderTags = new StartDepositData.OrderTags
{
IfProfitSharing = true
},
MerchantTradeNo = nonce,
OrderAmount = (double)_data.PaymentAmount,
Currency = _data.PaymentCurrencyId,
Description = "BinancePay",
GoodsDetails = new List<StartDepositData.GoodDetail>
{
new ()
{
GoodsType = GoodsType,
GoodsCategory = GoodsCategory,
ReferenceGoodsId = _data.Reference,
GoodsName = "BinancePay",
GoodsDetail = "BinancePay"
}
}
};
// TODO: API Specification ambiguous, payload could be:
// 1. var payload = body;
// 2. var payload = timestamp + "\n" + nonce + "\n" + body + "\n";
// 1 may just be the payload, 2 may be needed when creating signature maybe
var timestamp = DateTime.UtcNow.ToUnixTimeMilliseconds().ToString();
var body = JsonConvert.SerializeObject(request);
var payload = body;
var signaturePayload = timestamp + "\n" + nonce + "\n" + body + "\n";
string signature = CreateSignature(signaturePayload, _secret);
string hexSignature = Hex(Encoding.UTF8.GetBytes(signature));
return (payload, hexSignature, nonce);
}
private string CreateSignature(string payload, string secretKey)
{
// Initialize a new HMACSHA512 instance with the provided secret key
var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(secretKey));
// Compute the hash of the payload
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
// Convert the hash to a hexadecimal string, remove any dashes typically included by BitConverter, and convert to uppercase
return BitConverter.ToString(hash).Replace("-", string.Empty).ToUpper();
}
public static string Hex(byte[] bytes)
{
StringBuilder result = new StringBuilder(bytes.Length * 2);
string hexAlphabet = "0123456789ABCDEF";
foreach (byte b in bytes)
{
result.Append(hexAlphabet[b >> 4]);
result.Append(hexAlphabet[b & 0xF]);
}
return result.ToString();
}
// A random string with 32 bytes, e.g. random ascii decimal within a-z and A-Z and loop 32 times to form a random string
private static string GetBinanceNonce(int length = 32)
{
const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[new Random().Next(s.Length)]).ToArray());
}
As for the sending it, I send it as so:
var (payload, signature, nonce) = GetData();
var timestamp = DateTime.UtcNow.ToUnixTimeMilliseconds().ToString();
var headers = new {
Content_Type = "application/json",
BinancePay_Timestamp = timestamp,
BinancePay_Nonce = nonce,
BinancePay_Certificate_SN = _apiKey,
BinancePay_Signature = signature
};
var reply = await _binanceClient.PostAsync(Endpoint, new StringContent(payload), headers);
// TODO: {"status":"FAIL","code":"400002","errorMessage":"Signature for this request is not valid."}
// TODO: Check whether the signature parameter and method comply with signature algorithm requirements.
var content = await reply.Content.ReadAsStringAsync();
EDIT: This works: var timestamp = DateTime.UtcNow.ToUnixTimeMilliseconds().ToString();
var payload = jsonRequest; var signaturePayload = timestamp + "\n" + nonce + "\n" + jsonRequest + "\n"; private string CreateSignature(string payload) { byte[] keyBytes = Encoding.UTF8.GetBytes(Secret); using (HMACSHA512 hmacsha512 = new HMACSHA512(keyBytes)) { byte[] sourceBytes = Encoding.UTF8.GetBytes(payload);
byte[] hash = hmacsha512.ComputeHash(sourceBytes);
// Convert the hash to a hexadecimal string, remove any dashes typically included by BitConverter, and convert to uppercase
return BitConverter.ToString(hash).Replace("-", "").ToUpper();
}
}
// A random string with 32 bytes, e.g. random ascii decimal within a-z and A-Z and loop 32 times to form a random string
private static string GetBinanceNonce(int length = 16)
{
const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var randomCharacters = new string(Enumerable.Repeat(chars, length)
.Select(s => s[new Random().Next(s.Length)]).ToArray());
return BitConverter.ToString(Encoding.UTF8.GetBytes(randomCharacters)).Replace("-", "");
}
string signature = CreateSignature(signaturePayload);
return (payload, signature, nonce, timestamp);