- 新平台
本文就iFrame方案进行介绍,主要包括整体交互流程,前端token获取示例,以及部分定制化功能。
官方文档可以参考:https://www.checkout.com/docs/four/integrate/frames
交互流程
Step 1, 在商户前端页面中初始化Checkout.com的iFrame组件
Step 2,用户输入卡信息并提交支付,iFrame会负责处理卡信息和Checkout.com系统之间的交互,并返回浏览器前端一个卡Token及相关卡信息
Step3,商户将token信息和订单信息发送给商户后端系统
Step4,商户后端系统使用token调用Checkout.com支付API
#若为非3DS卡支付#
Step5,若为非3DS卡支付,同步返回支付结果
Step6,商户也可以通过主动查询Get Payment Detail获取支付结果,或者等待Checkout.com Webhook 异步通知确认支付结果
#若为3DS卡支付#
Step5,若为3DS卡支付,将用户重定向到发卡行的3DS验证页面,等待用户完成3DS验证及支付处理
Step6,用户完成3DS验证并支付后重定向至商户定义的URL
Step7,商户通过主动查询Get Payment Detail获取支付结果,或者等待Checkout.com Webhook 异步通知确认支付结果(至少必须实现Webhook异步通知机制)
系统交互图
iFrame获取卡Token示例
可以参考官方文档查看如何集成iFrame:https://checkout.com/docs/integrate/frames
其中包含sample code:
https://www.checkout.com/docs/integrate/frames/get-started#Initialize_Frames
以下为iFrame返回前端数据sample:
{
"type":"card",
"token":"tok_5eyi6oiemp6ulh5j5iuz4q3rze",
"expires_on":"2022-04-28T08:37:38Z",
"expiry_month":1,
"expiry_year":2023,
"scheme":"Visa",
"last4":"4242",
"bin":"424242",
"card_type":"Credit",
"card_category":"Consumer",
"issuer_country":"GB",
"product_id":"F",
"product_type":"Visa Classic"
}
其中最为关键的是token字段:tok_5eyi6oiemp6ulh5j5iuz4q3rze,可用于后续调用后端Payment API,其有效期为15分钟,且仅可以使用一次。
同时我们也返回其他卡信息,如:
- 有效期:”expiry_month”:1,”expiry_year”:2023
- 卡组:”scheme”:”Visa”
- 前六后四:”bin”:”424242”,”last4”:”4242”
- 发卡行国家:”issuer_country”:”GB”
- 卡类型:”card_type”:”Credit”
- 卡种类:”card_category”:”Consumer”
可以方便的让用户完成其他路由逻辑,进一步优化成本和成功率。
在初始化iFrame时需要配置商户自己的public key,以下为一个示例:
Frames.init({{pk_xxxxxxxxx}});
iFrame个性化
iFrame支持多种个性化选择,例如:
- 语言的选择
- 是否收集CVV信息
- 从右向左的展示形式,方便中东用户的使用
- 安全设置,禁止用户copy and paste卡信息
- css自定义
例如以下示例,从右向左输入,语言为阿拉伯语: 更多功能可以参考官方文档:https://www.checkout.com/docs/integrate/frames/frames-reference
iFrame代码参考
上述示例可以参考以下代码,替换其中的pk来进行测试。
multi_iframes_demo.zip
其他样式可参考官方文档:https://www.checkout.com/docs/integrate/frames/get-started#Initialize_Frames
- 单行简洁样式
- 标准多行样式
后端请求示例
3DS支付
若商户自身没有完善的风控工具和体系,为了减少欺诈和拒付问题,可以添加请求参数来发起一笔3DS的卡支付,支付过程中将用户从商户的收银台页面跳转至发卡行的页面并完成身份验证。
涉及的参数为 3ds.enabled
Payment请求示例:
{
"source": {
"type": "token",
"token": "tok_2no7vsa2tw6udg6e3qfimbw65m",
},
"amount": 1000,
"currency": "USD",
"reference": "ORD-5023-4E89",
"description": "Set of 3 masks",
"3ds": {
"enabled": true
},
"success_url": "http://example.com/payments/success",
"failure_url": "http://example.com/payments/fail",
}
Payment返回示例:
{
"id": "pay_khki4a3qpug2zbog6hkj7hhnuq",
"status": "Pending",
"reference": "ORD-5023-4E89",
"customer": {
"id": "cus_wjublof3mese5aqkj6xeip5edq"
},
"3ds": {
"downgraded": false,
"enrolled": "Y"
},
"_links": {
"self": {
"href": "https://api.sandbox.checkout.com/payments/pay_khki4a3qpug2zbog6hkj7hhnuq"
},
"redirect": {
"href": "https://3ds2-sandbox.ckotech.co/interceptor/3ds_u442wyet2aue7obbyvl6muup54"
}
}
}
非3DS支付
若不适用3DS支付,则可以不发送3ds参数,或者3ds.enalbed = false
Payment请求示例:
{
"source": {
"type": "token",
"token": "tok_kiiigfqqzpaubdsysyuk6kgwju",
},
"amount": 1000,
"currency": "USD",
"reference": "ORD-5023-4E89",
"description": "Set of 3 masks",
"success_url": "http://example.com/payments/success",
"failure_url": "http://example.com/payments/fail",
}
Payment返回示例:
{
"id": "pay_qicyo5eruv62rpezioauy6lynu",
"action_id": "act_qicyo5eruv62rpezioauy6lynu",
"amount": 1000,
"currency": "USD",
"approved": true,
"status": "Authorized",
"auth_code": "065473",
"scheme_id": "940603026984262",
"response_code": "10000",
"response_summary": "Approved",
"risk": {
"flagged": false
},
"source": {
"id": "src_ixf6eh4xr6kurezwjz4tnfkizm",
"type": "card",
"expiry_month": 1,
"expiry_year": 2023,
"scheme": "Visa",
"last4": "4242",
"fingerprint": "038243847473D6ABE9CDF2E1E812A656CC71C3A5552C09CB3D1FE6E3AC676C84",
"bin": "424242",
"card_type": "Credit",
"card_category": "Consumer",
"issuer_country": "GB",
"product_id": "F",
"product_type": "Visa Classic",
"avs_check": "S",
"cvv_check": "Y",
"payouts": true,
"fast_funds": "d"
},
"customer": {
"id": "cus_xftk4whpvadexb3rr6ji2mebeu"
},
"processed_on": "2022-04-28T11:32:32Z",
"reference": "ORD-5023-4E89",
"processing": {
"acquirer_transaction_id": "0169449662",
"retrieval_reference_number": "450498206396"
},
"_links": {
"self": {
"href": "https://api.sandbox.checkout.com/payments/pay_qicyo5eruv62rpezioauy6lynu"
},
"actions": {
"href": "https://api.sandbox.checkout.com/payments/pay_qicyo5eruv62rpezioauy6lynu/actions"
},
"capture": {
"href": "https://api.sandbox.checkout.com/payments/pay_qicyo5eruv62rpezioauy6lynu/captures"
},
"void": {
"href": "https://api.sandbox.checkout.com/payments/pay_qicyo5eruv62rpezioauy6lynu/voids"
}
}
}
后端Postman参考
可通过以下链接获取Postman的参考:
Postman Link:
密码请咨询负责贵司的工程师。
导入以上Postman collection后,替换Header中的Authorization值为您沙箱环境的secret key后即可开始测试。
特殊使用场景
允许多次提交Token请求
iFrame的默认逻辑为用户点击一次Button提交后,就不可以再次点击,以避免用户重复支付。商户可以根据自身的业务场景修改这一默认配置,允许用户多次提交,并获取多个卡Token。
修改方式如下:
在获取卡token(CardTokenized)的EventHandler中启用:Frames.enableSubmitForm(); 如:
Frames.addEventHandler(Frames.Events.CARD_TOKENIZED, onCardTokenized);
function onCardTokenized(event) {
Frames.enableSubmitForm();
var el = document.querySelector(".success-payment-message");
el.innerHTML =
"Card tokenization completed<br>" +
'Your card token is: <span class="token">' +
event.token +
"</span>";
}
持卡人姓名及账单地址
在使用iFrame时,可以通过两种方式发送持卡人姓名和账单地址信息。
方案一 在前端收集持卡人姓名及账单地址
可以由商户在前端设计表单收集相关数据,或者直接使用商户端的已存数据。
可以参考以下代码示例,其中Frames.cardholder即持卡人姓名及账单地址信息:
Frames.cardholder = {
name: “John Smith”,
billingAddress: {
addressLine1: “623 Slade Street”,
addressLine2: “Apartment 8”,
zip: “31313”,
city: “Hinesville”,
state: “Georgia”,
country: “US”,
},
phone: “9125084652”
};
<body>
<!-- add frames script -->
<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>
<form id="payment-form" method="POST" action="https://merchant.com/charge-card">
<div class="card-frame">
<!-- form will be added here -->
</div>
<!-- add submit button -->
<button id="pay-button" disabled>
PAY GBP 24.99
</button>
</form>
<script>
var payButton = document.getElementById("pay-button");
var form = document.getElementById("payment-form");
Frames.init("pk_test_6ff46046-30af-41d9-bf58-929022d2cd14");
Frames.addEventHandler(
Frames.Events.CARD_VALIDATION_CHANGED,
function (event) {
console.log("CARD_VALIDATION_CHANGED: %o", event);
payButton.disabled = !Frames.isCardValid();
}
);
Frames.addEventHandler(
Frames.Events.CARD_SUBMITTED,
function () {
payButton.disabled = true;
// display loader
}
);
Frames.addEventHandler(
Frames.Events.CARD_TOKENIZED,
function (data) {
Frames.addCardToken(form, data.token);
form.submit();
}
);
Frames.addEventHandler(
Frames.Events.CARD_TOKENIZATION_FAILED,
function (error) {
// catch the error
}
);
form.addEventListener("submit", function (event) {
event.preventDefault();
Frames.cardholder = {
name: "John Smith",
billingAddress: {
addressLine1: "623 Slade Street",
addressLine2: "Apartment 8",
zip: "31313",
city: "Hinesville",
state: "Georgia",
country: "US",
},
phone: "9125084652"
};
Frames.submitCard();
});
</script>
</body>
方案二 在后端Payment 接口中发送账单地址
当前端通过iFrame获取卡Token后,也可以在请求Payment接口时增加账单地址: