# 支付宝支付产品代码开发校验清单

本文档整理了支付宝支付集成过程中的通用校验项，仅包含必须校验和高危项目。代码实现后、集成收口前必须逐项核对；逐项核对不等于为每项安装工具或启动运行环境，自动执行边界以 `../flow.md` 步骤 8 为准，无法自动取得证据时标记为“人工待验证”。默认按第八节摘要模板输出，用户要求明细时再展开全部逐项结果。校验结果供参考，开发者务必按照支付宝最新开放平台文档进行检查。

---

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:aipay,webpay,apppay -->
## 一、密钥与安全校验

| 校验项 | 校验要求 | 说明 |
|----------|----------|----------|
| 私钥存储位置 | 私钥不得保存在客户端代码中 | 构造交易数据并签名必须在商家服务端完成，私钥绝对不能保存在商家APP客户端中，也不能从服务端下发。商户需妥善保存私钥，不建议在代码或配置中明文写入私钥，应当通过加密配置文件或密钥管理平台进行管理 |
| 私钥日志安全 | 私钥不得出现在日志中 | 私钥的保密等级比源码高，出现在日志中将增加私钥泄露的风险 |
| 私钥仓库安全 | 私钥不得上传公共仓库 | 私钥泄露将导致应用和支付宝交互的安全性完全丧失 |
| 沙箱配置后置校验 | 沙箱 appId、应用私钥、支付宝公钥接入项目后必须完成配置准确性校验 | `sandboxConfigState=READY` 时，Unix/macOS/Linux 必须确认商家服务端加载器直接读取已验证的 `.alipay-sandbox.json`，从同一 `appIds[0]` 选择当前语言字段且不在源码、普通日志或额外 `.env` 留下密钥副本；Windows 必须确认项目实际读取值属于本次手工申领和密钥配置的同一沙箱应用。待配置时本项直接不通过，代码只能保留会在配置缺失时明确失败的加载边界，禁止占位符、示例值或其他来源密钥 |
| 用户项目文件保护 | 既有项目结构、文件和无关支付能力均保留；新项目只创建在尚不存在或为空的目录 | 检查本轮变更不存在未经独立二次确认的既有文件删除、既有文件整体覆盖，或与已确认目标产品无关的修改；新建文件不属于既有文件整体覆盖。发现违规立即判定不通过并停止后续流程 |
| 沙箱配置防提交 | Unix/macOS/Linux 快速沙箱：配置未被 Git 跟踪，项目根目录 `.gitignore` 包含精确规则 `/.alipay-sandbox.json`，配置权限为 `0600`；Windows 手工沙箱：实际敏感配置未被 Git 跟踪并具有对应忽略保护，Windows 文件访问控制能核验时仅当前用户可访问，不能核验时标记人工待验证 | 禁止私钥、沙箱账号或密码随项目进入 Git 暂存区或公共仓库；缺少适用保护时判定不通过 |
| 沙箱配置稳定定位 | Unix/macOS/Linux 项目代码从已确认的规范化项目根定位 `.alipay-sandbox.json` | 禁止依赖 `cwd`、`getcwd()`、`Directory.GetCurrentDirectory()`、`user.dir` 或 Agent 启动目录 |
| SDK 公钥/证书模式一致 | 公钥模式使用普通执行 API；证书执行 API 只在应用公钥证书、支付宝公钥证书和支付宝根证书均已配置时使用 | 禁止公钥配置模式误用证书执行 API |
| 支付校验无旁路 | 生产源码中不存在 Mock、测试或沙箱开关可触达的跳过验签、固定成功或支付校验旁路 | 沙箱与生产必须共用相同验证控制流 |

---

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:webpay,apppay -->
## 二、异步通知校验

先区分两种验收层级，再判断是否通过：

- **本地正式验收 / 本地生产参数验收模式**：允许暂时没有可公网访问的 HTTPS `notify_url`。这一层必须检查“通知处理代码是否已实现”和“支付结果是否可通过主动查询兜底确认”；公网可访问性标记为“人工待验证”，不作为阻断本地正式验收的单一条件。
- **真实生产上线**：必须具备可公网访问的 HTTPS `notify_url`，并完成验签、关键字段校验、幂等、成功响应 `success` 和补偿查询。未满足时不得判定生产就绪。

