Z Zise Developers

报价(收银台确认页的数字;建上游待支付单,不锁钱

POST /v1/qrpay/quotes scope: qrpay:write
代会员调用 · 必带 x-on-behalf-of

解码只告诉你「要付 250 THB」,这一条告诉你会员的数字资产会被扣掉多少

没有它就做不出确认页 —— 只能直接调 POST /v1/qrpay/payments

让用户在钱已经锁掉之后才第一次看见金额。

⚠⚠ 这一步在上游侧已经建了一笔待支付交易,不是免费的只读试算

POST /v1/remit/quotes 才是)。所以:

  • 同一个(会员 + code_value + currency + amount)在 60 秒

复用同一笔上游单,不重复外呼;

  • 按会员限流 30 次 / 60 秒(与商户级的总量闸叠加,两层都要过);
  • 用的是 qrpay:write 而不是 :read —— 它有上游副作用。

把报价当轮询用会在上游堆出一串永远不会被支付的待支付单,

并把你自己的会员限进 429。一次结账调一次。

customer_total 是预告不是承诺。 POST /v1/qrpay/payments

自己重报一次价再锁钱:上游报价带有效期,而用户会在你的确认页上

停留。拿旧报价锁钱的后果是上游按新价结算、我方按旧价扣款。

成交金额一律以 payments 的响应为准,两个数字可能差几个最小单位。

expires_at上游给的报价有效期(空串 = 上游这次没给)。

命中 60 秒备忘时它可能已经临近甚至过去 —— 按这个字段判断,

不要假设「刚拿到的报价一定新鲜」。

扣款币种不由你指定。 chosen 是按该会员自己的支付优先级挑出来的

那一个,options 是这次上游报得出价、我方也上架了的全部币种。

options[].asset 恰好就是 payments 的 preferred_asset合法取值集

—— 传一个不在这个集合里的资产,payments 会直接拒,不会静默换一个

sufficient会员的余额够不够付这一单,不是你的预付账户。

这里不下发余额数字:那是 GET /v1/balancesbalances:read)的事,

塞进来等于让一把只有 qrpay:write 的 Key 顺带拿到余额读权限。

⚠ 这里也不下发「你的预付够不够」 —— 那个布尔可以被二分反推出我方

给你的批发价,而 /v1/merchant/lines 正是为了不出批发价才那么写的。

你的预付余额在 GET /v1/merchant/balances

required_payer_fields 非空的码在开放 API 上走不通(见

POST /v1/qrpay/decode)—— 这一条同样不收付款人字段。

前置条件

  • 扫码付这条线已对你开启,且我方至少有一个可用上游
  • 这张码的码制我方支持(见 GET /v1/qrpay/schemes
字段类型必填说明
x-on-behalf-of string 必填 给谁报价。必填 —— 实付金额取决于该会员的支付优先级与余额, 实名位也按他的真实等级填给上游。

请求体

字段类型必填说明
code_value string 必填 二维码原文。与之后调 payments 时传的那一份必须一致。
currency string 可选 收单侧法币币种(如 THB)。只在自定义金额码上传amount_editable: true),固定金额码上不许传。
amount string 可选 收单侧法币金额(如 "250.00"),不是数字资产数量。 只在自定义金额码上传。

响应

