文档 / 集成

账单

一张账单对应一次购买:以法币或稳定币计价的价格、有效期,以及顾客选择后确定的支付币种和收款地址。

创建

POST/v1/invoices

请求头:Authorization(CP-HMAC)、Idempotency-Key、Content-Type: application/json。

请求体
{
  "order_id": "ORDER-1001",
  "price_amount": "49.99",
  "price_currency": "USD",
  "allowed_assets": ["USDT-TRON", "USDC-BASE", "BTC"],
  "return_url": "https://shop.example/orders/ORDER-1001",
  "expires_in_seconds": 1800,
  "metadata": { "user_id": "42", "plan": "pro" }
}
字段必填规则
order_id是1–128 个字符,在商户范围内唯一(重复将返回 409 duplicate_order)
price_amount是大于 0 的十进制字符串,小数点后最多 18 位
price_currency是USD、EUR、USDT 或 USDC
allowed_assets否最多 30 个资产 id(GET /v1/assets)。留空表示所有可用资产。账单实际采用与可用资产的交集;交集为空则返回 422 invalid_allowed_assets
return_url否https://…,用于「返回商店」按钮
expires_in_seconds否300–86 400,默认 1800(30 分钟)
metadata否最多 20 个键,键名格式 [A-Za-z0-9_.-]{1,64},值最长 500 个字符;会在账单中原样返回

响应 201:

JSON
{
  "id": "inv_x7k2…",
  "order_id": "ORDER-1001",
  "status": "created",
  "price_amount": "49.99",
  "price_currency": "USD",
  "allowed_assets": ["USDT-TRON", "BTC"],
  "checkout_url": "https://pay.coinetic.money/pay/inv_x7k2…#t=…",
  "return_url": "https://shop.example/orders/ORDER-1001",
  "expires_at": "2026-10-12T15:30:00Z",
  "created_at": "2026-10-12T15:00:00Z",
  "quote": null,
  "paid_amount": "0", "outstanding_amount": "0", "overpaid_amount": "0",
  "refunded_amount": "0", "refundable_amount": "0",
  "payments": [],
  "metadata": { "user_id": "42", "plan": "pro" },
  "livemode": true
}
  • price_amount 以规范形式返回,去掉末尾的零:传入 "3.00" 会返回 "3"。请按十进制数比较金额,不要用 float,也不要逐字节比较。
  • checkout_url 在 # 之后包含支付页面的令牌。请勿将其写入日志或公开。
  • livemode: false 表示沙盒账单。生产环境的商店应拒绝此类账单。

哪些资产会出现在账单中

资产可用的条件是:Coinetic 已启用该资产,您在该网络上有有效的收款钱包,并且您没有在后台(「设置」→「可支付资产」)中将其排除。每种资产都有最低金额(GET /v1/assets 中的 min_amount):如果账单金额折算成该资产后低于最低金额,该资产就不会出现在账单中。例如:BTC = 60 000 USD 时,一张 3 USD 的账单折合 5 000 聪,而最低金额为 10 000 聪,因此这张账单只会提供稳定币。

selectable_assets 字段列出 allowed_assets 中当前可以选择的资产;支付页面只展示这些资产。

幂等性

  • Idempotency-Key:8–128 个可打印 ASCII 字符,不含空格,且不能以 d: 开头。建议基于订单号生成,例如 order-ORDER-1001。
  • 相同的键和相同的请求体,返回相同的响应(同一张账单)。
  • 相同的键但请求体不同,返回 409 idempotency_conflict。
  • 首次请求仍在处理中,返回 409 idempotency_in_progress,请一秒后重试。
  • 因业务规则被拒绝的结果(例如 422)同样会被记住。

查询

GET/v1/invoices/{id}

顾客选择币种后,账单中会出现 quote:

quote
{
  "asset_id": "USDT-TRON", "network": "tron", "token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "address": "TX…", "amount_due": "49990000", "decimals": 6, "display_amount": "49.99",
  "payment_uri": "tron:…", "rate": "1", "rate_valid_until": null,
  "network_warning": "请仅通过 TRON 网络(TRC-20)发送 USDT…"
}

payments 为付款列表:tx_hash、amount(以最小单位计)、confirmations、required_confirmations、state(mempool、included、confirmed、reorged、replaced、failed、dropped)。

unmatched_payments 为转入账单地址但未计入的转账:来自其他 EVM 网络(wrong_network),或使用了不在白名单中的代币(token_not_whitelisted)。它们不会改变账单状态和 paid_amount。

列表

GET/v1/invoices?status=paid&from=…&to=…&limit=50&cursor=…

响应:{ "items": [...], "next_cursor": "…" | null },按从新到旧排序,limit 取值 1–200。

状态

状态含义商店应如何处理
created账单已创建,尚未选择币种等待
awaiting_payment已选择币种并分配地址等待
detected链上已看到付款(内存池)显示「已检测到付款」,不要发货
confirming已打包进区块,确认数尚未达到要求显示进度,不要发货
paid已足额支付并确认完成订单
overpaid支付金额超出应付金额完成订单;多付部分可按需退款
underpaid已确认金额少于应付金额(扣除容差后)请顾客向同一地址补付
expired已过期,未收到付款提供新账单(见下文)
late_payment付款在过期后才到账由您决定:完成订单或退款
manual_review付款正在接受 AML 审查等待审查结果;不要发货
refunded、cancelled已关闭不要发货
核心规则仅当通过 GET /v1/invoices/{id} 获取到 paid 或 overpaid 状态时才完成订单。

过期后使用稳定币付款

以 USD 计价的账单用 USDT 或 USDC 支付不存在汇率风险,因此过期后(30 天内)的付款会被自动计入:已收到 invoice.expired 的账单会变为 paid,并发送带有 data.late: true 的 invoice.paid。因此,请不要因为 invoice.expired 就不可逆地关闭订单。对于波动性资产,此类付款会进入 late_payment 状态。

金额与汇率

  • 价格以账单币种设定。顾客选择支付币种时,Coinetic 会锁定对应的加密货币金额。
  • 与计价币种对应的稳定币(USD 账单使用 USDT):按 1:1 计算,金额在账单有效期内固定不变。
  • 波动性资产(BTC、ETH 等):取 Kraken、Coinbase 和 Bitstamp 汇率的中位数,锁定 20 分钟。
  • amount_due 以资产的最小单位表示(TRON 上的 USDT 为 6 位小数:"49990000" = 49.99)。display_amount 是同一金额的常规写法。
  • 少付容差(默认 0.5%)用于覆盖钱包的舍入误差。

参考汇率:GET /v1/rates?base=BTC&quote=USD。请不要据此向顾客展示“精确”的加密货币金额:只有账单给出的金额才具有约束力。