上报会员入金
x-on-behalf-of
需 x-idempotency-key
动钱 · 仅自营主体增加会员 available 和 merchant.custody;不扣商户预付余额
失败处置见下方响应表。超时(504)用同一把幂等键重试——我方可能已经处理完;业务失败要换新键,同键会原样返回那次失败。
仅平台自营主体(platform_hosted)可调用。 非自营商户merchant_hosted 禁止给 member 入金,只使用商户实际充值的预付余额。即使历史 Key 已批准 deposits:write,也返回 403 insufficient_scope。商户类型从服务端读取,请求体中的 custody_model / merchant_id 不能改变权限。该限制先于幂等回放执行,旧成功响应也不能绕过;可通过 GET 查询历史入金。
自营主体仍须满足全部条件:强制签名、稳定业务流水号、单笔与日累计限额、资产白名单、会员风控准入和全量审计。仅有入金声明不等于平台链上实收证明。
凭证是 member.available credit W / merchant.custody debit W。该接口不从 merchant.available 划款,不能作为商户预付充值入口。
幂等规则
x-idempotency-key挡网络重试:同键同体 24 小时内回放,同键异体 409。reference是入金的稳定业务流水号,进入mdep:<商户>:<reference>,永久防止同一笔入金重复记账;不能在每次重试时随机生成。- 首次返回 201;同一
reference已过账时返回 200 +replayed: true。金额与链上字段以首次保存的数据为准,响应回显已保存的那份。
链上溯源与资产白名单
network / txid / from_address / to_address 可选;有 txid 或任一地址必须有 network,否则 400 invalid_fields。network 自动大写且不校验平台链目录;长度上限分别为 32 / 128 / 200 / 200。txid 不去重,因为一条链上交易可以承载多笔入金;去重依据是 reference。元数据本身不构成已验证到账证明。
没有资产白名单行时按平台目录放行;一旦配置任何白名单行,就必须逐资产命中且启用,否则 asset_not_allowed。
失败处理
超时或 504 使用原幂等键查证、重试。明确业务失败后换新键;limit_exceeded 通过 limit_type(single/daily)确认限额。非自营商户的 403 不能通过重试或申请权限解决,应使用商户预付资金模式。
前置条件
- 仅平台自营主体 platform_hosted;非自营主体即使有旧权限也拒绝
- 请求已签名(此端点强制,不受 Key 的 signature_required 影响)
- 资产在平台目录内且已启用;若该商户配了白名单,还必须逐资产命中且启用
- 会员未被封禁 / 拉黑 / 冻结(照常过平台准入)
请求头
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
x-on-behalf-of |
string | 必填 | 给哪个会员记这笔入金 |
x-idempotency-key |
string | 必填 | UUID。格式不对直接 400 idempotency_key_invalid。 |
x-signature |
string | 必填 | HMAC 签名。此端点不可关闭签名,与 Key 上的
signature_required 配置无关。 |
x-timestamp |
string | 必填 | Unix 秒。容差 ±300 秒,超窗回 timestamp_out_of_range。 |
x-nonce |
string | 必填 | 一次性随机串。重放窗口内重复使用回 nonce_reused。 |
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
asset |
string | 必填 | 资产代码。我方会自动转成大写,所以 usdt 与 USDT
等价。不在目录/白名单内一律 asset_not_allowed。 |
amount |
string | 必填 | 入账数量,必须 > 0。字符串定点,位数 = 该资产
ledger_scale。小数位多于 scale 且尾数非全 0 时
直接 400 —— 我方不做四舍五入,宁可让你自己决定。USDT(ledger_scale=6)形如 1500.000000 |
reference |
string | 必填 | 你那边这笔入金的稳定业务流水号,≤ 120 字符。
它进账本幂等键,是「同一笔钱只入账一次」的唯一依据。
⚠ 每次调用现生成一个 = 这道闸完全失效。
⚠ 它同时是 GET /v1/deposits/{id} 的路径参数。含 /
的流水号请改用 GET /v1/deposits?reference= —— 斜杠
在路径里是分段符,转义也不可靠。 |
network |
string | 可选 | 链上网络机读码,如 BSC / TRON / ETH。可选,
自动转大写,≤ 32 字符,我方不做白名单校验。
⚠ 传了 txid 或任一地址时必填。 |
txid |
string | 可选 | 链上交易哈希,≤ 128 字符。可选。多笔入金共用一个 txid 是允许的(UTXO 的多个 vout、批量转账)。 |
from_address |
string | 可选 | 发起方地址(这笔钱是从哪儿来的),≤ 200 字符。可选。 这是"入金来源地址"那件事在我方模型下的落点 —— 我方不另设登记接口,因为它天生属于这一笔入金。 |
to_address |
string | 可选 | 你这一侧的收款地址,≤ 200 字符。可选。 |
响应
{
"id": "dep_0xa3f1c2e9-0",
"reference": "0xa3f1c2e9-0",
"external_member_id": "u_10023",
"asset": "USDT",
"amount": "1500.000000",
"ledger_scale": 6,
"status": "credited",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
"replayed": true
}{
"id": "dep_0xa3f1c2e9-0",
"reference": "0xa3f1c2e9-0",
"external_member_id": "u_10023",
"asset": "USDT",
"amount": "1500.000000",
"ledger_scale": 6,
"status": "credited",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
"replayed": false
}invalid_request 缺字段 / 金额非法 / reference 超 120 字符 ·
invalid_fields 链上字段超长,或给了 txid/地址却没给 network ·
asset_not_allowed 资产不在目录或不在该商户白名单内 ·
limit_exceeded 超限(看 limit_type = single 或 daily,
limit_scope = merchant) ·
request_rejected 会员被平台准入拦下(不下发原因) ·
insufficient_balance 过账时余额类 CHECK 被撞 ·
idempotency_key_required / idempotency_key_invalid 幂等键问题signature_required 没带签名 · invalid_signature 签名不匹配 ·
timestamp_out_of_range 时间戳超窗 · nonce_reused nonce 重放insufficient_scope;不得给 member 入金。idempotency_key_reused 同一把幂等键配了不同的请求体 ·
idempotency_in_progress 首次请求还在处理中,稍后同键重试curl -X POST 'https://api.zinfra.vip/v1/deposits' \
-H 'x-auth-token: Bearer $TOKEN' \
-H 'x-on-behalf-of: $MEMBER_ID' \
-H 'x-idempotency-key: $IDEMPOTENCY_KEY' \
-H 'content-type: application/json' \
-d '{
"asset": "USDT",
"amount": "1500.000000",
"reference": "0xa3f1c2e9-0",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}'const res = await fetch("https://api.zinfra.vip/v1/deposits", {
method: "POST",
headers: {
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
"x-idempotency-key": "$IDEMPOTENCY_KEY",
"content-type": "application/json",
},
body: JSON.stringify({
"asset": "USDT",
"amount": "1500.000000",
"reference": "0xa3f1c2e9-0",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}),
});
// 金额按字符串读,别让它变成 number
const data = await res.json();import requests
res = requests.post(
"https://api.zinfra.vip/v1/deposits",
headers={
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
"x-idempotency-key": "$IDEMPOTENCY_KEY",
"content-type": "application/json",
},
json={
"asset": "USDT",
"amount": "1500.000000",
"reference": "0xa3f1c2e9-0",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
},
)
# 金额用 Decimal(str(...)),不要 float
data = res.json()req, _ := http.NewRequest("POST", "https://api.zinfra.vip/v1/deposits",
strings.NewReader(`{
"asset": "USDT",
"amount": "1500.000000",
"reference": "0xa3f1c2e9-0",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}`))
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
req.Header.Set("x-idempotency-key", "$IDEMPOTENCY_KEY")
req.Header.Set("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
// 金额字段用 string 接,不要 float64HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.zinfra.vip/v1/deposits"))
.header("x-auth-token", "Bearer $TOKEN")
.header("x-on-behalf-of", "$MEMBER_ID")
.header("x-idempotency-key", "$IDEMPOTENCY_KEY")
.header("content-type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"asset": "USDT",
"amount": "1500.000000",
"reference": "0xa3f1c2e9-0",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}
"""))
.build();
// 金额字段用 String / BigDecimal,不要 double$ch = curl_init('https://api.zinfra.vip/v1/deposits');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'x-auth-token: Bearer $TOKEN',
'x-on-behalf-of: $MEMBER_ID',
'x-idempotency-key: $IDEMPOTENCY_KEY',
'content-type: application/json',
],
CURLOPT_POSTFIELDS => <<<'JSON'
{
"asset": "USDT",
"amount": "1500.000000",
"reference": "0xa3f1c2e9-0",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}
JSON,
]);
$res = curl_exec($ch);
// 金额用 bcmath / 字符串,不要 floatval
{
"id": "dep_0xa3f1c2e9-0",
"reference": "0xa3f1c2e9-0",
"external_member_id": "u_10023",
"asset": "USDT",
"amount": "1500.000000",
"ledger_scale": 6,
"status": "credited",
"network": "BSC",
"txid": "0xa3f1c2b7d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f",
"from_address": "0x9C3f1B7a5E2d4C6b8A0f2E4d6C8b0A2f4E6d8C0b",
"to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
"replayed": true
}