﻿# 集成步骤

![](https://img-cdn-sg.payermax.com/public/20240801-605d7da7-9564-4e74-b71f-f8eeccaa3478.jpg)

### 1. 实现流程

对接前：需要提供 https 域名给 payermax 配置（正式环境和测试环境共两个域名），用于 ApplePay 发起支付。

::: danger 特别提醒：
测试时，`127.0.0.1`、`局域网`、`localhost` 都无法拉起 ApplePay。

:::

(a) 商户提供其测试环境和产线环境域名给 PayerMax；

(b) PayerMax 将为商户生成各域名对应证书；

(c)商户将证书文件 apple-developer-merchantid-domain-association 添加到 ./well-known 路径下；

::: warning 注意：
请注意证书配置路径。
:::

![](https://img-cdn-sg.payermax.com/public/20240524-9f7ef725-cee1-4292-9926-782900278249.jpg)

(4) 商户配置好了证书后，通知 PayerMax 验证域名证书，PayerMax将在Apple开发者后台操作域名证书验证。

::: warning 如果验证失败：
1. 可能证书路径配置错误：`请再次检查路径是否正确；`

2. 可能域名防火墙拦截了苹果检查服务：请配置[链接页面](https://developer.apple.com/documentation/apple_pay_on_the_web/setting_up_your_server#3179116)域名至服务器白名单，可参考下方截图；

3. 可能已经配置过其他MerchantID的证书：`可使用新域名，或在原开发者账号上删除对应域名证书。`
:::

![](https://img-cdn-sg.payermax.com/public/20240524-7664a72c-3658-4c63-a671-0540e1b95de6.png)

#### 1.1 获取 clientKey 和 sessionKey

接口详细说明请参阅：[接口参数](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-applyDropinSession/post)。

(a) 请求API；环境及地址如下：

| 请求环境 | 请求地址                                                                       |
| -------- | ------------------------------------------------------------------------------ |
| Test     | https://pay-gate-uat.payermax.com/aggregate-pay/api/gateway/applyDropinSession |
| Live     | https://pay-gate.payermax.com/aggregate-pay/api/gateway/applyDropinSession     |

(b) 从返回值获取 clientKey 和 sessionKey。

::: warning 注意：
服务端获取到的`clientKey`、`sessionKey`返回给前端用于组件初始化。
:::

请求Header示例：

```json
{
    'Content-Type': 'application/json;charset=utf-8',
    'Accept': 'application/json',
    'sign': <参考：https://docs-v2.payermax.com/202606-version/developer/config-settings.html>
};
```

请求Body示例：

```json
request.body = 
    {
        "version": "1.1",
        "keyVersion": "1",
        "requestTime": <替换>, 
        "merchantNo": <替换>,
        "appId": <替换>, 
        "data": {
            "country": "MY", 
            "currency": "MYR", 
            "totalAmount":"50",
            "userId": "20220622_00086",
            "componentList":["APPLEPAY","CARD"] 
        }
    }

response={
  "msg": "",
  "code": "APPLY_SUCCESS", 
  "data": {
    "sessionKey": "bf2c47b085e24c299e45dd56fd751a70",
    "clientKey": "bbd8d2639a7c4dfd8df7d005294390df" 
    }
}
```

#### 1.2 渲染组件

+ **前端示例**

下载[Demo示例](https://img-cdn-sg.payermax.com/public/20240801-a9cce221-531b-4bad-9b53-9ce7720a269c.zip)，替换 clientKey 和 sessionKey 后，需要部署在带有ApplePay证书的域名打开可以看到效果。

+ **前端集成步骤**

(a) 在相关 HTML 页面上引入 CDN 包；

```html

```

(b) 通过 div 标签嵌入一个 iframes；

```html

  

```

(c) 初始化 PayerMax Frames；

```js
// 初始化卡组件
const applePay = PMdropin.create('applepay', {
  clientKey: "客户端公钥", // 在步骤1.1中获取到的 data.clientKey
  sessionKey: "会话令牌", // 在骤1.1中获取到的 data.sessionKey
  sandbox: true, // 默认是 false，即生产环境
  theme: 'dark',// 主题，默认light
});
// 挂载实例
applePay.mount('.frame-applepay'); // 将挂载至匹配到的第一个 dom 元素上
// 组件加载完成时机
applePay.on('ready', () => {
    // 移除自定义loading               
})
```

(d) 监听 applePay 按钮点击，获取 paymentToken；

::: warning 注意：
获取到 `paymentToken`, 用于发起支付接口。
:::

```js
applePay.on('payButtonClick', (res) => {
  applePay.emit('setDisabled', true) // 冻结表单，防止按钮重复点击
  applePay.emit('canMakePayment')
    .then(res => {
      if (res.code === 'APPLY_SUCCESS') {
        const paymentToken = res?.data?.paymentToken // 支付token，支付接口使用
        // ❗️发起支付接口
        // 商户自己请求后端接口进行下单, 
        // 商户自己用params构造请求参数，需要带上paymentToken
          _postapi('orderAndPay',params).then(res =>{
            const code = (res || {}).code
            //商户将支付结果返回到前端
            if (code == 'APPLY_SUCCESS') {     
              applepay.emit('paySuccess')//支付成功，ApplePay控件消失
            } else {
              applepay.emit('payFail')//支付失败，ApplePay控件消失
            }
        applePay.emit('setDisabled', false) // ❗️支付接口完成后解冻表单
      } 
    })
    .catch(err => {
      applePay.emit('setDisabled', false) // 发生异常后解冻表单
    })
})
```

(e) 发起支付，具体可查看1.3中的服务端发起支付。

#### 1.3 商户后台下单

+ **下单时机**

请在前端回调 card.emit('canMakePayment') 后，当 response.code 为 'APPLY_SUCCESS' 时发起下单请求，此时可从 canMakePayment 方法获取到 paymentToken，用在后续下单接口入参。

+ **下单步骤**

(a) 商户前端向商户后端发起下单，传入 canMakePayment 方法获取到的 paymentToken；

(b) 商户服务端生成订单号（outTradeNo）后向 PayerMax 服务端发起支付请求；

(c) 处理 PayerMax 响应结果。

+ **响应处理**

服务端下单会返回支付结果，处理完支付结果需要响应到前端，前端根据响应结果调用applepay.emit('paySuccess')或者applepay.emit('payFail')。

+ **API 环境及地址**

| 请求环境 | 请求地址                                                                |
| -------- | ----------------------------------------------------------------------- |
| Test     | https://pay-gate-uat.payermax.com/aggregate-pay/api/gateway/orderAndPay |
| Prod     | https://pay-gate.payermax.com/aggregate-pay/api/gateway/orderAndPay     |

请求Header示例：

sign 字段的取值请参阅【[配置与签名](/202606-version/developer/config-settings.md)】。

```json
{
    'Content-Type': 'application/json;charset=utf-8',
    'Accept': 'application/json',
    'sign': <XXX>
};
```

请求Body示例：

下单详细字段请参阅[接口参数](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderAndPay(for-drop-dont-copy-me)/post)。

```json
{
    "appId": "<替换>",
	"version": "1.4",
	"merchantNo": "<替换>",
	"requestTime": "2024-06-05T10:46:01.694+08:00",
	"keyVersion": "1",
	"data": {
		"totalAmount": 77.44,
		"country": "HK",
		"expireTime": "7200",
		"paymentDetail": {
			"paymentToken": "332e4cc1af1740aeafe9e7df82aeb5a1",
			"buyerInfo": {
				"clientIp": "59.82.59.92",
				"userAgent": "Safari"
			},
			"sessionKey": "86409e2c04b44536a484caa5ce3ce0e9"
		},
		"frontCallbackUrl": "<替换>",
		"subject": "<替换>",
		"outTradeNo": "1003052024060510454400707",
		"notifyUrl": "<替换>",
		"currency": "HKD",
		"userId": "3ff0495692d152be96d84dbc9352dc57",
		"integrate": "Direct_Payment",//固定
		"terminalType": "WEB"
	}
}
```
### 2. 其他定制

前端接口详情请参阅【[ApplePay前端接口](/202606-version/receipt/front-end-component/configuration-applepay.md)】文档。
