SCA 的實作
透過以下方式生成 SCA-compliant 的預訂:Rapid API
無論您是將「Rapid API」設為正式收款商,還是允許旅客於抵達時付款,皆可採用 Rapid 的 API 解決方案,以生成符合 SCA 法規的預訂。我們的 API 透過在預訂流程中採用 3D-Secure (3DS) 2.0,以符合 SCA 規範。透過 3DS 2.0,我們支援「risk-based」驗證機制,此機制賦予銀行酌情決定何時要求旅客進行安全驗證的權限,從而降低旅客的交易摩擦。
3DS 2.0 的解決方案包含三個明確的步驟:
您將在 check-out 頁面中加入一個 iframe,該 iframe 用於託管發卡銀行為旅客提供的驗證流程。在整合文件中,這被稱為 3DS iframe。
>> 進一步了解 iframes您還需在 check-out 頁面中加入一個新的 client-side JavaScript 函式庫,該函式庫用於收集瀏覽器資料、與 iframe 進行通訊,並在 iframe 內顯示 SCA 體驗。在整合文件中,這被稱為 3DS 連接器函式庫。
Rapid API 將接受銀行的付款人資訊,並在完成安全驗證後完成預訂。
當同時使用 JavaScript 和 Rapid API 時,採用 SCA 的預訂流程現在會在呼叫預訂 API 之前和之後,增加幾個額外的步驟。下圖為更新後的預訂流程:

更新後的預訂流程中,上一步驟的輸出資料用做下一步驟的輸入資料。也就是資料會在瀏覽器的 JavaScript 和 Rapid 之間傳輸。
整合所需元件詳細說明
SCA 的實作始於瀏覽器端的 check-out 體驗,隨後會導入 Rapid API 的流程中。
Browser
此 iframe 置於「check-out」體驗中,用於載入向使用者顯示的認證流程,並將任何 traveler-supplied 資訊直接傳送至其銀行;該內容由旅客所屬的 card-issuing 銀行所擁有的 URL 提供。該 iframe 應預設為隱藏狀態,並能在用戶嘗試預訂後需進行身份驗證時,將其疊加顯示於頁面之上。
JavaScript 函式庫
此函式庫已新增至 check-out 頁面,並會在預訂時被呼叫,以支援驗證流程。此函式庫的 API 支援以下所述的功能。
Traveler 裝置資訊
在嘗試預訂之前,必須先收集旅客裝置的相關資訊,以便為預訂進行身份驗證做準備。該資訊會傳送至旅客的銀行,以便評估風險、決定該筆交易是否需要進行 3DS 2.0 驗證,並確保其顯示正確。根據 3DS 2.0 規範,將從旅客的瀏覽器收集以下資料:語言、色彩深度、螢幕高度、螢幕寬度、時區、使用者代理程式,以及 Java 是否已啟用。
驗證畫面
嘗試進行預訂後,該函式庫會用來顯示 iframe 覆蓋層,並將銀行的內容載入其中。在驗證過程中,銀行可能會蒐集有關旅客裝置的額外資訊,以協助進行風險評估。此步驟是完成預訂的必要程序。
Rapid API
Rapid API 包含可與 client-side JavaScript 函式庫協同運作的 API。這些 API 目前支援以下功能:
旅客及付款詳情
在嘗試預訂之前,Rapid API 需要收集有關旅客的額外資訊,以準備進行身分驗證,其中包括旅客的相關資訊,例如預訂地點及付款方式。這些資料隨後會傳送至旅客的銀行,以便評估風險,並決定該筆交易是否需要進行安全驗證。請參閱「Rapid Booking API」中的「Register Payment API」,以了解更多資訊。
付款與預訂確認
嘗試預訂後,當瀏覽器中的 SCA 流程完成時,必須再次呼叫 Rapid API。在後台,我們將確認驗證成功,以便確認預訂。請參閱「Rapid Booking API」中的「完成付款」章節,以了解更多資訊。
預訂流程
以下是旅客啟動預訂後所需的 API 呼叫順序示意圖。該程式碼序列同時包含對 JavaScript 函式庫的呼叫,以及對 Rapid API.