200customer_total / fee定点十进制串,小数位 = 同一项的 ledger_scale(用它解析,不要用 display_scale —— 后者只决定 收银台上显示几位,拿去解析会掉精度)。 acquirer_currency / acquirer_amount 是收单侧法币那一端, 与 customer_total 不是同一个数、也不是同一个币:会员实付 = 上游报价 + 我方成本保护 + 溢价 + 手续费,天然更大。 blocked_reason 非空 = payments 会以这个码当场拒(超单笔 / 超日累计 / 未达起付额 / 触发实名门槛)。它只针对 chosen 那个币种 —— 换成 options 里的别的币要按那一项自己再判一次。 为空不等于一定成交:payments 还会重报价、再走一遍闸。
{
  "payee": "Bangkok Coffee Co.",
  "acquirer_currency": "THB",
  "acquirer_amount": "250.00",
  "expires_at": "2026-08-13T09:31:05Z",
  "chosen": {
    "asset": "USDT",
    "ledger_scale": 6,
    "display_scale": 2,
    "customer_total": "7.320000",
    "fee": "0.030000",
    "sufficient": true
  },
  "options": [
    {
      "asset": "USDT",
      "ledger_scale": 6,
      "display_scale": 2,
      "customer_total": "7.320000",
      "fee": "0.030000",
      "sufficient": true
    },
    {
      "asset": "USDC",
      "ledger_scale": 6,
      "display_scale": 2,
      "customer_total": "7.321000",
      "fee": "0.030000",
      "sufficient": false
    }
  ],
  "blocked_reason": ""
}
400qr_code_invalid 码解不出来 / 上游拒绝 · corridor_not_supported 这条走廊没开通(换十张码也一样,别让用户重扫)· amount_out_of_range 金额超出这张码允许的范围 · kyc_required 触发实名门槛 · insufficient_balance 一个可扣款的 资产都凑不出来(上游给的币我方一个都没上架)· request_rejected 会员被拉黑 / 账户冻结 / 卡资金保护中 · product_not_available 这条线未对你开启 · service_unavailable 此刻没有可用上游 · invalid_request · member_context_required · member_not_found
403insufficient_scope —— 这把 Key 没有 qrpay:write
429rate_limited —— 该会员 60 秒内的报价次数用尽(或你整体的写入 配额用尽)。按响应头 Retry-After 退避,不要立刻重试。
502upstream_error —— 上游 5xx / 网络层失败 / 说不出更细原因的拒绝。 这一档还没动钱(只是没建成待支付单),可以原样重试。
请求
curl -X POST 'https://api.zise.com/v1/qrpay/quotes' \
  -H 'x-auth-token: Bearer $TOKEN' \
  -H 'x-on-behalf-of: $MEMBER_ID' \
  -H 'content-type: application/json' \
  -d '{
    "code_value": "00020101021229300012D156000000000510A93FO3230Q...",
    "currency": "THB",
    "amount": "250.00"
  }'
const res = await fetch("https://api.zise.com/v1/qrpay/quotes", {
  method: "POST",
  headers: {
    "x-auth-token": "Bearer $TOKEN",
    "x-on-behalf-of": "$MEMBER_ID",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "code_value": "00020101021229300012D156000000000510A93FO3230Q...",
    "currency": "THB",
    "amount": "250.00"
  }),
});
// 金额按字符串读,别让它变成 number
const data = await res.json();
import requests

res = requests.post(
    "https://api.zise.com/v1/qrpay/quotes",
    headers={
        "x-auth-token": "Bearer $TOKEN",
        "x-on-behalf-of": "$MEMBER_ID",
        "content-type": "application/json",
    },
    json={
      "code_value": "00020101021229300012D156000000000510A93FO3230Q...",
      "currency": "THB",
      "amount": "250.00"
    },
)
# 金额用 Decimal(str(...)),不要 float
data = res.json()
req, _ := http.NewRequest("POST", "https://api.zise.com/v1/qrpay/quotes",
    strings.NewReader(`{
  "code_value": "00020101021229300012D156000000000510A93FO3230Q...",
  "currency": "THB",
  "amount": "250.00"
}`))
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
req.Header.Set("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
// 金额字段用 string 接,不要 float64
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.zise.com/v1/qrpay/quotes"))
    .header("x-auth-token", "Bearer $TOKEN")
    .header("x-on-behalf-of", "$MEMBER_ID")
    .header("content-type", "application/json")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
{
  "code_value": "00020101021229300012D156000000000510A93FO3230Q...",
  "currency": "THB",
  "amount": "250.00"
}
"""))
    .build();
// 金额字段用 String / BigDecimal,不要 double
$ch = curl_init('https://api.zise.com/v1/qrpay/quotes');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'x-auth-token: Bearer $TOKEN',
    'x-on-behalf-of: $MEMBER_ID',
    'content-type: application/json',
  ],
  CURLOPT_POSTFIELDS => <<<'JSON'
{
  "code_value": "00020101021229300012D156000000000510A93FO3230Q...",
  "currency": "THB",
  "amount": "250.00"
}
JSON,
]);
$res = curl_exec($ch);
// 金额用 bcmath / 字符串,不要 floatval
200
{
  "payee": "Bangkok Coffee Co.",
  "acquirer_currency": "THB",
  "acquirer_amount": "250.00",
  "expires_at": "2026-08-13T09:31:05Z",
  "chosen": {
    "asset": "USDT",
    "ledger_scale": 6,
    "display_scale": 2,
    "customer_total": "7.320000",
    "fee": "0.030000",
    "sufficient": true
  },
  "options": [
    {
      "asset": "USDT",
      "ledger_scale": 6,
      "display_scale": 2,
      "customer_total": "7.320000",
      "fee": "0.030000",
      "sufficient": true
    },
    {
      "asset": "USDC",
      "ledger_scale": 6,
      "display_scale": 2,
      "customer_total": "7.321000",
      "fee": "0.030000",
      "sufficient": false
    }
  ],
  "blocked_reason": ""
}