关于 integrate-apple-pay
为开发者提供 Payroc Apple Pay 集成指导,从商户域名设置到 UAT 测试交易。内容涵盖 Apple Pay JS API 与 Payroc Payments API 的配合,并用本地参考资料核对接口形状和值。
主要功能
- 01指导域名验证与商户设置
- 02衔接 Apple Pay 会话和支付 API
- 03处理加密支付令牌
- 04按资料核对 API 与 JS 字段
- 05检查支付按钮可用性
- 06诊断集成错误
适用场景
- 01为现有 Payroc 结账添加 Apple Pay
- 02构建独立的 Apple Pay 支付流程
- 03在 UAT 验证会话和付款步骤
MCP 相关
README 提到可选运行 MCP 连接检查工具;未说明该技能提供 MCP 服务或管理 MCP 服务器。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ payroc/ skills --skill integrate-apple-pay安装后在 Claude Code 中输入/integrate-apple-pay确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/_sources.mdadd-apple-pay-to-your-integration.mdapi-schema.mderror-response-format.mdidempotency.mdidentity-call.mdset-up-apple-pay-for-a-merchant.mdreferences/third-party/apple-applepaysession.mdapple-pay-button.mdapple-payment-token.mdapple-server-setup.md详细介绍
Payroc Apple Pay 集成
版本检查(请先运行)
在发布任何消息或开始流程之前,请确认此技能是最新版本:
- 从上方 frontmatter 的
metadata.version字段读取此技能的版本。 - 获取已发布的副本并读取其
metadata.version:https://raw.githubusercontent.com/payroc/skills/main/plugins/payroc/transaction/skills/integrate-apple-pay/SKILL.md - 按语义版本比较两者:
-
此版本 >= 已发布版本 → 静默继续,不发送消息。(开发者使用尚未发布的较新版本是正常且可以接受的。)
-
此版本 < 已发布版本 → 告知开发者:
⚠️ 此技能已有更新版本(v<published>)发布 — 你正在运行 v<current>。建议升级以获得最佳效果。
然后询问他们是要继续使用当前版本,还是先停止并升级,并尊重他们的选择。
-
无法获取(离线、网络错误、404)→ 简要说明无法验证版本,然后继续。
-
首次调用时,向开发者介绍:
Payroc Apple Pay 集成 我将指导你完成从商户设置到成功执行 UAT 测试交易的全过程。 本指南介绍如何在结账页面上使用 Apple Pay 作为支付方式 — 通过 Apple Pay JS API 显示支付表单,并使用 Payroc Payments API 处理加密支付数据。
Apple Pay 与 Payroc 的工作方式(分为四个部分):
- 通过 Self-Care Portal 向 Apple 验证你的域名,并获取域名 ID
- 客户轻点 Apple Pay 按钮时,Apple Pay JS API 会触发
onvalidatemerchant事件 — 你的服务器调用 Payroc API 启动会话,并将响应返回给 Apple。有两个可用的端点变体:适用于新集成的新版POST /v1/payments/apple-pay/sessions(首选),以及原始的POST /v1/processing-terminals/{processingTerminalId}/apple-pay-sessions。- Apple 显示支付表单;客户通过 Face ID / Touch ID 授权
onpaymentauthorized事件会携带加密支付数据触发 — 你的服务器将其转换为十六进制,并 POST 到 Payroc 支付端点重要: Apple Pay 仅适用于 Apple 设备(iPhone、iPad、Mac),并且需要 Safari 或基于 WebKit 的浏览器。务必使用
ApplePaySession.canMakePayments()有条件地显示 Apple Pay 按钮。Apple Pay 与 Hosted Fields / HPP 的区别: Apple Pay 是独立的支付流程 — 它不使用 Hosted Fields JS 库或 HPP 表单。它是这些集成的补充,而非替代方案。
[如果有可用的 MCP 连接检查工具,请在此处运行,并在继续之前展示结果。]
快速参考
# Identity service (Bearer token — server-side only)
POST https://identity.uat.payroc.com/authorize
x-api-key: <api-key>
# Apple Pay JS API — provided by Safari / WebKit; there is no script tag to load
# Apple Pay session start — payments-path variant (PREFERRED for new integrations)
# processingTerminalId is a body field; no path parameter needed
POST https://api.uat.payroc.com/v1/payments/apple-pay/sessions
Authorization: Bearer <token>
Content-Type: application/json
# Apple Pay session start — terminal-path variant (original; still supported)
POST https://api.uat.payroc.com/v1/processing-terminals/{processingTerminalId}/apple-pay-sessions
Authorization: Bearer <token>
Content-Type: application/json
# Payments API (server-side — process the hex-encoded Apple Pay token)
POST https://api.uat.payroc.com/v1/payments
Authorization: Bearer <token>
Content-Type: application/json
# Production base URLs (swap when going live — see Completion)
# identity.payroc.com/authorize | api.payroc.com/v1/...
确切的值、枚举集以及请求/响应结构不包含在此区块中 — 请按照各步骤的指引,从 references/ 文件中读取。这是端点的速览图,不能替代参考文件。
参考资料
所有枚举值、架构和 Apple Pay JS API 接口都记录在下方的本地 references/ 文件中——
此技能依据这些文件生成内容,不使用实时查询或记忆。每个文件负责解答不同类型的问题;用错资料来源是已知的失败模式:
references/api-schema.md— Payroc API 中传输的值和结构的权威来源。 字段名称、枚举值、必填字段、请求和响应架构(会话启动和支付请求)。需要了解 Payroc API 字段叫什么 或 接受哪些值 时,请阅读此文件。它是此技能的权威副本。- Payroc 叙述指南(本地副本)— 实施方法的权威来源。 如何安排调用顺序、Apple Pay 流程如何与 Payroc 的会话启动和支付端点组合,以及端到端的整体结构。使用这些指南了解 如何组合 集成。
- Apple 衍生说明(位于本地
references/third-party/下)— Apple Pay JS API 的权威来源。ApplePaySession构造函数、事件名称(onvalidatemerchant、onpaymentauthorized、oncancel)、方法(canMakePayments、completeMerchantValidation、completePayment)、状态常量和 Apple Pay 支付令牌格式均由 Apple 定义,而非 Payroc。这些说明用我们自己的文字记录了 API 的实际情况。Payroc 叙述指南说明这些内容 如何与 Payroc 端点交互,但不负责定义 Apple API 本身的结构。
如果你想问“如何构造 Payroc 会话启动或支付请求?”,答案在 references/api-schema.md。如果你想问“调用的顺序是什么?”,答案在 Payroc 叙述指南中。如果你想问“ApplePaySession 的构造函数签名是什么?”或“客户授权时会触发哪个事件?”,答案在 Apple 衍生说明中。Payroc 负责其解密端点和 Apple 支付令牌的封装;浏览器端支付界面的一切则由 Apple 负责。
| 来源 | 本地文件 | 用途 |
|---|---|---|
| API 架构参考 | references/api-schema.md | 所有 Payroc 枚举值、必填字段、请求/响应架构(两种会话启动方式 + 支付)。包含新的 POST /v1/payments/apple-pay/sessions 支付路径端点(新集成首选)和原有的 POST /v1/processing-terminals/{processingTerminalId}/apple-pay-sessions 终端路径端点。 |
| 错误响应格式 | references/error-response-format.md | 错误封装(RFC 7807)+ Payroc errors[] + 标准错误类型目录 |
| 为商户设置 Apple Pay(Payroc 叙述指南) | references/set-up-apple-pay-for-a-merchant.md | 域名验证/Self-Care Portal 设置、获取域名 ID |
| 在集成中添加 Apple Pay(Payroc 叙述指南) | references/add-apple-pay-to-your-integration.md | Bearer 令牌、会话启动调用、销售流程组合 |
Apple — ApplePaySession(衍生说明) | references/third-party/apple-applepaysession.md | JS API 构造函数、事件/方法名称、状态常量 |
| Apple — Apple Pay 按钮(衍生说明) | references/third-party/apple-pay-button.md | 如何渲染按钮(CSS 与 Web 组件 + SDK 脚本),以及如何正确控制按钮是否可用 |
| Apple — 支付令牌格式(衍生说明) | references/third-party/apple-payment-token.md | 为 Payroc 进行十六进制编码的令牌 JSON 字段名称 |
| Apple — 服务器/商户验证设置(衍生说明) | references/third-party/apple-server-setup.md | 商户验证流程相关事实、域名关联文件 |
这些文件是本地快照,是此技能的权威资料来源。其来源 URL 和上次同步日期记录在 references/_sources.md 中——
如果内容看起来过时,请从该文件重新生成。
核心原则
- 先检查,再提问——提问前先阅读代码库;根据所发现的内容跳过显而易见的问题,并提出有针对性的问题。
- 先提问,再编码——编写实现代码前,通过提问了解未知信息。
- 先验证,再推进——当前步骤的检查点通过 UAT 并获得开发者确认前,不要进入下一步。
- 阅读参考资料,不要猜测——并为问题选择正确的参考资料。 此集成有 三个 信息来源,而不是两个。针对问题使用错误的来源,会导致记住但错误的值混入实现。
- Payroc API 架构、字段名称、枚举、必填字段 →
references/api-schema.md。 任何传输到 Payroc API 的内容都适用此项。接受特定字符串的字段值(channel、paymentMethod.type、paymentMethod.serviceProvider、币种以及其他枚举类型参数)应来自架构参考资料,而不是训练数据。即使某个字符串听起来合理,只要它不在参考资料中,就会导致 API 错误。 - 方案、调用顺序、Apple Pay 与 Payroc 的配合方式 → Payroc 叙述指南。“哪个调用先执行?”和“Payroc 对会话启动请求体有何要求?”这类问题应参考指南。
- Apple Pay JS API 结构、事件名称、方法名称 →
references/third-party/下 Apple 的派生说明。ApplePaySession、其构造函数签名、事件处理程序(onvalidatemerchant、onpaymentauthorized、oncancel)、方法(canMakePayments、completeMerchantValidation、completePayment)以及状态常量均由 Apple 定义。Payroc 叙述指南会引用这些内容,但并非其结构的权威来源——如需确认 JS API 的任何细节,请阅读 Apple 的派生说明。 - 请求和响应架构并不相同——两者都要查。 不要假设 Payroc 响应与 Payroc 请求的结构相同;请在
references/api-schema.md中分别查询。 - 不要混淆来源。
channel属于 Payroc 支付请求,不属于 Apple Pay 会话对象。Apple 的支付网络常量(例如"visa"、"masterCard")来自 Apple 的派生说明,属于ApplePaySession请求,而不是 Payroc 支付请求。每个值都要查阅正确的参考资料。
- Payroc API 架构、字段名称、枚举、必填字段 →
- 逐个值先查阅,再输出。 输出任何枚举值(Payroc:
channel、paymentMethod.type、paymentMethod.serviceProvider、币种;Apple:支付网络、商户功能、状态常量)、任何ApplePaySession构造函数选项,或 Apple Pay JS API 上的任何事件或方法名称前,都要先从相关的本地参考资料中查阅。不要凭记忆输出。不要把此技能的失败模式提示(见步骤 3、步骤 5、错误分类)当作权威依据——它们的作用是帮助你根据症状识别错误,而不是让你跳过参考资料查阅。听起来合理的英文值是此类错误最常见的形式。 - 绝不硬编码凭据——API 密钥和终端 ID 必须来自环境变量或机密管理器,绝不能写入源代码。
- 继续前先诊断——如果某个步骤失败,请暂停并根据错误分类排查后再继续。
信息收集
首先,扫描代码库。 查找以下内容:
- 服务端使用的语言和框架
- 现有的结账或支付相关路由和处理程序
- 任何现有的 Payroc 集成(HF 或 HPP)——API 密钥和终端 ID 可能已经配置
- 环境变量或配置的管理方式
- 域名是否已为 Apple Pay 配置(
.well-known目录、现有的 Apple Pay JS 代码)
根据查找结果,避免询问你已经可以推断的信息。
然后询问你仍需要了解的内容。至少确认:
问题 1 — Apple Pay 是合适的产品吗?这是新增功能还是独立构建?
| Apple Pay(此技能) | Hosted Fields | Hosted Pages(HPP) | |
|---|---|---|---|
| 客户体验 | 轻点 Apple Pay 按钮;通过 Face ID / Touch ID 授权——无需输入卡片信息 | 在你自己的表单中输入卡片信息,使用嵌入的 Payroc 小组件 | 重定向到 Payroc 托管的页面完成支付,然后返回你的网站 |
| 卡片数据存放位置 | Apple 钱包;你的服务器会收到加密令牌 | 页面中的 Payroc 小组件 | Payroc 托管的页面 |
| 可用性 | 仅限使用 Safari / WebKit 的 Apple 设备——始终通过 canMakePayments() 进行检查 | 任何现代浏览器 | 任何现代浏览器 |
| 此技能 | ✓ 涵盖 | 独立技能 | 独立技能 |
Apple Pay 是卡片输入方式的补充,而不是替代方案——因为它只适用于 Apple 设备,大多数集成都会同时提供 Hosted Fields 或 HPP,以供其他用户使用。明确这一点后,确认这是新增功能还是独立构建:
- 将 Apple Pay 添加到现有的 Payroc 集成(HF 或 HPP) → API 密钥和终端 ID 很可能已经配置;重点关注 Apple Pay 专属步骤
- 全新集成,仅使用 Apple Pay → 从头开始,包括配置凭据
问题 2 — 域名配置状态:
Apple Pay 要求通过 Payroc Self-Care Portal 向 Apple 验证商户域名。询问是否已完成验证,以及开发者是否有域名 ID。
- 域名已验证,且有域名 ID → 跳过商户配置步骤
- 尚未完成 → 从步骤 1(商户配置)开始
等待开发者回答后再继续。
先决条件
这些条件是运行和端到端测试 Apple Pay 所必需的,并非编写代码所需。如果开发者已经具备这些条件,那很好。如果没有,也不要停下来:将代码接入环境变量以读取每个值,然后继续构建。开发者可以在测试前提供真实值。
- API 密钥 — 用于从 Payroc 的身份服务获取 Bearer 令牌。与 Hosted Fields 使用的是同一凭据;该凭据由 Payroc Integrations 团队提供。
- 处理终端 ID — 由 Payroc Integrations 团队提供的 UAT 终端 ID。
- 域 ID — 商户通过 Self-Care Portal(见步骤 1)向 Apple 验证域名后返回;每个 Apple Pay 会话请求都需要包含此 ID。代码可以从
APPLE_PAY_DOMAIN_ID这样的变量读取它。 - 在处理终端上启用 Apple Pay — Payroc 必须先为商户的处理终端启用 Apple Pay,之后才能在 Self-Care Portal(步骤 1)中为商户进行设置。请 Payroc Integrations 团队启用此功能。
- 可公开访问的 HTTPS 域名 — Apple Pay 域验证需要 Apple 的服务器能够访问相应 URL。
localhost不足以用于验证和实时测试;必须使用暂存或生产域名。这不会阻止编写集成代码,但会阻止验证和测试。
如果缺少任何条件——提醒,但不要阻止。 扫描代码库,查找现有的环境变量命名惯例并沿用;否则,建议使用 PAYROC_API_KEY、PAYROC_TERMINAL_ID 和 APPLE_PAY_DOMAIN_ID 这样的名称。编写代码以从环境中读取这些值,然后明确告知开发者:
⚠️ 我已接入代码,使其从
<VAR names>读取 API 密钥、终端 ID 和 Apple Pay 域 ID。要实际运行或测试 Apple Pay,你需要 Payroc UAT 终端和 API 密钥(请联系 Payroc Integrations 团队),以及通过可公开访问的 HTTPS URL 验证的域名(步骤 1)。与此同时,我可以继续构建。
主动提出帮助他们获取缺少的条件;如果他们愿意,就继续开发。
检查点
凭据和域名均已确认,或者开发者已了解尚缺少哪些条件、如何获取,以及代码从哪些环境变量读取这些值,并已选择继续。不要对缺少的条件只字不提,但也不要因此阻止开发。
步骤 1 — 为商户设置 Apple Pay
阅读:references/set-up-apple-pay-for-a-merchant.md
开始操作前先阅读该页面。确认参考文档中的确切步骤——但在撰写本文时,步骤如下:
- 确认 Payroc 已在商户的处理终端上启用 Apple Pay。否则无法完成设置
- 登录 UAT 终端对应的 Self-Care Portal
- 前往 Settings → Apple Pay Domains
- 下载 Apple Pay 域验证文件
- 将文件放在商户域名下的
/.well-known/apple-developer-merchantid-domain-association路径中(必须可通过 HTTPS 公开访问) - 在门户中添加域名并保存
- 记下显示的域 ID——安全存储;每个 Apple Pay 会话请求都需要使用它
必须先确保域验证文件可访问,再在门户中添加域名。 Apple 会在域注册步骤中验证该文件。
这是可以与开发并行进行的门户/托管任务。如果域名尚未验证,不要因此停下来——继续构建会话和支付代码,并使用 APPLE_PAY_DOMAIN_ID 变量;同时提醒开发者,必须完成验证后才能进行 Apple Pay 实时测试。
检查点
保存后,Self-Care Portal 中是否显示域 ID?能否通过 HTTPS 在 /.well-known/ 路径获取验证文件?如果还不能,请将其记为测试时需要完成的事项,并继续构建。
步骤 2 — 进行身份验证:获取 Bearer 令牌
阅读:references/identity-call.md——Bearer 令牌交换的权威参考。不要猜测身份验证端点 URL、请求头名称或响应结构——只输出此文件中记录的内容。
阅读:references/add-apple-pay-to-your-integration.md——Payroc 说明;确认 Bearer 身份验证如何融入 Apple Pay 流程。
开始编写前,请阅读这两份参考资料。根据参考资料,确认:
- 身份服务端点
- 必需的请求头及其格式
- 包含访问令牌的响应字段
实现一个服务端函数,使用 API 密钥向身份服务发送 POST 请求并返回访问令牌。此函数必须在服务端运行——绝不能将 API 密钥发送到浏览器。
检查点
此调用是否返回状态码 200 和 access_token?
步骤 3 — 实现 Apple Pay 按钮和支付界面
开始编写前,请阅读两份参考资料:
- Payroc 说明(组合方式):
references/add-apple-pay-to-your-integration.md——客户端部分。你将在此了解 Payroc 对 JS 事件与服务器之间交互的要求。 - Apple 的 JS API 接口(结构):
references/third-party/apple-applepaysession.md——关于ApplePaySession构造函数、每个事件名称、每个方法名称以及每个状态常量的衍生说明。Payroc 说明会按名称引用这些内容,但并非其准确拼写、签名或集合的权威来源。 - Apple Pay 按钮渲染(结构):
references/third-party/apple-pay-button.md——如何实际绘制按钮。这里有两种方法,不能互换:CSS-webkit-appearance: -apple-pay-button方法(无需脚本)和<apple-pay-button>Web 组件(必须加载 Apple 的apple-pay-sdk.js脚本,否则不会渲染)。此说明还涵盖下方的条件判断陷阱。apple-applepaysession.md不涉及按钮渲染——请阅读此文件了解相关内容。
在发出 new ApplePaySession(...) 或任何 session.* 调用之前——对照 Apple 派生说明进行确认
- 要阅读的内容。 Apple
ApplePaySession派生说明(references/third-party/apple-applepaysession.md)。还要从该说明中确认构造函数所需的paymentRequest结构,而不是依赖训练数据。 - 要核实的内容。
- 构造函数签名(
new ApplePaySession(version, paymentRequest))以及当前适用的version值。 - 会话实际触发的事件处理程序(
onvalidatemerchant、onpaymentauthorized、oncancel等),以及各事件载荷的确切结构。 - 会话公开的方法(
completeMerchantValidation、completePayment、abort等)。 - 状态常量(
STATUS_SUCCESS、STATUS_FAILURE,以及你要用于分支判断的其他常量)。
- 构造函数签名(
- 确认后再发出代码。 为每个事件处理程序使用 Apple 派生说明中记录的确切名称。只调用文档所述接口中的方法。如果你假设某个方法存在,但派生说明中没有记录,不要另造一个名称再试——Apple 可能已将该职责移至其他位置(例如移入某个付款请求属性)。
实现客户端集成:
- 检查可用性并渲染按钮——将所有内容放在
ApplePaySession.canMakePayments()的判断中。仅当此方法返回true时才渲染 Apple Pay 按钮;否则显示其他付款方式。阅读references/third-party/apple-pay-button.md,了解如何渲染按钮——选择一种方案并完整输出:要么使用 CSS-webkit-appearance: -apple-pay-button按钮(无需加载任何内容),要么使用<apple-pay-button>Web 组件,并添加其必需的apple-pay-sdk.js脚本标签(没有该脚本时,Web 组件不会渲染任何内容)。**确保隐藏操作确实生效:**如果你自己的 CSS 为按钮设置了display,HTMLhidden属性会被悄然覆盖(作者 CSS 的优先级高于用户代理的[hidden]规则),因此要在 JS 中通过style.display/类切换可见性,或确保按钮的基础 CSS 不设置display,并确认ApplePaySession不存在时按钮确实处于隐藏状态。不要假设hidden的优先级高于你的样式表。 - 使用所需的
paymentRequest对象创建ApplePaySession(包括商户名称、支持的网络、商户能力、国家/地区代码、货币代码和总金额)——从 Apple 派生说明中读取确切的属性名称,包括支持网络常量的拼写(例如"visa"还是"Visa"——对于此技能,以派生说明为准)。 - 处理商户验证事件——此事件会在付款表单打开时触发。客户端必须调用你的服务器(例如
POST /checkout/apple-pay/session),并传入事件中的验证 URL。你的服务器调用 Payroc API 启动会话(第 4 步),并返回会话响应。客户端将该响应传给 Apple 文档所述的完成方法(从 Apple 派生说明中读取其确切名称和签名)。 - 处理付款授权事件——客户通过 Face ID / Touch ID 授权时会触发此事件。事件包含加密付款数据。客户端将其发送给你的服务器(第 5 步)进行处理,然后使用文档所述的成功/失败状态常量调用文档所述的付款完成方法。
- 调用会话的启动方法以显示付款表单(从 Apple 派生说明中读取其确切名称)。
已知的 Apple Pay JS 形态故障模式
列出这些模式是为了便于识别症状——修复方法始终是阅读 Apple 派生说明(references/third-party/apple-applepaysession.md),并按其记录的内容实现,而不是“使用下面的值”。
- **症状:**假定的处理程序名称始终不会触发;支付表单会打开,但商户验证步骤被悄然跳过。**过去的错误做法:**臆造类似方法调用的写法,例如
session.validateMerchant(),而实际 API 是基于事件的(在 session 上设置on*处理程序)。**验证:**派生说明列出了各个事件;请根据文档中的事件名称,将处理程序设为 session 的属性。 - 症状:
completePayment接受了调用,但表单未能正确关闭,或状态常量被拒绝。**过去的错误做法:**臆造状态常量(例如STATUS_OK)或使用了错误的参数形式。**验证:**派生说明列出了ApplePaySession类导出的状态常量,请使用这些确切名称。 - **症状:**浏览器端在 session 构造函数或按钮渲染时出现
TypeError。**过去的错误做法:**构造函数参数数量错误,或调用了类中不存在的方法。**验证:**派生说明记录了构造函数签名和完整的方法列表。 - **症状:**即使在有可用卡片的 Safari 中,Apple Pay 按钮也始终不显示(高度为零或没有图标)。**过去的错误做法:**输出
<apple-pay-button>Web 组件,却未加载 Apple 的apple-pay-sdk.js脚本,因此自定义元素从未注册。**验证:**查看references/third-party/apple-pay-button.md——要么为 Web 组件加载 SDK 脚本,要么改用 CSS-webkit-appearance: -apple-pay-button方式。 - **症状:**Apple Pay 按钮在非 Apple 浏览器中也会显示(本应隐藏),尽管门控逻辑设置了
hidden属性。**过去的错误做法:**作者 CSS 规则为按钮设置了display,覆盖用户代理的[hidden] { display: none }规则,导致门控失效。**验证:**查看references/third-party/apple-pay-button.md——通过 JS 切换style.display或类来控制显示,而不要只依赖hidden属性;并确认在ApplePaySession不存在时按钮确实处于隐藏状态。
检查点
在 Apple 设备或模拟器上点击按钮时,Apple Pay 支付表单是否会显示?商户验证事件是否会触发?
步骤 4 — 启动 Apple Pay 会话
阅读:references/api-schema.md(applePaySessions 的两个 schema 部分——terminal-path 变体和 payments-path 变体)以及 references/add-apple-pay-to-your-integration.md(会话启动说明)。
不要使用来自训练知识的任何 endpoint URL、字段名或响应结构。在选择实现方案之前,请先阅读
references/api-schema.md中的两个会话启动 endpoint schema。
目前有两个受支持的 endpoint 可用于启动 Apple Pay 会话——在编写任何代码之前,请阅读 references/api-schema.md,确认每个 endpoint 的确切 schema:
| 变体 | Endpoint | processingTerminalId 位置 | 使用时机 |
|---|---|---|---|
| Payments-path(新 — 首选) | POST /v1/payments/apple-pay/sessions | 请求体 | 新集成 |
| Terminal-path(原有) | POST /v1/processing-terminals/{processingTerminalId}/apple-pay-sessions | URL 路径 | 已在使用此路径的现有集成 |
对于新集成,请实现 payments-path 变体。对于已在使用 terminal-path 变体的现有集成,无需迁移——两者都受支持。
触发 onvalidatemerchant 时,你的服务器必须调用 Payroc API,与 Apple 验证会话。请从参考资料中确认:
- 使用哪个 endpoint 变体(以及测试环境和生产环境的确切 URL)
- 所选变体所需的请求体字段(请阅读
references/api-schema.md中相关的 schema 部分) - 要传回
completeMerchantValidation的响应对象
Payments-path 变体请求体(从 references/api-schema.md 中的 applePaySessions (payments-path variant) 读取):
processingTerminalId— 必填(从 URL 路径移至请求体)appleDomainId— 步骤 1 中的域 IDappleValidationUrl— 事件中的validationURL,原样传入
Terminal-path 变体请求体(从 references/api-schema.md 中的 applePaySessions (start-session request body) 读取):
appleDomainId— 步骤 1 中的域 IDappleValidationUrl— 事件中的validationURL,原样传入processingTerminalId— 位于 URL 路径中,不在请求体内
两种变体都返回相同的 applePayResponseSession 结构:{ startSessionResponse: "..." }。将未包装的 startSessionResponse 传给 completeMerchantValidation。
实现一个服务器端 endpoint,以便:
- 接收来自客户端的
validationURL - 生成(或复用)有效的 Bearer 令牌
- 使用正确的请求体字段,向所选的 Payroc 会话启动 endpoint 发送 POST 请求
- 将响应体返回给客户端
检查点
completeMerchantValidation 是否成功(未抛出错误)?支付界面是否保持打开并继续显示支付卡?
步骤 5 — 处理支付
此步骤涉及两个来源——Apple 负责事件中加密令牌的格式;Payroc 负责你将 POST 到 /v1/payments 的包装结构和枚举值。请阅读这两份参考资料:
- Apple Pay 支付令牌格式(Apple 整理的说明):
references/third-party/apple-payment-token.md— 授权事件中payment.token.paymentData载荷的结构。这些说明记录了令牌的 JSON 结构;你需要先将此 JSON 编码为十六进制,再发送给 Payroc。 - Payroc 说明与 schema: 组合方式请参阅
references/add-apple-pay-to-your-integration.md,确切的字段名和枚举值请参阅references/api-schema.md(paymentRequest、paymentMethod的 digitalWallet 变体)。
不要使用来自训练知识的任何字段名、endpoint URL 或加密数据格式。 两种转换分别对应两个来源:Apple 的令牌格式见
references/third-party/apple-payment-token.md,Payroc 的支付请求结构见references/api-schema.md。编写代码之前请先阅读两者。 当支付授权事件触发时,事件中包含来自 Apple 的加密支付数据。你的服务器必须:
- 从事件中提取加密支付数据(其结构来自 Apple 支付令牌衍生说明,而非训练数据)。
- 将其转换为十六进制格式(Payroc API 要求采用此格式——请从 Payroc 叙述性文档中读取确切要求;如果没有明确说明,请检查
references/api-schema.md中encryptedData字段的文档约束)。 - 向 Payroc 支付端点发送 POST 请求。要发送的结构(从
references/api-schema.md中读取)通常类似于:paymentMethod.type— 从references/api-schema.md中读取数字钱包的当前枚举值(paymentMethod.type枚举);不要凭记忆假定为"digitalWallet"。paymentMethod.serviceProvider— 从references/api-schema.md中读取 Apple Pay 的当前枚举值;不要凭记忆假定为"apple"。paymentMethod.encryptedData— 第 2 步中经过十六进制编码的令牌。- 以及标准的
channel、processingTerminalId、order字段(均须先读取再写入;参见下方的枚举提示)。 order.orderId— 为每笔支付生成的唯一标识符,长度限制为 1–24 个字符(从references/api-schema.md中读取此约束)。参见下方的 orderId 提示。
- 收到 HTTP 201 时 — 使用客户端上文档记录的成功状态常量,调用文档记录的支付完成方法(从 Apple 衍生说明中读取)。
- 出现任何错误时 — 使用文档记录的失败状态常量调用同一方法,以便支付界面顺利关闭。
从
references/api-schema.md中读取 Payroc 的channel枚举。channel属于 Payroc 支付请求,而不是 Apple Pay 会话。过往已知失败案例(来自同类集成): 某个模型因为channel: "internet"听起来适合浏览器内结账,就输出了这个值——Payroc 返回 HTTP 400,错误详情中列出了枚举值。正确做法不是在这里记住正确值,而是在构造请求体时从架构参考中读取channel。听起来合理的相近值(internet、online、ecommerce、card-not-present)是此类失败最常见的形式。
根据
responseCode判断支付是否成功,不要猜测transactionResult.status的取值子集。 请阅读references/api-schema.md。批准信号是responseCode === 'A'(成功响应还包含approvalCode和值为OK的responseMessage)。transactionResult.status表示生命周期状态:当responseCode为A时,ready(已排队/已捕获)和pending(已授权,等待捕获——例如预授权或autoCapture: false)都表示授权成功;declined/expired等状态则不是,且approved不属于该枚举。过往已知失败案例(来自同类集成和基准测试): 某个模型构建了批准状态列表(或只在"approved"时分支),因此悄然将真实授权判定为失败。不要凭记忆列举状态集合——成功分支应以responseCode === 'A'为依据,并用status判断生命周期。应有意处理E(延迟处理)和P(部分批准);将D/R/C视为拒绝。
确保
order.orderId不超过 24 个字符。 从references/api-schema.md中读取此约束(order.orderId长度为 1–24)。过往已知失败案例: 某个模型生成了order-${uuidv4()}(42 个字符)或原始的crypto.randomUUID()(36 个字符),Payroc 因 HTTP 400"orderId size must be between 1 and 24"拒绝了每笔支付,因此成功分支始终无法触发。原始 UUID/GUID 不符合长度限制。请使用始终符合限制的方案:较短的十六进制 ID(例如crypto.randomBytes(8).toString('hex')→ 16 个字符)、加上几个随机字符的 base36 时间戳,或商家自有的短订单号。在完整集成中,orderId只是众多字段之一,因此很容易出错——务必有意生成符合要求的值。
检查点
支付 API 在 UAT 中是否返回 HTTP 201?Apple Pay 支付界面是否显示成功确认信息?
本地测试策略
Apple Pay 有两项 localhost 无法满足的可访问性要求——上文已分别介绍,这里汇总起来以便查阅:
- 需要一台装有 Wallet 卡片的真实 Apple 设备或模拟器,并使用 Safari / WebKit,才能显示按钮并呈现支付界面(否则
canMakePayments()会返回 false——参见错误分类)。 - 需要一个可公开访问的 HTTPS 域名来进行域名验证(前提条件和第 1 步):Apple 的服务器会直接获取
/.well-known/apple-developer-merchantid-domain-association文件,因此无法验证localhost。请使用暂存域名,或使用可通过 HTTPS 提供验证文件的隧道(ngrok、VS Dev Tunnels、Cloudflare Tunnel),并在 Self-Care Portal 中注册该域名。
此流程中没有入站 Webhook——唯一需要公开可访问的是域名关联文件。
错误分类
| 症状 | 可能原因 | 解决方法 |
|---|---|---|
| Apple Pay 按钮始终不显示 | canMakePayments() 返回 false | 在已将卡片添加到 Wallet 的 Apple 设备或模拟器上测试;如果配对的 iPhone 已启用 Apple Pay,macOS 上的 Safari 也可以使用 |
| 即使在已添加卡片的 Apple 设备上,Apple Pay 按钮也只显示为空白(高度为零/没有图标) | 使用了 <apple-pay-button> Web 组件,但没有加载 Apple 的 apple-pay-sdk.js 脚本,因此自定义元素从未注册 | 阅读 references/third-party/apple-pay-button.md;添加 apple-pay-sdk.js 脚本标签,或改用 CSS -webkit-appearance: -apple-pay-button 方案 |
| Apple Pay 按钮在非 Apple 浏览器上可见(本应隐藏) | 作者 CSS 规则为按钮设置了 display,覆盖了用户代理的 [hidden] { display: none } 规则,导致隐藏条件失效 | 阅读 references/third-party/apple-pay-button.md;通过在 JS 中切换 style.display/类名来控制显示,或避免在按钮的基础 CSS 中设置 display;确认在 ApplePaySession 不存在时按钮确实处于隐藏状态 |
Payments API 返回 400 "orderId size must be between 1 and 24" | order.orderId 超过 24 个字符——通常是原始 uuidv4()/crypto.randomUUID()(36 个字符)或带前缀的 UUID | 阅读 references/api-schema.md 中对 order.orderId 的 1–24 个字符限制;使用始终符合限制的方案(短十六进制字符串、base36 时间戳加短随机字符串,或较短的商户订单号) |
onvalidatemerchant 触发,但 completeMerchantValidation 抛出异常 | 会话启动 API 调用失败,或响应不是原始 Apple 会话对象 | 记录完整的 Payroc 响应;确认直接将响应正文(而非包装后的对象)传递给 completeMerchantValidation |
| 会话启动返回 404 | 端点 URL 错误,或路径中的 processingTerminalId 不正确(终端路径变体) | 重新查阅 references/api-schema.md 中的端点 URL;确认终端 ID 是 UAT 终端 |
会话启动返回 400,错误提示缺少 processingTerminalId | 使用 Payments 路径变体(POST /v1/payments/apple-pay/sessions),但请求正文中未包含 processingTerminalId——此端点不再将其用作路径参数 | 阅读 references/api-schema.md(Payments 路径变体架构);将 processingTerminalId 添加到请求正文中 |
| 会话启动返回 400 | appleDomainId 或 appleValidationUrl 缺失或无效 | 在 Self-Care Portal 中确认域名 ID;确认 validationURL 未经修改,直接从事件传入 |
| 在 Self-Care Portal 中域名验证失败 | 无法通过 HTTPS 访问验证文件 | 确认文件路径准确为 /.well-known/apple-developer-merchantid-domain-association,且没有扩展名;添加域名之前,先用 curl 测试 |
| Payment API 返回 401 | Bearer 令牌已过期,或 API 密钥错误 | 重新获取 Bearer 令牌;验证 x-api-key 的值 |
| Payment API 返回 400 | encryptedData 不是十六进制格式,或缺少必填字段 | 重新查阅 encryptedData 格式要求;检查 Apple 支付数据转换为十六进制格式的过程是否正确 |
Payment sheet 在 STATUS_SUCCESS 后显示失败 | Payment API 返回的状态不是 201,却被错误地当作成功处理 | 仅将 HTTP 201 分支视为成功;其他所有状态均视为失败 |
Payments API 返回 HTTP 400,错误详情中指出 "channel"(或其他枚举类型字段),并列出可接受的值 | 输出了非枚举值(同类集成过去曾出现:channel: "internet"、"online"、"ecommerce");用听起来合理的近似值替代了文档中的值 | 从 references/api-schema.md 中查阅 channel(或相关字段),并输出列出的值之一。不要根据英语表达是否合理来推断枚举值。 |
Payroc API 拒绝 paymentMethod.type 或 paymentMethod.serviceProvider | 技能输出了训练数据中记住的 digitalWallet/apple 值,而不是从 references/api-schema.md 中查阅所得的值 | 从 references/api-schema.md 中查阅当前的 paymentMethod.type 和 paymentMethod.serviceProvider 枚举,并输出其中列出的值。即便记住的值碰巧正确,不查阅参考资料本身也是造成问题的原因。 |
Apple Pay 会话构造函数抛出 TypeError,或 on<event> 处理程序从未被调用 | 构造函数签名或事件名称取自训练数据,而非 Apple 衍生说明;自行假定的名称与文档所述的接口不符 | 阅读 Apple 的 ApplePaySession 衍生说明(references/third-party/apple-applepaysession.md)。确认构造函数签名、要绑定的每个事件名称以及要调用的每个方法。不要杜撰或重命名——如果衍生说明中没有你假定的名称,说明 Apple 已将相应职责移至其他位置。 |
应用记录了支付失败,但银行实际上已批准——Payroc 响应显示 responseCode: "A",并带有 approvalCode/OK 消息 | 成功分支根据猜测的 transactionResult.status 子集进行判断(过去曾出现的问题:只接受 "approved"——它甚至不是枚举成员;或批准状态列表遗漏了 pending 等已授权状态) | 根据 references/api-schema.md,以 responseCode === 'A' 作为成功分支条件;将 ready 和 pending 视为已授权状态,而 status 仅表示生命周期。不要凭记忆列出批准状态。 |
验证清单
- 从环境变量读取 API 密钥和终端 ID,而不是写在源代码中
- 在服务器端生成 Bearer 令牌,而不是暴露给浏览器
- 仅当
ApplePaySession.canMakePayments()返回true时才渲染 Apple Pay 按钮,并验证 Apple Pay 不可用时按钮确实隐藏(不能让作者 CSS 覆盖hidden属性,从而绕过门控) - 通过有文档说明的方式绘制 Apple Pay 按钮:CSS
-webkit-appearance: -apple-pay-button,或使用<apple-pay-button>并加载其apple-pay-sdk.js脚本标签 -
order.orderId生成的字符数为 1–24,而不是原始 UUID/GUID - 域名验证文件可通过 HTTPS 在
/.well-known/apple-developer-merchantid-domain-association访问 - 安全存储域名 ID(环境变量或配置),而不是硬编码
-
onvalidatemerchant:将validationURL从事件原样传递给服务器;将服务器响应原样传递给completeMerchantValidation -
onpaymentauthorized:在发送到 Payroc API 之前,将加密数据转换为十六进制格式 - 使用 Apple Pay 测试交易时,支付 API 在 UAT 中返回 HTTP 201
- 支付 API 响应后,使用正确的状态调用
session.completePayment()
反模式
无条件渲染 Apple Pay 按钮——它会在非 Apple 设备或非 Safari 浏览器上静默失败。务必使用 canMakePayments() 进行门控。
使用 hidden 属性进行门控,同时 CSS 强制按钮显示——作者 CSS(例如 .apple-pay-button { display: block })会覆盖用户代理的 [hidden] { display: none } 规则,因此即使门控设置了 hidden,按钮仍会显示。改为在 JS 中切换 style.display 或类,并验证缺少 ApplePaySession 时按钮确实隐藏。请参阅 references/third-party/apple-pay-button.md。
使用 <apple-pay-button> Web 组件,却不加载其 SDK 脚本——只有加载 https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js 后,才会注册此自定义元素;否则按钮不会渲染任何内容。请加载该脚本,或使用 CSS -webkit-appearance: -apple-pay-button 方式。请参阅 references/third-party/apple-pay-button.md。
将原始 UUID 用于 order.orderId——uuidv4()/crypto.randomUUID()(36 个字符)及带前缀的变体都会超过 1–24 个字符的限制,导致 Payroc 以 HTTP 400 拒绝支付。请使用始终符合限制的方案。
修改 validationURL——应将其从 Apple 事件中原样传递。任何修改(编码、去除首尾空格)都会导致商户验证失败。
包装会话启动响应——Apple 的 completeMerchantValidation 需要 Payroc API 返回的原始会话对象。不要再将其包装进另一个对象,也不要再次进行 JSON 编码。
在支付 API 响应前调用 completePayment(STATUS_SUCCESS)——务必等待 Payroc API 响应后再调用 completePayment。提前调用会使会话处于未定义状态。
硬编码域名 ID——UAT 与生产门户中的域名 ID 不同;请从环境变量读取。
完成
确认 HTTP 201 且所有检查项均已通过后:
**集成完成。**你已完成以下工作:
- 域名验证 — 你的域名已通过 Self-Care Portal 在 Apple 注册;域名 ID 用于授权会话请求。
- 商户验证 — Apple Pay 支付界面打开时,你的服务器会调用 Payroc,与 Apple 验证会话;客户将获得可信赖的支付体验。
- 支付处理 — 客户通过 Face ID / Touch ID 授权;你的服务器会将加密的支付数据转换为十六进制,并将其发送到 Payroc 支付端点。
- 已在 UAT 中验证 — 已确认 Apple Pay 端到端交易。
**上线前:**将会话启动调用和支付 API 调用中的 UAT 端点 URL 替换为生产环境 URL(
api.uat.payroc.com→api.payroc.com)。如果使用 payments-path 变体,请将https://api.uat.payroc.com/v1/payments/apple-pay/sessions→https://api.payroc.com/v1/payments/apple-pay/sessions。在生产环境的 Self-Care Portal 中注册生产域名,并获取其域名 ID。
可提供的后续步骤:
- Google Pay — 将 Google Pay 添加为并行的数字钱包选项;流程类似,但使用 Google Pay JS API 和不同的
serviceProvider值 - Hosted Fields — 如果开发者还需要为非 Apple 用户提供银行卡信息输入表单作为备用方案,请使用 Hosted Fields 技能