You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Binance Pay创建订单API签名无效问题求助(Kotlin Android)

Binance Pay创建订单API签名无效(错误码400002)排查

我在Kotlin Android应用中调用Binance Pay创建订单API实现支付功能,严格遵循官方API协议规则构建请求载荷与签名,但始终请求失败,收到错误响应:

{"status": "FAIL", "code": "400002", "errorMessage": "Signature for this request is not valid."}

相关代码

签名生成函数

private fun createSignature(payload: String, secretKey: String): String {
    val sha512HMAC = Mac.getInstance("HmacSHA512")
    val secretKeySpec =
        SecretKeySpec(secretKey.toByteArray(), "HmacSHA512") 
    sha512HMAC.init(secretKeySpec)
    val digest = sha512HMAC.doFinal(payload.toByteArray())
    return digest.toHex()
}

请求构建逻辑

val timestamp = System.currentTimeMillis() + clockOffset
val nonceStr = generateNonce()
val body = Gson().toJson(
    OrderRequest(
        Env("APP"),
        merchantTradeNb,
        0.02,
        "USDT",
        Goods("01", "D000", "7876763A3C", "phone", "Good new phone")
    )
)
val payload = timestamp.toString() + "\n" + nonceStr + "\n" + body + "\n"

val signature: String = createSignature(
    payload.toByteArray(Charsets.UTF_8).toString(), secretKey
).uppercase()

val retrofitData = retrofitBuilder.binanceApi.createOrder(
    "application/json", timestamp, nonceStr, certSn, signature, body
)

retrofitData.enqueue(object : Callback<OrderResponse> {
    override fun onResponse(
        call: Call<OrderResponse>,
        response: Response<OrderResponse>,
    ) {
        response.body()
    }

    override fun onFailure(call: Call<OrderResponse>, t: Throwable) {
    }
})

Retrofit接口定义

interface BinancePayApi {

    @POST("/binancepay/openapi/v2/order")
    fun createOrder(
        @Header("Content-type") contentType: String,
        @Header("BinancePay-Timestamp") timestamp: Long,
        @Header("BinancePay-Nonce") nonce: String,
        @Header("BinancePay-Certificate-SN") apiKey: String,
        @Header("BinancePay-Signature") signature: String,
        @Body request: String
    ): Call<OrderResponse>
}

问题排查关键点

  • 载荷编码错误:调用createSignature时,将payload转成UTF-8字节数组后又调用toString(),会导致字节被错误解码(默认用平台编码而非UTF-8),直接破坏签名原始数据。应直接传入原始payload字符串,或在签名函数中统一用UTF-8编码处理。
  • 签名载荷格式:Binance要求载荷格式为timestamp\nnonce\nbody\n,必须确保换行符是\n(Unix格式),且末尾保留一个空行,不能多也不能少。
  • JSON序列化一致性:Gson默认序列化的字段顺序可能和服务器预期不符,需确保body的JSON输出和官方示例完全一致(包括字段顺序、空格、数值格式),建议显式指定字段顺序或使用官方推荐的序列化方式。
  • 时间戳准确性:clockOffset必须准确,若本地时间与Binance服务器时间差超过5分钟,签名会直接失效,建议调用Binance的时间同步接口校准时间。
  • 密钥配对检查:确认certSn是正确的API Key,secretKey是对应的密钥,二者必须严格配对,不能混淆。
  • 签名函数编码统一:签名函数中,secretKey和payload都应该用UTF-8编码转字节数组,避免因编码不一致导致签名错误。

修正后的核心代码示例

修正的签名函数

private fun createSignature(payload: String, secretKey: String): String {
    val sha512HMAC = Mac.getInstance("HmacSHA512")
    // 统一用UTF-8编码处理密钥和载荷
    val secretKeySpec = SecretKeySpec(secretKey.toByteArray(Charsets.UTF_8), "HmacSHA512")
    sha512HMAC.init(secretKeySpec)
    val digest = sha512HMAC.doFinal(payload.toByteArray(Charsets.UTF_8))
    return digest.toHex().uppercase()
}

修正的载荷调用

val payload = "$timestamp\n$nonceStr\n$body\n"
// 直接传入payload字符串,无需转字节再转字符串
val signature = createSignature(payload, secretKey)

内容的提问来源于stack exchange,提问作者Shadi Amine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 14:10:34