錯誤
所有 4xx/5xx 回應都帶有相同的 JSON 信封:
{
"code": 400,
"message": "invalid_input",
"details": [
{ "field": "items[0].unit_price", "message": "must be a positive decimal string" }
]
}code— 數值型的 HTTP status(400、401、404…)。用於通用的 HTTP 層處理很方便,但需要分支邏輯時請改用message—code無法區分如invalid_input與payment_method_not_supported(兩者都是 400)這類情境。message— lower-snake-case 的 sentinel 名稱,即 sentinel 名稱的 lower snake case 形式(例如INVALID_INPUT變成"invalid_input")。跨版本穩定 — 以此分支。details— 僅在驗證錯誤時出現。{ field, message }物件陣列,讓 client 能將錯誤對應到輸入欄位。其他情境下會省略。
錯誤 body 不包含 trace ID 或 timestamp。回報問題時,請向 support 提供回應的 Date 標頭、X-RateLimit-* 標頭、你的 merchant ID、endpoint,以及大約的請求時間。
驗證失敗使用不同的形態。 上面的信封是 API 對大多數錯誤所回傳的格式。在處理之前就被拒絕的請求 —— /b2b/v1/* 呼叫上缺失 / 非法的 X-Signature、未知的 X-Client-ID,或過期的 X-Timestamp —— 會以 { "error": "...", "message": "..." } 的形態回傳,其中 error 是粗粒度 slug(unauthorized / bad_request / service_unavailable),message 攜帶具體資訊。沒有數值 code,也沒有 details。請先依 HTTP 狀態分支,再讀 message。範例(401):
{ "error": "unauthorized", "message": "invalid signature" }HTTP 狀態 → 常見 code
| HTTP | 常見 code 值 | 意義 |
|---|---|---|
| 400 | INVALID_INPUT、MISSING_REQUIRED、INVALID_FORMAT、INVALID_LENGTH、INVALID_VALUE、PAYMENT_METHOD_NOT_SUPPORTED、AMOUNT_BELOW_MINIMUM | 請求有誤 — 請看 details |
| 401 | INVALID_CREDENTIALS、INVALID_TOKEN、TOKEN_EXPIRED、INVALID_SIGNATURE(B2B);SESSION_EXPIRED(僅儀表板) | 驗證失敗 — 金鑰錯誤、timestamp 過期、簽章不符。儀表板登入相關的 code 與 B2B 整合無關。 |
| 402 | INSUFFICIENT_CREDIT | 商家預付餘額用盡 — 請先儲值再重試 |
| 403 | FORBIDDEN、IP_BLOCKED | 金鑰有效但缺少呼叫此 API 所需的 scope / IP 許可 |
| 404 | NOT_FOUND、RECORD_NOT_FOUND | 資源不存在(或對此商家不存在) |
| 409 | ALREADY_EXISTS | 不同 body 的冪等 replay,或狀態機拒絕該轉移 |
| 429 | TOO_MANY_REQUESTS、TOO_MANY_ATTEMPTS | 觸發速率限制;請退避後重試 |
| 500 | INTERNAL_SERVER_ERROR、EXTERNAL_SERVICE_ERROR | 我們的問題;可帶退避安全重試。 |
| 503 | SERVICE_UNAVAILABLE | 下游依賴出問題。請退避後重試 |
完整 code 參考
你可能看到的 code 值:
身分驗證(401)
INVALID_CREDENTIALS— API 金鑰組合被拒絕INVALID_TOKEN— token 無法解析或被竄改TOKEN_EXPIRED— token 已過期SESSION_EXPIRED— 儀表板 session 已過期INVALID_SIGNATURE— B2B / webhook 呼叫的 HMAC 簽章不符
授權(403)
FORBIDDEN— 已驗證,但你無權執行此動作IP_BLOCKED— 來自此 IP 位址的請求已被封鎖
找不到(404)
NOT_FOUND— 通用RECORD_NOT_FOUND— 找不到該 ID 對應的列
衝突(409)
ALREADY_EXISTS— 通用
驗證(400)
INVALID_INPUT— 通用;請查detailsMISSING_REQUIRED— 缺少必要欄位INVALID_FORMAT— 值不符合預期格式(例如 UUID、URL、email)INVALID_LENGTH— 值過短或過長INVALID_VALUE— 值超出允許的 enum / 範圍PAYMENT_METHOD_NOT_SUPPORTED— 該 provider / 資產組合未對此商家啟用AMOUNT_BELOW_MINIMUM— 訂單金額低於該網路或環境的下限。回應的details.floor_usd攜帶目前設定的下限(USD),可直接取用顯示;message文字也會說明它。INSUFFICIENT_BALANCE— 買家的錢包持有的支付資產不足以支付此次轉帳。INSUFFICIENT_GAS— 買家的錢包缺少用於支付網路手續費(gas)的原生代幣,無法廣播此次轉帳。
付款 / 計費(402)
INSUFFICIENT_CREDIT— 商家預付餘額不足以支付網路手續費(gas)/ 平台手續費。請從儀表板儲值後再重試
速率限制(429)
TOO_MANY_REQUESTS— 超過 IP 速率限制TOO_MANY_ATTEMPTS— 對同一資源(例如 OTP)反覆失敗導致觸發 throttle
伺服器錯誤(500)
EXTERNAL_SERVICE_ERROR— 第三方 provider 失敗INTERNAL_SERVER_ERROR— 非預期錯誤;請聯繫 support,並提供回應的Date標頭與X-RateLimit-*標頭
可用性(503)
SERVICE_UNAVAILABLE— 服務暫時無法使用;請退避後重試
驗證錯誤(400)
當問題是請求 body 不正確時,details 是陣列,讓你可以把錯誤對應
回欄位:
{
"code": 400,
"message": "invalid_input",
"details": [
{ "field": "items[0].unit_price", "message": "must be a positive decimal string" },
{ "field": "success_url", "message": "must be a valid https URL" }
]
}身分驗證錯誤(401)
INVALID_SIGNATURE 有三個常見原因:
- Secret key 錯誤(再次確認環境變數)
- Timestamp 漂移 > 5 分鐘(同步 NTP)
- Canonical string 錯誤(最常見:忘記
\n分隔符,或簽了一份 經過 parse-then-re-stringify 與實際送出不同的 body)
確切的簽章演算法請見身分驗證。
速率限制(429)
| 範圍 | 限制 |
|---|---|
所有 API 路由(含 /b2b/v1/*) | 以 IP 位址計算 — 500 req/min,共享 bucket。並非以商家為單位。 |
公開結帳(/checkout/*) | 更嚴格的子 bucket — 每 IP 20 req/min |
X-RateLimit-Limit 與 X-RateLimit-Remaining 會包含在每一個
受速率限制的回應中,不只是成功的回應。請把它們視為
你 IP 的即時預算。
被速率限制的回應會包含 Retry-After 標頭(距離視窗重置的秒數)—
請遵循它。作為備援,可以 jitter 退避 — 1s 基底 + 指數成長到 30s。
速率限制可能會調整。如果你的合法流量達到上限(例如對帳大量歷史 資料),請聯繫 support。
信用額度不足(402)
INSUFFICIENT_CREDIT(HTTP 402 Payment Required)代表你的預付
餘額無法支付你嘗試的操作所需的網路手續費(gas)與平台手續費,典型情境是結算
加密支付,或網路手續費由平台代付的鏈上動作。請從商家儀表板
(Billing → Add credit)儲值後再重試該操作;
已在處理中的操作會在儲值後自動接續。
伺服器錯誤(5xx)
500 代表我們無法處理該請求。請以退避方式重試 — 你的
idempotency_key 確保即使原請求部分成功,也不會被重複收費。
若 1 分鐘內重試仍未恢復,請對買家顯示通用的「付款暫時無法使用」
訊息,並向 support 回報失敗的 endpoint、你的 merchant ID、回應的
Date 標頭與 X-RateLimit-* 的值,以及大約的請求時間 — 這些資訊
足以讓我們找到該請求。
Webhook 投遞錯誤
Webhook 投遞是獨立的失敗通道 — 它們不會以 API 錯誤的形式出現, 因為呼叫的不是你的伺服器。當投遞回非 2xx(或逾時)時,會以指數 退避重試:0s、1min、5min、15min、1h、6h(共 6 次嘗試,與 Webhooks → 總覽相同排程)。完整的每次 投遞歷史在儀表板的 Developers → Webhooks → [endpoint] → Delivery log 中。第 6 次嘗試失敗後,儀表板會將該投遞標示為 「Failed」,你的伺服器恢復後可手動 replay。