Accepting Multiple Cards
The Hosted Session allows you to support scenarios where your payer wants to use more than one card for a single booking. In this case, you must create a separate payment session and a separate order for each card.
You must store the unique session ID created for each card on your server, and then assemble all the different orders generated from the separate payment sessions into a single booking. The payer can choose to remove a card during the payment page interaction, and this action removes the session data associated with the card from your server.
Implementing Multiple Hosted Sessions
To accept multiple cards, you must invoke the PaymentSession.configure()
function with the scope
argument for each card the payer wants to use. The value of this argument can be any unique string, used to identify a block of card payment data, and does not need to reference any specific HTML element on the page. The data stored by you on your server for each card needs to be retained in a separate scope.
PaymentSession.configure('configuration', scope)
After an initial PaymentSession.configure()
call is invoked with scope
, the scope
argument becomes mandatory on the following Hosted Session function calls, as shown in the examples below:
PaymentSession.updateSessionFromForm('card', 'card-type', scope)
PaymentSession.setFocus('cardNumber', scope)
The scope
argument is optional on the following calls if an interaction is configured with a scope. If a scope is not specified on these calls, the function or callback applies to all card data sets within the hosted iFrame.
PaymentSession.setFocusStyle([<HostedFieldsRole>], styles, scope)
PaymentSession.setHoverStyle([<HostedFieldsRole>], styles, scope)
PaymentSession.onFocus([<HostedFieldsRole>],function(selector), scope)
PaymentSession.onBlur([<HostedFieldsRole>], function(selector), scope)
PaymentSession.onChange([<HostedFieldsRole>], function(selector), scope)
PaymentSession.onMouseOver([<HostedFieldsRole>], function(selector), scope)
PaymentSession.onMouseOut([<HostedFieldsRole>], function(selector), scope)
Multiple Hosted Sessions Example
<html> <head> <!-- INCLUDE SESSION.JS JAVASCRIPT LIBRARY --> <script src="https://na.gateway.spring.citi.com/form/version/72/merchant/<MERCHANTID>/session.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> <div>Cardholder Name: <input type="text" id="cardholder-name" class="input-field" title="cardholder name" aria-label="enter name on card" value="" tabindex="1" readonly></div> <div>Card Number: <input type="text" id="card-number" class="input-field" title="card number" aria-label="enter your card number" value="" tabindex="2" 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="3" 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="4" 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="5" readonly></div> <div><button id="payButton" onclick="pay();">Pay Now</button></div> <!-- 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; } var sessions = []; PaymentSession.configure({ 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) { // HANDLE INITIALIZATION RESPONSE }, formSessionUpdate: function(response) { // HANDLE RESPONSE FOR UPDATE SESSION AS PER USUAL MANNER. if (response.status) { if ("ok" == response.status) { // RECORD THE SESSIONID RETURNED AND ASSOCIATE IT WITH THE SCOPE CONFIGURED. sessions.push(JSON.parse('{ "scopeId": "' + response.scopeId + '", "sessionId": "' + response.session.id + '"}')); } } else { console.log("Session update failed: " + response); } } }, interaction: { displayControl: { formatCard: "EMBOSSED", invalidFieldCharacters: "REJECT" } } }, 'card-payment-details-#1'); // ADD ANY UNIQUE STRING IDENTIFIER VALUE TO THE CONFIGURE CALL function pay() { sessions.forEach(function (e) { // UPDATE THE SESSION WITH THE FIELD VALUES. THE SCOPE MUST BE THE THIRD PARAMETER. PaymentSession.updateSessionFromForm('card', undefined, e.scopeId); }); } </script> </body> </html>