API 文档与开发者指南

v1 · 正式版

快速接入

在站点上接收加密支付只需三步:创建 API 密钥、登记收款钱包地址、开出第一笔订单。由于全程非托管,收款资金直接进入由您控制的钱包。

  • 控制面板 → API 密钥 — 登录后在此生成密钥对(KeyId 与 Secret)。Secret 仅在生成时显示一次。
  • 面板 → 设置或 POST /v1/static-addresses — 登记 USDT 等代币收款所用的固定钱包地址(每个网络与资产各一个)。
  • 面板 → 设置或 POST /v1/sweep-addresses — 登记归集 TRX、BNB、GRAM 等原生币收款的主钱包(归集地址)。
  • POST /v1/webhooks — 登记付款完成时接收通知的 URL 接口。
API 密钥的 Secret 在服务端加密存储,出于安全考虑仅在创建时显示一次。若遗失,可在控制台生成新密钥并一键停用旧密钥。

请求签名(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 秒 内会被拒绝。

Python 签名请求客户端示例
PYTHON
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, cancelled
  • pending → confirming, partially_paid, expired, cancelled
  • confirming → paid, overpaid, failed
  • paid ⇄ 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 的价值。手续费同样按到账金额计提。

结清订单所需的最小金额是商户设置,并在开具订单时写入订单。商户若未设定自己的数值,则沿用通用设置(默认为应付金额的 25%);两者均可在面板修改。低于下限的付款保持 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)
Python 回调验签示例
PYTHON
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.pending
  • invoice.confirming
  • invoice.partially_paid
  • invoice.paid
  • invoice.overpaid
  • invoice.expired
  • invoice.cancelled
  • payment.reverted
  • deposit.unmatched
  • credit.low
  • credit.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_error422填写的内容有误,请检查各字段。
unauthenticated401邮箱或密码不正确。
forbidden403您没有执行此操作的权限。
not_found404未找到相应记录。
conflict409该记录已存在。
insufficient_credit402手续费余额不足,请在控制台充值。
rate_limited429请求过于频繁,请稍候重试。
unsupported_asset400暂不支持该网络与资产组合。
upstream_error502暂时无法连接区块链服务,请稍后重试。
stale_rate503汇率报价已过期,请重新获取。
amount_space_exhausted503该地址的可区分金额已用尽,请稍后重试。
有三种响应不使用该结构:{"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。

区块链网络资产小数位数收款模式合约地址
TRONTRX6逐单动态地址原生币
TRONUSDT6固定地址 + 唯一金额TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
BSCBNB18逐单动态地址原生币
BSCUSDT18固定地址 + 唯一金额0x55d398326f99059fF775485246999027B3197955
BSCUSDC18固定地址 + 唯一金额0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d
TONGRAM9逐单动态地址原生币
TONUSDT6固定地址 + 唯一金额EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs
EthereumUSDT6固定地址 + 唯一金额0xdAC17F958D2ee523a2206206994597C13D831ec7
EthereumUSDC6固定地址 + 唯一金额0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
SolanaSOL9逐单动态地址原生币
SolanaUSDT6固定地址 + 唯一金额Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
SolanaUSDC6固定地址 + 唯一金额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 或用于生成客户端代码。

POST /v1/static-addresses
字段类型必填约束说明
networkstring是tron | bsc | ethereum | ton | solana链标识。
assetstring是2–16资产符号,服务端会转为大写。
addressstring是20–128你自己的钱包地址,按对应链的格式校验。
POST /v1/sweep-addresses
字段类型必填约束说明
networkstring是tron | bsc | ethereum | ton | solana链标识。
addressstring是20–128你自己的钱包地址,按对应链的格式校验。
POST /v1/webhooks
字段类型必填约束说明
urlstring是—接收通知的 HTTPS 地址。
eventsstring[]否—订阅的事件列表。留空表示订阅全部事件。
POST /v1/invoices
字段类型必填约束说明
networkstring否tron | bsc | ethereum | ton | solana链标识。
assetstring否2–16资产符号,服务端会转为大写。
allowed_assetsstring[]否≤ 32提供给付款方选择的资产:USDT(全部网络)或 tron:USDT(指定网络)。
amountdecimal否> 0直接指定的加密资产金额,不能与 fiat_amount 同时提供。
fiat_amountdecimal否> 0法币金额;汇率在订单创建时锁定。
fiat_currencystring否3–8法币币种代码。提供 fiat_amount 时必填。
order_idstring否≤ 128你自己的订单号,在商户账户内需唯一。
expires_ininteger否60–86400订单有效期,单位为秒。
callback_urlstring否—仅用于本订单的通知地址,将覆盖已注册的回调地址。
return_urlstring否—付款完成后付款方跳转的地址。
localestring否—收银页语言。未提供时回退到付款方的浏览器语言。
balance_paymentboolean否—余额支付。默认 false。启用后,付款方发送的金额多于或少于显示金额,订单同样完成;webhook 报告实际到账金额。下限取自商户设置。不能与储值订单同时使用。
metadataobject否—自定义对象,会原样出现在响应与回调通知中。
PUT /v1/credit/auto
字段类型必填约束说明
enabledboolean是—是否开启服务余额自动充值。
max_amountdecimal否> 0单次自动充值的上限。

查询参数

GET /v1/rates
字段类型必填约束说明
fromstring是2–16源资产符号,例如 USDT。
tostring是3–8目标法币币种,例如 TRY。
GET /v1/invoices
字段类型必填约束说明
statusstring否—订单状态——取值见上文生命周期章节。
networkstring否tron | bsc | ethereum | ton | solana链标识。
created_afterdatetime否—创建时间晚于该时间点的记录。
created_beforedatetime否—创建时间早于该时间点的记录。
limitinteger否1–200返回记录的最大条数。
cursordatetime否—分页游标:返回早于该时间的记录。请回传响应中的 next_cursor。
GET /v1/webhooks/deliveries
字段类型必填约束说明
invoice_iduuid否—按单个订单过滤。
statusstring否—投递状态:pending、succeeded、dead_letter。
limitinteger否1–200返回记录的最大条数。
GET /v1/credit/entries
字段类型必填约束说明
kindstring否—记录类型:topup、fee、reversal、adjustment。
statusstring否—记录状态:pending、applied、void。
invoice_iduuid否—按单个订单过滤。
limitinteger否1–200返回记录的最大条数。
cursordatetime否—分页游标:返回早于该时间的记录。请回传响应中的 next_cursor。
GET /v1/deposits/unmatched
字段类型必填约束说明
include_resolvedboolean否—同时返回已完成关联的入账。
limitinteger否1–500返回记录的最大条数。
GET /v1/static-addresses
字段类型必填约束说明
include_inactiveboolean否—同时返回已释放的地址。
API 文档与开发者指南 · Coinzen