更新日志
更新日志
新增了什么、改动了什么,新的排在前面,每条都注明日期。
- API
确认付款的四个错误码合并为一个
当确认付款无法在客户所选的代币和网络上开启付款时,现在只返回一个 503:
payment_method_unavailable。它取代了no_available_address、address_lease_failed、bridge_unavailable和collection_disabled。这三者描述的其实是同一种情况:该代币在该网络上当前无法接收付款,重试或改选通常就能成功。除此之外,这三个名字还描述了我们自己的内部机制,并被发送到你结账页面上买家的浏览器里。提示文案同样如此;现在无论出于哪种原因,文案都一致。
不会有任何分叉:旧的三个码从来没有对应过三种不同的处理方式。判定背后的原因仍记录在我们这边,那里才是支持团队用得上的地方。
如果你的集成按这三个旧字符串分支,请立即改用新码。它们不再被发出,也没有新旧并发的过渡期。错误信封中的
type链接跟随新名称,因此保存的旧锚点链接将无法打开。完整列表见错误码。
- API
一个转出错误码改名
目标网络无法完成转出时返回的 503,现在叫
withdrawal_network_unavailable,此前是hot_wallet_insufficient_liquidity。触发条件没有变:同一个接口、同一个 503、同一种情况——该代币在此网络上当前无法完成,换个网络或者稍后重试通常可以。变的是名字和文案:它们讲的是我们这边的转出过程,而不是你需要知道的事。
如果你的集成按旧字符串分支,现在就改。旧的码不再下发,也没有两者并行的过渡期。错误信封里的
type链接跟着新名字走,指向旧锚点的收藏链接会打不开。完整清单见错误码。
- Dashboard
控制台里的金额缩短显示
控制台里的每个金额现在都一眼扫得完,指针悬停上去看完整精度。余额列因此对得齐,不会每一行都停在不同的小数位上。
一种币显示几位小数,是按币种定的,不是一条规则套到所有币上:美元锚定的稳定币截在分位就够读,黄金锚定的 XAUT 反过来要多留几位——同样一位小数,在这两种币上值的钱差得远。账本不受影响,缩短只发生在显示这一层,底下存着的一直是完整数字。
- Withdrawals
单笔或一份名单,控制台里都是同一个对话框
转给一个收款人和转给一批收款人,以前要开两个不同的界面。现在都在同一个对话框里:进去先定这次是单笔还是一份名单,全部内容在同一屏核对完,再发出去。一组地址的审批也在这里做,不用一个一个来。
已经完成的转出可以从列表里直接再跑一遍。对固定收款人做例行付款时,早就用过、也早就批过的地址不必重新敲一次。
列表里现在显示收款人标签。这一次还能带多少个收款人,发出去之前就写在字段旁边:账户上限减掉已经在途的转出,剩下多少就是多少,不用等被拒才知道。
- API
收款通道进了八个 SDK
收款通道、它的 webhook 和充值数据流,八个官方 SDK 里现在都有:.NET、Go、Java、PHP、Python、Ruby、Rust、TypeScript。签名、重试和类型化错误都由库处理,每份 README 给的是一条跑得通的完整流程,不是一份方法清单。
数据流读取器有一点值得单说:它不会提前收手。只要轮询方把游标一直推到末尾,中途进程出过什么事都不影响,每一笔已结算的充值都恰好经过一次。
- Payment Channels
代币列表现在带最低充值额
通道返回的代币不再只是一个符号。每一项现在都带
minimum_deposit,也就是走这条线路最少要转多少才会入账。这个下限属于「代币 + 网络」这一对,不属于代币本身。同一种代币挂在不同的链上,门槛就是两个不同的数,取一个拿去到处用会出错。数值在每次读取时实时给出,请从当前这次响应里取,不要写死。
把它显示在收款地址旁边。低于下限的转账不入账,也不会自动退回。
项目那一侧同时改了:项目现在接受的是代币符号,不是「网络 + 符号」的组合。再开一条新网络,不必把每种代币重新过一遍。
- Dashboard
项目怎么接,建的时候问一次
以前是三个各自独立的开关,现在合成一个问题,建项目时问一次,五个答案里挑一个:你自己的后端调 API、付款在 Telegram 机器人里完成、由商城插件接管收银、收银员在终端当面收款,或者用低代码片段嵌在你自己的页面上。
答案定了,控制台就按这条路给你东西看。用得上的设置和上手步骤留下,用不上的不再出现。Telegram 机器人项目本来就没有托管付款页,那一页的地址自然也不会给你。
这个选择建完之后改不了。要换一种接法,就是另一个项目。
地址上还有一处改动:
/pos现在 308 跳到/terminal,收银员存过的旧书签照样打得开。 - Payment Channels
给每个付款人一组长期收款地址
账单是一次性的:写好金额,倒计时开始,付完到终点。收款通道这三样都没有。一个付款人对应一条通道,在每条支持的网络上各留一个永久地址,长期有效。地址上到账多少、什么时候到,都记成一笔充值计入你的余额。
通道用你自己的
external_id建立。付款人在你系统里原本是什么标识,这里就用什么,不必再维护一套对照表。项目标识加上这个外部标识,这一对本身就是幂等键:每次结账都调一次也没关系,重复的调用拿回同一条通道,不会多开一条。充值从一条单独的数据流里读。它只给已确认的,最早的排在前面,游标只往前走。把每次拿到的游标存下来、下一轮从那里接着读,已结算的款项就会一笔不落地经过你手里。读到空的一页不等于读完了——这条流没有结尾,存好游标接着按节奏轮询就是。
通道可以随时停用和重新启用,沙箱里能模拟一笔充值。先从创建通道看起。
- Localization
德语和西班牙语上线,六种语言到齐
收银台这次补上德语和西班牙语。土耳其语和简体中文 7月20日就已经在了,剩下的缺口这一批补齐——付款人能看到的语言现在有六种:英语、俄语、土耳其语、简体中文、德语、西班牙语。
选哪一种,由付款人这一侧决定:先看链接,再看 cookie,然后看浏览器发来的
Accept-Language,都不命中才回到英语。付款人想换一种,在页面上直接换,账单不用重开。对做欧洲和拉美市场的独立站来说,变化落在买家那一侧——付款页不再是一屏英文,德语和西班牙语买家不用靠认按钮位置来付钱。
- Checkout
账单可以直接开在 Telegram 对话里
项目的渠道现在可以选 Telegram 机器人。选了之后,这个项目开出的账单返回的不再是付款页地址,而是一条指向 Paymos 机器人的深链。
买家点开链接就进对话。先选代币,再选这笔转账走哪条网络,机器人随即给出这一组合的收款地址、一个复制按钮、一张二维码,以及这张账单还剩多少时间。不用另开浏览器,也不用在 Paymos 注册。
此后账单状态每变一次,消息都发回同一段对话。付完就退出应用的人,回头点开消息列表,看到的就是最新结果。
怎么配置,见 Telegram 收款。
- Partners
合作伙伴计划
推荐一个商户,从它产生的 Paymos 处理费里分成。四个等级从 20% 到 40%,活跃商户满 5 个、满 20 个各跳一档;最高一档按申请授予,不设门槛。
被推荐的商户每结算一张账单,分成就在结算的那一刻入账——不是按月,不是按打款周期,也不是攒够某个下限才给。交易量没有上限,佣金总额也没有。等级变化对名下全部商户生效,不只对之后推荐的那些。
佣金是从 Paymos 手续费里切出来的,不是加在上面,所以被推荐的商户付的,和任何商户付的一样。
推荐链接和当前等级见合作伙伴计划。
- Dashboard
支付数据分析
数据分析页回答三个问题:进来了多少钱、多少比例的账单付了款、付款人花了多久付。
转化率只按已成熟的账单计算——那些结果已经能观察到的账单。20 分钟前创建的账单并没有失败,把它算成未支付,只会无端拉低这个比率,让每个刚过去的小时都像一次事故。
付款耗时给的是分布,不是平均值:0–5 分钟、5–10、10–15、15–20,以及 20 分钟以上。交易额按代币、按网络、按项目拆分,每项各列前五,不是完整清单。账单活动按星期几和小时分桶,时区自选。
打开数据分析。
- Audit
特权操作的审计日志
特权操作会记录操作者、操作内容、目标、结果和时间。商户一侧和运营一侧,写在同一条日志里。
每条记录显式写出操作名——
merchant.add_whitelisted_address、operator.engage_freeze——并快照当时的操作者是谁,包括其角色。下个月的一次晋升,不会改写某个 Viewer 在三月做过的事。脱敏发生在写入时,不在读取时。密钥、令牌、哈希和签名在记录落库之前就被剥掉,所以审计日志永远不会变成日后泄露凭据的那个地方。
商户看到的是自己账户的历史,其中登录活动带设备和 IP。完整的平台日志仅限运营方——它包含其他商户的操作,任何形式的对外开放都不安全。
- Notifications
邮件与 Telegram 两条通知通道
账户和资金事件现在通过两条通道送到商户手里。每一条通知都同时是一封邮件和一条 Telegram 消息,出自同一个事件,所以接上 Telegram 是多一条投递路径,不是把邮箱静音。
资金动作都在其中——转出已创建、转出已完成——此外还有团队变更、放弃重试的 webhook 投递,以及安全那一组:开启或关闭两步验证、添加或删除通行密钥、绑定登录方式、增加或撤销白名单地址、轮换 API secret、吊销凭据。
日常类别可以自行关闭。安全类不行,也没有任何设置能把它们藏起来:转出地址被改动的通知,宁可多发一封不想收的邮件,也好过反过来。这里没有短信通道。
- API
统一的错误封装
每个失败的端点都用同一个形状回应:RFC 9457 Problem Details,以
application/problem+json返回。做程序化判断的字段是
code——一个发布之后语义永不改变的稳定字符串。title和detail写给人看,可能在版本之间被改写、补充或本地化,所以解析detail的集成,会因为一次文案修改而崩。单字段校验错误带field;多个字段同时出错时,改由errors[]数组承载逐字段的明细。type深链到该错误码在文档里的那一行,日志里一个陌生的字符串,因此变成一次点击。完整目录见 /docs/errors/codes。 - API
幂等创建
external_order_id就是幂等键。创建账单时带上它,重复调用返回已有的那张,而不是再开一张。不需要生成和保存
Idempotency-Key头,因为真正管用的那个标识,调用方手里本来就有:订单号、购物车 ID、付款参考号。新账单返回201 Created;同一个标识重放,返回200 OK和原来那张账单。转出同理,这条特性也正是在这里最值钱:重试一次转出调用,返回的是第一笔转出,而不是把钱发两次。唯一性的范围,账单按项目,转出按商户。调用方这边的网络超时,从此是可以直接重试的事,不是需要排查的事。
- API
每把凭据一份 IP 白名单
每把 API 凭据都有自己的白名单:最多 50 条,IPv4 或 IPv6,单个地址或 CIDR 段。列表为空,表示该凭据不做 IP 限制。
对 Payout 密钥来说,空列表不会持续。刚生成的 Payout 凭据在添加至少一个地址之前保持不可用,因此一把在创建当天就被偷走的密钥,没有任何地方可以调用它。Payment 密钥没有 IP 检查——它创建账单,不动资金。
修改白名单属于升级认证操作,并写入审计日志,记的是设置后的完整列表,不是差异。给一把能动钱的凭据放宽防火墙,应该留下是谁放宽的记录。
- API
分作用域的 API 密钥
凭据分两种。Payment 密钥(
pk_)创建账单、查询账单状态;Payout 密钥(rk_)创建和取消转出、查询余额。作用域检查是集中的,不按路由。访问级别在每个请求上由密钥类型推导,所以一把泄露进前端包的 Payment 密钥,无论指向哪条路径都动不了资金——请求在到达 handler 之前就被拒绝,而不是靠某条路由记得去检查。
API secret 带
sk_前缀,webhook 签名 secret 带whsec_。环境也编码在前缀里,于是pk_live_…和pk_test_…在配置文件里一眼就是两样东西,不是两串要盯着看才分得清的字符。在 开发者 → API 密钥 管理。
- Auth
两步验证
任何账户都可以开启 TOTP 两步验证(2FA):身份验证器里的 6 位验证码,每 30 秒轮换一次。
登录是其中较小的一半。较大的一半是升级认证——一份很短的操作清单,执行时当场要一个新验证码,而不是接受一个一小时前通过过 2FA 的会话。添加转出地址、删除转出地址、修改某个 API 密钥的 IP 白名单、关闭两步验证,各自是独立的作用域,为其中一项截获的验证码,授权不了另一项。
开启或关闭都会通过邮件和 Telegram 发出安全通知,不受通知偏好影响。在账户安全中配置。
- Auth
通行密钥登录
用通行密钥(passkey)登录——Face ID、Touch ID、Windows Hello,或一把硬件密钥。走 WebAuthn 和 FIDO2,流程里没有密码,因为这里从来就没有密码可被钓走。
通行密钥是一对密钥。私钥留在设备上,永远不会到我们这里;服务端保存公钥,校验签名;被签名的那个挑战值只能用一次。我们这边没有值得偷的东西,你那边也没有值得填进一个仿真登录页的东西。
一个账户可以注册多台设备,添加或删除其中任何一台,都会触发一条无法关闭的安全通知。魔法链接、Google 和 Telegram 仍然可用——通行密钥是多一条入口,不是替掉其他方式。
在账户安全中注册。
- Support
Telegram 机器人内置客服
Paymos 机器人里有一条客服对话。打开「客服」,写一条消息,它会送到平台一侧的客服手里。
这是一条对话,不是工单队列。回复回到同一个聊天里,最近的消息一直留在屏幕上;客服还没回复之前再发一条,这条不会送达——机器人会直接说明,而不是把它塞进一个没人读的积压队列。
绑定 Paymos 账户不是前提。对付款人来说,未绑定本来就是正常状态:付款卡在中途的人,没有账户也能来问自己那张账单。绑定只影响机器人里展示账户状态的那部分。
- Plugins
八个电商平台的官方插件
官方插件已发布:WooCommerce、WHMCS、OpenCart、PrestaShop、Magento 2、Shopware 6、CS-Cart 和 Easy Digital Downloads。
连接是点一下,不是复制粘贴。店铺打开一个 Paymos 标签页,商户对着自己已经选中的项目批准这次请求,插件直接拿到该项目的凭据。没有敏感信息要手动填进设置表单,存下来的值也不会再回到浏览器——一个泄露出去的插件发行包,对每个商户都是同一个,里面根本没有密钥。
订单状态来自带签名的 webhook,不来自买家跳回成功页。关掉一个浏览器标签页,不能让一笔已付款的订单丢失,所以回调是事实来源,回跳地址只是附带的便利。
八个插件的安装指南都在 /docs。
- Networks
Plasma 上线
Plasma 开始接受 USDT。它是第十三条主网网络,列表目前就到这里。
它上面只有 USDT 一种资产。一种资产会出现在某条网络的收银台上,是因为它在那里被启用了,不是因为这条链技术上能承载它——由代币注册表按网络、按代币决定,不会因为链上碰巧存在某个合约就自动推断出来。
现在十三条网络、五种资产,都在同一个创建账单的调用后面。今天接入的商户,写的请求和一月接入的商户完全一样:网络列表是数据,不是 API 的某个版本。
- API
八个语言的服务端 SDK
官方客户端已发布:TypeScript、Python、PHP、Go、.NET、Java、Ruby 和 Rust。
每个 SDK 覆盖的是完整契约,不是一个子集:账单、转出、余额、服务器时间、游标分页、错误封装、重试、请求签名和 webhook 验证。最值得交给库去做的是签名。规范化字符串、时间戳窗口、base64 HMAC,手写时都容易在细节上出错,而一个细节上的错误只会返回
401,别的线索一点没有。Webhook 验证是另一套规则下的第二个签名,所以每个验证器取的都是 JSON 解析之前的原始请求字节。传给它一个重新序列化过的 body,校验就会失败——这是对的。
仓库地址、发布标签和运行时要求见 /docs/server-sdks。
- Tokens
XAUT——用黄金结算
Ethereum 上开始接受 XAUT。它是这里第一种不是稳定币的资产,也不该当稳定币看。
一枚 XAUT 代表伦敦「合格交割」标准金锭上的一金衡盎司纯金,所以 XAUT 余额跟的是黄金,不是美元。有些商户宁可持有黄金,而不是一份美元债权——这正是它的意义。代价也在这里:余额会双向波动,这不是一枚锚定美元的代币要做的事。
机制上没有任何特殊之处。只在 Ethereum 上,同一套金额分档确认策略,同样按资产记账的余额,转出时同样走白名单。现在可接受的是四种稳定币加一种黄金资产。
- Networks
Sui 上线,只收 USDC
Sui 开始收款,上面只有 USDC 一种资产。
Sui 不是 EVM,也不是列表里任何一条链的分叉。它的地址是 32 字节,写作
0x加 64 位十六进制字符——长度是 EVM 地址的两倍,光凭这一点,商户的记录里就不会把两者搞混。它的代币模型也和 ERC20 的余额完全不同,因此充值检测走的是自己的一条路径,不是借来的。这些商户都看不到。在项目里打开 Sui,收银台上它就和其他网络并排出现;账单、webhook 和余额的行为,与任何一条网络上完全一样。
- Tokens
USD1 与 DAI
新增两种稳定币:USD1 在 Ethereum 和 Solana 上,DAI 在 Ethereum 上。
两者不是同一类工具。USD1 和 USDT、USDC 一样,由法币储备支撑。DAI 由链上的加密资产抵押,而不是银行存款——同样是一美元的计价单位,背后的支撑模式不同,余额记在哪一种上,值得看清楚。
入账时都不做兑换。一张 DAI 账单入的是 DAI 余额,转出也是 DAI,中间不绕一道 USDT,也不吃中间的价差。可接受的稳定币由此增至四种。
- Settlement
确认深度按金额分档
确认策略现在读两个输入:网络,以及账单的美元金额。同一条链上,40 美元的账单和 40000 美元的账单,不再等同样多的区块。
Ethereum 的档位是 100 美元以内 2 个确认,1000 美元以内 6 个,10000 美元以内 12 个,再往上 32 个——最浅一档约 24 秒,最深一档约六分钟。Tron 是 2、6,然后封顶在 19,即 27 个超级代表中 19 个确认的区块固化标准。Arbitrum 的 40 / 120 / 240 / 800 看着夸张,只是因为它的出块间隔不到一秒;按实际耗时算,和 Base、Optimism 相当。
有原生最终性的链不走分档。BSC 和 Polygon 在网络最终性时确认,Solana 在
finalized承诺级别确认,TON 一个区块即确认——它的每个主链区块本身就已经是终局的。确认数是配置项,只有我们调整它才会变。由它推出的时间不是:拥堵时出块更慢,所以这里的每个时间都只是估算,不是结算保证。
- Networks
Solana 上线
Solana 上线,USDT、USDC 和 USD1 都在上面结算。
Solana 数确认的方式和 EVM 链不同,平台也不假装相同。充值在
finalized承诺级别扫描,一被看到就确认——单一档位,不分金额。finalized在 Solana 上是什么意思,这里的「付款已确认」就是什么意思。充值地址是 base58 编码的 ed25519 公钥,不是
0x开头的字符串,商户自己的记录里不会把 Solana 地址错当成 EVM 地址。余额仍然按资产汇总:在 Solana 收到的 USDC 和在 Base 收到的 USDC 合成一个数字。 - Networks
Avalanche 上线
Avalanche 开始收款。USDT 和 USDC 都在 C-Chain 上结算。
地址和交易哈希是 EVM 形态。商户已经在对 Ethereum 或 Base 做对账,就不必多解析一种格式。确认这件事在这里不走金额分档:Snowman 最终性一次性替所有金额把话说定,链上报最终,充值就入账——和 BSC、Polygon 一样的单档处理,不是 Ethereum 和各 rollup 要等的分档区块数。
转出到 Avalanche 只能发往商户白名单中已有的地址。该路径的手续费和最低金额,在确认转出之前就会显示。
- Infra
多实例容错
平台现在以多实例运行。区块管道、归集 worker、webhook 投递器与 outbox 处理器,全部通过 PostgreSQL advisory lock 协调——任一时刻、任一工作负载,恰好只有一个实例是 leader。
leader 挂掉时,另一个实例在下一个轮询周期接过锁。无脑裂、无重复处理、无手动切换。Worker 按幂等设计——如果同一段区块区间因 leader 交接被处理了两次,结果与处理一次完全相同。
数据库是可变状态的唯一事实来源。内存缓存只允许用于不可变查找(代币精度、网络常量)。任何可能变化的东西都存在 PostgreSQL 里。
- Pricing
按项目的手续费策略
手续费策略现在按项目配置,不再只按商户。每笔账单的平台费在创建时计算并钉在账单上——客户在收银台看到的金额,就是链上结算的金额。
每个项目两个开关:平台费(向商户收取的百分比)与客户加价(platform fee 中加到展示金额之上、向付款人收取的百分比)。两者都设为 0,商户承担全部;加价推到 100%,客户支付全部手续费。
手续费存储在账单本身,而不是事后按充值金额重算。重算是一类我们不会有机会犯的账务 bug。
- Withdrawals
转出 watchdog 与 RBF 重广播
卡在链上的转出——gas 给低了、nonce 冲突、被 mempool 逐出——现在由专门的 watchdog 捕获并自动推进。
在 EVM 链上,watchdog 使用 replace-by-fee:一笔交易超过配置的超时仍未被打包,就用同一个 nonce、更高的 gas 价格重广播。原交易在 mempool 中被取代,操作身份不变。
广播错误被平台分类为可处理的桶:revert(由 handler 决定)、nonce 冲突(用新 nonce 重广播)、价格过低(RBF 加价)、余额不足(告警运营)。每个分类都暴露在转出状态中——不用猜哪里出了问题。
- Auth
团队与角色
邀请同事加入商户账户,不必交出主凭据。每个成员获得一个角色,展开为一组细粒度权限,在授权管道层强制——不只是在 UI 里隐藏。
转出与白名单管理默认仅 Owner 可用。Admin 可管理账单、webhook、项目与团队成员,但没有显式授权就不能动用资金。
在 设置 管理。
- Sandbox
带支付模拟的 Sandbox
完整的 sandbox 环境与生产环境并行运行。同样的控制台、同样的 API 面,独立数据库、独立签名密钥、独立 webhook 端点——边界两侧互不穿越。
在 sandbox 里可以完全不动 mainnet 就模拟一笔支付。调用模拟端点并传入阶段值(
paid、overpaid、underpay、cancel),平台会算出正确的充值金额,并触发与生产完全一致的生命周期事件。Webhook、签名、重试节奏——一切相同。意义在于:在 sandbox 通过集成测试的东西,就能在生产上线。没有「测试环境不一样」的意外。用顶栏的环境开关切换。
- Branding
品牌化收银台——你的 logo,你的颜色
- Webhooks
签名 webhook 与至少一次投递
Webhook 投递现在使用 outbox 模式。领域事件在变更业务状态的同一个数据库事务内写入 outbox——事件要么被持久记录,要么状态变更根本没发生。独立的 worker 取出事件并投递。
每个载荷都用 HMAC-SHA256 签名。签名基于原始 body 字节加上时间戳头计算,重放防护内建——接收方拒绝超过配置窗口的旧签名。密钥可在控制台按端点轮换。
投递为至少一次。重试节奏为 1 分钟、2、4、8、16、32 分钟,然后 1、2、4、8 小时——共十一次尝试,跨度约 16 小时。接收方必须按事件 ID 幂等,事件 ID 包含在载荷与
X-Webhook-Id头中。 - POS
线下门店 POS 收银终端
POS 收银终端现在是平台的一部分。一键创建账单并生成 QR 码——收银员把手机递给客户,客户扫码,款项进入商户余额。
终端页为平板和手机设计,不是桌面。大字号金额输入键盘、醒目的「付款」按钮,充值最终化后状态实时翻转为已确认。一个项目拿到一条终端地址,柜台需要几部手机或平板就在几部上打开——不用配对,也没有按设备的设置。
入口:/pos。
- API
公开商户 API
公开 REST API 进入生产环境。JSON 进,JSON 出,带 OpenAPI 规范。
凭据按商户、环境和密钥类型划分范围,所以收款密钥和出款密钥是两把够不到对方的凭据——收款密钥被打包进前端,也只能创建账单。限流按商户计数,用以 PostgreSQL 为后端的固定窗口计数器:不论调用走哪把密钥,用的都是同一份额度,也没有需要同步的边缘缓存状态。
认证管道与保护控制台的是同一条:每个端点带权限特性,归属按凭据范围校验,环境最先检查。平台拒绝用生产密钥读取 sandbox 数据,没有例外。
在 开发者 → API 密钥 管理凭据。完整文档见 /docs。
- Widget
组件构建器与实时预览
组件构建器已上线控制台。可视化地搭建付款组件——选择颜色、logo、支持的网络、默认金额、跳转行为——调整时实时预览即时更新。
URL 状态被编码进页面,配置好的组件可以作为单个链接分享。导出方式:可直接嵌入任意网站的 JavaScript 代码片段,或带显式尺寸的 iframe 以便更严格地控制布局。组件对接的是稳定的公共端点,所以我们发布内部变更不会破坏已部署的集成。
在低代码页面打开构建器。
- Architecture
CQRS 管道与编译期授权
每个命令与查询现在都流经类型化管道:Logging → Validation → Authorization → Retry → Transaction → Handler。每一步都对请求类型泛型——新增一个 behavior 只是一次 DI 注册,不是一次重构。
授权在启动时编译,而不是按请求用反射解析。每个命令带一个特性(attribute),映射到权限范围、归属校验与环境守卫。编译后的表让按请求的授权变成一次字典查找,而不是一次特性遍历。
校验最先运行,因为在坏输入碰到数据库之前拒绝它,是最便宜的失败方式。Transaction 是 handler 之前的最后一个 behavior——handler 不自己开事务,事务由外部传入。
- Payment Page
托管付款页
托管付款页今日交付。客户打开一个 URL,选择想用来付款的网络,看到地址与 QR 码,页面随充值到账实时更新。
底层实现:付款页是一个独立的 Blazor 宿主,运行自己的 SignalR 通道。客户选定网络后,平台为这张账单派生出地址,页面订阅该账单的状态更新。无轮询、无刷新、没有手动的「查询状态」按钮。
一张账单覆盖项目启用的每一条网络——开一次票,客户手上有 Tron、BSC 还是 Polygon 就用哪条结。地址由这次选择创造:选之前没有,选之后正好一个,欠款金额也就此对着这次选择定死。
地址为
/invoice/{invoice-id}。 - Dashboard
商户控制台
- Reliability
迟到支付防护——过期以链上时间为准
一笔账单只有在链的进度越过账单过期时间戳之后,才能被解决(resolve)。这在 domain 层强制——不是散落在各 handler 里的检查,而是一个一旦违反就显式失败的不变量。
为什么重要:在基于确认数的最终性下,一笔充值从链的视角可能「在」过期前落块,却被管道在过期「后」观测到——这个竞态若处理不当,会造成重复扣款或资金静默丢失。平台同时跟踪最新已处理区块与最新已最终化区块,解决动作等待两者。
测试套件里的回归测试在每次提交时反复捶打这个不变量。这里没有悄悄上线的 bug。
- Settlement
资金自动归集
到达账单专属地址的资金,现在会自动归集进热钱包,无需商户干预。归集(sweep)以后台 worker 形式运行,是平台侧操作——商户余额在充值确认的那一刻入账,而不是在归集时。
在 EVM 链上,归集分两阶段:先一笔 gas 充值交易,再执行代币转账。两笔都由平台支付。在 Tron 上,平台用自己的余额覆盖网络费,商户永远看不到 gas 这一项。失败的归集按退避重试;watchdog 会捕获卡住的任务并上报给运营。
结果:商户拿到的是一个余额,而不是一个需要维护的钱包。
- Rates
实时汇率
汇率子系统进入生产环境。加密货币兑法币、加密货币兑加密货币的换算,现在基于实时市场价,而不是过期查询结果。
主数据源是 CoinGecko,通过轮询 HTTP 池访问,带按端点的限流退避。报价在内存中缓存,TTL 很短——足以吸收收银台的取价延迟,又足够短以跟上真实行情。商户用 EUR 开票,USDT 金额在付款人选定代币和网络的那一刻定下来,随后钉在这张账单上:行情继续走,欠款金额不走。
报价过期时回退到最近的已知值;如果上游在 TTL 窗口之后仍不可用,依赖汇率的操作会显式失败,而不是按猜测值定价。
- Tokens
USDC 覆盖全部 EVM 链
我们支持的全部六条 EVM 链现在都接受 USDC:Ethereum、BSC、Polygon、Arbitrum、Optimism 与 Base。代币注册表按网络跟踪标准合约地址——不可能把原生 USDC 与跨链桥版本混淆。
商户可以在项目设置页按项目启用 USDC。每个项目有自己的可接受代币列表;计价规则按代币生效,不按项目。
- Networks
TON 上线——八条网络在线
TON 加入网络列表。加上 Tron、六条 EVM 链与 TON,平台现在通过一个 API 在八条网络上结算。
TON 的架构与 EVM 完全不同。智能合约钱包按地址部署,jetton 存在于自己的合约对中(master + 每用户钱包),最终性由每隔几秒轮换的验证人集合达成。我们的管道包含专用 TON RPC 客户端、jetton 钱包推导,以及 TON 专用的转账解析器。
TON 交易使用 Ed25519 兼容的签名路径,而不是 ECDSA 网络所用的 secp256k1 方案,同时保留与其他 Paymos 通道相同的转出地址与审计管控。
- Networks
Arbitrum、Optimism、Base 上线
三条 L2 rollup 加入网络列表:Arbitrum One、Optimism 与 Base。三者共用 EVM 管道,继承其预过滤与重组处理。
rollup 上的 gas 明显低于 L1 Ethereum,这让在 Base 或 Arbitrum 上用 USDC 结算成为低客单价场景的现实选项。确认阈值按链调优——Base 与 Optimism 在达到配置的确认深度后,按 sequencer 最终性结算。
在 项目 下按项目启用。
- Networks
Ethereum、BSC、Polygon 上线
三条 EVM 网络一起交付:Ethereum mainnet、BNB Smart Chain 与 Polygon PoS。同一条区块管道驱动三条链——链特定的最终性策略按网络插入。
充值检测通过
eth_getLogs滑动窗口执行,先用 bloom filter 对照标准代币注册表做预过滤,只抓取我们真正关心的代币日志。重组处理沿父哈希回退,标记孤立区块,并从新的分叉点重放。每条链有自己的 RPC 池,带轮询负载均衡与按端点的限流退避。新增一条 EVM 链是配置变更,不是代码变更。
- Tokens
USDT-TRC20 端到端打通
第一枚稳定币上线:Tron 上的 USDT。以 TRC20 USDT 开具的账单可被接受、按区块最终性确认并计入商户余额——归集(sweep)手续费由平台支付,不从商户结算金额中扣除。
代币精度在加载标准注册表时直接从合约读取。金额计算基于代币原生单位,绝不基于展示字符串,所以舍入误差不会从 UI 反向传播到账簿里。
- Networks
Tron 上线
第一条网络进入生产环境。USDT-TRC20 通过 Paymos 端到端结算——账单创建、充值检测、确认数跟踪、余额入账。
一笔付款需要多深的确认,取决于网络,也取决于金额——小额比大额更早结清。区块管道读取自管理的 RPC 池,带自动故障切换。充值检测基于 calldata 优先的解析器,而不是扫描所有日志——更便宜,也更可靠。
Tron 最先上线。最深一档要等区块固化,即 27 个超级代表中的 19 个确认;1000 美元以上的付款因此约一分钟达到最终性。
- Custody
转出地址管控
转出目前只能发往事先批准、由商户控制的地址。白名单为空时,转出被禁用,而不是回退到不受限制的地址。
敏感的白名单变更需要升级认证,并写入审计日志。转出请求保持幂等,重放同一个请求不会产生第二笔付款。
在事故调查期间,运营方还可以停止全部转出,或冻结某个资产与网络的组合。
- Ledger
复式记账账簿
平台上的每一笔资金变动现在都记录进复式记账账簿。充值、手续费、结算、退款、冲正——每一笔都在事务提交前与账簿另一侧配平。
借贷必须相等。校验在写入分录的同一个数据库事务内执行,所以一笔不平的账根本无法落库。商户余额与链上实况之间的漂移,是一类我们不会有机会犯的 bug。
账簿只追加。调整以引用原交易的新交易形式入账——历史保持完整,可重放。
- Architecture
领域驱动基础
核心 domain 层已就位。带私有 setter 的富模型、对每个输入都做校验的工厂方法,以及覆盖所有货币金额的值对象。
Money 是绑定到某个 token 的值对象,不是裸的 decimal。跨 token 的算术在编译期表达意图,在运行期显式失败——把 USDT 加到 TRX 上,既不能编译,也无法运行。
业务操作返回
Outcome<T, Error>,而不是抛异常。异常留给真正的 bug。可预期的失败以值的形式在管道中传递。 - Engineering
工程启动
Paymos 今日正式启动开发。技术栈为 .NET 10,宿主层使用 Blazor Server,持久层使用 PostgreSQL 与 EF Core 9,命令与查询管道使用 MediatR。
代码库分为四层——domain、application、infrastructure 与 host,严格依赖倒置。Domain 不依赖任何东西。Infrastructure 适配 application 层定义的端口。Host 负责把它们组装起来。
测试先行是规则,不是例外。CI 在每次 push 时运行完整测试套件。