| 校验项 | 校验要求 | 说明 |
|----------|----------|----------|
| 验签必须执行 | 收到异步通知后必须先验签 | 确保通知来自支付宝 |
| 关键信息校验 | 检验 out_trade_no、total_amount、app_id、seller_id 等商户请求关键参数| 防止伪造订单、金额篡改等 |
| 交易状态判断 | 仅 `TRADE_SUCCESS` 或 `TRADE_FINISHED` 才算支付成功 | 其他状态不算支付成功 |
| 幂等处理 | 必须进行幂等处理，过滤重复的通知 | 同一笔订单可能收到多次异步通知 |
| 响应值 | 商户侧处理成功后需返回字符串 `success` | 否则支付宝会重试通知 |
| URL 格式 | notify_url 不能包含空格和 HTML 标签 | 否则可能导致通知失败 |
| 重定向 | notify_url 不能重定向 | 重定向会导致支付宝收不到 success |
| 外网可访问 | 真实生产上线时，notify_url 必须外网可访问；本地生产参数验收模式下标记为人工待验证 | 需确保支付宝服务器可访问；本地 `localhost`、局域网地址或 TLS 未就绪域名不阻塞本地正式验收 |

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:aipay,webpay,apppay -->
## 三、适用接口覆盖校验

| 校验项 | 校验要求 | 说明 |
|----------|----------|----------|
| AI 网页应用收款/AI 移动应用收款 | 已实现产品下单、交易查询、退款、退款查询、关闭交易和异步通知处理代码 | 以产品和接口文档为准；缺少本地示例不得作为省略理由。公网通知联调是否完成单独在上一节判断 |
| AI 按量付费 | 已实现 402 协议、`alipay.aipay.agent.payment.verify` 和 `alipay.aipay.agent.fulfillment.confirm` | 不使用 AI 网页应用收款/AI 移动应用收款的通用收单接口 |
| 限定范围 | 用户明确排除的适用接口已列为待办 | 存在未实现的适用接口时不得判定完整集成 |

---

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:webpay,apppay -->
## 四、支付结果处理校验

| 校验项 | 校验要求 | 说明 |
|----------|----------|----------|
| 前台同步结果防范 | 前台同步跳转结果仅作通知，**不能作为支付成功的依据** | 必须以异步通知或查询接口结果为准 |
| AI 网页应用收款回跳默认行为 | 用户未明确关闭同步回跳时，已配置项目实际 `return_url` | 地址不得包含示例域名、占位符、猜测端口或未实现路由 |
| AI 网页应用收款回跳页可用性 | 启动服务后 GET 访问精确 `return_url`，并在 Agent 具备浏览器/UI 能力时验证页面正常渲染；当前环境无法取得 UI 证据时标记人工待验证 | 不得出现 404、500、空白页、可见报错、认证循环或重定向循环；单页应用直接刷新路由也必须可用 |
| AI 网页应用收款回跳状态展示 | 先验证同步参数签名，或使用与当前用户会话绑定的服务端订单标识；再通过服务端查询或已验签通知状态展示最终支付结果 | 同步回跳参数不得直接改写订单或作为支付成功依据，不得使用可任意修改的订单号访问其他订单 |
| AI 网页应用收款关闭同步回跳 | 仅当用户已明确表示不使用同步回跳时适用；SDK 请求未传 `return_url` | 用户未明确关闭时，缺少 `return_url` 必须修复为默认同步回跳分支；关闭分支必须保留异步通知、交易查询和商户订单查询页，且沙箱提示不得声称付款后会自动返回商户网站 |
| 支付成功判断 | 仅 `trade_status` 为 `TRADE_SUCCESS` 或 `TRADE_FINISHED` 时才认定付款成功 | 其他状态不算支付成功 |
| 主动查询兜底 | 主动查询订单状态必须作为支付结果确认的兜底逻辑 | 无论异步通知是否到达，都应具备主动查询订单状态的能力，防止因网络抖动、通知延迟或丢失导致的状态不一致 |
| 未知异常处理 | 网络超时或未知异常时，必须调用查询接口确认 | 不能简单推断为成功或失败 |
| 商家资损防范 | 不依赖前台同步结果，以异步通知或查询为准 | 防止用户未付款但商家判定成功 |
| 用户资损防范 | 未确认支付结果前不要求用户再次付款 | 防止用户已付款但商家判定失败导致重复扣款 |

> AI 按量付费不使用前台同步跳转结果和异步通知作为支付成功依据，需按下一节专项校验。

