Z Zise Developers
稳定币账户 › 指南

两条路:一步成交,或先锁价再成交。成交是原子的,没有中间态。

站内兑换


GET  /v1/exchange/pairs     ← 开了哪些方向
POST /v1/exchange/quotes    ← 报价(可选锁价)
POST /v1/exchange/orders    ← 成交

按方向配,不是按币对

USDT → USDUSD → USDT两条独立记录:费率不必对称,可以只开一个方向。清单里没有的方向就是没开。

⚠ 别把它建模成一个「币对」再加一个方向位。那样在你这边就只有一套费率,

而我方两个方向可以配成不一样的。


两条成交路径,按你的界面形态选

A. 一步成交(不锁价)

拿报价只是给用户看一眼,下单时按成交那一刻的价重新算


POST /v1/exchange/quotes   { from_asset, to_asset, from_amount }
POST /v1/exchange/orders   { from_asset, to_asset, from_amount }

适合「输入金额、立刻确认」这种一屏完成的交互。

⚠ 不锁价时 quote_ttl_sec 只是个参考值,不是承诺。

响应里没有 quote_id 字段(是字段不存在,不是 null ——

这样你能分清「我没要锁价」和「我要了但没给我」)。

B. 锁价成交

要给终端用户一屏确认(「1000 USDT 换 999.5 USD,确认吗」)就锁价:


POST /v1/exchange/quotes   { …, "lock": true }
   → { quote_id: "exc_…", quote_expires_at: "…", quote_ttl_sec: 120 }

POST /v1/exchange/orders   { "quote_id": "exc_…" }

锁住的窗口是 quote_ttl_sec 秒(我方按币对配,库级限制在 30–600 秒)。过了这个点成交一律被拒,不会按新价悄悄成交。

⚠⚠ quote_id 就是这一单的订单号。 成交后 POST /v1/exchange/orders

返回的 id 与它逐字符相同GET /v1/exchange/orders/{id} 也认它。

这带来一个很有用的性质:锁价请求超时也不要紧 ——

你手上已经有那个 id 了,直接查它就知道这一单到底成没成。

⚠ 锁价会建一张真的 quoted 订单行。别为「让用户看一眼」就无脑锁

一是你自己的订单清单会灌满从未成交的 quoted 行;

二是一份锁定的报价对你就是一个 N 秒的免费期权(只在对你有利时才成交),

我方对滥用是有观测的。


幂等键:两个端点的规则相反

端点幂等键为什么
POST /v1/exchange/quotes可选报价本身没有幂等语义。带了就顺手去重 —— 超时重发拿回同一份锁价,而不是攒出两张只有一张会用掉的报价单
POST /v1/exchange/orders必须,且重试沿用同一把它动钱

成交是原子的

下单返回的那一刻钱已经换完了。没有「处理中」这个状态,所以也没有「取消」「重试」「退款」。

⚠ 这意味着 POST /v1/exchange/orders网络超时是「结果不明」,不是失败

同一把幂等键重试,或者(锁价那条路上)直接查 quote_id

当失败处理的表现是同一笔换了两次。


手续费在哪一侧

报价里有 fee_amountfee_asset —— 后者告诉你费用是从哪一侧收的。

别自己按「金额 × 费率」算。 从付出侧收和从换得侧收,

算出来的数不一样,而用户会拿你的数去对账。

直接用 fee_amount / fee_asset

金额都是字符串定点,两侧的位数分别由 ledger_scale_from / ledger_scale_to 给出 —— 两种资产的位数往往不同,别复用一个。

相关端点