AllSwap

错误与速率限制

Allswap API 的所有错误都用同一个 JSON 信封 —— 你的错误处理只需要支持一种形状。code 给机器用,message 给人看,requestId 是你开 ticket 时要带给我们的。

错误信封

{
  "error": {
    "code":     "quote_expired",
    "message":  "Quote qt_01HW9... expired at 2026-06-22T10:01:32Z.",
    "requestId":"req_01HW9..."
  }
}

常见错误码

错误码HTTP含义可以重试?
unauthorized401X-Key-Id / Bearer 缺失或无效。
forbidden403密钥有效但缺少必需的 scope 权限。
invalid_request400请求体格式错误 / 缺少必填字段。先修
unsupported_pair400from → to 之间没有支持的路由。
amount_too_low400低于该交易对的最小可交易金额。先修
amount_too_high400超过该交易对当前的流动性上限。先修
quote_expired409quoteId 已超过 expiresAt —— 重新报价。先修
quote_consumed409quoteId 已被前一次 /v1/swap 调用消费过。
rate_limited429RPM 预算已用完。请遵守 Retry-After。退避
upstream_timeout504路由未在超时内响应,可以安全重试。退避
internal_error500我们这边出问题了。请上报 requestId。退避

速率限制

每个密钥有两个限制:每分钟请求数(RPM,控制突发)和 每月报价次数(档位月配额)。具体档位数字见 定价页

每条响应都包含当前 RPM 桶的状态:

X-RateLimit-Limit:     300
X-RateLimit-Remaining: 248
X-RateLimit-Reset:     1718983261

当你打到 0,下一次请求返回 429 rate_limited,带 Retry-After header(秒)。务必遵守。

重试策略

按类别推荐做法:

  • 你这边的问题 4xxinvalid_requestunauthorizedforbiddenunsupported_pair):不要 重试。把错误展示给开发者/用户即可;重试只会浪费配额。
  • 429 rate_limited:按 Retry-After 给出的秒数等待后重试。用值本身 —— 别自己估,我们在故障期间会动态调整这个值。
  • 5xxupstream_timeoutinternal_error):带抖动的指数退避。建议 base = 500ms、cap = 8s、最多重试 4 次。
  • 报价相关 409:先重新报价,再重试 swap。quote_consumed 是终态 —— 这个 quoteId 永远废了。

参考:退避伪代码

async function withRetry<T>(fn: () => Promise<T>): Promise<T> {
  let attempt = 0;
  while (true) {
    try {
      return await fn();
    } catch (err: any) {
      const code = err?.body?.error?.code;
      const status = err?.status;
      if (status === 429) {
        const wait = Number(err.headers["retry-after"] ?? 1) * 1000;
        await sleep(wait);
        continue;
      }
      const retriable = code === "upstream_timeout" || code === "internal_error";
      if (!retriable || attempt >= 4) throw err;
      const base = Math.min(8000, 500 * 2 ** attempt);
      const jitter = Math.random() * base * 0.3;
      await sleep(base + jitter);
      attempt++;
    }
  }
}