錯誤與速率限制
Allswap API 的所有錯誤都會回傳簡潔 JSON 信封。error 字串給機器處理;可選的 detail 和 upstream 欄位用於定位 provider 側失敗。
錯誤信封
{
"error": "unknown originAsset/destinationAsset",
"detail": "originAsset or destinationAsset is not available in /v1/assets",
"upstream": {
"status": 404,
"path": "POST /aggregate/quotes"
}
}常見錯誤碼
| 錯誤碼 | HTTP | 含義 | 可以重試? |
|---|---|---|---|
origin not allowed | 403 | 請求 Origin 不在允許列表。 | 否 |
body too large | 413 | POST 請求體超過允許大小。 | 先修 |
unknown originAsset/destinationAsset | 400 | 某個 CAIP-19 資產 ID 不在可路由資產列表中。 | 先修 |
no provider supports this pair | 404 | 目前沒有 provider 能路由這組 originAsset 到 destinationAsset。 | 否 |
amount_too_low | 400 | 低於該交易對的 provider 最小可交易金額。 | 先修 |
amount_too_high | 400 | 超過該交易對目前流動性上限。 | 先修 |
providerId required (route_A | route_B) | 400 | 建立訂單需要傳入報價預覽中選定的 provider。 | 先修 |
missing txHash | 400 | 提交入金記錄時必須提供來源鏈交易哈希。 | 先修 |
order not found | 404 | 訂單 ID 不存在,或目前呼叫方不可見。 | 否 |
order already in terminal state | 410 | 訂單已經是 SUCCESS、REFUNDED 或 FAILED。 | 否 |
rate limit exceeded | 429 | 請求預算已耗盡。降低頻率後再試。 | 退避 |
upstream timeout | 504 | 路由 provider 未在逾時內回應。 | 退避 |
upstream error | 502 | 路由 provider 回傳了非預期錯誤。 | 退避 |
internal error | 500 | Allswap 內部處理失敗。聯絡支援時請附上回應詳情。 | 退避 |
速率限制
每個金鑰有兩個限制:每分鐘請求數(RPM,控制突發)和 每月報價次數(檔位月配額)。具體檔位數字見 定價頁。
每條回應都包含目前 RPM 桶的狀態:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 248
X-RateLimit-Reset: 1718983261當你打到 0,下一次請求回傳 429 rate_limited,帶 Retry-After header(秒)。務必遵守。
重試策略
按類別建議做法:
- 輸入問題(
unknown originAsset/destinationAsset、providerId required、missing txHash):先修請求;重複提交同一 payload 只會浪費配額。 - 不支援的交易對:不要立即重試。重新整理
/v1/assets或/v1/swappable-targets,仍不可用就從 UI 中移除該路線。 - 429 rate limit:等待後再試。用伺服器端節流,避免單個使用者耗盡整個整合的共享預算。
- 5xx / upstream 失敗:帶抖動的指數退避。建議 base = 500ms、cap = 8s、最多重試 4 次。
- 訂單終態:訂單進入
SUCCESS、REFUNDED或FAILED後,新使用者動作應建立新訂單。
參考:退避偽碼
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++;
}
}
}
