欧洲 PSD2 合规
了解新的欧洲经济区 (EEA) 卡支付法规会对您的业务产生哪些影响
概述
《支付服务指令 2 (PSD2)》是一项 EEA 法规,要求对涉及 EEA 国家发行的信用卡的所有交易的付款和预订流程进行变更。
PSD2 提高了安全性并减少了欺诈,但它也从根本上改变了整个欧洲的支付方式。作为这些法规的一部分,在法规范围内处理电子消费者支付时,需要采用一种强客户身份验证解决方案。所有发卡机构、收单银行和商户都必须支持这种强客户身份验证解决方案。由于 EEA 内的银行正在践行该法规,不遵守规定将导致付款失败。
本页说明了受支持的 Rapid 付款类型受到怎样的影响,以及合作伙伴在为旅客提供服务时可以采取哪些措施以遵守规定。如果您想更详细地了解该指令,请访问欧盟委员会官方网站查看该法规。
合规性要求
在 EEA 中实现合规交易的步骤会因记录商户及如何向 Rapid 付款而有所不同。
合作伙伴为记录商户
Expedia 联盟伙伴收款
使用 EAC 的预订不受 PSD2 法规的影响。无需因合规要求而变更与 Rapid 的付款流程或 API 集成。但是,如果您是记录商户并在欧盟法规范围内向旅客的信用卡、借记卡或其他付款方式收取费用,则可能会受到该法规的影响。该法规可能会要求您在付款流程中支持符合 PSD2 规定的双重身份验证 (2FA)。请联系您的付款处理方,详细了解他们具备哪些能力,可帮助商户符合 PSD2 规定并避免交易失败。
合作伙伴卡
如果贵公司为记录商户且使用贵公司所有、EEA 发行的信用卡或借记卡向 Rapid 付款,您可能会受到该法规的影响。符合 PSD2 规定的卡有:
- 在 EEA 发行的一次性虚拟卡。
- 在 EEA 发行给贵公司而非个人的公司卡。
- 在 EEA 外发行的任何卡。
如果您在 EEA 法规范围内向旅客的信用卡、借记卡或其他付款方式收取费用,则可能也会受到该法规的影响。该法规可能会要求您在付款流程中支持符合 PSD2 规定的双重身份验证 (2FA)。请联系您的付款处理方,详细了解他们具备哪些能力,可帮助商户符合 PSD2 规定并避免交易失败。
如果上述符合 PSD2 规定的合作伙伴卡不是首选,贵组织可以直接向发行您合作伙伴卡的银行申请豁免。如果获得豁免,该卡上的交易将不需要身份验证,除非可能会使用 2FA 进行一次性在线验证。这种一次性验证要求可能因银行而异。请注意,获得豁免可能是一个漫长的过程,这也意味着您的银行可能会要求您承担所有欺诈性付款的负责。
Rapid 为记录商户
如果贵公司将旅客的卡发送给 Rapid,使用 Rapid 作为记录商户,您可能会受到该法规的影响。当旅客在无零售客服介入的情况下在线预订时,该法规要求 Rapid 需让旅客验证他们是否发起了付款。针对此要求,符合 PSD2 规定的流程是在付款流程中采用双重身份验证 (2FA)。想要通过 EEA 发行的任意信用卡或借记卡将 Rapid 作为记录商户使用,合作伙伴将需要采用 Rapid v2.2+ 中提供的针对 2FA 的 Rapid 解决方案。
但是,通过零售客服或呼叫中心客服预订的交易不需要满足 2FA 要求。只需明确表明预订是在客服的协助下进行,这些交易即符合规定。表明可使用房态 API 的 sales_channel
字段。
住宿为记录商户
如果贵公司使用住宿收款,您可能会受到该法规的影响。在一些情况下,住宿可能会在旅客不在场的情况下尝试从旅客的卡中收取费用,例如“预订后未入住”费用或押金。如果在收费之前没有进行双重身份验证或 2FA,这些收费都是不合规的。想要通过 EEA 发行的信用卡或借记卡针对旅客使用住宿收款,合作伙伴将需要采用 Rapid v2.2+ 中提供的针对 2FA 的 Rapid 解决方案。
Rapid 解决方案概述
如何运作
使用 Rapid 记录商户或住宿收款向旅客卡收费的合作伙伴可以采用 Rapid 的 API 解决方案来生成符合该法规的预订。API 在预订流程中支持 3DS 2.0 的双重身份验证,从而符合 PSD2 的规定。借助 3DS 2.0,我们可支持基于风险的身份验证,通过授权银行自行决定何时需要或不需要使用 2FA 验证旅客,来减少与旅客的矛盾。
2FA 的解决方案由三个不同部分组成:
- 合作伙伴添加到付款页面的内嵌框架,用于为旅客提供发卡银行的 2FA 体验。在集成文档中,它称之为 3DS 内嵌框架。
- 一个驻留在付款页面上的新客户端 JavaScript 库,用于收集浏览器数据、与内嵌框架通信以及在内嵌框架中显示 2FA 体验。在集成文档中,它称之为 3DS 连接器库。
- Rapid 接受银行的付款人信息并在执行 2FA 后完成预订。
当同时使用 JavaScript 和 Rapid 时,采用 2FA 的预订流程现在将在调用预订 API 前后增加一些步骤。下图描绘了这个更新后的预订流程。
在修订后预订流程的每个步骤中,一个步骤的输出中包含着用作下一步输入的数据。数据将需要在浏览器上的 JavaScript 和 Rapid 之间传递。
注:上图是实际 API 的简化流程,旨在用于介绍。请参考集成文档,了解有关完整 API 流程的更多信息。
集成组件详细信息
浏览器内嵌框架
付款体验中的内嵌框架托管一个归旅客发卡银行所有的 URL。此 URL 将向用户显示 2FA 体验,并将旅客提供的任何信息直接传输给他们的银行。内嵌框架最初应该隐藏,当尝试预订后需要 2FA 挑战时,可以将其覆盖在页面上。
浏览器 JavaScript 库
该库被添加到付款页面,在预订时调用以支持 2FA 流程。该库的 API 支持下述功能。
自动收集旅客的设备信息
在尝试预订之前,必须收集旅客设备的有关信息以针对 2FA 做好预订准备。这些信息随后将发送给旅客的发卡银行进行审核,以便银行评估风险,决定交易是否需要进行 2FA,并确保其正确显示。根据 3DS 2.x 规范,将从旅客的浏览器收集以下数据:语言、色彩深度、屏幕高度、屏幕宽度、时区、用户代理以及是否启用 Java。
在浏览器内嵌框架中显示 2FA 体验
尝试预订后,该库用于显示内嵌框架覆盖并将银行的内容加载到内嵌框架中。在 2FA 流程中,银行的内容可能会收集有关旅客设备的其他信息,以支持他们的风险评估。完成预订需要此流程。
Rapid
Rapid v2.2 及更高版本包含可与客户端 JavaScript 库结合使用的新 API。这些 API 现在支持下述功能。
旅客及付款详情注册
在尝试预订之前,必须收集有关旅客的更多信息以针对 2FA 做好预订准备。这些数据包括旅客在销售网站的账户和旅客付款的详细信息,随后将发送给旅客的发卡银行进行审核,以便银行评估风险,决定交易是否需要进行 2FA。请查看 Rapid v2.2+ 中的注册付款 API,了解更多信息。
完成付款和确认预订
在使用 Rapid 进行预订尝试并在浏览器上完成 2FA 流程后,必须再次调用 Rapid。在后台,我们将确认 2FA 切实成功,因此预订才可以得到确认。请查看 Rapid v2.2+ 中的完成付款会话,了解更多信息。
预订流程
概述
如果合作伙伴配置文件 Rapid 支持中启用了 2FA,那么价格检查 API 将返回注册付款 API 而不是创建预订 API 的链接。以下是旅客发起预订后所需的 API 调用序列图。该序列涉及对 JavaScript 库和 Rapid 的调用。
针对 2FA 准备预订时,可能并不总是需要 2FA。是否需要 2FA 由用于付款的信用卡的发卡银行决定。决定会在交易期间做出,并在创建预订 API 响应中指示。
以下是使用保留与继续功能时所需的 API 调用序列图。
注:上图是实际 API 的简化流程,旨在用于介绍。请参考集成文档,了解有关完整 API 流程的更多信息。
更多信息
有关 2FA 体验的技术要求的更多信息,请查看 EMVCo 的 3D 安全协议和核心功能规范
Rapid 和双重身份验证集成指南
概述
支持双重身份验证 (2FA) 将需要与新的 JavaScript 库(称为 3DS 连接器)和 Rapid 集成。两者结合使用,可在付款页面上显示 2FA 并确认预订。这种解决方案同时支持 Expedia 收款和住宿收款业务模式。
支持 2FA 预订所需的 API 调用序列概述如下,并在以下部分中做了详细说明。
- JavaScript 设置方法
- Rapid 注册付款信息 API
- JavaScript 初始化会话方法
- Rapid 预订 API
- JavaScript 挑战方法
- Rapid 完成付款 API
要支持此序列,Rapid 合作伙伴支持必须为各个合作伙伴配置文件启用 2FA。
Rapid
如果为合作伙伴配置文件启用了双重身份验证,API 响应将有所不同,支持采用 2FA 的修改后的预订流程。
房态 API
API 请求中 sales_channel
字段的值必须准确,才能在法规允许的情况下获得 2FA 豁免。该值及许多其他因素会由发卡银行进行审核,在预订时做出决定。只有客服工具才可免于进行 2FA。要指明这一点,请将 sales_channel
的值设置为 agent_tool
。
价格检查 API
API 响应将包含指向注册付款 API 而不是创建预订 API 的链接。
启用 2FA 时的响应示例:
{
"status": "matched",
"occupancies": {
//...(example omitted for length)
},
"links": {
"payment_session": {
"method": "POST",
"href": "/v3/payment-sessions?token=QldfCGlcUAVgBDRwdWXBBL"
}
}
}
注册付款 API
这将是 JavaScript-Rapid PSD2 预订流程的第二步,发生在 JavaScript setup
方法之后。
该请求将包含属于非 PSD2 预订流程一部分的详细付款信息以及支持成功执行 2FA 的新字段。其中两个字段 encoded_browser_metadata
和 version
是从 JavaScript API 的 setup method
返回的。
响应将包含 payment_session_id
和 encoded_init_config
。这些被指定为 JavaScript 库 initSession
方法的输入。响应中包含的预订链接应在 initSession
方法之后使用。
示例请求:
{
"version": "1",
"browser_accept_header": "\*/\*",
"encoded_browser_metadata": "ZW5jb2RlZF9icm93c2VyX21ldGFkYXRh",
"preferred_challenge_window_size": "medium",
"merchant_url": "https://server.adomainname.net",
"customer_account_details": {
"authentication_method": "guest",
"authentication_timestamp": "2018-02-12T11:59:00.000Z",
"create_date": "2018-09-15",
"change_date": "2018-09-17",
"password_change_date": "2018-09-17",
"add_card_attempts": 1,
"account_purchases": 1
},
"payments": [
{
"type": "customer_card",
"card_type": "VI",
"number": "4111111111111111",
"security_code": "123",
"expiration_month": "08",
"expiration_year": "2025",
"billing_contact": {
"given_name": "John",
"family_name": "Smith",
"email": "smith@example.com",
"phone": "4875550077",
"address": {
"line_1": "555 1st St",
"line_2": "10th Floor",
"line_3": "Unit 12",
"city": "Seattle",
"state_province_code": "WA",
"postal_code": "98121",
"country_code": "US"
}
},
"enrollment_date": "2018-09-15"
}
]
}
响应示例:
{
"payment_session_id": "76d6aaea-c1d5-11e8-a355-529269fb1459",
"encoded_init_config": "QSBiYXNlNjQgZW5jb2RlZCBvYmplY3Qgd2hpY2ggY29udGFpbnMgY29uZmlndXJhdGlvbiBuZWVkZWQgdG8gcGVyZm9ybSBkZXZpY2UgZmluZ2VycHJpbnRpbmcgYW5kL29yIDNEUyBNZXRob2Qu",
"links": {
"book": {
"method": "POST",
"href": "/v3/itineraries?token=MY5S3j36cOcLfLBZjPYQ1abhfc8CqmjmFVzkk7euvWaunE57LLeDgaxm516m"
}
}
}
创建预订 API
这将是 JavaScript-Rapid PSD2 预订流程的第四步,发生在 JavaScript initSession
方法之后。该请求不会包含任何用于 PSD2 的新字段,所有需要的信息都包含在注册付款 API 返回的预订链接的令牌中。如果成功,响应将始终包含 itinerary_id
。但是,仅此并不表示预订已确认,因为可能需要 2FA。
如果需要 2FA,响应还将包含 encoded_challenge_config
。注册付款返回的 encoded_challenge_config
和 payment_session_id
将需要作为参数传递给 JavaScript challenge
方法。
响应还将包含一个 complete_payment_session
的新链接。此链接应在 JavaScript 库的 challenge
方法之后使用。
如果不需要 2FA,则确认预订并且响应将包含 retrieve
、cancel
和可选的 resume
链接。
如果需要 2FA,则创建预订响应的示例如下:
{
"itinerary_id": "8999989898988",
"links": {
"complete_payment_session": {
"method": "PUT",
"href": "/v3/itineraries/8999989898988/payment-sessions?token=MY5S3j36cOcLfLBZjPYQ1abhfc8CqmjmFVzkk7euvWaunE57LLeDgaxm516m"
}
},
"encoded_challenge_config": "ABElifsiejfacies2@033asfe="
}
完成付款会话 API
这将是 JavaScript-Rapid PSD2 预订流程的第六步,发生在 JavaScript challenge
方法之后。要完成付款并通知 Rapid 2FA 尝试已完成(无论成功与否),需要此 API。
请求将不包含任何用于 PSD2 的新字段。
如果成功,响应将包含 itinerary_id
,以及 retrieve
、cancel
和 可选的 resume
链接。响应若成功则表明预订已确认。
响应示例:
{
"itinerary_id": "8999989898988",
"links": {
"retrieve": {
"method": "GET",
"href": "/v3/itineraries/8999989898988?token=MY5S3j36cOcLfLBZjPYQ1abhfc8CqmjmFVzkk7euvWaunE57LLeDgaxm516m"
}
}
}
3DS 连接器 JavaScript 库和 3DS 内嵌框架
使用 PSD2 预订工作流程时,付款页面必须包含新的内嵌框架和 JavaScript 库。内嵌框架又称 3DS 内嵌框架,将使用 3D-Secure2.x 向旅客展示身份验证体验。JavaScript 库又称 3DS 连接器库,将支持向发卡银行传输信息并将银行的内容加载到内嵌框架
添加 3DS 内嵌框架和 JavaScript 库
添加 3DS 内嵌框架
应将 3DS 内嵌框架包装在一个容器中,最初为隐藏状态,但在需要身份验证挑战以处理付款时可以显示。
容器的设计可以自定义,以适应托管页面需求。以下例子展示了一个使用 bootstrap 模式的实施示例,仅作参考:
<div id="threeDsIframeModal" class="modal" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body iframe-container">
<div class="embed-responsive embed-responsive-16by9">
<iframe id="threeDsIframe" src="<<3DS iframe URL>>"> </iframe>
</div>
</div>
</div>
</div>
</div>
内嵌框架的源必须设置为以下两个值之一:
URL 类型 | URL | 备注 |
---|---|---|
生产 | https://static.pay.expedia.com/3ds/threeDsIframe.html | 支持生产 2FA |
测试沙盒 | https://static.pay.expedia.com/3ds/sandboxThreeDsIframe.html | 支持 2FA 测试 |
测试 URL 为测试提供支持,本文档后面会回顾此主题。要在测试期间限制内嵌框架的内容,内嵌框架可具备沙盒的属性,但必须支持以下内容:
sandbox = 'allow-scripts allow-forms allow-same-origin';
添加 3DS 连接器 JavaScript 库
3DS 连接器库与 3DS 内嵌框架通信并将数据发送到提供内嵌框架内容的发卡银行。下面的例子展示了如何将库添加到付款页面的示例。
<head>
<script src="<<3DS connector script URL>>" integrity="<<actual integrity value>>"></script>
</head>
脚本元素的源和 integrity 值应设置为以下值:
库版本 | 属性 | 值 |
---|---|---|
1.3.39 | src | https://static.pay.expedia.com/3ds/1.3.39/pay-3ds-js-libs-connector.min.js |
integrity | sha384-par0I4Q5cfljwzqw2mAggM4dKdYzGyj4uZiL4cMviGjI3qVzEgWGuZ2075mYutbT | |
1.3.65 | src | https://static.pay.expedia.com/3ds/1.3.65/pay-3ds-js-libs-connector.min.js |
integrity | sha384-gYopPw6xE5DZwnZXGavkwnvs3NkDOobnHqjroUnSHpGXvs/J9xjHX/8aGzKtSgWI |
注:随着未来新版本的推出和采用,源 URL 和 integrity 将发生变化。较新的版本应该不会破坏现有的集成。较旧版本的脚本仍然可以访问。
使用 3DS 内嵌框架和 JavaScript 库
库需要使用 JavaScript Promises。下面的例子展示了一个仅供参考的实施示例,演示了数据是如何在 JavaScript 方法和 Rapid 之间交换的。
// Initialize the library
let connector = new PayThreeDSConnector.ThreeDSConnector("threedsiframe", "https://static.pay.expedia.com");
RapidIntegration.priceCheck(priceCheckLink)
.then(priceCheckResponse => {
paymentSessionLink = priceCheckResponse.links.payment_session.href;
// Setup an authentication session with the library
return connector.setup({ referenceId: '1000' })
}).then(setupResponse => {
console.log("Setup Response: ", setupResponse);
// Send information from setup to Rapid's Register Payments API
return RapidIntegration.registerPayment(paymentSessionLink,
setupResponse);
}).then(paymentSessionResponse => {
console.log("Register Payments Response: ", paymentSessionResponse);
paymentSessionId = paymentSessionResponse.paymentSessionId;
bookLink = paymentSessionResponse.links.book.href;
if (paymentSessionResponse.encoded_init_config) {
// If the payment session response contains an encoded_init_config
// field, initialize an authentication session with the library
// using information returned from Rapid's Register Payments API
connector.initSession({
paymentSessionId: paymentSessionId,
encodedInitConfig: paymentSessionResponse.encodedInitConfig
}).then(initSessionResponse => {
console.log("Init Session Response: ", initSessionResponse);
// Then create a booking with Rapid's Book API
return RapidIntegration.createBooking(bookLink,
paymentSessionId);
})
} else {
// Otherwise, create a booking with Rapid's Book API directly
return RapidIntegration.createBooking(bookLink, paymentSessionId);
}
}).then(createBookingResponse => {
console.log("Create Booking Response: ", createBookingResponse);
itineraryId = createBookingResponse.itinerary_id;
if (createBookingResponse.encoded_challenge_config) {
// If the Create Booking API contains an encoded_challenge_config field,
// display the authentication challenge window
$('#threeDsIframeModal).modal('show');
completePaymentSessionLink = createBookingResponse.links.complete_payment_session.href;
// Perform the challenge using the information returned from Rapid's Register Payments API
// and Create Booking API
connector.challenge({
paymentSessionId: paymentSessionId,
encodedChallengeConfig: createBookingResponse.encodedChallengeConfig
}).then(challengeResponse => {
console.log("Challenge Response: ", challengeResponse);
// Complete a booking with Rapid's Complete Payment Session API
return RapidIntegration.completePaymentSession(completePaymentSessionLink, itineraryId);
}).then(completePaymentSessionResponse => {
console.log("Complete Payment Session Response: ", completePaymentSessionResponse);
return completePaymentSessionResponse;
}).finally(() => {
// Close the authentication challenge window
$('#threeDsIframeModal').modal('hide');
});
} else {
return createBookingResponse;
}
}).then(bookingResponse => {
...
});
注:对 RapidIntegration
类的引用是示例的一部分,而不是 3DS 连接器库的一部分,旨在演示支持将信息传输到 API 的包装器。
注:此例子对应在运行时确定的参数使用了静态值,例如:referenceId
付款页面指南
支持 2FA 的信用卡品牌可能需要按照其指南展示其徽标和品牌。
信用卡品牌 | 2FA 品牌 | 徽标和指南 |
---|---|---|
万事达卡 | Mastercard Identity Check | (https://brand.mastercard.com/debit/mastercard-brand-mark/downloads.html))] |
维萨卡 | Visa Secure | [https://www.merchantsignage.visa.com/brand_guidelines |
注:其他信用卡品牌的徽标和指南一旦可用即将包含在内。
3DS 连接器 JavaScript 库文档
等级:ThreeDSConnector
构造函数
new ThreeDSConnector(threeDsIFrameId, threeDsIFrameOrigin)
参数:
名称 | 类型 | 说明 |
---|---|---|
threeDsIFrameOrigin | 字符串 | 3DS 内嵌框架的 ID。 |
threeDsIFrameOrigin | 字符串 | 3DS 内嵌框架的源。用于在与 3DS 内嵌框架通信时以传出窗口消息为目标和筛选传入消息。 |
方法
设置
通过收集后端 3DS 服务所需的浏览器基本详细信息(如屏幕尺寸、色彩深度等)来设置付款会话。
方法签名:
setup(setupRequest)
参数:
名称 | 类型 |
---|---|
setupRequest | SetupRequest |
返回:
承诺一个 SetupResponse
初始化会话
初始化会话以使用 3DS 进行身份验证。作为初始化的一部分,可能会从浏览器收集其他数据。如果发卡机构要求,可以将 3DS 方法 URL 加载到内嵌框架中,以使发卡机构的访问控制服务器能够直接从浏览器收集数据。客户端不需要等待调用完成回调,就可以创建订单。
方法签名:
initSession(initSessionRequest)
参数:
名称 | 类型 |
---|---|
initSessionRequest | InitSessionRequest |
回报:承诺 InitSessionResponse
挑战
如果发卡机构要求,则需要加载 3DS 身份验证体验。
方法签名:
challenge(challengeRequest)
参数:
名称 | 类型 |
---|---|
challengeRequest | ChallengeRequest |
回报:承诺 ChallengeResponse
类:SetupRequest
设置调用的请求结构。
属性:
名称 | 类型 | 说明 |
---|---|---|
referenceId | string | 用于标识旅客付款会话的参考 ID。用于记录和跟踪。使用下划线连接您的 APIKey 和 Customer-Session-ID 。示例:[APIKey]_[SessionID] |
类:SetupResponse
来自设置调用的响应。
属性:
名称 | 类型 | 说明 |
---|---|---|
version | 字符串 | 此库的版本,与库的 URL 路径中显示的版本相同。 |
encodedBrowserMetadata | 字符串 | 包含收集的浏览器详细信息的编码对象。客户端应将此视为不公开数据,无需解析即可传递给后端付款服务。 |
类:InitSessionRequest
initSession
方法的请求结构。
属性:
名称 | 类型 | 说明 |
---|---|---|
paymentSessionId | 字符串 | Rapid 注册付款信息 API 返回的唯一 ID。 |
encodedInitConfig | 字符串 | 包含初始化所需数据的配置对象的编码列表,由 Rapid 注册付款信息 API 返回。 |
类:InitSessionResponse
initSession
方法的响应结构。
属性:
名称 | 类型 | 说明 |
---|---|---|
statusCode | 字符串 | initSession 调用的状态。 |
message | 字符串 | 可选。指明失败原因。 |
statusCode
的可能值:
值 | 说明 |
---|---|
SUCCESS | 初始化成功完成。 |
SKIPPED | 没有进行初始化。 |
FAILED | 初始化失败。消息字段包含有关失败的其他信息。 |
TIMEOUT | 初始化未在有效时间内完成。超时持续时间为 10 秒。 |
注:对于所有的 initSessionresponse
statusCode
值,请继续使用 Rapid 预订 API。
等级:ChallengeRequest
挑战方法的请求结构。
属性:
statusCode 值 | 测试 encoded_Challenge_config 值 | 说明 |
---|---|---|
SUCCESS | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIlNVQ0NFU1MifV0 | 没有用户内嵌框架互动 |
SUCCESS/FAILED | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIlNIT1cifV0 | 没有用户内嵌框架互动 |
FAILED | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIkZBSUxFRCJ9XQ | 没有用户内嵌框架互动 |
TIMEOUT | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIlRJTUVPVVQifV0 | |
ERROR | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmdlT3V0cHV0Q29uZmlnIjogIkVSUk9SIn1d |
statusCode 的可能值
值 | 说明 |
---|---|
SUCCESS | 3DS 挑战成功完成。 |
SKIPPED | 外部应用程序错误。 |
FAILED | 由于持卡人无法正确响应身份验证挑战,3DS 挑战未成功完成。 |
TIMEOUT | 挑战未在有效时间内完成。超时持续时间为 1200 秒。 |
注:对于所有的 challengeResponse
statusCode
值,请继续使用适用完成付款会话的 Rapid。
使用 Rapid 和双重身份验证进行测试
您与 Rapid 和 3DS 连接器方法的集成可以使用与 API 支持的特定场景相对应的输入参数值来进行测试。
Rapid
要测试 Rapid,请在 HTTP 请求中包含一个名为 Test 的额外 HTTP 标头,并使用该 API 支持的一个值来测试支持的场景。
在 PSD2 预订流程中,Rapid 的测试响应也可用于测试 3DS 连接器库方法。
注册付款
以下测试标头值会在 API 响应中产生不同的 encoded_init_config
值和不同的 HTTP 响应代码。encoded_init_config
可以传递到 JavaScript 库的 initSession
调用中,以触发 3DS 连接器库中的不同测试案例。
测试标头值 | HTTP 代码和响应 | initSession 测试案例 |
---|---|---|
standard | 201 – Standard Response | SUCCESS |
init_skip | 201 - Response Without encodedInitConfig | 不支持 |
init_fail | 201 – Standard Response | FAILED |
init_timeout | 201 – Standard Response | TIMEOUT |
internal_server_error | 500 – Internal Server Error | |
internal_server_error | 503 - Server Unavailable |
注:3DS 连接器 Library.t_config
中不同的 init_skip
测试案例可以传递给 initSession
并强制执行 SKIPPED 的 statusCode
创建预订
除了 Rapid 预订测试请求中为非 PSD2 预订流程定义的测试标头之外,PSD2 工作流程还支持其他测试标头值。
测试标头值会产生不同的 encodedChallengeConfig
值,这些值可以传递至 JavaScript 库的 challenge
调用中,以触发不同的测试案例。
测试标头值 | HTTP 代码和响应 | initSession 测试案例 |
---|---|---|
complete_payment_session | 201 – Response with Complete Payment Session link | SUCCESS without user iframe Interaction |
complete_payment_session_show | 201 – Response with Complete Payment Session link | SUCCESS/FAILED with user iframe Interaction |
complete_payment_session_fail | 201 – Response with Complete Payment Session link | FAILED without user iframe Interaction |
complete_payment_session_timeout | 201 – Response with Complete Payment Session link | TIMEOUT |
complete_payment_session_error | 201 – Response with Complete Payment Session link | ERROR |
完成付款会话
测试标头值会产生不同错误案例,可能会在尝试完成付款和确认预订时发生。
测试标头值 | HTTP 代码和响应 |
---|---|
payment_declined | 400 - Payment Declined Response |
price_mismatch | 409 - Price Mismatch Response |
rooms_unavailable | 410 - Rooms Unavailable Response |
3DS 连接器库和内嵌框架
要在没有外部依赖因素的情况下测试 3DS 连接器,特定的参数值应对应于支持的方法响应。仅当内嵌框架使用测试沙盒 URL 加载时才支持此行为。
初始化会话
InitSessionResponse statusCode
的受支持值可以通过改变 initSessionRequest encodedInitConfig
来进行测试。
statusCode 值 | 测试 encodedInitConfig 值 |
---|---|
SUCCESS | W3sicHJvdmlkZXJJZCI6IDAsICJz YW5kYm94SW5pdE91dHB1dENvbmZpZyI6ICJTVUNDRVNTIn1d |
FAILED | W3sicHJvdmlkZXJJZCI6IDAsICJz YW5kYm94SW5pdE91dHB1dENvbmZpZyI6ICJGQUlMRUQifV0= |
TIMEOUT | W3sicHJvdmlkZXJJZCI6IDAsICJz YW5kYm94SW5pdE91dHB1dENvbmZpZyI6ICJUSU1FT1VUIn1d |
SKIPPED | 目前不支持。 |
注:encoded_init_config
值也可以使用注册付款 API 的受支持测试标头生成。
挑战
challengeResponse statusCode
的受支持值可以通过改变 challengeRequest encondedChallengeConfig
来进行测试。
statusCode 值 | 测试 encoded_Challenge_config 值 | 说明 |
---|---|---|
SUCCESS | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIlNVQ0NFU1MifV0 | 没有用户内嵌框架互动 |
SUCCESS/FAILED | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIlNIT1cifV0 | 没有用户内嵌框架互动 |
FAILED | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIkZBSUxFRCJ9XQ | 没有用户内嵌框架互动 |
TIMEOUT | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmd lT3V0cHV0Q29uZmlnIjogIlRJTUVPVVQifV0 | |
错误 | W3sicHJvdmlkZXJJZCI6IDA sICJzYW5kYm94Q2hhbGxlbmdlT3V0cHV0Q29uZmlnIjogIkVSUk9SIn1d |
注:encodedInitConfig
值也可以使用预订 API PSD2 流程的受支持测试标头生成。
注:当 SUCCESS 或 FAILED 的挑战状态代码值测试基于使用内嵌框架的用户输入时,挑战方法响应将等待内嵌框架中的模拟身份验证 UI 完成。
3DS 内嵌框架中的 UI 示例:
示例用法
以下例子展示了一个实施示例,仅作参考。该例子演示了如何使用预定义的参数值来针对 3DS 挑战对库进行测试,而无需用户与内嵌框架互动。
var c = new PayThreeDSConnector.ThreeDSConnector('threedsiframe', 'https://static.pay.expedia.com'); // change to match the 3DS iframe ID
c.setup({ referenceId: '1000' })
.then((setupResponse) => {
console.log('Setup Output: ', setupResponse);
return c.initSession({
paymentSessionId: 1,
encodedInitConfig: ' W3sicHJvdmlkZXJJZCI6IDAsICJzYW5kYm94SW5pdE91dHB1dENvbmZpZyI6ICJTVUNDRVNTIn1d',
}); // SUCCESS
})
.then((initResponse) => {
console.log('InitSession Output: ', initResponse);
$('#threedsIframeModal').modal(); // replace with code to show the modal containing the 3DS iframe
return c.challenge({
paymentSessionId: 1,
encodedChallengeConfig:
' W3sicHJvdmlkZXJJZCI6IDAsICJzYW5kYm94Q2hhbGxlbmdlT3V0cHV0Q29uZmlnIjogIlNVQ0NFU1MifV0=',
}); // SUCCESS
})
.then((challengeResponse) => {
console.log('Challenge Output: ', challengeResponse);
})
.finally(() => {
$('#threedsIframeModal').modal('hide'); // replace with code to hide the modal containing the 3DS iframe
});
双重身份验证和住宿收款
关于住宿收款的双重身份验证
当使用住宿收款预订时,Expedia 不会从卡上扣款,而只是将其发送给住宿进行处理。住宿可能会在客户入住前使用此信息验证卡。在办理入住时,旅客应亲自付款。
但是,有时旅客无法办理入住,住宿可能会收取预订后未入住费用。这些费用可能会受到 PSD2 法规的影响,因为它们涉及到在旅客不在场的情况下对卡进行收费。
如果交易受到影响,付款可能会失败,如果收费不符合规定,住宿也可能会面临信用卡品牌方的处罚。
为了保护我们与住宿之间的关系并继续为我们的合作伙伴服务,Expedia Group 为住宿提供了一条可选的合规途径。受影响的住宿现在可以利用 Expedia Group 代表他们提供 2FA。这样一来,住宿便可以保护他们的业务,确保 Rapid 可以继续提供同样的多样化住宿。
Rapid 2.4+ 在住宿内容文件和住宿内容中提供了 <payment_registration_recommended=true>
的标记,可以帮助您识别项目中可能涉及的住宿。
注:只有欧洲经济区 (EEA) 内的住宿才有资格使用 2FA。
注:可能需要 2FA 的住宿集不是静态的,可能会随着其他住宿选择启用此功能而增长。住宿的这一属性在 Rapid 内容 v.2.4 中可用。
住宿收款的 2FA 会对集成带来怎样的影响?
如果合作伙伴想要提供可能需要 2FA 的住宿,那么预订路径应支持 2FA。在不支持 2FA 的情况下,如果发卡银行确定交易需要 2FA(例如在 EEA 发行的卡),预订这些住宿可能会失败。
如果住宿收取了预订后未入住费用,Rapid 将为记录商户。卡账单汇总上的收费描述符不会由住宿定义。描述符的值会由合作伙伴定义。要自定义此文本,请联系 Rapid 合作伙伴支持。
为遵守信用卡品牌和 Rapid 上线流程的要求,请在预订后未入住的情况下使用已接受付款 API 在付款页面上显示 processing_country
。这对于 Rapid 为记录商户的所有交易来说都是必需的,如果使用 2FA 并且出现预订后未入住的情况,就可能会发生这种情况。
如何减轻对集成的影响
如果 Rapid 集成在预订流程中不支持 2FA,则可以通过不售卖住宿来降低预订失败的风险。
请联系 Rapid 合作伙伴支持团队,从房态 API 响应中删除这些受影响的住宿收款价格。
使用客服工具时,根据规定,交易可免于 2FA。可使用房态 API 的 sales_channel
字段表明此情况。
错误处理
创建预订 API 和完成付款会话 API 可能会导致确认的预订和付款交易。
您的集成应考虑以下说明,以避免财务损失和客户操作案例:
来源 | 功能 | 建议的超时设置 | 错误恢复过程 | 所需操作 |
---|---|---|---|---|
Rapid API | 注册付款令牌的预订前价格检查 | 10 秒 | 重试或选择其他住宿、房型或房价 | - |
JavaScript | 3DS 连接器设置 | 10 秒 | 重试相同的请求 | - |
Rapid API | 注册付款会话 | 10 秒 | 在没有“Expect: 100-Continue”流程的情况下重试相同的请求 | - |
JavaScript | 启动付款会话 | 10 秒 | 重试相同的请求 | - |
Rapid API | 创建预订 | 90 秒 | 重试相同的请求 | 对于所有错误:使用 affiliate_reference_id 检索预订 |
JavaScript | 显示 2FA 挑战 | 10 秒 | 重试相同的请求 | - |
JavaScript | 等待 challenge.statusCode | 180 ~ 1200 秒 | 请求完成付款会话 | - |
Rapid API | 完成付款会话 | 90 秒 | 重试相同的请求 | 对于所有错误:使用 affiliate_reference_id 检索预订 |
Rapid API | 对于所有错误:使用 affiliate_reference_id 检索预订 | 30 秒 | 重试相同的请求 | 对于所有错误:等待 90 秒后再重试,以通过 API 响应代码 404 或 200 确认预订的最终状态 |