---

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:aipay -->
## 五、AI 按量付费专项校验

| 校验项 | 校验要求 | 说明 |
|----------|----------|----------|
| 订单持久化 | 返回 `Payment-Needed` 前必须持久化 `out_trade_no`、`resource_id`、金额、状态、过期时间 | 付款后携带 `Payment-Proof` 回来时必须能映射回商户本地订单 |
| Payment-Proof 验证 | 收到 `Payment-Proof` 后必须调用 `alipay.aipay.agent.payment.verify` | 验证成功只代表支付宝凭证有效，不代表本地订单已完成校验 |
| 本地订单匹配 | 验付成功后必须查询本地订单并校验状态 | 防止凭证有效但商户订单不存在、过期或状态异常 |
| 资源防串 | 必须校验本地订单的 `resource_id` 与验付结果/请求资源一致 | 防止用户通过篡改资源标识获取其他资源 |
| 金额一致性 | 必须校验本地订单金额与 `Payment-Needed` 账单金额和服务定价一致；若验付接口返回金额字段，再校验实际支付金额 | 防止金额篡改或错误定价 |
| 幂等履约 | 同一订单重复携带 `Payment-Proof` 时不得重复发放资源 | 应返回历史履约结果或可重试确认结果 |
| 履约确认 | 资源生成后必须调用 `alipay.aipay.agent.fulfillment.confirm` | 确认成功后再标记订单 `FULFILLED` 并返回成功交付 |
| 自动联调成功证据 | 必须同时具备 HTTP 200、非空 `resource_id` / `resourceId`、非空 `content`、无明确业务失败，以及当前五语言示例有效的 `Payment-Validation` | 204、空体、空对象、`VERIFY_FAILED`、履约失败或异常响应头均不得判为通过 |
| 敏感过程产物 | 单次联调的临时目录/文件权限不得宽于 `0700/0600`，命令结束时立即清理 | 禁止打印 Payment-Proof 或 Payment-Validation 原始值；失败后重新执行完整联调 |
| 沙箱 serviceId | 沙箱联调的 `serviceId` 固定为 `api_mock_service_id` | 不向用户索要正式 `serviceId`，不使用其他占位符 |
| 沙箱空字段边界 | 沙箱联调中字段为空可用于排查定位，生产环境关键字段为空必须按异常处理 | 不得把沙箱容错逻辑直接迁移成生产跳过校验 |
| 生产实现完整性 | 订单持久化、本地订单匹配、金额一致性、资源防串、幂等履约、待确认状态和确认失败重试均已实际实现 | 任一关键控制仍为 TODO、注释、内存演示或伪代码时只能判定沙箱演示可测试，不得判定生产就绪 |

---

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:webpay,apppay -->
## 六、退款校验

| 校验项 | 校验要求 | 说明 |
|----------|----------|----------|
| 退款使用场景 | 所有退款业务都必须调用退款接口 | 撤销接口不能用于退款业务，撤销接口仅用于在不确定支付结果情况下对交易发起撤销 |
| 退款是否成功判断 | 退款接口返回 `fund_change=Y` 或退款查询返回 `refund_status=REFUND_SUCCESS` 才算退款成功 | 其他状态不算退款成功 |
| 退款幂等保障 | 接口未退款成功且不明确交易情况时，重试请务必保证退款请求号 out_request_no 以及请求参数一致，避免发生多次退款 | 防止多次退款 |
| 新退款与重试区分 | 每次新退款使用新的 `out_request_no`；同一次退款的异常重试复用原编号、金额和请求参数 | 新的一次部分退款不能复用其他退款编号，重试也不能临时生成新编号 |
| 退款金额计算 | 使用十进制定点金额，并在调用前校验累计退款不超过原订单实付金额 | 禁止二进制浮点误差或超额退款 |

---

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:aipay,webpay,apppay -->
## 七、上线前校验

