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

使用aiohttp调用Backpack API时签名无效问题求助

排查Backpack API签名无效问题

问题描述

使用aiohttp向Backpack交易所API发送POST请求时,持续收到「Invalid signature」错误。已验证除X-Signature外,其余请求头及请求体参数均正确(修改参数会得到不同响应)。

要求的请求头

headers = {
    'X-Timestamp': str(timestamp),
    'X-Window': str(self.WINDOW),
    'X-API-Key': self.public_key,
    'X-Signature': signature
}

签名结构示例

签名需按以下结构拼接字符串,使用与公钥配对的私钥进行签名:

instruction=orderExecute&postOnly=False&price=1&quantity=10&selfTradePrevention=Allow&side=Bid&symbol=SOL_USDC&timeInForce=IOC&timestamp=1710451343478&window=6000

相关代码

class Site:
    WINDOW = 6000

    def __init__(self, token, private_key):
        self.public_key = token
        self.private_key = private_key

    async def headers(self, params: dict, instruction: str) -> dict:
        timestamp = await self._unix_time()
        params["window"] = self.WINDOW
        params["timestamp"] = timestamp
        sorted_params = sorted(params.items())
        query_string = f"instruction={instruction}&"+'&'.join(f"{key}={value}" for key, value in sorted_params)
        signature = await self._sign(query_string)
        headers = {
            'X-Timestamp': str(timestamp),
            'X-Window': str(self.WINDOW),
            'X-API-Key': self.public_key,
            'X-Signature': signature
        }
        return headers

    async def _sign(self, data):
        private_key_bytes = base64.b64decode(self.private_key)
        private_key = Ed25519PrivateKey.from_private_bytes(private_key_bytes)
        signature = private_key.sign(data.encode())
        signature_base64 = base64.b64encode(signature).decode()
        return signature_base64

    @staticmethod
    async def _unix_time():
        async with aiohttp.ClientSession() as session:
            async with session.get("https://api.backpack.exchange/api/v1/time") as response:
                return await response.text()


class Trade(Site):
    def __init__(self, public_key, private_key):
        super().__init__(public_key, private_key)

    async def buy_order(self):
        params = {
            "orderType": OrderType.LIMIT.value,
            "postOnly": PostOnly.FALSE.value,
            "price": "1",
            "quantity": "10",
            "selfTradePrevention": SelfTradePrevention.ALLOW.value,
            "side": Side.BUY.value,
            "symbol": Symbol.SOL.value,
            "timeInForce": TimeInForce.IOC.value,
            }
        headers = await self.headers(params=params, instruction=Instruction.ORDER_EXECUTE.value)
        headers['Content-Type'] = 'application/json; charset=utf-8'
        body = json.dumps(params)
        r = await _handle_post(headers=headers, body=body)

排查与修复方案

1. 时间戳类型不匹配

_unix_time方法返回的是API返回的文本字符串,而签名需要的是毫秒级整数格式的时间戳。如果返回的字符串包含非数字内容(如引号),会导致签名字符串不匹配。修改如下:

@staticmethod
async def _unix_time():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.backpack.exchange/api/v1/time") as response:
            # 将返回的文本转为整数
            return int(await response.text())

2. 请求体与签名参数不一致

当前代码直接修改了原params字典,添加了window和timestamp,导致请求体中包含这两个字段,但Backpack API可能要求这两个字段仅用于签名,不包含在请求体内。需使用副本处理签名参数:

async def headers(self, params: dict, instruction: str) -> dict:
    timestamp = await self._unix_time()
    # 创建参数副本,避免修改原请求体参数
    sign_params = params.copy()
    sign_params["window"] = self.WINDOW
    sign_params["timestamp"] = timestamp
    sorted_params = sorted(sign_params.items())
    query_string = f"instruction={instruction}&"+'&'.join(f"{key}={value}" for key, value in sorted_params)
    signature = await self._sign(query_string)
    headers = {
        'X-Timestamp': str(timestamp),
        'X-Window': str(self.WINDOW),
        'X-API-Key': self.public_key,
        'X-Signature': signature
    }
    return headers

3. 参数值大小写/内容不匹配

对比签名示例与代码中的参数值:

  • 示例中side=Bid,需确认Side.BUY.value的返回值是否为"Bid"而非"Buy";
  • 示例中postOnly=False,需确认PostOnly.FALSE.value是否为"False"(首字母大写)而非"false";
  • 检查symbol参数:示例为SOL_USDC,代码中Symbol.SOL.value是否对应正确的交易对字符串。

4. 签名字符串拼接验证

在生成query_string后,打印输出并与官方示例对比,确保:

  • 无多余空格或字符;
  • 参数顺序与示例逻辑一致(官方要求按参数名升序排序,代码中sorted(params.items())已实现,但需确认排序后的结果与示例匹配);
  • 未多传/漏传参数:比如代码中params包含orderType,需确认Backpack的orderExecute接口是否要求该字段包含在签名中。

5. Ed25519签名细节确认

  • 确保私钥是Backpack提供的base64编码Ed25519私钥,解码后长度正确(Ed25519私钥为32字节);
  • 确认使用的cryptography库版本正确,Ed25519PrivateKey.sign方法默认使用的签名格式符合Backpack要求(无需添加额外上下文或哈希算法)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:27:08