嵌入式集成
工作原理
后端集成
提示
确保对 IOTPay 端点的请求是在商户的服务器上执行的(而不是客户端浏览器上执行),以避免潜在的跨源资源共享(CORS)错误。
银行卡支付
在您的后端服务器上对 cc_purchase
API 端点进行 POST 请求。
端点
https://ccapi.iotpaycloud.com/v3/cc_purchase
方法
POST
头部
Content-Type: application/json;charset=UTF-8
请求
名称 | 必填 | 类型 | 示例 | 描述 |
---|---|---|---|---|
mchId | y | String(30) | 10000701 | 由 IOTPay 分配 |
mchOrderNo | y | String(30) | 1234567890abc | 由商户分配的订单号(不可重复) |
amount | y | Int | 1500 | 以分为单位 |
currency | y | String(3) | CAD | 目前仅支持 CAD |
loginName | y | String(12) | jack123 | 商户的登录名 |
subject | n | String(64) | ||
body | n | String(250) | ||
channel | y | String | PF_CC | PF_CC 或 UPI_EX |
notifyUrl | y | String(200) | 支付成功时获取通知 | |
returnUrl | y | String(200) | https://example.com | 付款后重定向到此 URL |
sign | y | String(32) | C380BEC2BFD727A4B6845133519F3AD6 | 签名算法 |
响应
名称 | 必填 | 类型 | 示例 | 描述 |
---|---|---|---|---|
retCode | y | String | SUCCESS or FAIL | |
retMsg | y | String | ||
retData.redirectUrl | y | String | 对于重定向支付,请忽略此字段,嵌入式集成请使用 retData.secureId 字段 | |
retData.secureId | y | String | 仅供嵌入式 SDK 集成使用 |
Info
确保将 secureId 提供给客户端。
银行卡令牌化
在您的后端服务器上对 cc_addCard
API 端点进行 POST 请求。
端点 - 添加银行卡
https://ccapi.iotpaycloud.com/v3/cc_addCard
方法
POST
Header
Content-Type: application/json;charset=UTF-8
请求
名称 | 必填 | 类型 | 示例 | 描述 |
---|---|---|---|---|
mchId | y | String(30) | 0000701 | 由 IOTPay 分配 |
cardId | y | String(30) | 604567999 | 由商户分配,必须唯一 |
loginName | y | String(12) | jack123 | 商户的登录名 |
channel | y | String | PF_CC | PF_CC 或 UPI_EX |
returnUrl | y | String(200) | 添加卡后重定向到此 URL | |
sign | y | String(32) | C380BEC2BFD727A4B6845133519F3AD6 | 签名算法 |
请注意
每个 cardId
只能绑定一张信用卡,如果一个用户需要绑定多张卡,请使用不同的 cardId
响应
名称 | 必填 | 类型 | 示例 | 描述 |
---|---|---|---|---|
retCode | y | String | SUCCESS or FAIL | |
retMsg | y | String | ||
retData.redirectUrl | y | String | 对于重定向支付,请忽略此字段,嵌入式集成请使用 retData.secureId 字段 | |
retData.secureId | y | String | 仅供嵌入式 SDK 集成使用 |
Info
确保将 secureId 提供给客户端。
前端集成
Info
您将需要上面响应中的 secureId
来通过 JS SDK 创建 IOTPay iframe 实例。
添加一个占位符 div
<div id="iotpay_normal"></div>
添加一个 HTML script
标签
<script
type="text/javascript"
src="https://ccapi.iotpaycloud.com/cc/iotpaycc.js"
></script>
const script = document.createElement('script')
script.src = 'https://ccapi.iotpaycloud.com/cc/iotpaycc.js'
script.type = 'text/javascript'
script.async = true
从 API 调用中获取 secureId 后,将 iframe 挂载到占位符 div 中
注意
为了符合 PCI 合规性, 您必须直接从 https://ccapi.iotpaycloud.com/cc/iotpaycc.js 加载 IOTPay.js。请不要将其包含在捆绑包中或自行托管。
<script>
let callback = function (event) {
console.log(event)
if (event.result == 'SUCCESS') {
// 添加/支付成功
// 返回的数据将包含在 event.detail 中
// if (event.detail.retData && event.detail.retData.redirectUrl) {
// window.location.replace(event.detail.retData.redirectUrl);
// }
} else if (event.result == 'FAIL' && event.message == 'Timeout') {
// 银联要求查询订单。在尝试 30 次后,我们将超时,商户需要查询订单。
//
} else if (event.result == 'FAIL') {
// 添加/支付失败
// 返回的数据将包含在 event.detail 中
// if (event.detail.retData && event.detail.retData.redirectUrl) {
// window.location.replace(event.detail.retData.redirectUrl);
// }
}
if (event.detail.retData && event.detail.retData.redirectUrl) {
window.location.replace(event.detail.retData.redirectUrl)
}
}
let secureId = '3abcd*******3abcd' // 从 addCard 或 Purchase 终点获取 secureId
let iotpay_normal = Iotpay(secureId, 'Pay') // 第二个参数必须是 Add(添加卡)或 Pay
iotpay_normal.mount('#iotpay_normal', callback)
</script>
async loadIOTLibrary() {
const script = document.createElement('script');
script.src = "https://ccapi.iotpaycloud.com/cc/iotpaycc.js";
script.type = "text/javascript";
script.async = true;
return new Promise((resolve, reject) => {
script.onload = () => {
// 首先,我们需要调用 API 获取 secureId
let reqBody = {
mchUserId: "test",
mchOrderNo: uuidV4(),
amount: this.state.order.total * 100, // 确保单位为分
channel: "PF_CC", // 或者 UPI_EX
returnUrl: "https://test.merchant.com/payment/result",
notifyUrl: "https://test.merchant.com/webhook/getNotify"
}
// 用商户的 API 密钥替换第二个参数
reqBody = this.getSignedBody(reqBody, "==== merchantAPIKey ====");
// 向商户的后端服务器发出请求,在那里会调用 'cc_purchase'
axios.post('http://test.merchant.server/v1/iotpay/purchase', reqBody)
.then(res => {
if (res.status === 200 && res.data.retCode === "SUCCESS" && res.data.retData.secureId) {
let order = this.state.order;
order.payment_id = res.data.retData.secureId;
this.setState({ order })
// iframe 选项,此字段不是强制性的
const options = {
"darkMode": true,
"theme": "card",
"button": {
"text": "立即支付!",
"color": "#fff",
"backgroundColor": "#f90",
"backgroundImage": "none",
"boxShadow": "none",
"height": "60px",
"borderRadius": '0px'
}
};
// 第二个参数必须是 Add(为将来的购买添加客户信用卡)或 Pay
let iotpay_normal = window.Iotpay(res.data.retData.secureId, 'Pay', options);
// IOTCallback 是处理支付结果回调的函数
iotpay_normal.mount('#iotpay_normal', this.IOTCallback);
} else {
// 处理失败的请求 - 例如:
reject(new Error(res.data.retMsg))
}
})
resolve();
}
script.onerror = () => {
reject(new Error('加载 IOTPay 库失败。'));
};
document.body.appendChild(script);
})
}
IOTCallback(event) {
console.log(event);
if (event.result === 'SUCCESS') {
// 添加/支付成功
// 返回的数据将包含在 event.detail 中
// if (event.detail.retData && event.detail.retData.redirectUrl) {
// window.location.replace(event.detail.retData.redirectUrl);
// }
} else if (event.result === 'FAIL' && event.message === 'Timeout') {
// 银联要求查询订单。在尝试 30 次后,我们将超时,商户需要查询订单。
//
} else if (event.result === 'FAIL') {
// 添加/支付失败
// 返回的数据将包含在 event.detail 中
// if (event.detail.retData && event.detail.retData.redirectUrl) {
// window.location.replace(event.detail.retData.redirectUrl);
// }
}
if (event.detail.retData && event.detail.retData.redirectUrl) {
window.location.replace(event.detail.retData.redirectUrl);
}
}
附加的 SDK 和文档
iOS 集成:iOS sdk
Android 集成:Android sdk
PHP 和 JS 集成:Php sdk