當一筆訂單準備進行驗證時,未必總是需要進行驗證。是否需要進行驗證,由用於付款的信用卡發卡銀行決定。此判定是在交易過程中進行的,並會顯示於「建立預訂」API 的回應中。
Rapid Lodging API 亦提供「暫停與恢復」功能。以下是該功能所需的 API 呼叫順序。

如需進一步了解 3DS 2.0 體驗的技術要求,請參閱 EMVCo 的 3D Secure 協定與核心功能規格書。
3DS 2.0 整合指南
若要支援 SCA,則需將 Rapid API 與一個名為「3DS Connector」的新 JavaScript 函式庫進行整合。這兩項功能會配合使用,用以在「check-out」頁面中呈現 3DS 2.0 並確認預訂。此解決方案同時支援 Expedia 的「先取貨、後付款」及「先付款、後取貨」兩種商業模式。
注意: 3DS 2.0 必須由 Rapid Partner Support 針對個別合作夥伴檔案啟用,才能支援修訂後的預訂流程。
步驟 1:呼叫可用性 API
若法規允許豁免認證,則 API 請求中的「sales_channel」欄位值必須準確無誤,方能獲得認證豁免。發卡銀行會在預訂時,綜合考量此數值及其他許多因素,以做出決定。唯有代理工具不受《安全通信法》(SCA)的規範。若需註明此項目,請把 sales_channel 的值設為 agent_tool。
JavaScript 函式庫是預訂流程中後續步驟的基礎。您將使用 JavaScript API 初始化一筆付款會話,然後透過 Rapid API.
步驟 2:呼叫「價格查詢」或「詳細資訊」API
就住宿 API 而言,SCA 的價格查詢 API 回應中將包含一個指向「註冊付款」API 的連結。
Lodging API 的 3DS 2.0 回應範例
{
"status": "matched",
"occupancies": {
//...(example omitted for length)
},
"links": {
"payment_session": {
"method": "POST",
"href": "/v3/payment-sessions?token=QldfCGlcUAVgBDRwdWXBBL"
}
}
}針對 SCA 流程,「車輛與活動」API 的 Details 端點回應,與其「non-SCA」流程的回應相同。
步驟 3:呼叫「註冊付款」API
對於 Lodging API,您需要特別執行此呼叫。「車輛」與「活動」API 已將此呼叫整合至「詳情」或「建立預訂」API 中。該請求將包含屬於 non-SCA 預訂流程的一部分之付款詳細資訊,以及用於支援成功驗證的新欄位。其中兩個欄位,encoded_browser_metadata 和version,是由 JavaScript API 的 setup 方法所傳回的。
回應中會包括 payment_session_id 和 encoded_init_config,並成為 JavaScript Library initSession 方法的輸入資料。在呼叫initSession 方法之後,應使用回覆中包含的預訂連結。
住宿 API 請求範例
{
"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": "2027-02-12T11:59:00.000Z",
"create_date": "2027-09-15",
"change_date": "2027-09-17",
"password_change_date": "2027-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": "2027",
"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": "2027-09-15"
}
]
}住宿 API 回應範例
{
"payment_session_id": "76d6aaea-c1d5-11e8-a355-529269fb1459",
"encoded_init_config": "QSBiYXNlNjQgZW5jb2RlZCBvYmplY3Qgd2hpY2ggY29udGFpbnMgY29uZmlndXJhdGlvbiBuZWVkZWQgdG8gcGVyZm9ybSBkZXZpY2UgZmluZ2VycHJpbnRpbmcgYW5kL29yIDNEUyBNZXRob2Qu",
"links": {
"book": {
"method": "POST",
"href": "/v3/itineraries?token=MY5S3j36cOcLfLBZjPYQ1abhfc8CqmjmFVzkk7euvWaunE57LLeDgaxm516m"
}
}
}「Car」或「Activities」API 請求範例
{
"type": "customer_card",
"number": "4111111111111111",
"security_code": "123",
"expiration_month": "08",
"expiration_year": "2028",
"billing_contact": {
"given_name": "John",
"family_name": "Smith",
"email": "smith@example.com",
"phone": {
"country_code": "1",
"area_code": "487",
"number": "5550077"
},
"address": {
"line_1": "555 1st St",
"city": "Seattle",
"state_province_code": "WA",
"postal_code": "98121",
"country_code": "US"
}
},
"strong_customer_authentication": {
"rapid": {
"version": "2.0.1",
"browser_accept_header": "*/*",
"encoded_browser_metadata": "ZW5jb2RlZF9icm93c2VyX21ldGFkYXRh",
"preferred_challenge_window_size": "medium",
"merchant_url": "https://server.adomainname.net",
"enrollment_date": "2024-05-08",
"customer_account_details": {
"authentication_method": "guest",
"authentication_timestamp": "2026-02-12T11:59:00.000Z",
"create_date": "2025-09-15",
"change_date": "2025-09-17",
"password_change_date": "2025-09-17",
"add_card_attempts": 1,
"account_purchases": 1
}
}
}
}「Car」或「Activities」API 回應範例
{
"payment_token": "K~IjM455rG_zUnz9LlKCw8bbLfxqk2Kb...",
"expires": "2026-01-30T16:32:10.557287774Z",
"payment_session_id": "ern:pay:pa:sec::5bcca93d-cdae-00b7-2cd4-d72d84cb2665",
"encoded_init_config": "W3sicHJvdmlkZXJJZCI6IjEiLCJwYXlt..."
}步驟 4:呼叫「建立預訂」API
此請求不會為 SCA 新增任何欄位——所有必要資訊均已包含於預訂連結的憑證中。對於「住宿 API」,此資訊可於「註冊付款 API」的回應中找到;至於「租車」或「活動 API」,則可於「詳細資訊」端點中找到。若回應成功,一定會包含 itinerary_id。然而,這並不代表預訂已確認,因為可能需要進行 3DS 2.0 驗證。
如有需要,回覆中亦將包含一個 encoded_challenge_config. 由「註冊付款 API」傳回的「encoded_challenge_config」與「payment_session_id」,必須作為參數傳入 JavaScript 驗證方法中。
回覆中還將包含一個新連結,分別指向complete_payment_session(住宿或活動)或resume_after_payment_challenge(汽車)。此連結應在 JavaScript 函式庫的 challenge 方法之後使用。
若無需進行 3DS 2.0 驗證,預訂即告確認,回應中將包含retrieve、cancel 以及 (針對住宿 API 請求) 的連結resume。
住宿 API 回應範例
{
"itinerary_id": "8999989898988",
"links": {
"complete_payment_session": {
"method": "PUT",
"href": "/v3/itineraries/8999989898988/payment-sessions?token=MY5S3j36cOcLfLBZjPYQ1abhfc8CqmjmFVzkk7euvWaunE57LLeDgaxm516m"
}
},
"encoded_challenge_config": "ABElifsiejfacies2@033asfe="
}活動 API 請求範例
{
"email": "traveler@example.com",
"payment_token": "K~xxxxxxxxxxxxxxxxxxxx",
"affiliate_reference_id": "AFF-REF-12345",
"primary_traveler": {
"name": {
"given_name": "Jane",
"family_name": "Doe"
},
"phone": {
"country_code": "1",
"number": "5551234567"
},
"ticket_id": "182552"
}
}包含驗證碼的範例活動 API 回應
{
"itinerary_id": "9045006342737",
"encoded_challenge_config": "<opaque challenge config from issuing bank>",
"links": {
"complete_payment_session": {
"method": "PUT",
"href": "/v2/itineraries/9045006342737/activity/payment-sessions?token=<token>"
}
}
}步驟 5:完成預訂
預訂流程的這部分發生在 JavaScript 挑戰方法之後。必須傳回「完整付款會話 API (住宿與活動)」或「付款挑戰後繼續 API (汽車)」的回應,才能完成付款,並通知 Rapid API 已嘗試進行安全驗證 (無論是否成功)。
該請求將不會包含任何針對 SCA 的新欄位。
若回應成功,其中將包含預訂的確認資訊,包括預訂確認碼 (itinerary_id) 以及retrieve、cancel 及 (針對住宿 API 請求) 的連結resume。
住宿 API 回應範例
{
"itinerary_id": "8999989898988",
"links": {
"retrieve": {
"method": "GET",
"href": "/v3/itineraries/8999989898988?token=MY5S3j36cOcLfLBZjPYQ1abhfc8CqmjmFVzkk7euvWaunE57LLeDgaxm516m"
}
}
}範例活動 API 回應
{
"itinerary_id": "9045006342737",
"links": {
"retrieve": {
"method": "GET",
"href": "/v2/itineraries/9045006342737/activity"
}
}
}Iframe 與 JavaScript 函式庫的實作
使用 SCA 預訂工作流程時,check-out 頁面必須包含一個新的 iframe 以及 JavaScript 函式庫。此 iframe (以下稱為「3DS iframe」) 將透過 3D-Secure 2.0 顯示驗證流程。JavaScript 函式庫 (以下稱為「3DS 連接器函式庫」) 將支援將資訊傳輸至發卡銀行,並將銀行的內容載入至 iframe 中。
新增 iframe
3DS iframe 應包在開始時為隱藏的容器中,當付款程序判定為必須進行驗證時,則會再顯示。
容器設計可配合裝載頁面來自訂。以下為使用 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>iframe 的源 (source) 必須設為以下兩個值之一:
| URL 類型 | URL | 備註 |
|---|---|---|
| 正式環境 | https://static.pay.expedia.com/3ds/threeDsIframe.html | 支援生產驗證 |
| 測試沙箱 | https://static.pay.expedia.com/3ds/sandboxThreeDsIframe.html | 支援身份驗證測試 |
此測試網址支援測試功能。您可以在測試期間使用以下指令,將 iframe 的內容限制在沙盒內:
sandbox = 'allow-scripts allow-forms allow-same-origin';加入 JavaScript 函式庫
3DS Connector Library 負責和 3DS iframe 溝通,並傳送資料給發卡銀行;銀行為 iframe 內容提供者。以下範例顯示如何將 3DS Connector Library 新增到付款頁面。
<head>
<script src="<<3DS connector script URL>>" integrity="<<actual integrity value>>"></script>
</head>Script 元素的來源與完整性值應設定為以下數值。
| Library 版本 | 屬性 | 值 |
|---|---|---|
| 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 | |
| 2.0.1 | src | https://static.pay.expedia.com/3ds/2.0.1/pay-3ds-js-libs-connector.min.js |
| integrity | sha384-1ntftSOl8ZSqJ/m7qqxXTNGOx3JLbF7Uw5YX8i/ageTjgmTnUMZ3ROpxxMiUkYma |
註: 隨著未來版本陸續推出並可供採用,來源網址與完整性值將會有所變更。新版不會破壞現有的整合。舊版的 script 元素仍可存取。
使用 3DS 和 JavaScript 進行 SCA
3DS 連接器函式庫需要使用 JavaScript 承諾。以下範例示範了 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,使用了靜態值。
Check-out 頁面設計指引
支援 3DS 驗證的信用卡品牌,可能會要求依照其指引顯示其標誌及品牌標識。
註: 其他信用卡品牌的標誌及指引將於取得後陸續納入。