Embedded 3DS (EG JS Library)
Overview
Implements 3DSv2 via the EG JavaScript connector and an embedded managed iFrame: collect browser data → get paymentSessionId + init config → initialize session → (if required) run challenge → resume booking. No partner cryptogram field mapping in this mode.
Key Artifacts: encodedBrowserMetadata, paymentSessionId, encodedInitConfig, encodedChallengeConfig.
High-Level Sequence
sequenceDiagram
autonumber
actor Client
participant UI as Partner UI
participant IFr as 3DS iFrame
participant JS as EG 3DS JS
participant XAP as XAPBooking
UI->>IFr: Load 3DS iFrame (test/prod)
UI->>JS: load connector script
JS->>IFr: setup() collect browser metadata
UI->>XAP: Initial booking + BrowserData
XAP-->>UI: 3DSINPROGRESS + paymentSessionId + encodedInitConfig
UI->>JS: initSession(paymentSessionId, encodedInitConfig)
UI->>XAP: Re-submit + paymentSessionId
XAP-->>UI: PENDING + encodedChallengeConfig
UI->>JS: challenge(paymentSessionId, encodedChallengeConfig)
IFr-->>UI: challenge completed (SUCCESS)
UI->>XAP: Resume booking
XAP-->>UI: BOOKED (itinerary/confirmation)Environment & Assets
3DS iFrame URL
- Test:
https://static.test.pay.expedia.com/3ds/threeDsIframe.html - Prod:
https://static.pay.expedia.com/3ds/threeDsIframe.html
3DS Connector Library
- Test:
https://static.test.pay.expedia.com/3ds/1.3.65/pay-3ds-js-libs-connector.min.js - Prod:
https://static.pay.expedia.com/3ds/1.3.65/pay-3ds-js-libs-connector.min.js
Steps
Step 1 — Embed the 3DS iFrame
Purpose: Provide a secure, isolated surface for the managed challenge.
<div id="threeDsIframeModal" class="modal" role="dialog" aria-hidden="true">
<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="https://static.test.pay.expedia.com/3ds/threeDsIframe.html"
sandbox="allow-scripts allow-forms allow-same-origin"
referrerpolicy="no-referrer"
allow="payment *"
></iframe>
</div>
</div>
</div>
</div>
</div>Step 2 — Load Connector Script
Purpose: Load the library early so browser data collection can start promptly.
<script src="https://static.test.pay.expedia.com/3ds/1.3.65/pay-3ds-js-libs-connector.min.js" integrity=""></script>Step 3 — Collect Browser Metadata
Purpose: Produce encodedBrowserMetadata used for frictionless risk evaluation.
const connectorBase = "https://static.test.pay.expedia.com";
const iFrameId = "threeDsIframe";
const c = new PayThreeDSConnector.ThreeDSConnector(iFrameId, connectorBase);
c.setup({ referenceId: "1000" }).then(setupResponse => {
console.log("Setup Output:", setupResponse);
});output:
{
"encodedBrowserMetadata": "eyJicm93c2VySmF2YUVuYWJsZWQiOmZhbHNlLCJicm93c2VyTGFuZ3VhZ2UiOiJlbi1VUyIsImJyb3dzZXJDb2xvckRlcHRoIjoyNCwiYnJvd3NlclNjcmVlbkhlaWdodCI6MTA4MCwiYnJvd3NlclNjcmVlbldpZHRoIjoxOTIwLCJicm93c2VyVFoiOjQyMCwiYnJvd3NlclVzZXJBZ2VudCI6Ik1vemlsbGEvNS4wIC4uLiJ9",
"version": "1.3.65"
}Step 4 — Initial Booking (submit BrowserData)
Purpose: Start booking; receive 3DS continuation tokens when 3DS required.
{
"Title": "Hotel Booking Automation",
"BrowserData": {
"IpAddressV4": "216.251.118.195",
"BrowserAcceptHeader": "text/html",
"EncodedBrowserMetadata": "<from setup()>",
"MerchantUrl": "https://www.expedia.com/hotel"
},
"...": "other booking fields"
}Response:
{
"status": "3DSINPROGRESS",
"paymentSessionId": "ern:pay:pa:r1::93c9aa11-810f-0b02-2e33-30f98980831d",
"encodedInitConfig": "<opaque-init-config>"
}Step 5 — Initialize 3DS session
Purpose: Register the session so platform can correlate subsequent challenge.
c.initSession({ paymentSessionId, encodedInitConfig })
.then(r => console.log("Init session:", r));output:
{ "message": "", "statusCode": "SUCCESS" }Step 6 — Re-submit Booking With paymentSessionId
Purpose: Advance state so platform decides if challenge is required.
{
"TwoStepPaymentDetails": {
"PaymentType": "3DS",
"PaymentSessionId": "ern:pay:pa:r1::93c9aa11-810f-0b02-2e33-30f98980831d"
},
"...": "other booking fields"
}Response:
{
"TransactionId": "cad9c2bc-c5b0-481d-abd5-a4cc24b7c14f",
"encodedChallengeConfig": "<opaque-challenge-config>",
"Status": "PENDING"
}Step 7 — Run Challenge
Purpose: Render issuer challenge inside managed iFrame until terminal outcome.
c.challenge({ paymentSessionId, encodedChallengeConfig })
.then(r => console.log("Challenge:", r));output:
{ "message": "Success", "statusCode": "SUCCESS" }Step 8 — Resume Booking
Purpose: Finalize booking after Challenge success
POST https://apim.expedia.com/hotels/bookings/{bookingId}/resume
{
"TransactionId": "dce81a0f-1afd-433d-853c-072c1cee10f2",
"ItineraryNumber": 791400669859,
"BookingDateTime": "2021-07-11T19:43:20-07:00",
"Status": "BOOKED",
"...": "..."
}