| 校验项 | 校验要求 | 说明 |
|----------|----------|----------|
| 网关地址切换 | 五语言 A2M 示例默认沙箱网关为 `https://openapi-sandbox.dl.alipaydev.com/gateway.do`；上线时显式切换为 `https://openapi.alipay.com/gateway.do` | 禁止把生产网关复制进沙箱运行配置 |
| APPID 切换 | 使用生产环境的 APPID | 与沙箱 APPID 不同 |
| 密钥切换 | 使用生产环境的应用私钥和支付宝公钥 | 与沙箱密钥不同 |
| 生产密钥对应关系 | `appId`、应用公钥、应用私钥属于同一套生产应用密钥 | 不得混用沙箱应用、其他生产应用或另一套重新生成的密钥 |
| 生产私钥格式 | 应用私钥格式与项目语言 SDK 匹配 | Java 使用 PKCS#8；非 Java 使用 PKCS#1。格式不匹配时使用支付宝开放平台密钥工具转换 |
| AI 按量付费 serviceId 替换 | 生产配置中不得保留 `api_mock_service_id` | 上线前替换为服务市场实际返回的真实 `serviceId` |
| 证书模式 | 只有明确采用证书模式时才切换为同一生产应用的完整证书链并使用证书执行 API | 应用公钥证书、支付宝公钥证书、支付宝根证书必须同时配置；公钥模式不得调用证书执行 API |
| 产品开通状态 | 确认产品已在生产环境开通 | 沙箱无需开通，生产环境需要申请开通 |
| 私钥安全 | 私钥不在代码、日志、公共仓库中明文存储 | 使用安全的方式管理私钥 |
| 日志安全 | 日志中不打印敏感信息（私钥、用户信息等） | 防止信息泄露 |
| HTTPS 通信 | 生产环境必须使用 HTTPS | 保证传输安全 |

---

<!-- ALIPAY_AIPAY_CHECKLIST_PRODUCTS:aipay,webpay,apppay -->
## 八、代码开发结果输出

> 内部逐项判断使用以下状态：
> - ✅ 通过：已实现且符合规范
> - ❌ 不通过：未实现或不符合规范，需整改
> - ⚠️ 部分通过：部分实现，需补充完善
> - ➖ 不适用：当前集成场景不涉及此项
> - 🟡 人工待验证：当前环境无法自动取得充分证据

先按当前证据逐项判断；本轮可修复时先修复、重检，不渲染中间结果。项目稳定后按 `../flow.md` 执行唯一 `checklist-result`，由 runner 在同一次最终调用中校验 scope 并对同一项目快照执行固定 implementation audit。审计失败是阻断缺口，不能被 Agent 自报结论覆盖；可修复时先返回结构化 findings，项目变化后重新加载 checklist 阶段取得新 scope。

最终 action、完整参数和失败转移只以 `../flow.md` 步骤 8 为准，本模块不复制命令。runner 只接受最终一轮实际证据：Unix/macOS/Linux 的 `sandboxConfigState` 复用脚本终态，Windows 复用步骤 1/3 的 `READY|VERIFY_PENDING`；待配置时不重跑或读取配置，并把配置及依赖动作列为未完成。

各产品结论差异如下，对客正文只在消息目录维护：

| 产品 | checklist 内部校验事实 | 实际待办来源 |
|---|---|---|
| `AIPAY` | 通过必须绑定本轮 AI 按量付费服务端联调成功；只有完整 402、沙箱收银、Payment-Proof 重试和资源交付证据才能称沙箱测试通过 | 失败/部分通过项、人工待验证项、联调恢复动作 |
| `WEBPAY` | 未提供浏览器付款入口和完整指引时不得通过；公网 HTTPS `notify_url` 未联调只能称本地验收完成，不能称生产就绪 | 失败/部分通过项、人工待验证项、待用户体验事项 |
| `APPPAY` | 当前没有沙箱付款验证结论，不据此生成通过或失败，也不临场补充沙箱付款步骤 | 失败/部分通过项、人工待验证项 |

`failedItems`、`manualItems` 必须包含确定下一步，无对应项时传“无”。`overallResult=通过` 要求两者为“无”、`sandboxConfigState=READY`、`blockingDefectState=NONE`；“部分通过”至少有一类缺口；“未通过”必须列出失败项。`blockingDefectState` 只表示沙箱配置及其直接依赖以外的代码、安全或必要依据缺口；单纯 UI、浏览器或公网联调待验证只进入 `manualItems`。`full_process` 仅在沙箱待配置且无其他阻断，或 `READY` 且只剩非阻塞人工项时继续 Onboarding。

内部保留适用项依据；明细按实际证据输出，不维护第二份模板。同一次代码开发只渲染一次；renderer stdout 是默认收口的唯一对客正文，前后不得追加摘要、风险或待办。

---

> 📖 本文档内容整理自支付宝开放平台官方文档，如有更新请以官方文档为准。
