Click to Pay Hosted Session 集成
按照以下步骤使用 Click to Pay SDK 和 JavaScript (JS) API 将 Click to Pay (C2P) 添加到您的 Hosted Session 集成中。 您可以在本主题末尾找到基本集成的 HTML 示例。
有关 C2P、测试已完成集成的更多信息以及一些常见问题,请参见 Click to Pay。
步骤 1: 创建和更新会话
使用 CREATE SESSION 操作创建会话。 响应将返回一个会话 ID,您必须在后续步骤中使用此 ID 来引用此会话。
您可以使用 UPDATE SESSION 操作在现有会话中添加或更新字段。 会话中至少需要以下字段:
session.id
付款会话的标识符。order.amount
订单总金额。order.currency
订单的货币。
有关服务器端 API 操作的请求示例,请下载 Postman 集合。
步骤 2: 在您的付款页中包含 Click to Pay JavaScript API
通过在 HTML 代码中的 head 元素内添加脚本元素,在付款页包含 Mastercard Gateway 提供的 C2P JavaScript SDK (click-to-pay.js
)。 这会将 ClickToPay 对象放入窗口命名空间。
<script type="text/javascript" src="https://testpg.mpgs.axisbank.com/form/static/click-to-pay/click-to-pay.min.js"></script>
步骤 3: 配置 Click to Pay 交互
此配置对象允许您在付款页上配置付款人和 C2P 之间的交互。 当付款人准备好支付订单并且您正在加载付款页时,通过调用 ClickToPay.configure()
函数发起 C2P 交互。 有关该函数的更多详细信息和示例,请参阅 API 参考。
C2P 库可能需要几秒钟来初始化。 在页面加载时尽早初始化组件,以便付款人可以使用 C2P 快速结账。
在 ClickToPay.configure()
函数中,配置 C2P 交互的参数、付款页组件和回调,如以下部分所定义。
配置参数
使用参数来定义 C2P 交互的详细信息。
表: 配置参数
字段 | 必需 | 类型 | 说明 |
---|---|---|---|
merchant.id |
是 | 字符串 | 您的商家 ID,网关将使用它来确定您的付款选项。 |
merchant.name |
是 | 字符串 | 您的交易名称,例如,付款人所知的名称。 |
merchant.url |
必需 | URL 字符串 | 付款人正在使用的您的网站的 URL。 |
session.id |
是 | 字符串 | 步骤 1 中的 CREATE SESSION 操作返回的会话 ID。 |
session.wsVersion |
是 | 整数 | 在步骤 1 中提交 CREATE SESSION 操作时使用的 WS API 版本。 此值必须 >= 62。 |
order.amount |
是 | 字符串 | 订单金额。 该值仅用于显示,不用于处理付款。 |
order.currency |
是 | 字符串 | 订单货币。 该值仅用于显示,不用于处理付款。 |
interaction.billingPreference |
否 | 枚举字符串 | C2P 交互过程中是否收集账单地址。 可能的值包括:
|
interation.collectShippingAddress |
否 | 布尔值 | C2P 交互过程中是否收集送货地址。 默认值为 false。 默认情况下,付款人可以选择任何送货地址国家/地区。 要限制商品送达国家/地区的名单,您必须通过 Merchant Administration (MA) 使用允许国家/地区列表或排除国家/地区列表为 C2P 配置商家配置文件。 如果您定义了限制,付款人只能选择允许的送货地址国家/地区。 您无法针对特定请求覆盖支持的送货地址国家/地区,只能在商家配置文件内针对所有请求覆盖。 |
interation.locale |
否 | 字符串 | C2P 交互期间使用的语言。 默认情况下,使用付款人浏览器中配置的语言。 如果付款人的语言无法确定或不受支持,将使用 en_US (除非您在此参数中提供其他值)。
|
interation.country |
否 | 字符串 | 在 C2P 交互期间向付款人呈现的国家/地区特定内容,例如条款和条件。 默认使用在网关中根据您的商家配置文件配置的值。 如果想要覆盖此交互的值,请将此参数设置为有效的 ISO 3166 alpha-3 国家/地区值。 |
interaction.cardSelectionAction |
否 | 字符串 | 付款人选择卡时要执行的操作。 可能的值包括:
|
interaction.skipDCFInteraction |
否 | 布尔值 | 付款人是否必须手动确认其电子邮件地址和电话号码。 目前仅适用于 Mastercard 卡注册。 configure() 函数内需要 customer.email 和 customer.mobilePhone 参数,用于使此功能生效。如果设置为 true,付款人不会在 DCF(数字卡服务商用户界面)组件上收到确认消息提示,将会短暂出现一个加载屏幕。 如果未提供,此值默认为 false。 |
customer.email |
是 | 字符串 | 付款人的电子邮件。 C2P 使用此值在 SRC (Secure Remote Commerce) 系统内查找付款人的个人资料。 电子邮件查找只会在设备无法识别时发起。 如果设备被识别,此字段将被忽略。 除非您已经告知付款人其电子邮件地址将用于查找他们的 C2P 个人资料,否则,在网站上提供付款人的电子邮件会被用于查找目的的信息。 您可以添加一条通知,告知您在与参与的卡组织合作提供 C2P 来实现更快的结账,以及付款人的电子邮件地址与参与的卡组织安全共享,用于检查他们是否已有 C2P 个人资料。 |
customer.mobilePhone |
否 | 电话号码 | 付款人的手机号码,采用 ITU-T E123 格式,例如,+1 607 1234 5678 此号码由以下部分组成:
|
customer.firstName |
否 | 字符串 | 付款人的名字。 |
customer.lastName |
否 | 字符串 | 付款人的姓氏。 |
srcDCFCancel |
是(仅当您打算支持 Visa 卡时) | - | 如果付款人选择 Visa DCF 组件右上角显示的“X”,Visa 当前的 C2P 设计就会关闭其 C2P 会话。 发送此事件时,建议您重新初始化 C2P(调用 configure() 函数),以确保所有卡组织均开启会话。 |
付款页组件
C2P 提供了几个可嵌入到您的付款页的组件,帮助增强 C2P 交互。 在您希望显示这些组件的付款页中的位置创建 div 元素,并在配置对象的元素部分标识 div 元素。
表: 可用付款页组件
字段 | 必需 | 说明 |
---|---|---|
cardList |
是 | 卡列表组件所显示的 DOM 元素 ID。 |
otp |
否 | 显示一次性密码 (OTP) 组件的 DOM 元素 ID。 如果未提供,OTP 将显示为覆盖图。 |
dcf |
是 | 显示 DCF 组件的 DOM 元素 ID。 如果未提供,DCF 组件将显示为覆盖图。 |
回调
您必须将 C2P 交互期间要调用的操作定义为回调。
onStateChange 回调
初始流量在您调用 configure()
函数后确定:
- 如果检测到有效的 C2P cookie,将使用“通过 cookie 识别返回用户”流,并显示卡列表组件。
- 如果检测到有效的 C2P 电子邮件,将使用“过电子邮件识别返回用户”流,并会在显示卡列表组件之前提示付款人输入 OTP。
- 如果未检测到有效的 Cookie 或电子邮件,将使用“新用户”流。
当 C2P 交互状态改变时触发 onStateChange
回调。 您可以使用它来确定哪些组件可见,以及付款人处于流中的哪个阶段。
oldState : { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email if not supplied in customer.email }, elementState: { cardList: {selector: 'cardListContainer', visible: true}, otp: {selector:'otpContainer', visible: false}, dcf: {selector:'dcfContainer', visible: false} } }, newState: { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: 'cardListContainer', visible: false}, otp: {selector:'otpContainer', visible: false}, dcf: {selector:'dcfContainer', visible: true} } }, diffState: { elementState: { dcf: {selector:'dcfContainer', visible: true} } }
下表提供了如何使用不同流管理状态变化的示例。
表: 状态变化
状态 | 旧状态字段值 | 新状态字段值 | 注释 |
---|---|---|---|
页面加载(cardlist 显示之前)isRecognized 显示之后、cardList 显示之前 | {} | { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: true}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
- |
点击卡之后、重定向到 DCF 之前 | { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: true}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
{ payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
- |
结账完成后 | { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
{ payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
onComplete 回调将返回 correlationId、scheme、digitalCardId。 转到步骤 6 |
“通过 cookie 识别返回用户”流
状态 | 旧状态字段值 | 新状态字段值 | 注释 |
---|---|---|---|
页面在 isRecognized() 之后、在卡列表显示之前加载 |
{} | { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: true}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
- |
在单击卡后,重定向到 DCF 组件之前 | { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: true}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
{ payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
- |
结账完成后 | { payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
{ payerState: { deviceRecognized: true, email: ‘payer@test.com’, //masked email }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
onComplete 回调返回关联 ID、组织和数字卡 ID。 从步骤 6 继续。 |
输入有效的 OTP 后 | { payerState: { email: ‘payer@test.com’, emailEnrolled: true, emailVerified: false }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: true}, dcf: {selector:'#dcfContainer', visible: false} } } } |
{ payerState: { email: ‘payer@test.com’, emailEnrolled: true, emailVerified: true }, elementState: { cardList: {selector: '#cardListContainer', visible: true}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
- |
点击卡后,重定向到 DCF 组件之前 | { payerState: { email: ‘payer@test.com’, emailEnrolled: true, emailVerified: true }, elementState: { cardList: {selector: '#cardListContainer', visible: true}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
{ payerState: { email: ‘payer@test.com’, emailEnrolled: true, emailVerified: true }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
- |
结账完成后 | { payerState: { email: ‘payer@test.com’, emailEnrolled: true, emailVerified: true }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
{ payerState: { email: ‘payer@test.com’, emailEnrolled: true, emailVerified: true }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
onComplete 回调返回关联 ID、组织和数字卡 ID。 从步骤 6 继续。 |
页面加载时显示电子邮件 | { } |
{ payerState: { deviceRecognized: false, email: ‘payer@test.com’, emailEnrolled: false, emailVerified: false }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
由于无法识别付款人的 C2P 个人资料,您可以显示卡输入字段,从付款人处收集详细信息,并更新会话。 如果未在配置参数中提供,电子邮件将为空白。 |
在 DCF 组件显示之前调用 checkoutWithNewCard() 函数 |
{ payerState: { deviceRecognized: false, email: ‘payer@test.com’, emailEnrolled: false, emailVerified: false }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
{ payerState: { deviceRecognized: false, email: ‘payer@test.com’, emailEnrolled: false, emailVerified: false }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
- |
结账完成后 | { payerState: { deviceRecognized: false, email: ‘payer@test.com’, emailEnrollled: false, emailVerified: false }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: true} } } |
{ payerState: { deviceRecognized: false, email: ‘payer@test.com’, emailEnrollled: false, emailVerified: false }, elementState: { cardList: {selector: '#cardListContainer', visible: false}, otp: {selector:'#otpContainer', visible: false}, dcf: {selector:'#dcfContainer', visible: false} } } |
onComplete 回调返回关联 ID、组织和数字卡 ID。 从步骤 6 继续。 |
onComplete 回调
当付款人完成与 DCF 组件的交互时,会触发 onComplete 回调。
此函数使用两个参数:
scheme
: 卡组织- correlationId: C2P 交互的唯一标识符(针对此组织)
必须在步骤 6 中使用这些详细信息来检索此 C2P 交互的付款详细信息。
onError 回调
如果在 C2P 交互期间发生错误,onError 回调将返回错误对象。 它包含两个字段:
{ errorCode: 'INVALID_INPUT', errorMessage: 'session id is required' }
表: 集成错误代码
错误代码 | 错误消息 | 您的操作 |
---|---|---|
CALLBACKS_ONCOMPLETE_ERROR |
缺少参数: 需要 onComplete 回调 | 在 configure() 函数中包含 onComplete 回调函数。 |
CALLBACKS_ONERROR_ERROR |
缺少参数: 需要 onError 回调 | 在 configure() 函数中包含 onError 回调方法。 |
MERCHANT_ID_ERROR |
缺少参数: 需要商家 ID | 在 configure() 函数中包含 merchant.id 字段。 |
MERCHANT_NAME_ERROR |
缺少参数: 需要商家名称 | 将 merchant.name 字段包含在 configure() 函数中。 |
MERCHANT_URL_ERROR |
缺少参数: 需要商家 URL | 将 merchant.url 字段包含在 configure() 函数中。 |
SESSION_ID_ERROR |
缺少参数: 需要会话 ID | 将 session.id 字段包含在 configure() 函数中。 |
MISSING_API_VERSION_ERROR |
缺少参数: 需要 API 版本 | 在 configure() 函数中包含 wsVersion 字段。 |
ORDER_AMOUNT_ERROR |
缺少参数: 需要订单金额 | 将 order.amount 字段包含在 configure() 函数中。 |
ORDER_CURRENCY_ERROR |
缺少参数: 需要订单货币 | 将 order.currency 字段包含在 configure() 函数中。 |
MIN_API_VERSION_ERROR |
API 版本应大于或等于 62 | 将 wsVersion 字段值至少更改为 62,所有操作均必须使用 62 或更大数字执行。 |
CARD_LIST_ERROR |
缺少参数: 需要 Elements.cardList | 包含链接到卡列表组件 div 的 elements.cardList 字段。 |
DCF_ERROR |
缺少参数: 需要 Elements.dcf | 包含链接到卡列表组件 div 的 elements.dcf 字段。 |
MISSING_EMAIL_ERROR |
缺少参数: 需要电子邮件 | 在 configure() 函数中包含 customer.email 字段。 |
CUSTOMER_EMAIL_ERROR |
客户电子邮件格式错误 | 确保您的网站仅接受有效的付款人电子邮件地址。 |
INTERACTION_LOCALE_ERROR |
交互区域设置格式错误 | 使用格式 <language>_<country> 提供有效的区域设置,如 en_US。 |
INTERACTION_COUNTRY_ERROR |
交互国家/地区格式错误 | 在 interaction.country 字段中提供有效的 ISO 3166 alpha-3 国家/地区值。 |
表: 结账错误代码
错误代码 | 错误消息 | 所需操作 |
---|---|---|
CARD_MISSING |
需要数字卡 ID 或加密卡对象,但缺少这些信息。 | C2P 不可用,恢复到来宾结账流。 |
CARD_ADD_FAILED |
执行组合流时无法添加卡 | C2P 不可用,恢复到来宾结账流。 |
CARD_SECURITY_CODE_MISSING |
执行组合流时必须提供卡安全性。 | 确保 cardSecurityCode 函数中的 ClickToPay.checkoutWithNewCard() 字段包含 3 位数字的值(对于 Amex,则为 4 位数字)。 |
CARD_INVALID |
执行组合流时卡号无效。 | 确保 ClickToPay.checkoutWithNewCard() 函数中的 primaryAccountNumber 字段是有效卡。 |
CARD_NOT_RECOGNIZED |
无法识别指定的卡。 | 确保 ClickToPay.checkoutWithNewCard() 函数中的 primaryAccountNumber 字段是有效卡。 |
CARD_EXP_INVALID |
卡过期日期无效。 | 确保 ClickToPay.checkoutWithNewCard() 函数中的 panExpirationYear 和 panExpirationMonth 字段有效。 |
MERCHANT_DATA_INVALID |
商家数据无效 | C2P 不可用,恢复到来宾结账流。 |
UNABLE_TO_CONNECT |
无法连接/启动 DCF。 | C2P 不可用,恢复到来宾结账流。 |
AUTH_INVALID |
联邦 ID 令牌无效。 | C2P 不可用,恢复到来宾结账流。 |
标准 C2P 错误代码
错误代码 | 错误消息 | 所需操作 |
---|---|---|
REQUEST_TIMEOUT |
请求占用的时间超过了允许的完成时间。 这可能意味着服务中有大量调用。 您应该稍后重试。 也可能是由于 SDK 无法与其内嵌框架通信。 | C2P 不可用,恢复到来宾结账流。 |
SERVER_ERROR |
这指示服务器遇到了意外情况,导致其无法执行请求。 | C2P 不可用,恢复到来宾结账流。 |
INVALID_PARAMETER |
为一个或多个请求参数提供的值被认为无效。 缺少必需字段时也会发生此错误。 注意: 只要有可能,您就应该提供客户端验证,以避免不必要的服务器往返。 简单的验证约束属于为 API 规范的一部分。 | C2P 不可用,恢复到来宾结账流。 |
INVALID_REQUEST |
服务器无法理解请求。 通常这意味着数据字段必须采用特定的格式,但事实并非如此。 例如,base64 解码可能失败。 消息字段可能会提供关于请求的哪些部分/字段被视为不正确的额外说明。 | C2P 不可用,恢复到来宾结账流。 |
AUTH_ERROR |
服务器理解请求,但无法进行身份验证。 | C2P 不可用,恢复到来宾结账流。 |
NOT_FOUND |
请求的资源/业务实体不存在。 此资源也可能由于安全原因被隐藏。 | C2P 不可用,恢复到来宾结账流。 |
TERMS_AND_CONDITIONS_NOT_ACCEPTED |
未接受条款和条件。 | 恢复到来宾结账流。 |
IS_CONFIGURED_ERROR |
configure() 未完成。 首先应该初始化配置。 | 确保您的集成调用了 configure() 函数。 确保在让 C2P 组件显示之前留出足够的时间让函数完成运行。 |
SRCI_ID_MISSING |
缺少 SRC 启动程序的标识符。 | C2P 不可用,恢复到来宾结账流。 |
DPA_ID_MISSING |
DPA 的标识符缺失 | C2P 不可用,恢复到来宾结账流。 |
SRCI_TXID_MISSING |
缺少 SRC 启动程序交易标识符。 | C2P 不可用,恢复到来宾结账流。 |
DPA_TXOPT_MISSING |
缺少 DPA 交易选项结构。 | C2P 不可用,恢复到来宾结账流。 |
INVALID_STATE |
账户存在,但对于此计划不是“活动”状态。 | 恢复到来宾结账流。 |
CONSUMER_ID_MISSING |
需要消费者身份但未提供。 | 恢复到来宾结账流。 |
FRAUD |
用户账户被锁定或禁用。 | 恢复到来宾结账流。 |
ID_FORMAT_UNSUPPORTED |
会话 ID 无效 | C2P 不可用,恢复到来宾结账流。 |
延迟通过电子邮件识别的返回用户的 OTP(可选)
如果付款人根据其电子邮件被 C2P 识别,则默认行为是自动显示 C2P 提供的 OTP。
如果出于任何原因,您想要发起 C2P 交互,但将 C2P 提供的 OTP 推迟到以后提供(在付款人继续之前向他们显示其他屏幕时),在 ClickToPay.configure()
函数中添加 interaction.suppressPayerInteraction
字段。
如果将 interaction.suppressPayerInteraction
字段设置为 true,configure() 函数将设置 C2P 交互,并检查付款人是使用电子邮件还是 cookie 识别,或者是新用户。 但此函数不会触发与付款人的 C2P 交互(显示任何相关组件)。
如果省略此字段或将其设置为 false
,configure()
函数将设置 C2P 交互,检查付款人是使用电子邮件还是 cookie 识别的,或是否是新用户,并立即触发与付款人的 C2P 交互。
如果 interaction.suppressPayerInteraction
字段设置为 true,则必须根据付款人的识别状态执行以下操作。 如果付款人是:
- 根据电子邮件识别(
emailEnrolled = true
和emailVerified = false
),商家应用可以在发起 C2P 的 OTP 检查之前在流中执行其他步骤。 之后,您必须调用ClickToPay.initiatePayerInteraction()
函数向付款人显示 OTP。 - 不根据电子邮件识别(新用户或通过 cookie 识别),商家应用必须立即调用
initiatePayerInteraction()
函数。
步骤 4: 更新电子邮件地址更改
如果付款人可以在显示 C2P 组件的同一页面上更改其电子邮件地址,则对付款人电子邮件地址的任何更改都需要推送到 C2P SDK。 每次付款人更新电子邮件地址时,调用 ClickToPay.lookupCustomer(email) 函数来更新 C2P SDK。 付款人电子邮件用于查找此付款人是否有与其电子邮件地址关联的现有 C2P 个人资料。
如果您在网站上从付款人收集电子邮件地址,告知付款人其电子邮件用于查找他们的 C2P 个人资料。 您可以在电子邮件输入框旁边添加一个工具提示,告知付款人“您与参与的卡组织合作提供 C2P 以实现更快的结账体验,其电子邮件会在安全的情况下与参与的卡组织共享,用来检查付款人是否已有 C2P 个人资料”。
如果更新后的电子邮件地址:
-
- 链接到现有 C2P 个人资料:
onStateChange
回调由newState.payerState.emailEnrolled = true
触发。- OTP 输入表单由 C2P JavaScript SDK 显示。
- 不会链接到现有的 C2P 个人资料,
onStateChange
回调由newState.payerState.emailEnrolled = false
触发。
步骤 5: 实施结账
如果付款人决定使用其 C2P 个人资料中的现有卡结账,在付款人从卡列表中选择卡后调用 ClickToPay.checkoutWithExistingCard()
函数。 此函数将付款人带到 DCF 组件中的卡确认屏幕。
如果付款人决定在 C2P 个人资料中注册新卡或没有个人资料:
- 将卡输入表单显示为 Hosted Session 字段,以便付款人可以输入付款详细信息并单击支付。 您必须显示以下信息的字段:
- 卡号
- 安全码
- 过期月份和年份
- 卡上的姓名
- 使用
PaymentSession.onCardTypeChange
回调从 Hosted Session 检索卡组织,当付款人在托管字段中填写卡号时触发。 - 使用此组织调用
ClickToPay.isEnrollmentAvailableForScheme()
函数。
此函数根据 PAYMENT OPTIONS INQUIRY 操作响应中的paymentTypes.card.walletProviders[n].secureRemoteCommerce.scheme[n].name
检查提供的计划,来确定您是否已启用该计划。
如果函数返回false
,退出此流,使用来宾结账流正常处理卡,不使用 C2P。 - 显示并收集同意确认:
- 如果您位于美国,提供以下信息:如果付款人选择继续,您将与参与的卡组织共享付款人的卡详细信息、账单地址和电子邮件,以允许为付款人注册 C2P 来更快地完成结账。
- 如果您位于美国境外,则显示:
- 未勾选的同意框。
- 同意文本,供付款人用来确认同意与参与的卡组织共享卡详细信息、账单地址和电子邮件,以允许为付款人注册 C2P 来更快地完成结账。
- 当付款人单击您的付款页上的支付按钮进入下一阶段时:
- 如果您位于美国境外且未勾选同意框,则表示付款人不同意与 C2P 共享数据。 按照来宾结账流正常处理卡,不使用 C2P。
- 如果您位于美国境内或境外,用户已经勾选同意框,使用
PaymentSession.updateSessionFromForm()
函数更新会话。
您还可以在 UPDATE SESSION 请求中,使用账单对象在会话更新可选billing
地址。 如果您将付款人账单详细信息插入付款会话,则付款人无需在 C2P 注册期间再次重新输入它们。
- 更新会话后,调用
ClickToPay.checkoutWithNewCard()
函数,这会将付款人带到 DCF 组件中的卡注册屏幕:
- 如果此函数失败,将调用
onError
回调。 采取必要的步骤处理错误。 - 如果此函数成功,付款人将被重定向到 DCF 组件。
- 如果此函数失败,将调用
- 付款人与 DCF 组件进行交互以推进注册。 调用
onComplete
回调后,C2P 交互即宣告完成,您可以继续执行步骤 6,在会话中更新 C2P 详细信息。
步骤 6: 使用 Click to Pay 付款详细信息更新会话
在付款人成功完成 C2P 交互后,您必须请求网关检索 C2P 交互的付款详细信息并将其存储在会话中。
提交服务器端 UPDATE SESSION FROM WALLET API 请求,包含:
- 请求 URL 中的会话 ID。
onComplete
回调中返回的关联 ID 和计划。
UPDATE SESSION FROM WALLET 请求示例 |
---|
URL: "https://testpg.mpgs.axisbank.com/form/version/<version>/merchant/<merchant_ID>/session/<session_ID> HTTP Method POST { "apiOperation":"UPDATE_SESSION_FROM_WALLET", "order":{ "walletProvider":"SECURE_REMOTE_COMMERCE" }, "wallet":{ "secureRemoteCommerce":{ "srcCorrelationId":"<correlationId_provided_in_payloadCallback>, "scheme":"<scheme_provided_in_payloadCallback>" } } } |
如果会话成功更新了来自 C2P 交互的付款详细信息,显示付款确认屏幕,在付款人进行付款之前确认所有详细信息均正确无误。 如果会话未成功更新,让付款人选择另一个结账选项。
步骤 7: 执行 3DS 支付验证(可选)
如果要对付款人进行身份验证,请使用会话执行 3DS 支付验证。 有关详细说明,请参见使用 3DS JavaScript API 的 3DS。
步骤 8: 执行付款操作
付款人进行付款后(并且 3DS 支付验证(如果执行)),使用会话从您的服务器提交付款进行处理。 例如,您可以提交 AUTHORIZE 请求。
来自 C2P 交互的会话中存储的付款详细信息用于处理付款。 您可以使用同一个会话执行多个 API 操作。 有关在会话中发出付款请求的更多信息,请参阅 会话基础知识。
对于来宾结账流,使用基本的 Hosted Session 实现从托管字段收集卡详细信息,然后在发送付款操作之前将其添加到会话中。
AUTHORIZE 请求示例 |
---|
URL: "https://testpg.mpgs.axisbank.com/form/version/{version}//merchant/<merchant_ID>/order/<order_ID>/transaction/<transaction_ID> HTTP Method PUT { "apiOperation":"AUTHORIZE", "session": { "id": "<session_ID>" } } |
集成的 HTML 示例
此部分介绍让 Hosted Session 可以收集付款人的信用卡详细信息和配置 C2P 的简单集成。
Hosted Session 集成示例
<html> <head> <!-- INCLUDE SESSION.JS JAVASCRIPT LIBRARY --> <script src="https://testpg.mpgs.axisbank.com/form/version/<Version>/merchant/<Merchant ID>/session.js"></script> <!-- INCLUDE CLICK-TO-PAY.MIN.JS JAVASCRIPT LIBRARY --> <script type="text/javascript" src="https://testpg.mpgs.axisbank.com/form/static/click-to-pay/click-to-pay.min.js"></script> <!-- APPLY CLICK-JACKING STYLING AND HIDE CONTENTS OF THE PAGE --> <style id="antiClickjack">body{display:none !important;}</style> </head> <body> <!-- CREATE THE HTML FOR THE PAYMENT PAGE --> <div>Please enter your payment details:</div> <h3>Credit Card</h3> <div>Card Number: <input type="text" id="card-number" class="input-field" title="card number" aria-label="enter your card number" value="" tabindex="1" readonly></div> <div>Expiry Month:<input type="text" id="expiry-month" class="input-field" title="expiry month" aria-label="two-digit expiry month" value="" tabindex="2" readonly></div> <div>Expiry Year:<input type="text" id="expiry-year" class="input-field" title="expiry year" aria-label="two-digit expiry year" value="" tabindex="3" readonly></div> <div>Security Code:<input type="text" id="security-code" class="input-field" title="security code" aria-label="three-digit CCV security code" value="" tabindex="4" readonly></div> <div>Cardholder Name:<input type="text" id="cardholder-name" class="input-field" title="cardholder name" aria-label="enter name on card" value="" tabindex="5" readonly></div> <div><button id="payButton" onclick="pay('card');">Pay Now</button></div> <!-- CREATE THE HTML FOR THE CLICK-TO-PAY INTERACTION --> <div>C2P Fields Below------</div> Email: <input id="payerEmail" onblur="updateEmail();" /><br/> <div id="cardListContainer" ></div><br/> <div id="otpContainer"></div><br/> <div id="cardFacilitator" ></div><br/> <div id="coid" ></div><br/> <!-- JAVASCRIPT FRAME-BREAKER CODE TO PROVIDE PROTECTION AGAINST IFRAME CLICK-JACKING --> <script type="text/javascript"> if (self === top) { var antiClickjack = document.getElementById("antiClickjack"); antiClickjack.parentNode.removeChild(antiClickjack); } else { top.location = self.location; } PaymentSession.configure({ session: "<your_session_ID>", fields: { // ATTACH HOSTED FIELDS TO YOUR PAYMENT PAGE FOR A CREDIT CARD card: { number: "#card-number", securityCode: "#security-code", expiryMonth: "#expiry-month", expiryYear: "#expiry-year", nameOnCard: "#cardholder-name" } }, //SPECIFY YOUR MITIGATION OPTION HERE frameEmbeddingMitigation: ["javascript"], callbacks: { initialized: function(response) { console.log('initialized: ' + response) if(response.status === 'ok') { //configure C2P configure() } }, formSessionUpdate: function(response) { // HANDLE RESPONSE FOR UPDATE SESSION if (response.status) { if ("ok" == response.status) { console.log("Session updated with data: " + response.session.id); //CHECK IF SECURITY CODE WAS PROVIDED BY THE USER if (response.sourceOfFunds.provided.card.securityCode) { console.log("Security code was provided."); } //CHECK IF THE USER ENTERED A MASTERCARD CREDIT CARD if (response.sourceOfFunds.provided.card.scheme == 'MASTERCARD') { console.log("The user entered a Mastercard credit card.") } ClickToPay.isEnrollmentAvailableForScheme(response.sourceOfFunds.provided.card.scheme, function (canEnroll) { console.log('Card can be enrolled', canEnroll) if(canEnroll) { ClickToPay.checkoutWithNewCard(); } }); } else if ("fields_in_error" == response.status) { console.log("Session update failed with field errors."); if (response.errors.cardNumber) { console.log("Card number invalid or missing."); } if (response.errors.expiryYear) { console.log("Expiry year invalid or missing."); } if (response.errors.expiryMonth) { console.log("Expiry month invalid or missing."); } if (response.errors.securityCode) { console.log("Security code invalid."); } } else if ("request_timeout" == response.status) { console.log("Session update failed with request timeout: " + response.errors.message); } else if ("system_error" == response.status) { console.log("Session update failed with system error: " + response.errors.message); } } else { console.log("Session update failed: " + response); } } }, interaction: { displayControl: { formatCard: "EMBOSSED", invalidFieldCharacters: "REJECT" } } }); function pay() { // UPDATE THE SESSION WITH THE INPUT FROM HOSTED FIELDS PaymentSession.updateSessionFromForm('card'); } </script> <script type="text/javascript"> var payloadCallback = function (correlationId, scheme) { console.log('Payload callback complete with correlation id %s and scheme %s', correlationId, scheme); }; var errorCallback = function (error) { console.log('Error callback triggered with error ' + error); console.log(error); }; var cancelCallback = function () { console.log('Cancel callback triggered'); }; function configure() { ClickToPay.configure({ merchant: { id: "<your_gateway_merchant_ID>", name: "<your_gateway_name>", url: "<your_web_site_URL>" }, session: { id: "<your_session_ID>", wsVersion: <api_version> }, order: { amount: <amount>, currency: "<currency>" }, interaction: { //BILLING PREFERENCE WITH ONE OF THE FOLLOWING VALUES: NONE, FULL, POSTAL_COUNTRY billingPreference: "FULL", collectShippingAddress: true, locale: "<locale>", country: "<country code>" }, customer: { email: "<payers_email_address>"//OPTIONAL }, elements: { cardList: "cardListContainer", otp: "otpContainer", // OPTIONAL dcf: "cardFacilitator" }, callbacks: { onComplete: function(correlationId, scheme) { console.log("onComplete fired"); console.log("Correlation ID: " + correlationId); console.log("Scheme: " + scheme); document.getElementById("coid").innerHTML = 'Correlation ID: ' + correlationId + ', Scheme: ' + scheme }, onStateChange: function(changeInfo) { console.log("onStateChange fired"); console.log(changeInfo); }, onError: function(errInfo) { console.log("onError fired"); console.log(errInfo); } } }); } function updateEmail() { ClickToPay.lookupCustomer(document.getElementById("payerEmail").value); } </script> </body> </html>