Apple Pay

Apple Pay 是一款全球消费者广泛使用的数字钱包,用于电子商务购物,通过提供更快速、更安全的结账体验来提高支付转化率。Apple Pay 占据了全球数字钱包市场份额的 30%,消费者可以无缝访问已保存的卡信息,并在无需手动输入的情况下完成支付。




支付方式属性

属性内容
可用国家代码香港(HK)、美国 (US)、英国(EU)、欧洲(UK)
消费者货币AUD, CAD, CHF, CZK, DKK, EUR, GBP, HKD, HUF, IDR, JPY, MXN, NOK, NZD, PEN, PLN, SEK, SGD, THB, USD, ZAR
处理货币美元 (USD)
结算货币美元 (USD)
类型 I信用卡及借记卡(Cards)
类型 IIapplepayus
最小交易金额

币种的最小单位乘以 2

(即如果币种为 USD,基于最小单位是 1 美分,则最小支付金额为 2 美分)

最大交易金额无限制
会话超时1 小时,取决于流程
退款支持全额退款、部分退款和多次部分退款
退款有效期360 天
拒付180 天
❗️

当国家代码与处理货币不一致时,FuturePay会按照国际卡费率处理交易。

1. 概述

Apple Pay 是 Apple 提供的安全支付方式,用户使用绑定在 Apple 钱包中的银行卡,通过 Face ID / Touch ID 快速完成付款。FuturePay 支持以下三种集成方式:

集成方式适用场景域名报备商户开发量
收银台链接跳转到 FuturePay 收银台付款不需要最少
SDK 弹窗在商户网页中嵌入 FuturePay SDK 弹窗需要少
API 直连(新增)商户在自己的页面中自行渲染 Apple Pay 按钮、完全控制交互需要较多
  • Apple Pay 只能在 HTTPS 网页 中使用,需在 Safari 或其他支持 Apple Pay 的浏览器、且用户设备已绑卡时才会展示。
  • 三种方式均不支持原生 iOS App 内直接调起 Apple Pay。
  • API 直连目前按白名单开通,如需使用请联系 FuturePay 商务或技术支持。

2. 收银台链接方式

商户通过 FuturePay 创建订单接口获取收银台 URL,用户跳转到收银台完成 Apple Pay 付款。

  • 特点:无需域名报备,开箱即用
  • 流程:
    1. 商户调用创建支付订单接口
    2. FuturePay 返回收银台链接
    3. 用户跳转收银台完成付款
    4. FuturePay 通过 Webhook 异步通知商户支付结果

3. SDK 弹窗方式

商户在自己的网页中嵌入 FuturePay SDK,用户在 SDK 弹窗中直接选择 Apple Pay 付款。

  • 特点:Apple 要求调起 Apple Pay 的域名必须事先报备并验证,流程见 第 5 节 域名报备。

4. API 直连方式(新增)

商户在自己的页面中使用 Apple Pay JS 渲染按钮、调起支付面板,通过 FuturePay 接口完成商户验证与扣款。商户对按钮位置、页面交互拥有完全控制权。

4.1 整体流程

 用户浏览器(商户页面)          商户后端                     FuturePay
        │                        │                             │
   ①点击 Apple Pay 按钮           │                             │
   new ApplePaySession(...)      │                             │
   session.begin()               │                             │
        │                        │                             │
   ②onvalidatemerchant ────────► │ ③POST /payin/applePaySession ►│ 向 Apple 申请 merchant session
        │                        │ ◄──────────── data ──────────│
   completeMerchantValidation ◄──│                             │
   (data)                        │                             │
        │                        │                             │
   ④用户在面板中授权付款           │                             │
   onpaymentauthorized ────────► │ ⑤POST /payin/paymentOrder ──►│ 解密 token 并扣款
        │                        │ ◄────────── 支付结果 ─────────│
   completePayment(status) ◄─────│                             │
        │                        │ ◄──── ⑥Webhook 异步通知 ──────│

关键要求:

  • 步骤 ③、⑤ 必须由商户后端调用,签名密钥不能放在前端。
  • 调起 Apple Pay 的页面域名必须已完成报备(见第 5 节),否则步骤 ③ 会被拒绝。
  • 每次付款都要重新申请 merchant session,session 只能使用一次,且有效期很短(约 5 分钟),不要缓存。

4.2 前端唤起 Apple Pay

<script src="https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js"></script>
<apple-pay-button buttonstyle="black" type="buy" locale="zh-CN" onclick="onApplePayClicked()"></apple-pay-button>
function onApplePayClicked() {
  // 必须在用户点击事件中【同步】创建并 begin,不能先 await 其他请求
  const session = new ApplePaySession(3, {
    countryCode: 'US',                       // 收单国家,开通时由 FuturePay 告知(如 US / HK)
    currencyCode: 'USD',                     // 与下单币种一致
    supportedNetworks: ['visa', 'masterCard'],
    merchantCapabilities: ['supports3DS'],
    total: { label: 'Example Shop', amount: '10.00' }  // 与下单金额一致
  });

  // ② 商户验证:调用商户自己的后端,由后端转调 FuturePay /payin/applePaySession
  session.onvalidatemerchant = async () => {
    try {
      const merchantSession = await fetch('/your-api/apple-pay/session', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ domain: window.location.hostname })
      }).then(r => r.json());
      // 传入 FuturePay 响应中的 data 字段,而不是整个响应体
      session.completeMerchantValidation(merchantSession);
    } catch (e) {
      session.abort();
    }
  };

  // ④ 用户授权后,把 token 交给商户后端,由后端调用 FuturePay /payin/paymentOrder
  session.onpaymentauthorized = async (event) => {
    const result = await fetch('/your-api/apple-pay/pay', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token: event.payment.token })
    }).then(r => r.json());
    session.completePayment(result.success
      ? ApplePaySession.STATUS_SUCCESS
      : ApplePaySession.STATUS_FAILURE);
  };

  session.begin();
}

页面通过 iframe 嵌入时:iframe 需要加 allow="payment" 属性,申请 session 时 domain 填顶层页面的域名,且顶层页面域名需完成报备。

4.3 接口一:申请 Merchant Session

商户后端在前端触发 onvalidatemerchant 时调用,返回 Apple 签发的 merchant session。

端点

环境地址
生产POST https://api.futurepay.global/payin/applePaySession
沙箱POST https://api.futurepay-develop.com/payin/applePaySession

鉴权:与创建支付订单接口 /payin/paymentOrder 完全一致——请求头携带 merchantId、appId、Authorization(签名),Content-Type: application/json;开启了 IP 白名单的商户需从白名单 IP 调用。

请求参数

字段必填类型说明
domain是String调起 Apple Pay 的页面域名,即前端的 window.location.hostname。只填域名,不带协议、端口和路径,例如 shop.example.com。必须已完成报备
displayName否String支付面板上显示的商户名,最长 64 个字符。不传时使用商户在 FuturePay 登记的名称

请求示例

{
  "domain": "shop.example.com",
  "displayName": "Example Shop"
}

响应参数

字段类型说明
codeString0 表示成功,其他见 4.5 错误码
msgString结果说明
dataObjectApple merchant session。原样传给前端 session.completeMerchantValidation(data),不要修改其中任何字段

响应示例

{
  "code": "0",
  "msg": "succeeded",
  "data": {
    "epochTimestamp": 1761100000000,
    "expiresAt": 1761103600000,
    "merchantSessionIdentifier": "SSH1A2B3C4D5E6F...",
    "nonce": "8a1b2c3d",
    "merchantIdentifier": "4F1E2D3C...",
    "domainName": "shop.example.com",
    "displayName": "Example Shop",
    "signature": "308006092a864886f70d0107...",
    "operationalAnalyticsIdentifier": "...",
    "retries": 0
  }
}

4.4 接口二:提交 Apple Pay 支付

用户在面板中授权付款后,前端在 onpaymentauthorized 中拿到 event.payment.token,交由商户后端调用创建支付订单接口完成扣款。

端点:POST /payin/paymentOrder(与常规 API 下单为同一接口,鉴权方式相同)

Apple Pay 相关参数

