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++;
    }
  }
}