关于 integrate-hosted-payment-pages
这是一个指导开发者集成 Payroc Hosted Payment Page 的技能,覆盖一次性销售、预授权和重复扣款。它以本地参考文件为字段、枚举和 API 形状的依据,并包含可选的后台验证 Webhook 指引。
主要功能
- 01集成 Hosted Payment Page 支付流程
- 02处理销售与预授权
- 03配置保存卡片及重复扣款
- 04参考本地 API 模式和字段说明
- 05实现可选后台验证 Webhook
适用场景
- 01为网站接入 Payroc 托管支付页
- 02先授权后调用捕获 API
- 03保存卡片并设置订阅扣款
- 04验证服务器到服务器通知
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ payroc/ skills --skill integrate-hosted-payment-pages安装后在 Claude Code 中输入/integrate-hosted-payment-pages确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/_sources.mdapi-schema.mdauthenticate-your-requests.mdbuild-receipt-page.mderror-response-format.mdidentity-call.mdimplement-background-validation.mdload-hosted-payment-page.mdpre-auth.mdrecurring.mdrepeat-payments-api-schema.mdsale.mdreferences/save-payment-details/authenticate-your-requests.mdbuild-receipt-page.mdload-hosted-payment-page.md详细介绍
# Payroc Hosted Pages 集成
范围:CNP(无卡支付)Hosted Pages — 单次销售交易、预授权,以及定期计费(在 Hosted Page 上保存客户的银行卡,然后通过 Payroc 的网关订阅或您自己的商户发起扣款进行重复扣款)。
版本检查(请先执行)
在发布任何通知或开始流程之前,请确认此技能为最新版本:
- 从上方 frontmatter 的
metadata.version字段读取此技能的版本。 - 获取已发布的副本并读取其
metadata.version:https://raw.githubusercontent.com/payroc/skills/main/plugins/payroc/transaction/skills/integrate-hosted-payment-pages/SKILL.md - 将两个版本按语义化版本进行比较:
-
此版本 >= 已发布版本 → 静默继续,不发送消息。(开发者运行尚未发布的较新版本是预期情况,且没有问题。)
-
此版本 < 已发布版本 → 告知开发者:
⚠️ 此技能已发布较新版本(v<published>)——您正在运行 v<current>。建议升级以获得最佳效果。
然后询问他们是要继续使用当前版本,还是先停止并升级,并遵从他们的选择。
-
无法获取(离线、网络错误、404)→ 简要说明无法验证版本,然后继续。
-
首次调用时,向开发者说明:
Payroc Hosted Pages 集成 我将指导您完成从凭据设置到成功执行 UAT 测试交易的全过程。 本指南涵盖通过 Payroc Hosted Payment Page 进行的无卡支付——销售交易、预授权(现在冻结资金,稍后请款),以及定期计费(保存银行卡以供日后使用,然后按计划或按需扣款)。
HPP 的工作原理(分为三个部分):
- 您的结账流程向 Payroc 的 HPP 端点提交 POST 请求——这会加载支付页面
- 客户在 Payroc 托管的页面上完成付款(或保存银行卡)
- Payroc 将客户的浏览器重定向回您的收据 URL,并在查询参数中附加交易详情
注意:还有一个可选的 Background Validation webhook——Payroc 服务器向您配置的单独 URL 发送的服务器端 POST 请求。这是扩展步骤,不属于上述主要流程。
HPP 与 Hosted Fields: 如果您需要将银行卡输入控件嵌入自己的表单,且不进行页面重定向,则应使用 Hosted Fields——这是本技能未涵盖的另一款产品。如果开发者似乎在询问嵌入式银行卡表单,请指出这一点。
[如果有可用的 MCP 连接检查工具,请在此处运行并在继续之前展示结果。]
快速参考
实施任何 REST API 调用(请款、订阅、MIT 付款)时,请阅读
references/identity-call.md,了解 Bearer 令牌交换详情。不要猜测身份端点 URL、标头名称或响应结构——只能使用参考文档中说明的内容。
# Identity service (Bearer token — used for REST APIs: capture, repeat payments)
# UAT/test: identity.uat.payroc.com · Production: identity.payroc.com (note: UAT has the .uat segment, prod does not)
POST https://identity.uat.payroc.com/authorize
x-api-key: <api-key>
# Hosted Payment Page — sale (form POST, loads the payment page)
POST https://payments.uat.payroc.com/merchant/paymentpage
Content-Type: application/x-www-form-urlencoded
# Hosted Payment Page — pre-auth (form POST)
POST https://payments.uat.payroc.com/merchant/preauthpage
# Hosted Payment Page — save a card / tokenize (form POST; ACTION=register|update)
POST https://payments.uat.payroc.com/merchant/securecardpage
# Capture API (pre-auth only)
POST https://api.uat.payroc.com/v1/payments/{uniqueRef}/capture
Authorization: Bearer <token>
Content-Type: application/json
# Repeat payments — gateway path (Bearer token)
POST https://api.uat.payroc.com/v1/processing-terminals/{terminalId}/payment-plans
POST https://api.uat.payroc.com/v1/processing-terminals/{terminalId}/subscriptions
# Repeat payments — your-own-software / MIT path (Bearer token; paymentMethod.type=secureToken)
POST https://api.uat.payroc.com/v1/payments
参考资料
所有值和结构都位于下方本地 references/ 文件中——本技能只依据这些文件生成内容,不依赖实时查询,也不依赖记忆。这里有三个互补的信息来源,各自负责不同类型的问题——对问题使用错误的信息来源是已知的失败模式:
如果你的问题是“捕获 API 请求正文是什么样的,以及会返回哪些 transactionResult 值?”——请查阅 references/api-schema.md。如果你的问题是“要设置订阅或使用已保存的令牌执行商户发起扣款,需要哪些端点/字段/枚举?”——请查阅 references/repeat-payments-api-schema.md。如果你的问题是“HPP 表单 POST 中需要哪些字段,哈希计算方法是什么?”——请查阅 HPP 说明文档(保存卡片流程请查阅 save-payment-details/ 下的副本)。如果你的问题是“回执回调可以携带哪些 RESPONSECODE 值?”——销售/预授权请查阅 references/build-receipt-page.md,保存卡片请查阅 references/save-payment-details/build-receipt-page.md(不要依赖记忆中的列表,即使本技能列举了示例也一样)。
| 来源 | 本地文件 | 用途 |
|---|---|---|
| API 架构参考 | references/api-schema.md | 交易 API、transactionResult 架构,以及任何 Payroc REST API 字段/枚举 |
| 错误响应格式 | references/error-response-format.md | 错误封装(RFC 7807)+ Payroc errors[] + 标准错误类型目录 |
| 重复付款 API 架构 | references/repeat-payments-api-schema.md | Secure Tokens、Payment Plans、Subscriptions 端点/枚举;Payments secureToken + standingInstructions(MIT) |
| 身份验证(HMAC 字段顺序、AMOUNT/DATETIME 格式) | references/authenticate-your-requests.md | Sale/预授权哈希方案——权威来源 |
| 加载托管支付页面(POST 字段 + 枚举) | references/load-hosted-payment-page.md | Sale/预授权 HPP 表单 POST 字段名称和可接受的枚举值——权威来源 |
| 构建收据页面(RESPONSECODE 枚举 + 收据回调字段) | references/build-receipt-page.md | Sale/预授权收据回调查询参数——RESPONSECODE 值及其他收据字段的权威来源 |
| 保存卡片——身份验证 | references/save-payment-details/authenticate-your-requests.md | 保存卡片(注册/更新)哈希方案——权威来源(不含 AMOUNT;使用 MERCHANTREF + ACTION) |
| 保存卡片——加载页面 | references/save-payment-details/load-hosted-payment-page.md | 保存卡片表单 POST——securecardpage 端点、ACTION、STOREDCREDENTIALUSE(大写)——权威来源 |
| 保存卡片——收据 | references/save-payment-details/build-receipt-page.md | 保存卡片收据回调——CARDREFERENCE、STOREDCREDENTIALTXTYPE、A/E14/E43/E44 RESPONSECODE 枚举——权威来源 |
| Sale 流程(步骤 2–4) | references/sale.md | Sale 流程(读取上述叙述性副本以核验字段/枚举) |
| 预授权流程(步骤 2–4) | references/pre-auth.md | 预授权流程(读取叙述性副本 + api-schema.md 以了解 capture) |
| 定期付款流程(保存卡片 + 重复付款) | references/recurring.md | 定期付款流程(读取 save-payment-details/ 副本 + repeat-payments-api-schema.md) |
| 后台验证 | references/implement-background-validation.md | Webhook 验证流程 |
| Bearer 令牌交换(REST API 调用) | references/identity-call.md | 身份服务端点 URL、x-api-key 标头、响应结构——capture + 订阅身份验证的权威来源 |
这些是本技能的本地快照,也是权威来源。其源 URL 和最后同步日期记录在 references/_sources.md 中——如果内容看起来已过时,请从那里重新生成。
核心原则
- 先检查,再提问 — 提问前先阅读代码库;利用查到的信息跳过显而易见的问题,并提出有针对性的问题。
- 先提问,再编码 — 编写实现代码前,通过提问了解未知事项;错误的假设会浪费开发者的时间。
- 先验证,再推进 — 在开发者确认当前步骤的检查点通过 UAT 前,不要进入下一步。
- 阅读参考资料,不要猜测——并为问题选对参考资料。 HPP 有 三个 源信息面,而非两个——针对问题使用了错误的参考资料,就会让记忆中看似正确、实际错误的值混入内容。第 1 步的哈希规则已经严格遵守了这一原则;请将其推广到其他每一步。
- HPP 表单 POST 和收据回调(PAYMENTMETHOD、RESPONSECODE、AMOUNT/DATETIME 格式、哈希字段顺序)→ HPP 说明文档副本。 这些内容属于表单 POST 信息面,
references/api-schema.md中没有。references/authenticate-your-requests.md、references/load-hosted-payment-page.md、references/build-receipt-page.md这几个说明文档副本是权威来源。输出表单 POST 字段或根据收据回调值进行分支判断前,先阅读相关说明文档副本。 - Capture API 及其他 Payroc REST API 信息面 →
references/api-schema.md;重复付款 REST 信息面 →references/repeat-payments-api-schema.md。 预授权的 capture 端点、transactionResult架构(包括完整的responseCode和status枚举值)位于api-schema.md中。Secure Tokens / Payment Plans / Subscriptions 端点以及 Payments 的secureToken+standingInstructions结构位于repeat-payments-api-schema.md中。字段名、枚举值、必填字段、请求/响应结构。 - 保存卡片流程是销售流程的同级流程,不是销售流程加一个字段。 它的端点(
/merchant/securecardpage)、哈希规则(TERMINALID:MERCHANTREF:DATETIME:ACTION:SECRET— 不含 AMOUNT,使用 MERCHANTREF + ACTION)、表单字段(ACTION、STOREDCREDENTIALUSE)、收据字段(CARDREFERENCE、STOREDCREDENTIALTXTYPE)以及收据RESPONSECODE枚举(A/E14/E43/E44)都有所不同。请从references/save-payment-details/中查阅;切勿原样套用销售流程的规则。 - 不同信息面中,储存凭证使用方式的大小写不同。 HPP 表单 POST 使用大写
STOREDCREDENTIALUSE(RECURRING);REST API 使用小写mitAgreement/processingModel(recurring)。请根据所在信息面使用相应大小写。 - 订阅依赖于预先创建的付款计划和安全令牌。 在网关流程中,先创建 Payment Plan,再创建将计划关联到令牌的 Subscription(令牌是 HPP
CARDREFERENCE)。计划尚不存在时,不要 POST 订阅。 - 步骤顺序、验证模式 → 流程文件。 何时调用验证端点、以何种顺序验证 webhook 签名、收据重定向如何与后台验证配合、保存卡片→重复付款的顺序。流程文件(
sale.md、pre-auth.md、recurring.md)涵盖流程;api-schema.md/repeat-payments-api-schema.md涵盖 JSON-API 侧的值;HPP 说明文档副本涵盖表单 POST 侧的值。 - 请求和响应架构并不相同 — 需要响应结构(例如 capture 响应、订阅响应)时,请单独查阅,不要从请求架构推断响应结构。
- 不要类比推断枚举值。 看似合理但不在文档枚举中的字符串会导致 API 错误。第 1 步中“不要使用训练知识中的任何算法名称”这一要求适用于所有值 —
PAYMENTMETHOD、RESPONSECODE分支、transactionResult.status、capture 响应代码等,不只是哈希规则。
- HPP 表单 POST 和收据回调(PAYMENTMETHOD、RESPONSECODE、AMOUNT/DATETIME 格式、哈希字段顺序)→ HPP 说明文档副本。 这些内容属于表单 POST 信息面,
- 逐个值先查阅,再输出。 输出任何 POST 字段枚举值(
PAYMENTMETHOD、国家、语言)、任何RESPONSECODE分支、任何 capture API 枚举(transactionResult.status、transactionResult.responseCode)或任何哈希输入字段名之前,先阅读相关本地参考资料(表单 POST 值请查阅 HPP 说明文档副本;capture 和transactionResult请查阅references/api-schema.md)。不要将本技能中的示例(例如表示批准的RESPONSECODE=A、表示拒绝的RESPONSECODE=D)视为完整列表——它们只是示例,并非权威清单。参考资料记载了完整列表;不阅读参考资料,就无法知道完整列表。 - 绝不硬编码凭证 — 终端 ID、密钥和 API 密钥必须来自环境变量或密钥管理器,不得写入源代码。
- 先诊断,再继续 — 如果某个步骤失败,请暂停,并先根据错误分类法排查。
初步了解
首先,扫描代码库。 查找:
- 服务端使用的语言和框架
- 现有的结账、订单或支付相关路由和处理程序
- 任何部分实现的 HPP(哈希函数、向支付 URL 提交表单、收据端点)
- 环境变量或配置的管理方式
- 订单或交易的标识方式(以便了解 ORDERID 策略)
利用你发现的信息,避免询问可以推断出的内容,并用开发者自己的术语提出后续问题。然后询问仍需了解的信息——不要想当然。
在继续之前,至少要得到以下三个路由问题的答案:
问题 1 — 集成类型:
| Hosted Pages(托管页面) | Hosted Fields(托管字段) | |
|---|---|---|
| 客户体验 | 客户会暂时离开你的网站,在 Payroc 托管页面上付款,然后返回 | 客户始终留在你的网站上——Payroc 卡片输入控件嵌入你自己的表单中 |
| 你的收据页面 | 接收带有查询参数的浏览器 GET 重定向 | 完全不同的流程 |
| 本技能 | ✓ 此处涵盖 | 阶段 2 — 尚未涵盖 |
- Hosted Pages → 继续使用本技能
- Hosted Fields → 尚未涵盖;说明其中的区别,并提出改用 Hosted Pages 继续,或停止
问题 2 — 定期扣款 / 保存卡片: 此集成是否需要保存客户的卡片以供后续使用,或进行定期 / 订阅 / 分期付款?
-
否 → 继续使用下方的一次性 CNP 流程(销售和/或预授权)。
-
是 → 这是定期扣款流程,分为两个阶段:在 Hosted Page 上保存卡片(令牌化 → 获取
CARDREFERENCE),然后进行重复付款。询问他们想采用哪种重复付款方式:- 使用 Payroc 的网关 — Payroc 保存计划并收取付款(Payment Plans + Subscriptions)。适合希望由 Payroc 管理账单周期的情况。
- 使用他们自己的软件 — 他们的系统使用已保存的令牌安排并执行每笔商户发起的扣款(
POST /payments,其中paymentMethod.type: secureToken)。适合他们已有账单逻辑的情况。
如果涉及定期扣款,下面的步骤 1–3 将变为保存卡片方案,并新增步骤 5 — 设置重复付款。到达步骤 1 时,阅读
references/recurring.md。
问题 3 — 交易类型: 此集成是否需要预授权(现在冻结资金,稍后扣款)、标准销售(立即授权并扣款),或两者都需要?
- 仅销售 → 继续使用下方的标准流程
- 预授权或两者都需要 → 注意,收据处理程序之后需要额外的 Capture 步骤,并确认商户账户支持预授权(双重定价、附加费计划或便利费均不支持)。到达步骤 2 时,除标准步骤外,还要阅读
references/pre-auth.md。
确认以上三项需求后,继续阅读“先决条件”。
前置条件
这些条件是运行和测试 UAT 集成所需的,不是编写代码所需的。如果开发者已经具备这些条件,那很好。如果没有,也不要停下:让代码从环境变量读取各项值(并从配置读取回执 URL),然后继续开发。开发者可以在测试前补齐所有信息。
- 终端 ID — Payroc Integrations 团队分配的 UAT 终端 ID。UAT 是 Payroc 的测试环境;凭据由团队手动提供(没有自助注册)。
- 终端密钥 — 在 Self-Care Portal 中为该 UAT 终端创建。
- 回执 URL — 应用中的一个 URL,Payroc 的 HPP 会在付款后将客户的浏览器重定向到该 URL,并附加交易详情作为查询参数。由于这是浏览器重定向(而不是 Payroc 服务器发起的调用),测试此步骤时可以正常使用 localhost。要使实时测试中的重定向成功,必须先在 Self-Care Portal 中为 UAT 终端注册该 URL,但你现在就可以构建回执处理路由,并从配置中读取 URL。
如果缺少任何信息,请提醒,不要因此阻塞开发。 检查代码库中是否已有环境变量命名规范,并遵循该规范;否则,可以使用 PAYROC_TERMINAL_ID、PAYROC_TERMINAL_SECRET 和 PAYROC_RECEIPT_URL 等名称。编写代码,从环境变量/配置中读取这些值,然后告知开发者还有哪些事项待办以及如何处理:
- 终端 ID/UAT 访问权限 → 联系 Payroc Integrations 团队。
- 终端密钥 → 获得 UAT 访问权限后,在 Self-Care Portal 中创建。
- 回执 URL → 现在确定路由并构建处理程序;在测试实时重定向前,在 Self-Care Portal 中注册该 URL(并参考本地测试部分了解隧道方案)。
此时请询问其他所需信息,例如 UAT 凭据是否已存放在某处,或者是否有现成的结账处理程序可供修改,而不是从头编写。
如果开发者已确认终端凭据(例如,环境变量或配置中可见终端 ID 和密钥),请指出回执 URL 是实时测试前仍需注册的主要事项,但仍应针对配置的 URL 构建回执处理程序,而不是等待 URL 确认。
检查点
终端 ID、终端密钥和回执 URL 均已确认;或者开发者已了解待办事项、获取/注册方式,以及代码从哪些环境变量和配置中读取这些值,并已决定继续。不要对缺失事项只字不提,但也不要因此阻塞开发。
步骤 1 — 验证请求
阅读与你的流程对应的参考资料:
- 销售 / 预授权:
references/authenticate-your-requests.md - 保存卡片(定期付款):
references/save-payment-details/authenticate-your-requests.md— 先阅读references/recurring.md,了解完整的保存卡片 → 重复付款流程顺序。
此步骤中,不要使用训练知识中的任何算法名称、格式字符串或字段名称。请从与你的流程对应的本地参考资料中读取每个值——哈希算法、AMOUNT 格式、DATETIME 格式和字段顺序。
定期付款:保存卡片的哈希计算方式不同。 格式为
TERMINALID:MERCHANTREF:DATETIME:ACTION:SECRET— 不包含 AMOUNT,使用 MERCHANTREF 替代 ORDERID,并额外包含 ACTION。请复现该参考资料中的示例哈希,而不是销售交易的示例。直接照搬销售交易的哈希函数会导致所有保存卡片请求失败。
开始编写之前,请完整阅读参考资料。根据资料确认并使用:
- 哈希算法
- 哈希输入字符串中的确切字段及其顺序
- AMOUNT 格式 — 请仔细阅读;这一点并不明显,格式错误会导致每个请求都失败,并返回晦涩的错误信息
- DATETIME 格式及其时区要求
- 用于验证的示例哈希 — 继续之前必须准确复现该哈希
使用开发者所用的语言和框架实现哈希函数。立即使用参考资料中提供的输入值对照示例进行测试。示例哈希是一份精确规范——如果你的函数无法与其匹配,说明存在错误。
检查点
哈希函数是否准确复现了参考资料中的示例哈希?如果没有,请先根据错误分类进行诊断,再继续。
步骤 2 — 加载托管支付页面
阅读与你的交易类型对应的参考资料:
- 销售:
references/sale.md— 步骤 2 - 预授权:
references/pre-auth.md— 步骤 2 - 保存卡片(定期付款):
references/recurring.md— 阶段 A,步骤 2(使用ACTION和STOREDCREDENTIALUSE向/merchant/securecardpage发送表单 POST)
对每个 POST 字段的枚举值,都遵循步骤 1 的做法。 正如编写哈希函数之前要先阅读验证请求的参考资料,在输出任何枚举类型的值之前,也要先阅读说明 HPP 表单 POST 字段的正文文档(销售 / 预授权:
references/load-hosted-payment-page.md;保存卡片:references/save-payment-details/load-hosted-payment-page.md)——包括PAYMENTMETHOD、ACTION、STOREDCREDENTIALUSE、国家、语言,以及任何其他只能接受特定字符串集合的字段。不要使用训练知识中的任何枚举值。已知的过往故障(来自其他集成): 模型输出了channel: "internet",因为该值听起来适用于浏览器内结账——网关在错误详情中返回枚举列表并拒绝了请求。这种故障最常见的形式,就是使用听起来合理但实际不符的值(例如internet、online、ecommerce、card-not-present);输出前请先阅读说明可接受值的参考资料。保存卡片提示: 此处的STOREDCREDENTIALUSE必须大写;端点是securecardpage,而不是paymentpage。
注意: HPP 的响应不包含交易类型。如果你的集成处理销售、预授权和 / 或保存卡片,请在提交 HPP 表单之前,在你自己的订单模型中记录交易类型。
检查点
提交表单后,浏览器是否会无错误地跳转到 Payroc UAT 页面(销售 / 预授权对应支付页面,保存卡片对应安全卡片页面)?如果没有,请先诊断,再继续。
第 3 步 — 构建收据页面
阅读与你的交易类型对应的参考文档:
- 销售:
references/sale.md— 第 3 步 - 预授权:
references/pre-auth.md— 第 3 步(收据响应与销售相同;UNIQUEREF的持久化存储要求仍然适用) - 保存卡片(定期付款):
references/recurring.md— 阶段 A,第 3 步(收据不同:需存储CARDREFERENCE;A/E14/E43/E44RESPONSECODE 枚举;单独的 Secure Token URL;响应哈希顺序不同)
将第 1 步的规范应用于 RESPONSECODE 分支判断和其他收据回调枚举。 编写处理程序前,先阅读收据说明文案——销售/预授权请看
references/build-receipt-page.md,保存卡片请看references/save-payment-details/build-receipt-page.md。不要根据记忆中的部分RESPONSECODE值进行分支判断——本技能的错误分类中,A/D/R/C是销售示例,并非权威全集;保存卡片的枚举则完全不同(A/E14/E43/E44,其中A表示“已存储”)。销售参考文档列出了A以外的批准代码(例如E);参考文档才是权威依据。已知的过往失败模式: 将RESPONSECODE == 'A'视为唯一成功情况,因为权威集合比记忆中的值更大,导致真实批准被错误归类。请阅读参考文档,并依据其中记载的集合进行分支判断。
定期付款:持久化存储
CARDREFERENCE。 这是用于重复扣款的安全令牌——请将它(以及MERCHANTREF)持久化到数据库中,切勿存入 session/TempData。信任响应前,请验证响应哈希(保存卡片的顺序:TERMINALID:RESPONSECODE:RESPONSETEXT:MERCHANTREF:CARDREFERENCE:DATETIME:SECRET)。
检查点
收据处理程序是否收到 Payroc 重定向、无错误地验证响应哈希,并正确解析收据字段(销售/预授权为 RESPONSECODE + UNIQUEREF;保存卡片为 RESPONSECODE + CARDREFERENCE,且已持久化存储)?如果没有,请先排查问题再继续。
第 4 步 — 测试交易
- 销售:
references/sale.md— 第 4 步 - 预授权: 使用相同的销售测试流程(
references/sale.md中的步骤 1–5),然后还需: 6. 使用已存储的UNIQUEREF触发 capture 调用 7. 确认 HTTP 200,且响应正文中包含transactionResult
对于预授权 capture:编写成功分支前,请先阅读
references/api-schema.md中的transactionResult架构。transactionResult.status和transactionResult.responseCode都是枚举。已知的过往失败(来自同类集成): 模型仅在status == "approved"时进行分支判断,因实际值为"ready"(已授权并排队等待 capture),且responseCode: "A"/responseMessage: "APPROVAL",导致真实批准被错误地视为失败。请阅读完整的transactionResult.status枚举,找出所有与银行批准对应的值,并依据完整集合进行分支判断——不要根据记忆中的部分值编写成功检查。
对于保存卡片(定期付款),第 4 步的里程碑是“卡片已成功保存”——保存卡片的收据中 RESPONSECODE=A,并且已捕获及存储 CARDREFERENCE。然后继续执行第 5 步,设置实际的重复付款。
检查点
是否已通过测试卡确认 RESPONSECODE=A,且响应哈希验证通过?(预授权:capture 是否也返回 HTTP 200,且已根据完整枚举验证 transactionResult 成功分支?保存卡片:是否已捕获并持久化存储 CARDREFERENCE?)如果没有,请使用错误分类。在满足所有条件前,不要标记为完成。
第 5 步 — 设置重复付款(仅限定期付款)
如果集成不需要定期计费,请跳过此步骤。请阅读:references/recurring.md — 阶段 B,以及 references/repeat-payments-api-schema.md,了解所有端点、字段和枚举值。
此阶段使用基于 Bearer 令牌的身份验证调用 REST API(与预授权捕获相同,需从身份服务获取令牌),而不是 HPP HMAC 哈希。请选择开发者在需求收集阶段选定的路径:
- 使用 Payroc 的网关 — 创建一个 Payment Plan(
POST .../payment-plans),然后创建一个 Subscription(POST .../subscriptions),其paymentMethod为{ "type": "secureToken", "token": "<CARDREFERENCE>" }。网关会按计划自动扣款(automatic),或者由你通过.../pay扣款(manual)。 - 使用他们自己的软件(MIT) — 每次扣款都使用
POST /payments,设置paymentMethod.type: secureToken和令牌,并添加order.standingInstructions区块(sequence:先为first,然后为subsequent;processingModel:unscheduled/recurring/installment)。
请根据具体值阅读对应的参考文档。 计划/订阅的枚举值(
type、frequency— 注意fortnightly/yearly、onUpdate、onDelete)以及 MIT 的standingInstructions/channel枚举值均见references/repeat-payments-api-schema.md。请勿类比推断。还要注意大小写变化:表单中的协议为大写STOREDCREDENTIALUSE;这里则是小写的mitAgreement/processingModel。
创建订阅前,必须先创建对应的付款计划(以及令牌)。 请先创建计划,再创建订阅。令牌已存在,即 HPP 的
CARDREFERENCE。
检查点
网关路径:订阅是否已创建,并且 UAT 中的 currentState.status 是否为 active(如适用,manual /pay 是否成功)?MIT 路径:首次扣款是否返回 HTTP 200,且 transactionResult 的成功分支已根据 references/api-schema.md 中的完整枚举值验证(实际获批时可能为 status: "ready",responseCode: "A")?在生成端点/枚举值前,是否已阅读重复付款架构文档?如果没有,请参阅错误分类。
本地测试策略
步骤 1–3(哈希生成、HPP 重定向和收据页面 — 适用于销售、预授权和保存卡)都可以在 localhost 上测试。收据重定向由客户的浏览器触发,Payroc 的服务器不会直接调用收据 URL,因此无需满足可访问性要求。(保存卡使用单独的 Self-Care 字段 Secure Token URL 进行重定向 — 使用 localhost 仍然可行。)
**步骤 4 捕获(预授权)和步骤 5 重复付款(定期付款)**是应用向 Payroc 发起的服务器到服务器 REST 调用,因此也可以在 localhost 上运行 — 只需从身份服务获取 Bearer 令牌(x-api-key → access_token),而非 HMAC 哈希。这些操作不需要公共 URL 或隧道。
从后台验证开始的后续步骤需要公共 URL。Payroc 的服务器会向验证 Webhook 端点发送 POST 请求,因此 localhost 无法使用。可选方案如下,按从最简单到最稳健的顺序排列:
- webhook.site — 在 Self-Care Portal 中将 webhook.site URL 注册为临时验证 URL;它会捕获原始 POST 请求,方便你在编写处理程序前检查确切的响应字段。即使之后计划使用隧道,这也是很好的第一步。
- VS Dev Tunnels(内置于 Visual Studio 和 VS Code)— 对 .NET 应用来说是自然的选择;只需少量设置,即可创建一个持久的公共 HTTPS URL,并通过隧道连接到本地端口。
- ngrok — 与语言无关,设置快捷,免费套餐可用于开发。
- Cloudflare Tunnel — 更适合使用时间较长的环境。
- 部署到预发布主机 — 如果无法使用隧道,请部署到任意可通过 UAT 访问的主机并在那里测试。
请将所用的公共 URL 注册到 Self-Care Portal 中,作为 UAT 终端的后台验证 URL(这是与收据 URL 不同的字段)。
错误分类
| 症状 | 可能原因 | 修复方法 |
|---|---|---|
| 重定向后立即收到来自 HPP 的错误 | 哈希无效 | 重新阅读 references/authenticate-your-requests.md;检查 AMOUNT 格式、DATETIME 格式和时区,以及字段顺序;根据参考文档中的示例哈希重新测试 |
RESPONSECODE=D | 交易被拒绝 | 在 UAT 中属于预期情况 — 请使用 Payroc 测试卡 |
RESPONSECODE=R | 转介 — 客户应联系银行 | 在 Phase 1 测试中将其视为拒绝 |
RESPONSECODE=C | 卡已报告丢失或被盗 | 请换用其他测试卡 |
应用记录了失败,但实际上获批了 — RESPONSECODE 的值不是 A(过往出现过:E) | 收据页面分支将 RESPONSECODE == 'A' 视为唯一成功情况,并在未提示的情况下错误归类了其他获批结果 | 阅读 references/build-receipt-page.md,了解完整的 RESPONSECODE 枚举。找出与银行批准结果相对应的所有值,并针对这些完整值进行分支处理 — A 只是示例,并非规范集合。 |
预授权:捕获 API 返回 HTTP 200,但应用记录了失败 — 响应显示 responseCode: "A" / responseMessage: "APPROVAL" | 服务端成功检查基于记忆中的 transactionResult.status 子集进行分支处理(过往故障:仅接受 "approved";将已授权且已排队等待捕获的 "ready" 默默当作失败处理) | 阅读 references/api-schema.md 中的 transactionResult.status 枚举,并针对与银行批准结果相对应的所有值进行分支处理。 |
| 付款后未重定向到收据页面 | 收据 URL 未在 Self-Care Portal 中注册,或注册时有拼写错误 | 收据结果通过浏览器 GET 重定向(查询参数)传递 — 而非服务端 POST。本地主机地址有效。最可能的原因是 URL 未注册或在 Self-Care Portal 中有拼写错误。请确认该 URL 与 UAT 终端注册的 URL 完全一致。 |
| 响应哈希验证失败 | 验证哈希中的字段或顺序错误 | 重新阅读 references/build-receipt-page.md;确认参与哈希计算的响应字段及其顺序完全正确 |
| 字段正确,但哈希仍不匹配 | 字符编码或空白字符 | 所有哈希输入都必须是纯 ASCII;检查任何字段值中是否包含 Unicode 字符、尾随空格或换行符 |
| 调用捕获 API 时出现 404 | UNIQUEREF 无效或预授权已过期 | 验证 UNIQUEREF 与收据响应中的值一致;请注意,预授权有由发卡机构定义的保留期限,超时后会过期 |
| 调用捕获 API 时出现 409 | 预授权已捕获 | 尝试捕获前请检查订单状态;不要重试已完成的捕获 |
| 调用捕获/重复付款 API 时出现 401 | Bearer 令牌已过期或 API 密钥错误 | 重新生成 Bearer 令牌;确认与身份服务搭配使用的 x-api-key 值 |
| 保存卡:重定向后立即收到来自 HPP 的错误,或哈希不匹配 | 保存卡时重用了销售哈希配方(保留了 AMOUNT、使用了 ORDERID,或遗漏了 ACTION),或提交到了 paymentpage 而非 securecardpage | 重新阅读 references/save-payment-details/authenticate-your-requests.md;配方为 TERMINALID:MERCHANTREF:DATETIME:ACTION:SECRET(不含 AMOUNT)。确认端点为 /merchant/securecardpage。 |
保存卡:网关拒绝 STOREDCREDENTIALUSE(或 REST 拒绝 mitAgreement/processingModel) | 对应接口的大小写格式错误 | HPP 表单 POST 使用大写(RECURRING);REST API 使用小写(recurring)。请阅读与你所调用接口相对应的参考文档。 |
| 保存卡:收据处理程序始终未触发 | 保存卡重定向注册在错误的 Self-Care 字段中 | 保存卡收据使用独立于销售/预授权收据 URL 的 Secure Token URL 字段。请确认已在该字段中注册。 |
| 保存卡:应用记录了失败,但卡已保存 | 使用了销售的 RESPONSECODE 集合进行分支处理,而非保存卡的集合 | 阅读 references/save-payment-details/build-receipt-page.md:保存卡枚举为 A/E14/E43/E44;A = 已保存。 |
| 创建订阅时出现 4xx | 付款计划或安全令牌尚不存在,或 paymentPlanId/token 错误 | 请先创建付款计划;将 paymentMethod 设为 { "type": "secureToken", "token": "<CARDREFERENCE>" }。阅读 references/repeat-payments-api-schema.md。 |
| 使用令牌的 MIT 付款被拒绝/顺序错误 | 缺少 standingInstructions,或 sequence/processingModel 错误 | 首次付款使用 sequence: first,后续付款使用 sequence: subsequent 和 referenceDataOfFirstTxn。如果发送 credentialOnFile.mitAgreement,则必须在 order 中发送 standingInstructions。 |
重复付款 REST 调用拒绝 channel | channel 值无效(例如 internet/online/ecommerce) | PaymentRequestChannel 的取值为 pos/web/moto — 请阅读 references/repeat-payments-api-schema.md,不要类比推断。 |
验证清单
- 终端 ID 和密钥从环境变量读取,而非写在源代码中
- 收据 URL 已在 Self-Care Portal 中注册,且可公开访问
- 已根据
references/authenticate-your-requests.md中的示例哈希验证哈希函数 - 加载 HPP 时已提供所有必需的 POST 字段
- 在信任任何响应数据前,先验证响应哈希
- 已在 UAT 中使用测试卡确认
RESPONSECODE=A - 已捕获并存储
UNIQUEREF - (仅预授权)已在订单模型中记录交易类型 — HPP 响应不包含该信息
- (仅预授权)已将
UNIQUEREF持久化到持久存储(数据库/订单记录),而非会话或 TempData - (仅预授权)已在 UAT 中测试 Capture API — 已确认 HTTP 200 和
transactionResult - 每个 POST 字段的枚举值(
PAYMENTMETHOD、国家/地区、语言等)均从references/load-hosted-payment-page.md中读取,而非来自训练数据或此技能的示例 -
RESPONSECODE分支涵盖references/build-receipt-page.md中列出的所有批准值 — 而非仅使用记忆中的子集(例如只有A) - (仅预授权)Capture 响应的成功分支对
transactionResult.status的处理涵盖references/api-schema.md枚举中的所有批准值(例如"ready") - (仅保存卡片)已根据
references/save-payment-details/authenticate-your-requests.md中的示例哈希验证哈希函数 — 此算法不包含 AMOUNT,且包含 ACTION - (仅保存卡片)表单 POST 到
/merchant/securecardpage;STOREDCREDENTIALUSE使用大写 - (仅保存卡片)收据分支使用保存卡片的
RESPONSECODE集合(A/E14/E43/E44),且CARDREFERENCE已持久化到持久存储(而非会话/TempData) - (仅保存卡片)保存卡片的重定向 URL 已在 Self-Care 的 Secure Token URL 字段中注册
- (仅周期性付款)已保存凭据使用方式的大小写形式与相应接口一致 — 表单中使用大写,REST API 中使用小写的
mitAgreement/processingModel - (仅周期性付款,网关)已在创建订阅前创建付款计划;订阅的
paymentMethod为{ type: secureToken, token: <CARDREFERENCE> };已在 UAT 中确认currentState.status为active - (仅周期性付款,MIT)首笔扣款使用
standingInstructions(sequence: first);后续扣款使用sequence: subsequent和referenceDataOfFirstTxn;channel是有效的枚举值 - (仅周期性付款)重复付款的端点、字段和枚举值均从
references/repeat-payments-api-schema.md中读取,而非凭记忆填写
反模式
将终端 ID 或密钥硬编码——凭据写入源代码后会留存在版本历史中,最终可能泄露。
跳过示例哈希验证——如果哈希函数有任何细微错误(字段顺序错误、AMOUNT 格式错误、时区错误),每笔交易都会失败。references/authenticate-your-requests.md 中的示例哈希是一项契约;在处理其他内容之前,先用它验证。
未验证响应哈希就信任 RESPONSECODE——如果不先验证哈希,攻击者可以伪造包含 RESPONSECODE=A 的 POST 请求,欺骗你的收据页面。
不存储 UNIQUEREF——没有它,你就无法退款或执行后续交易。
想当然地处理 AMOUNT 格式——正确格式已有文档说明,但并不显而易见。请仔细阅读。格式错误会导致每个请求的哈希都无效。
将 UNIQUEREF 存储在会话或 TempData 中——对于预授权集成,UNIQUEREF 必须在当前请求结束后仍然可用;临时存储会导致用户离开页面或会话过期后无法完成扣款。
认为第 1 步中“不要使用任何训练知识中的值”的要求只适用于第 1 步。 这项防护措施并非只针对哈希计算规则,而是适用于集成所输出或据此分支处理的所有文档值。POST 字段枚举(PAYMENTMETHOD)、RESPONSECODE 分支、扣款 API 的 transactionResult.status 值:每一项都有对应的本地参考文档(表单和收据相关内容请查阅 HPP 说明副本;扣款相关内容请查阅 references/api-schema.md)。在输出或据此分支处理值之前,请先阅读相关参考文档。哈希计算规则只是在早期迭代中最明显的失败点。
根据对枚举的片面印象编写成功判断。 这是 RESPONSECODE 和 transactionResult.status 判断失败背后的共同错误:凭记忆推断枚举值,或只参考此技能中的示例,而不阅读本地参考文档。每个授权判断都必须列出与银行授权对应的全部值,而不只是 A 或某个单独的状态值。
将销售哈希函数用于保存卡片。 保存卡片的计算规则是 TERMINALID:MERCHANTREF:DATETIME:ACTION:SECRET——不包含 AMOUNT,使用 MERCHANTREF 而不是 ORDERID,并且还要包含 ACTION。直接沿用销售哈希会导致每个保存卡片请求都因哈希错误而失败,且错误信息晦涩难懂。(这与想当然地处理 AMOUNT 格式属于同一类错误。)
在保存卡片/令牌化时收取 AMOUNT。 保存卡片是金额为 $0 的令牌化操作,而非销售交易——securecardpage 表单中没有 AMOUNT 字段。如果你发现自己在保存卡片请求中构造金额,说明你把它与销售流程混淆了。
将 CARDREFERENCE 存储在会话或 TempData 中。 安全令牌必须在当前请求结束后长期保留——下个月要向客户收费就要用到它。请将其持久化到可靠存储中,就像预授权的 UNIQUEREF 一样。
在付款计划(及令牌)创建之前调用 Subscriptions。 订阅会将计划关联到令牌,因此两者都必须先存在。使用 HPP 保存卡片时,令牌(CARDREFERENCE)已经存在;因此,先创建计划,再创建订阅。
混淆不同界面中已存储凭据的大小写。 HPP 表单使用大写的 STOREDCREDENTIALUSE;REST API 使用小写的 mitAgreement/processingModel。它们描述的是同一项协议,但网关会拒绝大小写与当前界面不匹配的值。
完成
确认 RESPONSECODE=A 且所有检查项均通过后:
集成完成。 以下是你已构建的内容:
- 身份验证哈希 — 使用你的终端密钥为每个付款请求签名,防止篡改。
- 结账处理程序 — 组装付款表单,并将其 POST 到 Payroc 的 Hosted Payment Page。
- 收据处理程序 — 接收 Payroc 的浏览器重定向(包含查询参数的 GET 请求),验证响应哈希,根据完整的 RESPONSECODE 审批集合进行分支处理,并获取 UNIQUEREF。
- 已在 UAT 中验证 — 已使用测试卡确认端到端交易。
- 预授权 + 捕获(如适用)— 结账时冻结资金;准备结算时通过 REST API 捕获;UNIQUEREF 用于关联这两次调用;捕获响应分支涵盖完整的
transactionResult.status审批集合。- 定期扣款(如适用)— 通过
securecardpage在 Hosted Page 上保存卡片(使用独立的哈希计算方式和收据),持久化存储CARDREFERENCE,并通过 Payroc 的网关(Payment Plan + Subscription)或你自己的商户发起扣款(secureToken+standingInstructions)设置重复付款,且已在 UAT 中验证。上线前: 将 UAT 端点 URL 替换为生产 URL — 这适用于 HPP 端点(
paymentpage/preauthpage/securecardpage)以及所有 REST 端点(capture、payment-plans、subscriptions、payments)— 请在参考资料中确认这些 URL。将凭据指向生产终端,确认收据 URL(如果保存卡片,也包括 Secure Token URL)已在生产 Self-Care Portal 中注册,并移除所有测试卡号。
后续步骤:
- 后台验证 Webhook — 每笔交易都会触发服务器到服务器的 POST,与收据重定向相互独立;可用于对账,并在重定向失败时作为备用方案
- 管理定期扣款生命周期(如适用)— 更新、停用或重新启用订阅,更新已保存的卡片(
ACTION=update或安全令牌更新端点),并处理逾期付款催收 - Hosted Fields(第 2 阶段)— 将 Payroc 托管的卡片输入组件嵌入你自己的表单中;无需页面重定向