NEWS
新闻中心
您的位置: 首页>新闻中心>专题新闻>线上支付

支付下单接口怎么设计?订单号、金额和状态是三个关键。线上支付第三讲

2026-07-27 15:39:01
分享:

这是《线上支付 API 接入实战》第03篇。前两篇分别讲清完整支付链路和五类支付入口;这一篇进入第一次真正的系统设计:商户向支付服务方下单之前,订单号、金额和状态应该怎样管理?

一家商城刚完成支付接口联调。

测试人员点击一次“立即支付”,能够正常调起付款页面;支付后,后台也能看到交易记录。大家以为项目已经接近完成。

可一进入异常测试,问题马上出现:

  • 顾客连续点击两次,系统创建了两张支付订单;
  • 下单请求超时,前端提示失败,顾客又重新支付;
  • 商品价格已经变更,旧页面仍然提交原金额;
  • 前端显示“取消支付”,后台直接把订单改成失败;
  • 同一张业务订单更换支付方式后,多个支付记录互相覆盖;
  • 客服只有商城订单号,技术日志里却只留下支付侧交易号。

这些问题并不是接口地址写错了,而是支付订单模型没有提前设计清楚。

先说结论

支付下单接口要先守住三个关键:

此外,还要先回答一个基础问题:一张业务订单,是不是永远只对应一张支付订单?

如果这个关系没有确定,后面的重复支付、换支付方式、超时重试和退款对账都会越来越难处理。

一、先分清业务订单、支付订单和支付尝试

很多系统只有一张“订单表”,既保存商品、客户和地址,又保存支付方式、支付状态和渠道交易号。业务简单时看起来方便,交易一复杂就容易混乱。

业务订单描述真实交易内容,例如:

  • 哪位顾客购买了哪些商品或服务;
  • 商品原价、优惠和应付金额;
  • 收货、预约、缴费或服务信息;
  • 订单是否已履约、取消或售后。

业务订单解决的是“这笔生意是什么”。

支付订单描述一次与支付相关的处理记录,例如:

  • 选择了哪种支付方式和接入场景;
  • 商户向支付服务方提交了哪个订单号;
  • 本次请求金额是多少;
  • 当前处于待下单、待支付、结果未知、成功还是关闭;
  • 支付侧返回了哪个交易标识。

支付订单解决的是“这次付款怎样处理”。

顾客可能:

  • 第一次调起后主动取消;
  • 下单请求超时,稍后重新发起;
  • 从微信支付切换到支付宝;
  • 从PC二维码切换到手机网页;
  • 原支付订单已经关闭,需要重新创建。

因此,一张业务订单常常需要允许存在多次支付尝试,但最终只能接受符合业务规则的一次成功结果。

推荐至少保留这组关系:

业务订单号 → 一个或多个支付尝试 → 每个尝试对应一个商户支付订单号 → 成功后关联支付侧交易号

不是所有项目都必须使用三张数据库表,但系统必须能够表达这层关系。

二、订单号为什么不能“随便生成一个时间戳”?

商户订单号会出现在下单、查单、回调、退款、账单和客服排查等多个环节。它不是为了让页面看起来有编号,而是跨系统追踪交易的主索引之一。

支付产品通常会对商户订单号的长度、字符范围和唯一性提出要求。例如,微信支付官方下单文档明确要求商户订单号在同一商户号下唯一,并限定可使用的字符和长度。不同产品的具体规则可能不同,正式生成前必须按实际接口文档核对。

不能只保证“今天不重复”。如果支付服务方要求在某个商户或应用范围内唯一,系统就要在该范围内长期避免重复。

数据库中应设置唯一约束,不能只依赖代码先查询再插入。并发请求到达时,代码层的“先查后写”仍可能同时通过。

同一次支付尝试发生网络重试时,是否复用原商户订单号,要按实际产品的幂等和重试规则设计;不能每重试一次HTTP请求就无条件创建新订单号。

否则,下游可能已经受理第一笔,而商户系统又创建第二笔,最终形成重复支付风险。

订单号可以包含业务类型、日期或分布式序列等有助于定位的元素,但不应直接拼入手机号、身份证号、姓名、银行卡号等个人信息。

例如可使用经过统一规则生成的随机或序列标识:

P20260727A8K4M2Q7

它只用于说明格式思路,不代表任何实际接口都接受这一长度和字符组合。