字段必填类型说明
paymentMethod.type是String固定 applepayus
paymentMethod.applePayToken是Stringevent.payment.token 整个对象序列化成的 JSON 字符串(包含 paymentData、paymentMethod、transactionIdentifier)。注意是字符串,不是对象
amount.value是Long支付金额,最小货币单位,必须与前端 total.amount 一致
amount.currency是String支付币种,ISO 4217,必须与前端 currencyCode 一致

其余字段(reference、shopperIP、returnUrl、Webhook 地址等)与常规 API 下单相同,请参考《创建支付订单》接口文档。

请求示例

{
  "reference": "ORDER-20261022-0001",
  "amount": { "value": 1000, "currency": "USD" },
  "shopperIP": "203.0.113.10",
  "paymentMethod": {
    "type": "applepayus",
    "applePayToken": "{\"paymentData\":{\"data\":\"...\",\"signature\":\"...\",\"header\":{\"publicKeyHash\":\"...\",\"ephemeralPublicKey\":\"...\",\"transactionId\":\"...\"},\"version\":\"EC_v1\"},\"paymentMethod\":{\"displayName\":\"Visa 1234\",\"network\":\"Visa\",\"type\":\"debit\"},\"transactionIdentifier\":\"...\"}"
  }
}

响应与结果通知:与常规 API 下单一致。商户后端根据同步响应决定前端调用 STATUS_SUCCESS 还是 STATUS_FAILURE,最终支付结果以 Webhook 通知或订单查询为准。

4.5 错误码

申请 Merchant Session 接口的错误码:

code含义处理建议
0成功把 data 传给 completeMerchantValidation
40001缺少参数(domain 为空,或未传 displayName 且商户名称未登记)补齐参数
40000参数错误(domain 不是合法域名或带了协议/端口/路径;displayName 超过 64 个字符)按说明修正参数
40026域名未报备,或该域名不属于当前商户按第 5 节完成报备;确认 domain 填的是顶层页面域名
40025Apple 返回错误或请求超时可提示用户稍后重试;持续出现请联系 FuturePay,常见原因是域名验证文件被删除或失效
40007签名无效检查签名算法和密钥
40011IP 不在白名单从已登记的服务器 IP 调用
429请求过于频繁降低调用频率

提交支付接口的错误码与常规 API 下单一致。

5. 域名报备(SDK 弹窗 / API 直连通用)

Apple 要求每一个调起 Apple Pay 的域名都必须事先报备并验证。主域名和子域名需要分别报备,例如 example.com 与 www.example.com、shop.example.com 是三个不同的域名。

流程:

  1. 商户提交域名
    将需要调起 Apple Pay 的完整域名列表提供给 FuturePay 技术支持,并说明使用 SDK 弹窗还是 API 直连。

  2. FuturePay 提供验证文件
    FuturePay 向商户提供域名验证文件 apple-developer-merchantid-domain-association.txt。

  3. 商户部署验证文件
    将文件放到每个报备域名的以下路径,保证公网可以通过 HTTPS 直接访问:

    https://{你的域名}/.well-known/apple-developer-merchantid-domain-association.txt
    • 文件名保留 .txt 扩展名,内容不得修改;
    • 必须返回 HTTP 200,不能重定向、不能需要登录、不能被 WAF / CDN 拦截;
    • 验证通过后请勿删除该文件,Apple 会不定期复核,文件失效会导致 Apple Pay 不可用。
  4. FuturePay 向 Apple 报备并验证
    商户告知部署完成后,FuturePay 向 Apple 提交该域名并完成验证。

  5. 开通完成
    FuturePay 通知商户开通结果,之后即可在该域名下使用 Apple Pay。

6. 注意事项

  • 收银台链接方式无需域名报备,可直接使用;SDK 弹窗与 API 直连必须先完成域名报备。
  • API 直连中,申请 session 与提交支付都必须由商户后端调用,切勿在前端暴露签名密钥。
  • 前端 total.amount / currencyCode 必须与下单的 amount 一致,否则用户看到的金额与实际扣款不符。
  • new ApplePaySession(...) 和 session.begin() 必须在用户点击事件中同步执行,否则浏览器会拒绝调起。
  • 新增、变更或下线域名请提前联系 FuturePay;域名验证文件需长期保留。
  • Apple Pay 支付的退款、查询、拒付处理与卡支付一致,使用相同接口。

Did this page help you?