Stable contract: success+msg+traceId.codevalues are still being unified — use message semantics +traceIdfor support.
| Case | Rule |
|---|---|
| Success | success == true |
| Business failure | success == false; HTTP may still be 200 |
| Support | Always keep traceId |
msg, not message. Envelope: response-envelope.| Category | Typical signal | Same key retry? | Merchant action |
|---|---|---|---|
| Auth failure | signature / unauthorized / timestamp | Re-sign; may reuse business key | Fix clock / signature |
| Validation | mandatory / required / invalid | No — new key | Fix params |
| Amount out of range | out of range / between | No | Adjust amount; check pair limits |
| Pair not enabled | supported / not matched | No | Ask Customer Success |
| Quote expired | expire / expired | No | New get-quote |
| In-flight | processing | Do not change key | Wait webhook / query |
| Timeout / unknown | no response | Yes — same key | Backoff retry |
| Terminal fail | fail / rejected | No | Handle terminal state |
| System error | internal / 5xx-like | Same key OK on idempotent APIs | Ticket with traceId |
{
"status": 500,
"code": "AMOUNT_OUT_OF_RANGE",
"msg": "sourceAmount must be between 100 and 500000 USDT, current: 10",
"success": false,
"traceId": "a1b2c3d4e5f6",
"data": null
}100–500000 is the USD-class default fallback — fiat pairs use configured min/max. See Convert · pairs & limits.{
"success": false,
"msg": "sourceAmount is required for STABLE_SWAP",
"traceId": "..."
}eventId.