API 文档与开发者指南
v1 · 正式版快速接入
在站点上接收加密支付只需三步:创建 API 密钥、登记收款钱包地址、开出第一笔订单。由于全程非托管,收款资金直接进入由您控制的钱包。
- 控制面板 → API 密钥 — 登录后在此生成密钥对(
KeyId与Secret)。Secret 仅在生成时显示一次。 - 面板 → 设置或
POST /v1/static-addresses— 登记 USDT 等代币收款所用的固定钱包地址(每个网络与资产各一个)。 - 面板 → 设置或
POST /v1/sweep-addresses— 登记归集 TRX、BNB、GRAM 等原生币收款的主钱包(归集地址)。 POST /v1/webhooks— 登记付款完成时接收通知的 URL 接口。
请求签名(HMAC)
所有 HTTP 请求均使用 HMAC-SHA256 签名。签名基于请求的原始报文体(raw bytes)计算,因此即使 JSON 字段顺序发生变化,签名依然有效。
METHOD \n PATH \n TIMESTAMP \n NONCE \n SHA256(raw_body)- X-Api-Key
- API 密钥 ID(pk_…)
- X-Timestamp
- Unix 时间戳(秒,允许服务器时钟容差)
- X-Nonce
- 唯一随机字符串(最长 128 字符,一次性)
- X-Signature
- hex(hmac_sha256(secret, canonical))
请求安全由两层保障:时间戳须落在容差窗口内,且每个 nonce 仅可使用一次。重复提交同一请求会被自动拒绝(HTTP 401)。
X-Timestamp 为 Unix 时间戳(秒),与服务器时间的偏差不得超过 300 秒。X-Nonce 每次请求唯一;已使用的 nonce 在 600 秒 内会被拒绝。
import hashlib, hmac, os, time, json, urllib.request KEY_ID = os.environ["COINZEN_KEY_ID"]SECRET = os.environ["COINZEN_SECRET"]BASE = "https://coinzen.cerceyn.com" def request(method: str, path: str, payload: dict | None = None) -> bytes: body = json.dumps(payload).encode() if payload is not None else b"" ts = str(int(time.time())) nonce = os.urandom(16).hex() canonical = "\n".join( [method.upper(), path, ts, nonce, hashlib.sha256(body).hexdigest()] ) signature = hmac.new(SECRET.encode(), canonical.encode(), hashlib.sha256).hexdigest() req = urllib.request.Request( BASE + path, data=body or None, method=method.upper(), headers={ "X-Api-Key": KEY_ID, "X-Timestamp": ts, "X-Nonce": nonce, "X-Signature": signature, "Content-Type": "application/json", }, ) with urllib.request.urlopen(req) as resp: return resp.read()权限范围
每个密钥只能调用其被授予权限范围内的接口;缺少权限时返回 403。权限范围在面板中生成密钥时选择。
| 权限范围 | 授予的能力 |
|---|---|
| invoices:read | 读取订单、余额、汇率与服务余额记录。 |
| invoices:write | 创建与取消订单、关联入账、修改服务余额设置。 |
| webhooks:read | 读取回调通知配置与投递历史。 |
| webhooks:write | 注册与停用回调通知,重新投递通知。 |
| addresses:write | 管理固定地址与归集地址。列表查询同样需要该权限。 |
addresses:read 权限。地址接口在路由层统一校验权限,因此列表查询同样需要 addresses:write。频率限制
限制按商户计算,采用一分钟滑动窗口。超出时返回 429 并附带 Retry-After 响应头。
- 常规接口 — 120 次请求 / 分钟
- 创建订单 — 30 次请求 / 分钟
幂等性
调用 POST /v1/invoices 时必须携带 Idempotency-Key 请求头;缺失时返回 422。每次请求都应生成新的唯一值。
Idempotency-Key: 7f3c1e9a4b8d42f0a1c6e5b3d9074a2e使用相同密钥重发相同请求体不会创建第二个订单:系统原样返回首次响应及其状态码。网络中断后可安全重试。
409 idempotency_key_reused。指纹由请求方法、路径与原始请求体计算——调整 JSON 字段顺序会被视为不同请求体。订单生命周期
创建订单后即进入状态机。若未指定网络与资产,订单以 selecting 状态开始。客户在支付页面选定网络与币种后,订单转入 pending 并分配收款地址。
selecting→pending,expired,cancelledpending→confirming,partially_paid,expired,cancelledconfirming→paid,overpaid,failedpaid⇄overpaid— 若客户对已付订单再次转账,金额会自动更新。
paid、overpaid、expired、cancelled 与 failed 为终态。遇到链上重组或迟到付款时,系统会自动更新状态并通过回调通知您的系统。
amount_exact 为 true 时,客户须转账与指定金额完全一致的数额,系统才能即时且无歧义地完成对账。余额支付
若您销售余额或储值,固定金额并不合适:付款方会把 5.188 抹零成 5,订单便金额不足。使用 balance_payment: true 开具订单后,实际到账即可结清订单——显示金额仅为建议,支付页也会明确告知付款方。
请依据 webhook 中的 received_amount 以及按锁定汇率计算的 received_fiat_amount 入账,而非 fiat_amount。即使订单要求 250 TRY,到账 5 USDT 时应入账的就是这 5 USDT 的价值。手续费同样按到账金额计提。
partially_paid。之后修改设置不影响已开具的订单。代币收款的地址是共享的,把付款与订单绑定的是金额。若同一网络/资产上同时有多笔余额订单,抹零后的付款无法归属;系统不作猜测——款项进入未匹配入账并触发 deposit.unmatched webhook。您可在面板中将其关联到正确订单。不能与储值订单同时使用。
回调通知
订单状态的每次变化都会推送到您登记的回调接口。每个数据包均使用 HMAC-SHA256 签名,您可据此确认数据完整且确实来自 Coinzen。
用于验证签名的 Webhook Secret(whsec_…)仅在登记回调接口时发放一次:可在控制台的回调页面获取,或从 POST /v1/webhooks 响应的 secret 字段获取。它不是 API 密钥的 Secret;后者仅用于为您发出的请求签名。重新登记同一地址会发放新的 Webhook Secret,并停用旧记录。
- X-Coinzen-Signature
- t=<unix>,v1=<hex hmac_sha256(secret, "<t>.<raw_body>")>
- X-Coinzen-Delivery
- 唯一投递 ID(UUID)
- X-Coinzen-Event
- 触发的事件名称(例如 invoice.paid)
import hashlib, hmac, time def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool: """X-Coinzen-Signature: t=<unix>,v1=<hex>""" parts = dict(p.split("=", 1) for p in header.split(",")) t, v1 = parts["t"], parts["v1"] if abs(time.time() - int(t)) > tolerance: return False expected = hmac.new( secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, v1)支持的回调事件
invoice.pendinginvoice.confirminginvoice.partially_paidinvoice.paidinvoice.overpaidinvoice.expiredinvoice.cancelledpayment.reverteddeposit.unmatchedcredit.lowcredit.exhausted
自动重试机制
首次投递在付款完成后立即进行。若您的服务器未返回 200 OK,系统会按 30 · 120 · 600 · 3600 · 21600 · 86400 秒的间隔分七级自动重试。全部重试失败后,记录转入 dead_letter 状态,可在控制台一键重新入队。
错误契约
所有错误使用统一结构。code 字段稳定,供程序判断;message 面向人阅读,内容可能变化。
{ "error": { "code": "conflict", "subcode": "order_id_exists", "message": "bu order_id zaten kullanılmış", "details": { "order_id": "A-1042" } }}subcode 字段用于细化类别码,例如以 order_id_exists 代替 conflict。请先读取 subcode,没有时回退到 code——该契约只会扩展,不会收窄。
请求未通过结构校验时(缺少字段、类型错误、数值超出范围),code 为 validation_error,details 将字段路径映射到错误类型:{"body.url": "url_scheme"}。类型用于程序匹配(如 missing、greater_than),说明文字位于 message。
| 代码 | HTTP | 含义 |
|---|---|---|
| validation_error | 422 | 填写的内容有误,请检查各字段。 |
| unauthenticated | 401 | 邮箱或密码不正确。 |
| forbidden | 403 | 您没有执行此操作的权限。 |
| not_found | 404 | 未找到相应记录。 |
| conflict | 409 | 该记录已存在。 |
| insufficient_credit | 402 | 手续费余额不足,请在控制台充值。 |
| rate_limited | 429 | 请求过于频繁,请稍候重试。 |
| unsupported_asset | 400 | 暂不支持该网络与资产组合。 |
| upstream_error | 502 | 暂时无法连接区块链服务,请稍后重试。 |
| stale_rate | 503 | 汇率报价已过期,请重新获取。 |
| amount_space_exhausted | 503 | 该地址的可区分金额已用尽,请稍后重试。 |
{"detail":"Not Found"} 表示没有任何路由匹配——即路径写错了;{"detail":"Method Not Allowed"} 表示该路径不支持所用的 HTTP 方法;意外的服务器错误则以非 JSON 响应体的 500 返回。手续费与服务余额
Coinzen 从不从客户付款中扣取手续费。USDT 及其他加密货币付款直接进入您的地址,该钱包的私钥仅由您持有。平台服务费从您预先充值的服务余额中扣减,因此收款始终足额。
- 标准费率为 1%。新开通账户前 45 天适用 0.1% 的优惠费率。当前适用费率可在
GET /v1/credit响应的fee_bps字段查看(基点:10 = 0.1%,100 = 1%)。 - 仅对成功完成的订单(
paid与overpaid)收取手续费。 - 已取消、已过期或金额不足的订单不收取任何手续费。
- 服务余额用尽时,已开订单的收款流程不受影响,正常处理;仅新建订单的请求会收到余额提示(HTTP
402)。
两步扣费模型
订单付款完成时,手续费记录立即以 pending 状态创建,不依赖任何外部服务,以免拖慢链上跟踪速度。汇率换算在后台完成后,净额从余额中扣减。
若发生链上重组导致付款回退,手续费扣减会立即作废;若已扣减,则以 reversal 记录退回余额。
服务余额充值
调用 POST /v1/credit/deposit-addresses 可获得专属的 USDT 长期充值地址。向该地址转入的资金在链上确认后即自动计入服务余额,无需人工审核或等待。
自动补足
启用后,即使服务余额归零,您的销售也不会中断。系统会将下一笔小额订单的收款直接转入服务余额,服务持续可用。
- 转入服务余额的该笔订单不再另行收取手续费。
- 出于安全考虑设有上限(默认 25 USD)。超过上限的订单不会被转入,大额订单不受影响。
- 可随时通过
PUT /v1/credit/auto接口或控制台启停,并自行设定上限。
余额提醒
服务余额低于阈值时触发 credit.low 事件,用尽时触发 credit.exhausted,让您提前知悉。
支持的区块链网络与资产
下表为正式网络注册表的摘要。如需运行时的实时清单,请调用 GET /v1/networks。
| 区块链网络 | 资产 | 小数位数 | 收款模式 | 合约地址 |
|---|---|---|---|---|
| TRON | TRX | 6 | 逐单动态地址 | 原生币 |
| TRON | USDT | 6 | 固定地址 + 唯一金额 | TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t |
| BSC | BNB | 18 | 逐单动态地址 | 原生币 |
| BSC | USDT | 18 | 固定地址 + 唯一金额 | 0x55d398326f99059fF775485246999027B3197955 |
| BSC | USDC | 18 | 固定地址 + 唯一金额 | 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d |
| TON | GRAM | 9 | 逐单动态地址 | 原生币 |
| TON | USDT | 6 | 固定地址 + 唯一金额 | EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs |
| Ethereum | USDT | 6 | 固定地址 + 唯一金额 | 0xdAC17F958D2ee523a2206206994597C13D831ec7 |
| Ethereum | USDC | 6 | 固定地址 + 唯一金额 | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |
| Solana | SOL | 9 | 逐单动态地址 | 原生币 |
| Solana | USDT | 6 | 固定地址 + 唯一金额 | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| Solana | USDC | 6 | 固定地址 + 唯一金额 | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
API 接口
| 方法 | 路径 | 功能说明 | 权限范围 |
|---|---|---|---|
| GET | /healthz | 服务健康检查 | public |
| GET | /readyz | 依赖与就绪状态 | public |
| GET | /v1/networks | 支持的区块链网络与资产 | public |
| POST | /v1/invoices | 创建收款订单 | invoices:write |
| GET | /v1/invoices | 订单列表(分页) | invoices:read |
| GET | /v1/invoices/{invoice_id} | 获取订单详情 | invoices:read |
| POST | /v1/invoices/{invoice_id}/cancel | 取消订单 | invoices:write |
| GET | /v1/rates | 获取可锁定的汇率报价 | invoices:read |
| GET | /v1/balances | 按网络与资产查询钱包余额 | invoices:read |
| GET | /v1/deposits/unmatched | 列出未匹配的入账转账 | invoices:read |
| POST | /v1/deposits/{deposit_id}/attach | 手动将入账转账关联到订单 | invoices:write |
| POST | /v1/static-addresses | 登记固定收款钱包 | addresses:write |
| GET | /v1/static-addresses | 列出已登记的固定地址 | addresses:write |
| DELETE | /v1/static-addresses/{address_id} | 释放固定地址。若该地址仍有待处理的金额占用,请求会被拒绝。 | addresses:write |
| POST | /v1/sweep-addresses | 登记原生币归集钱包 | addresses:write |
| GET | /v1/sweep-addresses | 列出已配置的归集地址。 | addresses:write |
| DELETE | /v1/sweep-addresses/{address_id} | 停用某个归集地址。 | addresses:write |
| GET | /v1/credit | 当前服务余额 | invoices:read |
| GET | /v1/credit/entries | 余额明细与变动记录 | invoices:read |
| GET | /v1/credit/deposit-addresses | 列出你的服务余额充值地址。 | invoices:read |
| POST | /v1/credit/deposit-addresses | 获取服务余额充值地址 | invoices:write |
| PUT | /v1/credit/auto | 更新自动补足设置 | invoices:write |
| POST | /v1/webhooks | 登记回调接口 | webhooks:write |
| GET | /v1/webhooks | 列出已注册的回调通知地址。 | webhooks:read |
| DELETE | /v1/webhooks/{webhook_id} | 停用回调通知地址。历史投递记录保留,不再发送新通知。 | webhooks:write |
| GET | /v1/webhooks/deliveries | 回调通知与投递记录 | webhooks:read |
| POST | /v1/webhooks/deliveries/{delivery_id}/replay | 重发失败的通知 | webhooks:write |
GET /openapi.json。未提供在线调试控制台:签名需按每个请求单独计算,浏览器直接发起的调用只会返回 401。请求结构
以下是接入首日会调用的接口请求体。全部接口的完整结构以机器可读格式发布在 GET /openapi.json,可导入 Postman 或用于生成客户端代码。
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| network | string | 是 | tron | bsc | ethereum | ton | solana | 链标识。 |
| asset | string | 是 | 2–16 | 资产符号,服务端会转为大写。 |
| address | string | 是 | 20–128 | 你自己的钱包地址,按对应链的格式校验。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| network | string | 是 | tron | bsc | ethereum | ton | solana | 链标识。 |
| address | string | 是 | 20–128 | 你自己的钱包地址,按对应链的格式校验。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| url | string | 是 | — | 接收通知的 HTTPS 地址。 |
| events | string[] | 否 | — | 订阅的事件列表。留空表示订阅全部事件。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| network | string | 否 | tron | bsc | ethereum | ton | solana | 链标识。 |
| asset | string | 否 | 2–16 | 资产符号,服务端会转为大写。 |
| allowed_assets | string[] | 否 | ≤ 32 | 提供给付款方选择的资产:USDT(全部网络)或 tron:USDT(指定网络)。 |
| amount | decimal | 否 | > 0 | 直接指定的加密资产金额,不能与 fiat_amount 同时提供。 |
| fiat_amount | decimal | 否 | > 0 | 法币金额;汇率在订单创建时锁定。 |
| fiat_currency | string | 否 | 3–8 | 法币币种代码。提供 fiat_amount 时必填。 |
| order_id | string | 否 | ≤ 128 | 你自己的订单号,在商户账户内需唯一。 |
| expires_in | integer | 否 | 60–86400 | 订单有效期,单位为秒。 |
| callback_url | string | 否 | — | 仅用于本订单的通知地址,将覆盖已注册的回调地址。 |
| return_url | string | 否 | — | 付款完成后付款方跳转的地址。 |
| locale | string | 否 | — | 收银页语言。未提供时回退到付款方的浏览器语言。 |
| balance_payment | boolean | 否 | — | 余额支付。默认 false。启用后,付款方发送的金额多于或少于显示金额,订单同样完成;webhook 报告实际到账金额。下限取自商户设置。不能与储值订单同时使用。 |
| metadata | object | 否 | — | 自定义对象,会原样出现在响应与回调通知中。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| enabled | boolean | 是 | — | 是否开启服务余额自动充值。 |
| max_amount | decimal | 否 | > 0 | 单次自动充值的上限。 |
查询参数
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| from | string | 是 | 2–16 | 源资产符号,例如 USDT。 |
| to | string | 是 | 3–8 | 目标法币币种,例如 TRY。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| status | string | 否 | — | 订单状态——取值见上文生命周期章节。 |
| network | string | 否 | tron | bsc | ethereum | ton | solana | 链标识。 |
| created_after | datetime | 否 | — | 创建时间晚于该时间点的记录。 |
| created_before | datetime | 否 | — | 创建时间早于该时间点的记录。 |
| limit | integer | 否 | 1–200 | 返回记录的最大条数。 |
| cursor | datetime | 否 | — | 分页游标:返回早于该时间的记录。请回传响应中的 next_cursor。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| invoice_id | uuid | 否 | — | 按单个订单过滤。 |
| status | string | 否 | — | 投递状态:pending、succeeded、dead_letter。 |
| limit | integer | 否 | 1–200 | 返回记录的最大条数。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| kind | string | 否 | — | 记录类型:topup、fee、reversal、adjustment。 |
| status | string | 否 | — | 记录状态:pending、applied、void。 |
| invoice_id | uuid | 否 | — | 按单个订单过滤。 |
| limit | integer | 否 | 1–200 | 返回记录的最大条数。 |
| cursor | datetime | 否 | — | 分页游标:返回早于该时间的记录。请回传响应中的 next_cursor。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| include_resolved | boolean | 否 | — | 同时返回已完成关联的入账。 |
| limit | integer | 否 | 1–500 | 返回记录的最大条数。 |
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
| include_inactive | boolean | 否 | — | 同时返回已释放的地址。 |