多台服务器同时下单时,精确到秒甚至毫秒的时间戳仍可能碰撞。更稳妥的方式是使用数据库序列、分布式ID、随机标识或经过验证的组合规则,并配合唯一索引兜底。

外部商户支付订单号不一定要直接等于业务订单号,但内部必须保存明确映射。客服输入任意一种编号,都应能够找到业务订单、支付尝试和渠道交易记录。

三、一张业务订单,到底该复用订单号还是重新下单?

这要区分“同一次请求重试”和“新的支付尝试”。

此时不能立刻认定失败,也不应马上换新订单号重复下单。

建议流程是:

能否复用原支付订单,取决于支付侧订单是否仍有效、原调起凭证是否过期以及产品是否允许重新调起。

不要只根据前端“取消”按钮判断。必要时先查询支付侧状态。

通常应视为新的支付尝试,生成新的商户支付订单号,并关联同一业务订单。

旧尝试不能直接删除,因为后续可能还有延迟通知或账单记录到达。

关闭通常是终态。若顾客仍需要支付,应按实际接口规则创建新的支付尝试,不能强行把已关闭订单改回待支付。

四、金额为什么必须由服务端重新计算?

前端可以告诉服务端“顾客想买哪些商品、用了哪张优惠券”,但不能成为最终支付金额的权威来源。

顾客提交订单时,商户服务端至少要重新核对:

如果直接采用前端上传的金额,攻击者可能篡改请求,让高价值订单以极低金额下单。

货币计算不宜直接使用可能产生二进制精度误差的浮点数。

系统可以采用“最小货币单位整数”或可靠的十进制定点类型进行计算和存储。例如,部分人民币支付接口使用整数“分”表示金额,但实际字段名称、单位和取值范围必须以具体接口文档为准。

不要只保存一个最终金额。建议至少记录:

  • 商品原始金额;
  • 商户优惠金额;
  • 平台或渠道优惠的可识别部分;
  • 运费或服务费;
  • 订单应付金额;
  • 用户实际支付金额;
  • 后续累计退款金额。

这些金额不是在所有时点都相同,退款与对账时尤其需要区分。

商品价格以后可能变化,但已经创建的业务订单需要保留当时的价格、优惠与计算依据。

支付订单应记录本次尝试使用的应付金额快照,不能每次查询都重新读取当前商品价格。

支付成功通知并不是只检查状态。系统还要按实际产品规则核对商户、应用、订单号、币种和金额,确认它与本地支付订单一致后再进入履约。

五、商品描述和附加数据,不能代替订单表

支付下单接口通常还会提供商品描述、附加数据或自定义字段。它们有助于账单展示和通知关联,但不能承担核心订单存储职责。

描述应能代表真实商品或服务,不建议全部写成“订单支付”“测试商品”等无法区分业务的内容。

同时不要写入完整手机号、身份证号或其他不必要的个人信息。

附加字段常有长度、字符和回传条件限制。可以放内部门店标识、业务类型或简短追踪码,但关键业务状态必须以本地数据库为准。

如果系统完全依赖附加字段恢复业务信息,一旦字段未返回、被截断或格式变化,订单就可能无法匹配。

六、支付状态为什么要设计成“状态机”?

支付状态不是一个可以随意修改的文本字段。

状态机会规定:

  • 当前允许进入哪些下一状态;
  • 哪些状态属于临时状态;
  • 哪些状态属于终态;
  • 收到重复、延迟或乱序消息时如何处理;
  • 哪些状态变更必须附带交易号、时间和操作来源。

这是商户内部设计示例,不是任何支付产品的固定枚举。外部返回状态应先映射到内部状态,再按内部规则处理。

七、状态不能被“后到的旧消息”覆盖

支付系统经常同时接收:

  • 前端返回结果;
  • 下单接口同步响应;
  • 支付成功异步通知;
  • 主动查单结果;
  • 关单接口结果;
  • 客服人工处理结果。

这些消息到达顺序不一定与业务发生顺序一致。

例如,系统先通过主动查单确认支付成功,几秒后又收到此前延迟的“待支付”查询结果。如果程序直接执行“把状态更新为接口返回值”,就可能把成功订单倒退成待支付。

因此,更新状态前必须判断:

数据库更新可以加入状态条件,例如“只有当前仍为待支付或结果未知时,才能更新为成功”。具体实现取决于技术架构,但原则是:先判断状态迁移,再写数据库。

八、业务订单状态与支付状态不要混成一个字段

