API 参考:账单和退款
账单相关的方法:createInvoice、getInvoices、deleteInvoice、refundInvoice。通用约定
(鉴权、外层结构、金额、spend_id)见商户 API 参考页面;
具体操作步骤见用账单收款。
createInvoice
POST /pay/api/createInvoice——权限范围 invoices,每分钟 60。
| 参数 | 类型 | 必填 | 含义 |
|---|---|---|---|
currency_type | string | 否 | crypto(默认)或 fiat |
asset | string | crypto 模式 | 要收的币种,比如 USDT。不能和 fiat 同时给 |
fiat | string | fiat 模式 | 标价用的法币(getCurrencies 里 is_fiat 的那些行) |
accepted_assets | string / array | 否 | 只在 fiat 模式下有效:付款人可以用来付的币种——逗号分隔的字符串("USDT,GRAM")或一个 JSON 数组。不给 = 全部支持的币种 |
amount | string | 是,除非设了 open_amount | 正的小数字符串:crypto 模式下是币种单位,fiat 模式下是法币单位(最多 2 位小数) |
open_amount | boolean | 否 | 扩展,只在 crypto 模式下有效:不定额——付款人在付的时候自己填(打赏和捐款)。跟 amount 互斥 |
description | string | 否 | 最多 1024 个字符,显示给付款人 |
hidden_message | string | 否 | 最多 2048 个字符,付款人付完才看得到 |
payload | string | 否 | 最多 4096 个字符的您自己的数据,会在账单和 webhook 里原样回传 |
allow_comments | boolean | 否 | 允许付款人附一条留言(默认 true) |
allow_anonymous | boolean | 否 | 允许付款人隐藏身份(默认 true) |
paid_btn_name | string | 否 | 付款后的按钮:viewItem、openChannel、openBot 或 callback |
paid_btn_url | string | 否 | 那个按钮的 http(s) URL——设了 paid_btn_name 就必须给 |
swap_to | string | 否 | 把收到的付款自动换成这个币种。尽力而为:付款时换不成的话,付款照样成功,只是没换 |
expires_in | integer | 否 | 多少秒之后账单过期,最大 2678400(31 天);省略或 0 = 使用默认有效期,请读取返回的 expiration_date |
rate_lock_seconds | integer | 否 | 扩展,只在 fiat 模式下有效:在开单时把折算汇率锁定这么长一段时间(见下) |
说明、付款后内容和按钮在审核期间或未获批准时可能对付款人隐藏,但账单金额仍可支付。
返回的结果——也就是 invoice_paid webhook 的 payload——是账单对象。它的主要字段:
- 标识和状态:
invoice_id、hash(pay_url里那个公开 ID)、status(active/paid/expired)、pay_url——您发给付款人的那条t.me链接 (bot_invoice_url、mini_app_invoice_url、web_app_invoice_url都是它的别名)。 - 金额:
amount(票面金额——法币账单上是法币单位,否则是加密货币;不定额账单没付掉之前 是null)、amount_minor,以及已付法币账单上的paid_asset/paid_amount/paid_fiat_rate——实际收的加密货币和用的汇率。 - 手续费:
fee_asset/fee_amount,在付款时确定并记录——这是您记账时的权威数字 (fee和usd_rate是已废弃的 Crypto Bot 别名)。见 费用和限额。 - 付款人:
paid_by_user_id(付款人选了匿名时是null)、paid_anonymously、comment。 - 退款(扩展):
refunded_amount/refunded_minor(累计)和refunded_at,全额退完 之后写入。 - 汇率锁定(扩展):
rate_lock_until和rate_lock_rates——记录下来的各币种汇率, 没申请锁定时是null。 - 开单时给的那些:
description、hidden_message、payload、paid_btn_name/paid_btn_url、expiration_date(expires_at是别名),以及兑换相关字段(swap_to、is_swapped、swapped_to、swapped_rate、swapped_output等等)。
错误:400 invalid_currency(asset 和 fiat 搞混了)、400 invalid_amount、
400 unknown_asset、400 unsupported_fiat、400 paid_btn_url_required,以及跟汇率锁定
有关的 400 rate_lock_fiat_only、409 ratelock_disabled、409 rate_unavailable
(某个接受的币种取不到最新汇率——重试即可)。
账单是怎么被付掉的
付款人在 Mini App 中用自己的钱包余额付款,余额充足并确认后即时完成,不收网络手续费。该选项可用时,也可用外部钱包充值支付:应用显示充值地址和付款期限,充值进入付款人自己的钱包。自动付款要求该地址收到充值、可用余额充足、无转出限制,且付款请求和账单均未过期。迟到的充值会留在付款人钱包中,并不能证明账单已付。两种方式最终都表现为正常的 paid 账单;配置 webhook URL 后还会产生 invoice_paid 事件,无需处理额外参数或字段。
法币账单的加密货币金额在付款时计算,并向上取整到所选资产的最小单位,然后从该金额扣除商户手续费。若既没有有效的锁定汇率,也取不到最新汇率,付款会失败,而不会按过时汇率结算。
给法币账单锁汇率
传 rate_lock_seconds,就会在开单时把每一个接受币种当下的汇率固定下来。锁定有效期间,
付款人看到的正是固定下来的那几个数额,付款也按固定下来的汇率折算——这段窗口里的汇率风险由您
承担。服务器会将所请求的时长调整到支持的范围内。请读取结果中的 rate_lock_until,确认实际截止时间。
锁定失效后,尚未过期的账单仍可按付款时汇率支付。若希望两个期限一致,请在支持的锁定范围内设置 expires_in,并比较响应中的 expiration_date 和 rate_lock_until。
getInvoices
GET /pay/api/getInvoices——权限范围 read。过滤条件:asset、fiat、invoice_ids
(逗号分隔)、status(active / paid / expired——expired 是扩展;active 不含已经
过了期限的账单),外加 offset / count。返回 {"items": [invoice, …]},按时间倒序。
deleteInvoice
POST /pay/api/deleteInvoice——权限范围 invoices。一个参数:invoice_id。取消一张
没付掉的账单,返回 true。错误:404 invoice_not_found、409 invoice_already_paid
——已付的账单删不掉,钱已经动了。
refundInvoice
POST /pay/api/refundInvoice——权限范围 refunds,每分钟 30。相对 Crypto Bot 的扩展:从应用余额向付款人退还实际支付的全部或部分加密货币。匿名付款也可退款,且不会暴露身份。法币账单使用 paid_asset 和 paid_amount,不会重新进行法币换算。
| 参数 | 类型 | 必填 | 含义 |
|---|---|---|---|
invoice_id | integer | 是 | 那张已付账单 |
amount | string | 否 | 退款的加密货币金额,使用原付款资产(法币账单为 paid_asset)。省略 = 退还全部未退余额。累计部分退款不得超过原付的加密货币金额 |
spend_id | string | 否 | 幂等键——请用上它,好让超时重试变成重放而不是退两次 |
返回的是更新后的账单对象,带累计的 refunded_amount / refunded_minor;账单全额退完之后
refunded_at 才写入。状态一直是 paid。平台手续费不退。即使 swap_to 已将收入换成其他资产,应用也须持有足够的原付款资产。每一次退款都会触发需要订阅的
refund_completed webhook。
错误:404 invoice_not_found、409 invoice_not_paid、409 already_refunded(没什么可退了)、
409 amount_too_big(超过还没退的余数)、409 insufficient_funds、400 invalid_amount,
以及 spend_id 那一对 409 idempotency_conflict / 409 idempotency_in_progress。
这篇文章对您有帮助吗?
谢谢反馈。