前置组件 - CARD
1. 交互流程
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#e6f0ff',
'primaryTextColor': '#333',
'primaryBorderColor': '#5b9bd5',
'lineColor': '#888',
'actorMargin': 40,
'noteBkgColor': '#0056b3',
'noteTextColor': '#ffffff',
'noteBorderColor': '#004a99'
}
}}%%
sequenceDiagram
participant User as 用户
participant Page as 商户页面
participant Component as PayerMax
前置组件
participant MServer as 商户服务端
participant PMServer as PayerMax服务器
participant Channel as 支付渠道
钱包/银行等
%% 1. 初始化阶段
User->>Page: 1.1 选择商品下单
Page->>MServer: 1.2 发送订单信息
如:收单国家、订单币种等
MServer->>PMServer: 1.3 获取前置组件初始化信息
clientKey和sessionKey
PMServer-->>MServer: 1.4 返回结果
clientKey和sessionKey
MServer-->>Page: 1.5 返回结果
含clientKey和sessionKey
Page->>Component: 1.6 创建并挂载PayerMax组件
%% 2. 获取 Token 阶段
User->>Page: 2.1 用户输入支付信息
Page->>Component: 2.2 获取paymentToken
Component->>PMServer: 2.3 获取paymentToken
PMServer-->>Component: 2.4 返回结果
含paymentToken
Component-->>Page: 返回paymentToken
%% 3. 提交订单与支付
User->>Page: 3.1 确认支付
Page->>Component: 3.2 提交支付
含paymentToken
Component->>MServer: 3.3 提交订单
含paymentToken
MServer->>PMServer: 3.4 创建支付
调用前置组件下单接口
PMServer->>Channel: 3.5 支付请求
PMServer-->>MServer: 3.6 返回结果
MServer-->>Component: 3.7 返回结果
Component-->>Page: 3.8 返回结果
%% 4. 获取支付结果 (逻辑框)
rect rgb(235, 245, 255)
Note over MServer, PMServer: 获取支付结果
Note over MServer, PMServer: 通过支付结果通知
PMServer->>MServer: 4.1 支付结果异步通知
MServer->>MServer: 4.2 更新支付结果
MServer-->>PMServer: 4.3 返回响应
Note over MServer, PMServer: 通过支付订单查询
MServer->>PMServer: 5.1 查询支付交易单
PMServer-->>MServer: 5.2 交易详情,含支付结果
MServer->>MServer: 5.3 更新支付结果
end
2. 接口介绍
2.1 接口列表
| 关联交互时序 | 调用方向 | 接口类型 | 接口PATH |
| 3.1 获取前置组件初始化信息 | 商户 -> PayerMax | 后端接口 | /applyDropinSession |
| 3.4 创建支付,调用前置组件下单接口 | 商户 -> PayerMax | 后端接口 | /orderAndPay |
| 3.4.1 支付结果异步通知 | PayerMax -> 商户 | 后端接口 | /collectResultNotifyUrl |
| 3.4.2 查询支付交易 | 商户 -> PayerMax | 后端接口 | /orderQuery |
2.2 环境信息
测试环境:https://
pay-gate-uat.payermax.com/aggregate-pay/api/gateway/<接口PATH>集成环境:https://
pay-gate.payermax.com/aggregate-pay/api/gateway/<接口PATH>
2.3 请求header
"headers": {
"Accept": "application/json",
"sign": "请参考签名规则:https://docs-v2.payermax.com/doc-center/developer/config-settings.html",//必须
"Content-Type": "application/json"
}3.开始集成
3.1 获取前置组件初始化信息
商户服务端通过/applyDropinSession API 接口,发起HTTP POST请求,获取前置组件初始化所需的客户端令牌clientKey和会话令牌sessionKey。
- /applyDropinSession API 接口请求示例:
{
"requestTime": "2024-11-20T01:56:36.753-02:00",
"keyVersion": "1",
"data": {
"country":"US",
"currency": "USD",
"totalAmount": "19.99",
"componentList": ["CARD","APPLEPAY"],
"userId": "1447410849000200"
},
"appId": "381ded7c863c439a9e29b4519867965a",
"version": "1.1",
"merchantNo": ""
}- /applyDropinSession API 接口响应示例:
{
"msg": "",
"code": "APPLY_SUCCESS",
"data": {
"sessionKey": "964bffa7c9eb4951bd5ba11a2691e5ed",
"notSupportedComponent": [],
"clientKey": "8eef820ecbd443b7a608c2e0863750eb"
}
}3.2 渲染前置组件
- 在相关 HTML 页面上引入 CDN 包。
<script src="https://cdn.payermax.com/dropin/js/pmdropin.min.js"></script>- 通过过
div标签,在商户页面嵌入一个card待展示区域。
<div class="frame-card">
<!-- 表单内容 -->
</div>- 初始化 PayerMax Frames。
// 初始化卡组件
const card = PMdropin.create('card', {
clientKey: "客户端公钥", // 在步骤3.1中获取到的 data.clientKey
sessionKey: "会话令牌", // 在步骤3.1中获取到的 data.sessionKey
sandbox: false, // 默认是 false,即生产环境
hideSaveCard: false, //是否隐藏保存卡信息选项,默认是false展示
hideCardBrands: false, //是否隐藏左上角卡品牌的Logo,默认是false展示
});
// 挂载实例
card.mount('.frame-card'); // 将挂载至匹配到的第一个dom元素上
// 组件加载完成时机
card.on('ready', () => {
// 移除自定义loading
})- 监听表单填写状态,动态设置支付按钮(可选)。通过表单监听事件,可实时监控用户填写信息的合法性,以此动态设定 按钮是否可点击。
card.on('form-check', (res) => {
// res.isFormValid 为表单状态。取值是false/true
// true 表示表单校验通过,可支付;false 表示校验未通过,不可支付,无法点击支付按钮。
console.log('[dropin][form-check]:', res)
})- 用户点击支付按钮,商户提交支付到PayerMax服务端
//用户点击支付按钮,提交支付
function goPay(){
card.emit('setDisabled', true) // 点击支付按钮后冻结表单,防止重复提交支付过程
card.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') {
if(res.threeDSUrl){
//使用PayerMax组件内弹窗完成3ds;也可以将threeDSUrl新开浏览器tab页打开完成3ds
handle3DS(threeDSUrl)
}
//支付成功,展示支付结果
} else {
//支付失败,展示失败结果
}
}
card.emit('setDisabled', false) // 支付接口完成后解冻表单
}
})
.catch(err => {
card.emit('setDisabled', false) // 发生异常后解冻表单
})
}
// orderAndPay后若获取到返回的url(即为threeDSUrl)就使用handle3DS方法唤起弹窗
function handle3DS(threeDSUrl) {
card.create3DSPopup({
url: threeDSUrl,
// width/height 不传则按设备与视口自动计算;也可显式传入如 '80%'、'400px' 等
})
.then(res => {
if (res.code === '3DS_PROCESSED') {
// 3DS 流程完成,继续支付流程。
console.log('3DS 流程完成', res.data);
// 此处商户需要维持现有逻辑,商户侧应该主动查询支付结果 继续商户侧后续的交互
proceedPayment(res.data);
}
})
.catch(err => {
if (err.code === 'USER_CANCEL') {
// 商户也可不做处理,但是应允许用户继续点击支付按钮
showMessage('您已关闭认证窗口');
} else {
showMessage('认证出现异常,请重试');
}
});
}- 当用户在前端确认支付后,前端
canMakePayment接口会返回paymentToken,用作后端发起支付。
前端返回数据结构如下:
{
"msg": "",
"code": "APPLY_SUCCESS",
"data": {
"paymentToken": "CPT771e98494eff41f1a03a715ebab69cc9",
"cardOrg": "VISA",
"maskCardNumber": "444433****1111",
"cardExpirationMonth": "12",
"cardType": "CREDIT",
"cardExpirationYear": "26",
"cardHolderFullName": "Jemy Cheung",
"agreementAccepted": true,
"cardBinNo": "444433",
"cardIssuingCountry": "US"
}
}3.3 创建支付
- 商户服务端:调用/orderAndPay API 接口发起HTTP POST请求,创建支付。
/orderAndPay API 接口请求示例:
{
"requestTime": "2024-11-20T01:56:45.802-02:00",
"keyVersion": "1.5",
"data": {
"currency": "USD",
"country": "US",
"totalAmount": 19.99,
"expireTime": "3600",
"paymentDetail": {
+ "paymentToken": "dbe78b7dd4fa4b668bacfdcc7153821d", // 用户输入卡信息后点击支付会回调前端paymentDetail
"buyerInfo": {
"clientIp": "146.75.136.237",
"userAgent": "Chrome"
},
+ "sessionKey": "abf62fdcf9c4408cb73117db6e740713"
},
"frontCallbackUrl": "https://",
"subject": "xxx Game HK Limited",
"outTradeNo": "ov1_5b89ced71d764ed9994e6882d88082f7",
"notifyUrl": "https://",
"userId": "1447410849000200",
"integrate": "Direct_Payment",
"terminalType": "WEB"
},
"appId": "381ded7c863c439a9e29b4519867965a",
"version": "1.4",
"merchantNo": "P04010116880289"
}- /orderAndPay API 接口响应示例:
WARNING
注意:返回中可能存在data.redirectUrl,这时请返回给前端引导用户完成3ds认证。
{
"msg": "Success.",
"code": "APPLY_SUCCESS",
"data": {
"outTradeNo": "test_da78b1f3c2f9443b966347fc89305fc9",
"tradeToken": "T2024052805951921811176",
"status": "SUCCESS"
}
}3.4 获取支付结果
创建支付/orderAndPay API 接口响应的data.status并非支付终态,因此,商户不应直接使用其更新支付结果。
3.4.1 通过支付结果通知
请查看支付结果-通过支付结果通知。
3.4.2 通过支付订单查询
请查看支付结果-通过支付订单查询。
4.卡支付前端接口
4.1 API
使用方法 PMdropin.API。
| API | 描述 | 详情 |
|---|---|---|
| create | 实例化一个内置组件 | 参阅create |
| mount | 将实例化组件挂载到div标签 | 参阅mount |
| on | 监听事件 | 参阅on |
| emit | 触发事件 | 参阅emit |
4.1.1 create
用于初始化组件,使用方法 PMdropin.create(ComponentName, Options)。
ComponentName详解
| ComponentName | 字段类型 | 描述 |
|---|---|---|
| card | string | 卡组件 |
Options详解
| Options | 是否必填 | 字段类型 | 描述 | 默认值 |
|---|---|---|---|---|
| clientKey | Y | String | 客户端公钥 | - |
| sessionKey | Y | String | 安全访问令牌 | - |
| sandbox | N | Boolean | 沙盒环境 | false |
| language | N | String | 语言 | en |
| theme | N | String | 主题 | light |
| customLocalization | N | Object | 自定义语言 | - |
| customTheme | N | Object | 自定义主题 | - |
| grayscale | N | String | 页面灰度 | '0' |
| isRtl | N | Boolean | 从右到左 | false |
| hideSaveCard | N | Boolean | 隐藏Save保存 | false |
| hideCardBrands | N | Boolean | 隐藏头部卡组织LOGO | false |
| hideCardHolderName | N | Boolean | 隐藏卡姓名 | false |
| saveCardChecked | N | Boolean | 保存卡信息的checkbox是否选中 true - 勾选 false - 不勾选 注:当hideSaveCard = false时,该字段生效 | true |
| ignoreUserCheckedCache | N | Boolean | 是否忽略用户勾选缓存 false - 默认不忽略 true - 忽略 注:当hideSaveCard = false时,该字段生效 | false |
| hideRecommendAccount | N | Boolean | 是否隐藏推荐卡模块 | false |
| openTermsInCurrentPage | N | Boolean | 是否在当前页面打开协议弹框 | false |
| termsPopupConfig | N | Object | 协议弹框配置 注:当openTermsInCurrentPage = true时,该字段生效 | - |
| >>showMask | N | Boolean | 是否展示遮罩层 | true |
| >>closeOnClickMask | N | Boolean | 点击遮罩是否关闭弹框 | true |
4.1.2 mount
用于挂载初始化组件实例,使用方法PMdropin.mount(Tag)。
Tag详解
| Tag | 描述 |
|---|---|
| id | 需要挂载的id元素值,如 PMdropin.mount('#card-frame') |
| class | 需要挂载的class元素值,如 PMdropin.mount('.card-frame') |
4.1.3 on
用于监听组件内置响应事件,使用方法PMdropin.on(Event, CallbackFunction)。
Event详解
| Tag | 描述 | 返回值 |
|---|---|---|
| ready | 组件加载完成时触发 | null |
| form-check | 实时监听卡组件校验状态 | 参阅下方 Event Response |
| load | 组件加载完成时触发 | Object - type:组件类型card/applepay/googlepay - code:响应码 SUCCESS 表示加载成功,其余枚举表示加载失败 - msg:响应 message |
示例:
PMdropin.on('form-check', function(event) {
if (event.isFormValid) {
// 表单校验通过
}
});4.1.4 create3DSPopup
用于在组件内弹窗打开3DS认证页面
**语言设置说明:**SDK会会自动从实例配置中获取语言,无需在create3DSPopup中单独传入
入参说明:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| url | string | 是 | - | 3DS 认证页面 URL(从 orderandpay 接口获取) |
| showMask | boolean | 否 | true | 是否显示背景遮罩 |
| width | string | 否 | 响应式计算 | 弹框宽度,不传则按设备/视口自动计算 |
| height | string | 否 | 响应式计算 | 弹框高度,不传则按设备/视口自动计算 |
返回:
| CODE | 说明 | 处理建议 |
|---|---|---|
3DS_PROCESSED | 3DS 流程已处理 | 继续后续支付流程,通过接口查询最终认证结果 |
USER_CANCEL | 用户关闭弹框 | 提示用户已关闭,可重试 |
INVALID_PARAMS | 调用入参不合法 | 根据 err.msg 检查入参(如 url 必填且非空、类型正确等),修正后重试 |
4.1.5 emit
用于调用组件内置方法,使用方法PMdropin.emit(Event, Params)。
| Event | Params | 描述 |
|---|---|---|
| canMakePayment | - | 获取卡标识 |
| switchLanguage | string | 切换语言 |
| switchTheme | string | 切换主题 |
| addLocalization | Object | 添加自定义语言 |
| addTheme | Object | 添加自定义主题 |
| setDisabled | Boolean | 设置组件可用状态 |
| setRtl | Boolean | 设置组件从右到左布局 |
| setGrayscale | string | 设置组件页面灰度 |
1. emit.canMakePayment
检查当前组件状态是否具备发起支付条件,如果校验通过则返回卡标识。
// 示例
PMdropin.emit('canMakePayment')
.then(function(response) {
// 验证成功
if (response.code === 'APPLY_SUCCESS') {
// 获取 paymentToken
var paymentToken = response.data.paymentToken
// 进行后续支付操作
}
})
.catch(function(error) {
// 捕获内部异常错误
console.log(error);
})canMakePayment Response:
// 接口成功示例
{
code: 'APPLY_SUCCESS',
data: {
// 卡标识
paymentToken: 'xxx'
},
msg: ''
}
// 接口失败示例
{
code: 'FORM_INVALID',
msg: 'Invalid params: cvv'
}| CODE码 | 描述 |
|---|---|
| APPLY_SUCCESS | 成功获取 paymentToken |
| FORM_INVALID | 表单校验失败 |
| UNKNOWN_ISSUE | 异常信息 |
2. emit.switchLanguage
- 参阅【定制化】
3. emit.switchTheme
- 参阅【定制化】
4. emit.addLocalization
- 参阅【定制化】
5. emit.addTheme
- 参阅【定制化】
6. emit.setDisabled
- 设置组件可用状态
- 类型
Boolean - 默认:
false
// 不可编辑状态
PMdropin.emit('setDisabled', true)
// 可编辑状态
PMdropin.emit('setDisabled', false)7. emit.setRtl
- 设置组件从右到左布局
- 类型:
Boolean - 默认:
false
// 从右到左布局
PMdropin.emit('setRtl', true)
// 从左到右布局
PMdropin.emit('setRtl', false)8. emit.setGrayscale
- 设置组件页面灰度
- 类型:
String - 默认:
0
// 设置 0 - 1 灰度值
PMdropin.emit('setGrayscale', '1')