业务订单和支付订单关注的问题不同。

支付成功后,业务订单可能进入:

  • 待发货;
  • 待预约;
  • 待开通;
  • 履约处理中;
  • 已完成。

支付订单则记录:

  • 待支付;
  • 支付成功;
  • 已关闭;
  • 进入退款。

如果只用一个字段,容易出现“支付成功是否等于订单完成”“退款中是否等于业务取消”等争议。

推荐分别维护:

它们之间通过明确事件联动,而不是互相覆盖。

九、下单接口超时,为什么不能直接返回“支付失败”?

接口超时只说明商户在规定时间内没有拿到响应,不代表支付服务方一定没有受理。

可能出现的情况包括:

  • 请求还没有到达支付侧;
  • 支付侧已受理,但响应在网络中丢失;
  • 支付侧仍在处理;
  • 商户服务端已收到响应,但内部写库失败;
  • 前端等待超时,但服务端任务仍在继续。

正确做法不是简单返回“失败,请重试”,而是:

“结果未知”是支付系统必须承认并管理的真实状态。

十、同一张业务订单出现两笔成功,系统怎么办?

理想情况下,唯一约束、幂等控制和状态机应避免这种情况。但项目仍要准备异常预案。

一旦发现同一业务订单对应多笔成功交易,应:

不能简单删除“多出来”的支付记录。删除记录会让退款、账单和审计失去依据。

十一、支付订单表至少应该保存哪些信息?

字段名称可以按企业架构调整,但建议至少覆盖:

  • 内部支付记录ID;

  • 业务订单ID和业务订单号;

  • 商户支付订单号;

  • 支付侧交易号;

  • 本次支付尝试序号。

  • 商户、门店或项目标识;

  • 应用标识;

  • 支付渠道与产品场景;

  • 终端入口;

  • 币种。

  • 本次应付金额;

  • 用户实际支付金额;

  • 累计退款金额;

  • 金额计算版本或快照关联。

  • 内部支付状态;

  • 下单时间、失效时间、支付成功时间;

  • 最近查询时间;

  • 最近状态来源;

  • 关闭或失败原因。

  • 请求追踪号;

  • 接口版本或路由标识;

  • 必要的响应摘要和错误码;

  • 创建人与更新时间;

  • 敏感字段的脱敏、加密或访问控制信息。

日志可以帮助排错,但不应无控制地记录私钥、完整签名材料、用户敏感信息或支付凭证。

十二、准备开发前,用这12项检查订单设计

如果其中任何一项没有答案,下单接口即使已经返回成功,订单系统仍不具备稳定上线条件。

写在最后

支付下单看似只是发送订单号、金额和通知地址,真正决定系统能否稳定运行的,是接口背后的订单模型。

订单号负责追踪,金额负责准确,状态负责控制变化。三者设计清楚,后续异步通知、主动查单、退款和对账才有可靠基础。

我们整理了一份《支付订单字段与状态设计清单》,覆盖业务订单、支付尝试、编号规则、金额快照、状态机、异常重试和数据库约束。

关注“宜收宝商户助手”,回复“API”,即可领取。

提交业务类型、订单结构、支付场景和当前异常后,还可以申请一次接入评估。

下一篇预告:

《收到支付成功通知后,为什么不能马上改订单状态?》

参考依据

- [微信支付商户文档中心:《开发指引——JSAPI支付》],介绍下单、支付有效时间、关单、查单、退款及普通支付订单状态流转;
- [微信支付商户文档中心:《商户订单号查询订单》],列出商户订单号、支付侧交易号及支付状态等查询字段;
- [微信支付商户文档中心:《JSAPI/小程序下单》],说明下单后生成预支付交易会话标识;
- [支付宝开放平台:《网页/移动应用》],介绍应用创建、开发配置、审核和上线流程。

本文用于一般业务与技术信息交流,不构成对某一支付产品的完整接口说明。订单号格式、金额单位、状态枚举、重试、关单、通知与查询规则,以宜收宝实际能力、合作机构审核、最新官方文档及正式协议为准。

 

富易付
银行联合收单 · 最高支持0手续费
以支付科技赋能中小微企业
3 分钟免费诊断|1 对 1 定制你的支付+收银解决方案
覆盖零售 / 餐饮 / 校园 / 能源 / 医美 / 休闲娱乐 6 大行业
扫码加顾问|立即定制属于您的方案
扫一扫|1对1专属顾问
扫码咨询