🚀 快速开始(Quick Start)
IntPay 内嵌信用卡支付接入文档(Iframe 模式)
IntPay 提供基于 Iframe + Token 化机制 的信用卡支付解决方案。
该方案通过将卡信息完全托管在 IntPay SDK中,实现:
- PCI DSS 合规(商户不接触卡数据)
- 数据隔离(卡信息不经过商户服务器)
- 灵活控制(支付流程由商户掌控)
核心理念:
卡信息在 iframe,交易控制在商户
架构说明
支付流程涉及两个核心角色:
| 组件 | 职责 |
|---|---|
| 父页面(商户) | 订单创建、业务校验、发起支付 |
| SDK(IntPay) | 卡信息采集、Token生成、3DS处理 |
通信方式:
window.postMessage()支付流程
sequenceDiagram
participant 用户
participant 父页面
participant SDK
participant IntPay
用户->>SDK: 输入卡信息
SDK->>父页面: PAY_CLICK
父页面->>父页面: 校验 + 创建订单
父页面->>SDK: PAY_READY
SDK->>父页面: PAYMENT_TOKEN
父页面->>IntPay: 调用支付接口
IntPay-->>父页面: 返回结果 / 3DS
父页面->>SDK: PAY_REDIRECT(如需要)接入步骤
1. 初始化支付接口《iframe Url》
当持卡人选择支付方式时,商户后端 初始化支付接口,获取iframe html地址 
请求参数:
{
"channel": "iframeTest",
"source": "shopyy",
"website": "www.qq.com",
"country": "US",
"payMethodId": "1",
"reference": "P1911",
"amount": 10000,
"currency": "USD"
}返回参数:
{
"requestId": "85b1f915-1c45-4ee0-8716-56d00c09dd28",
"success": true,
"data": {
"channel": "iframeTest",
"source": "shopyy",
"url": "https://api.links-pay.com?token=37f88b34-537b-4774-8692-5e307d12f4d8",
"expiresAt": "2025-10-14 17:32:38",
"expiresIn": 86400,
"iframeToken": "6861aa86-16c9-4721-8e9b-9bd69215e43b"
},
"timestamp": "2025-10-13T17:32:38.422+08:00"
}- iframeUrl 嵌入的html地址
- iframeToken 用于支付接口《payments》的参数
前端渲染:
<iframe src="{{IFRAME_URL}}" name="iframe_pay" onload="iframeLoaded()" id="iframe_pay" width="100%"></iframe>2. 监听事件

父页面嵌入iframeUrl后(执行iframeLoaded方法),需要监听以下几个消息:
window.addEventListener('message', (event) => {
const data = event.data;
console.log('Listener:', data);
if (data.type === 'IFRAME_SIZE' && typeof data.height === 'number') {
frameEl.style.height = data.height + 'px';
console.log('[parent] child height:', data.height, 'px');
return;
}
if (data.type === 'PAY_WINDOW') {
if (data.action === 'LOADING') {
// 页面加载loading动画
createAjaxLoading();
} else if (data.action === 'HIDELOADING') {
// 页面删除loading动画
removeAjaxLoading();
} else if (data.action === 'ERROR') {
// 页面删除loading动画,并渲染 失败提示给用户看
removeAjaxLoading();
moi.message({
content: data.msg,
type: 'error',
timer:4000
});
}
}
if (data.type === 'PAY_CLICK' ) {
// 进行表单校验以及订单创建等其他商户业务逻辑
const payRes = await saveOrder();
console.log('pay_submit');
console.log(payRes);
if (!payRes) {
// 如果校验不通过,或逻辑走不通,则return,SDK就不会继续往下走支付流程
return;
}
// 校验通过后,发送消息给SDK,告知SDK一切准备就绪
frameEl.contentWindow.postMessage({ type: 'PAY_READY', ready: true }, '*');
return;
}
// 监听支付token
if (data.type === 'PAYMENT_TOKEN' ) {
// 判断卡号校验状态是否成功
if (data.status === 'SUCCEEDED') {
// 加载loading
createAjaxLoading();
console.log('Payment success:', data.payToken);
// 通过后端接口 请求《payments》支付接口
} else {
// 如果失败,则告知客户
console.warn(' Payment failed:', data.message);
moi.message({
content: data.message,
type: 'error',
timer:4000
});
}
}
});3. 用户点击支付
- 用户输入完卡信息后点击支付按钮
- SDK发送消息告知父页面
postMessage({ type: 'PAY_CLICK', ready: 'true' })父页面需要:
- 校验用户的账单和物流地址,比如有没有哪些字段没有填写的
- 创建商城订单
- 如您不需要做任何的预处理,可以直接发送PAY_READY消息
如下图所示:
4. 通知SDK
当父页面一切就绪后,通过以下命令通知SDK,SDK会开始对卡信息进行加密
postMessage({ type: 'PAY_READY', ready: 'true' })5. 获取 Token
当SDK完成卡信息校验及信息加密后,会告知父页面结果。如 加密结果,以及加密状态。
postMessage({
type: 'PAYMENT_TOKEN',
status: 'SUCCEEDED',
payToken: 'xxx'
})6. 接收Token
父页面收到PAYMENT_TOKEN后,判断status 结果(可参考上面的JS监听器代码):
- 如 status = FAILED,则渲染失败告知用户且不进行下一步操作
- 如 status = SUCCEEDED,则进行下一步支付请求操作
7. 请求支付接口
如status = SUCCEEDED后,则携带payToken,由商户后端请求《payments》接口 切记:payToken是卡号加密信息,iframeToken是第一步初始化的时候返回的,两者都要带入《payments》接口
请求参数:
{
"iframeToken": "6861aa86-16c9-4721-8e9b-9bd69215e43b",
"amount": 10000,
"website": "www.links-pay.cc",
"subject": "Women’s 3D Embroidered Bandeau Elegant Mini Dress",
"channel": "iframeTest",
"type": "iframe",
"card": {
"payToken": "a4a4575c-d144-4e7f-9fec-89c234f78d77"
},
"billing": {
"country": "US",
"firstName": "Melissa",
"lastName": "Hughes",
"address": "1225 Wilshire Blvd Apt 804",
"city": "Los Angeles",
"phone": "+14155527689",
"postalCode": "90017",
"state": "CA",
"email": "melissa.hughes@example.com"
},
"reference": "R202512045",
"shipping": {
"country": "US",
"firstName": "Melissa",
"lastName": "Hughes",
"address": "1225 Wilshire Blvd Apt 804",
"city": "Los Angeles",
"phone": "+14155527689",
"postalCode": "90017",
"state": "CA",
"email": "melissa.hughes@example.com"
},
"notifyUrl": "https://www.links-pay.cc/notify",
"currency": "USD",
"returnUrl": "https://www.links-pay.cc/checkout.html",
"items": [
{
"unitPrice": 10000,
"name": "Women’s 3D Embroidered Bandeau Elegant Mini Dress",
"currency": "USD",
"quantity": "1",
"category": "Women Clothing",
"totalPrice": 10000
}
],
"browserInfo": {
"screenWidth": 1920,
"javaEnabled": false,
"os": "Windows 10",
"screenHeight": 1080,
"ipAddress": "168.168.168.168",
"browserName": "Chrome",
"timeZone": -480,
"javascriptEnabled": true,
"language": "en-US",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
"colorDepth": 24
},
"utm":{
"utmSource":"",
"utmMedium":"",
"utmTerm":"",
"utmContent":""
}
}返回参数:
{
"requestId": "b5cb20f9-6968-41ff-8e53-b1a9fc87a2b8",
"success": true,
"data": {
"id": "P251011144163273295845",
"reference": "R202512038",
"status": "SUCCESS",
"amount": 10000,
"currency": "USD",
"requiresAction": null,
"nextAction": null,
"failureMessage": null
},
"timestamp": "2025-10-11T14:41:23.406+08:00"
}响应结果处理说明:
当 success = false 时,表示本次接口调用失败,通常由于参数错误、签名错误、通道关闭或通道限额等原因。此时请直接读取并提示 error 字段中的错误信息。
当 success = true 时,表示接口调用成功,此时应根据 data.status 进行判定支付结果,如果失败请展示 failureMessage 失败原因。
顶层结构字段说明
| 字段 | 类型 | 示例值 | 说明 |
|---|---|---|---|
| requestId | string | 75daa341-66fd-4d87-949b-28f7f0ef6d64 | 本次通知的唯一追踪 ID,由服务端生成,用于日志追踪、链路排查与问题定位。每次通知通常唯一。 |
| success | boolean | true | 表示本次接口调用是否成功(接口层面)。true 表示通知调用成功并已返回业务结果;false 表示接口调用异常,如签名错误、参数缺失、权限拒绝、通道关闭等。 |
| data | object | {...} | 支付结果详情对象。当 success = true 时,商户应重点解析该对象中的业务字段。 |
| timestamp | string (ISO 8601) | 2025-10-10T16:39:23.765+08:00 | 通知生成时间,采用 ISO 8601 标准格式,包含毫秒与时区偏移。 |
data 对象字段说明(支付结果详情)
| 字段 | 类型 | 示例值 | 说明 |
|---|---|---|---|
| id | string | P1231823 | IntPay 平台交易号。用于标识平台侧唯一交易,可用于对账、查询与问题排查。 |
| reference | string | SAIDF01239-1230 | 商户订单号或交易参考号,由商户系统生成,用于关联商户内部订单。 |
| requiresAction | boolean | false | 是否仍需用户执行额外操作。通常用于表示是否需要完成额外验证步骤(如 3DS、OTP 等)。 |
| amount | number | 100 | 支付金额,单位为最小货币单位。例如 USD 下 100 表示 1.00 USD。 |
| currency | string | USD | 支付币种,遵循 ISO 4217 三位字母代码标准。 |
| failureMessage | string | fail | 失败原因描述。当交易失败时返回;成功状态下通常为空、为 null 或被省略。 |
| status | string | FAILED | 当前订单状态枚举值,商户应以此字段作为订单状态更新依据。 |
nextAction(当 requiresAction = true 时返回)
| 字段 | 类型 | 示例值 | 说明 |
|---|---|---|---|
| nextAction.type | string | redirect | 操作类型 |
| nextAction.url | string | https://3d.com | 跳转地址 |
| nextAction.method | string | GET | 访问协议 |
状态枚举
| 状态值 | 说明 | 商户建议 |
|---|---|---|
PENDING | 待处理。支付请求已创建,正在等待用户操作、发卡行响应或通道处理。 | 订单保持处理中,不要提前判定最终结果。 |
REQUIRES_ACTION | 需要下一步操作。通常表示用户需完成额外验证,如 3D Secure、OTP 或其他身份校验。 | 引导用户继续完成验证流程,并等待后续结果通知。 |
SUCCEEDED | 支付成功。发卡行授权通过,交易已成功完成。 | 将订单更新为成功,进入发货、入账或后续履约流程。 |
FAILED | 支付失败。可能由于发卡行拒付、风控拦截、余额不足、卡信息错误或其他原因导致。 | 将订单更新为失败,并视业务需要记录失败原因。 |
CANCELED | 已取消。订单被商户、用户或系统主动取消,通常未完成实际扣款。 | 将订单更新为已取消,结束本次支付流程。 |
REFUND_PENDING | 退款处理中。退款请求已提交,正在等待银行或通道处理。 | 将订单更新为退款处理中,并等待后续通知。 |
REFUNDED | 已退款。原支付金额已成功退回持卡人账户。 | 将订单更新为已退款,并同步售后或财务状态。 |
REFUND_FAILED | 退款失败。退款请求被通道或银行拒绝,未完成退款。 | 保留原支付成功状态,并记录退款失败原因。 |
CHARGEBACK | 拒付。持卡人已发起争议,款项可能被强制退回。 | 启动拒付处理流程,并同步风控、财务或客服系统。 |
不同支付产品或通道路由下,部分状态可能不会全部出现。
商户系统应至少完整兼容:PENDING、REQUIRES_ACTION、SUCCEEDED、FAILED、CANCELED、REFUNDED。
支付处理
接口失败
success 字段:表示本次接口调用是否成功(逻辑层面)。
✅ true:接口调用正常,业务执行完成(即便支付失败,如 cvv 错误、卡号不存在、余额不足也会返回 true)。
❌ false:接口调用异常,如签名错误、参数缺失、权限拒绝等。
{
"success": false,
"message": "invalid signature"
}- 展示 error
接口成功
data.status = FAILED:代表持卡人付款失败,需要渲染错误信息(failureMessage)data.status = SUCCESS:代表持卡人付款成功data.status = REQUIRES_ACTION:代表需要进行下一步操作,需要将nextAction.url发送给 SDK,由 SDK 完成后续处理
{
"requestId": "b5cb20f9-6968-41ff-8e53-b1a9fc87a2b8",
"success": true,
"data": {
"id": "P251011144163273295845",
"reference": "R202512038",
"status": "SUCCESS",
"amount": 10000,
"currency": "USD",
"requiresAction": null,
"nextAction": null,
"failureMessage": null
},
"timestamp": "2025-10-11T14:41:23.406+08:00"
}3DS 处理
您需要将nextAction.url 通过下面命令发送给SDK,由SDK自行完成后续操作
postMessage({
type: 'PAY_REDIRECT',
url: 'https://3ds-url'
})父页面监听事件说明
PAY_CLICK 支付按钮事件
1、监听到该事件后,意味着 持卡人成功在SDK页面输入卡信息并点击支付按钮 2、SDK会来询问父页面是否需要校验物流和账单信息或创建订单
{ "type": "PAY_CLICK", "ready": "true" }PAYMENT_TOKEN 支付TOKEN
父页面收到该事件后需立即请求《payments》支付接口
{
"type": "PAYMENT_TOKEN",
"status": "SUCCEEDED",
"payToken": "xxx"
}IFRAME_SIZE 宽高自适应
1、SDK初始化后以及页面宽高发生变动时会立即发送消息给父页面宽高度 2、父页面收到后需要立即设置iframe的width 和heigh ,给与客户更好的用户体验
postMessage({
type: 'IFRAME_SIZE',
height: '500px'
})PAY_WINDOW 加载事件
父页面收到PAY_WINDOW事件,需判断action 状态:
- 如果为LOADING 代表加载loading遮罩
- HIDELOADING 代表关闭loading遮罩
- ERROR 代表需要渲染错误信息给持卡人(但是不需要loading遮罩)
postMessage({
type: 'PAY_WINDOW',
action: 'LOADING/HIDELOADING/ERROR'
})