Authorizing the payment for a payment transaction using Mastercard Click to Pay using the Transpayrent UI Helper SDK requires the following steps:
- Create a Payment Session from the back-end and render the payment page
- Include the dependencies for the Transpayrent SDK, Transpayrent UI Helper SDK, the Mastercard Unified Checkout Solutions (UCS) browser SDK, and Mastercard's SRC UI Kit web components
- Implement the following Transpayrent UI Helper SDK methods to return the necessary data constructs to the Transpayrent SDK for payment method
205: - Instantiate the Transpayrent SDK, Transpayrent UI Helper SDK, and the Click-to-Pay helper
- Recognize the consumer (
init+getCards) and render the Click to Pay UI yourself using Mastercard's SRC UI Kit web components (card list, OTP input, loader) — unlike Apple Pay/Google Pay, Click to Pay has no native payment sheet; there is nothing fordisplayPaymentSheetto show - On
Pay, call checkoutWithCard / checkoutWithNewCard, apply the returned checkout handoff, then invoke the Transpayrent UI Helper SDK's completePayment method - Fulfill the order upon receiving the 620021 - Payment Successfully Authorized notification
Important
Transpayrent has complete support for Split Payment (Card + Miles for an Airline, Card + Loyalty Points or Card + Voucher for a Webshop etc.) and the amount in the notification may therefore be equal to or less than the total amount for the order. The Order shouldn't be considered paid until the Sum of the Payment Transaction(s) equal the total amount for the Payment Session. It is strongly recommended to implement validation of the amount before fulfilling the order.
What the helper does and does not do
The Transpayrent Click-to-Pay helper is infrastructure support around the Mastercard UCS browser SDK. It provides:
- Mastercard passthrough methods with identical names (
init,getCards,idLookup,authenticate,initiateValidation,validate,encryptCard,checkoutWithCard,checkoutWithNewCard,signOut) - Button rendering via
displayPaymentButton(orsdk.displayPaymentButton(205, ...)) - Transpayrent integration utilities: readiness checks, normalized errors/results, checkout handoff normalization/application, optional recognition storage, and opt-in debug logging
It does not render the recognition screen, card list, OTP screen, manual card entry form, or result screen — that UI is yours to build, using Mastercard's SRC UI Kit web components described below. This is what makes the integration fast: you are not building a card list or OTP widget from scratch, you are wiring Mastercard's existing components to the data the helper's passthrough methods return.
Include the dependencies for the Transpayrent SDK, Mastercard UCS SDK, and Mastercard SRC UI Kit
The Transpayrent UI Helper SDK uses the Transpayrent SDK to securely
communicate with Transpayrent's Payment Gateway, which in turn relies on the swagger-js client library.
For Click to Pay you additionally need the Mastercard UCS SDK, scoped to your srcDpaId, and Mastercard's SRC UI Kit
web components bundle (plus its stylesheet) used to build every Click-to-Pay screen.
<script src="https://storage.googleapis.com/static.[ENVIRONMENT].transpayrent.cloud/v1/swagger-client.js"></script>
<script src="https://storage.googleapis.com/static.[ENVIRONMENT].transpayrent.cloud/v1/transpayrent.js"></script>
<script src="https://[ENVIRONMENT].src.mastercard.com/srci/integration/2/lib.js?srcDpaId={YOUR_SRC_DPA_ID}&locale={en_US}"></script>
<script type="module" src="https://[ENVIRONMENT].src.mastercard.com/srci/integration/components/src-ui-kit/src-ui-kit.esm.js"></script>
<link rel="stylesheet" href="https://[ENVIRONMENT].src.mastercard.com/srci/integration/components/src-ui-kit/src-ui-kit.css">
The Mastercard UCS SDK script defines window.MastercardCheckoutServices / window.Click2Pay, which
TranspayrentClickToPayHelper wraps; getReadiness
checks for these globals before you show any Click-to-Pay UI. The SRC UI Kit script defines the <src-button>,
<src-card-list>, <src-otp-input>, and <src-card> custom elements used throughout this tutorial.
Implement the Transpayrent UI Helper SDK's callback methods to return the necessary data constructs to the Transpayrent SDK
The code snippet below illustrates how the payment page may implement the necessary methods required to complete a payment
with Click to Pay. Unlike a Payment Card or Google Pay, the authenticate and authorize requests must be enriched with
the Click-to-Pay checkout handoff (merchant_transaction_id / src_flow_id) via applyCheckoutHandoff
before being returned.
<script>
/* ========== COMMON DATA START ========== */
var address = { street : 'Arne Jacobsens Allé 7',
appartment : '5. sal',
city : 'Copenhagen S',
postal_code : '2300',
state : 'CO',
country: 208 }; // Denmark
var phone = { international_dialing_code: 45, // Denmark
phone_number: 12345678 };
var email = 'hello@transpayrent.dk';
var nationalIdentificationNumber = '31892554313';
/* ========== COMMON DATA END ========== */
/* ========== CREATE PAYMENT TRANSACTION DATA START ========== */
var createTransactionRequests = new Array();
// Click to Pay
createTransactionRequests[205] = { correlation_id : 'TP-'+ transpayrentConfig.sessionId,
amount: { currency : 208, // DKK
value : 100 } };
/* ========== CREATE PAYMENT TRANSACTION DATA END ========== */
/* ========== INITIALIZE PAYMENT DATA START ========== */
var initializePaymentRequests = new Array();
// Click to Pay: card enrollment/linking is handled by Mastercard's own vault via checkoutWithNewCard,
// not by Transpayrent's Secure Vault, so `save` is always false here.
initializePaymentRequests[205] = { payment_method_id : 205,
save : false };
/* ========== INITIALIZE PAYMENT DATA END ========== */
/* ========== AUTHENTICATE CONSUMER DATA START ========== */
var authenticateConsumerRequests = new Array();
// Click to Pay
authenticateConsumerRequests[205] = { payment_details : { payment_method_id : 205 },
billing_address : address, // Optional
shipping_address : address, // Optional
contact : { mobile : phone, // Optional
work : phone, // Optional
home : phone, // Optional
email : email } }; // Optional
/* ========== AUTHENTICATE CONSUMER DATA END ========== */
/* ========== AUTHORIZE PAYMENT DATA START ========== */
// Click to Pay
authorizePaymentRequests[205] = { payment_method_id : 205,
national_identification_number : nationalIdentificationNumber, // Optional: Required in Brazil
contact : { email : email }, // Optional: Required in Brazil
installments : 2 }; // Optional: 2 - 12
/* ========== AUTHORIZE PAYMENT DATA END ========== */
/* ========== IMPLEMENT TRANSPAYRENT UI HELPER SDK METHODS START ========== */
TranspayrentUIHelper.prototype.displayAuthenticationFailure = function (result) {
this._sdk.getLocalizedStatusMessage(result.status_code)
.then(text => {
if (this._container) {
this._container.style.visibility = 'hidden';
}
var message = document.createElement('h1');
message.className = 'failure';
message.innerHTML = '<img id="loader" src="/failure.png" width="30" height="30" alt="- completed -" />';
message.innerHTML += ` ${text} (${result.status_code})`;
document.body.appendChild(message);
});
}
TranspayrentUIHelper.prototype.displayPaymentConfirmation = function (authorization) {
this._sdk.getLocalizedMessage(`Payment transaction: ${authorization.transaction_id} successfully authorized`)
.then(text => {
if (this._container) {
this._container.style.visibility = 'hidden';
}
var message = document.createElement('h1');
message.className = 'success';
message.innerHTML = '<img id="loader" src="/success.png" width="30" height="30" alt="- completed -" />';
message.innerHTML += ` ${text}`;
document.body.appendChild(message);
});
}
// Override UI Helper SDK methods to return the correct request for the specified payment method
TranspayrentUIHelper.prototype.getCreateTransactionRequest = function (paymentMethodId) {
return createTransactionRequests[paymentMethodId];
}
TranspayrentUIHelper.prototype.getInitializePaymentRequest = function (paymentMethodId) {
return initializePaymentRequests[paymentMethodId];
}
// Enrich authenticate/authorize with the saved Click-to-Pay checkout handoff for payment method 205
TranspayrentUIHelper.prototype.getAuthenticateConsumerRequest = function (paymentMethodId) {
var request = authenticateConsumerRequests[paymentMethodId];
if (paymentMethodId === 205) {
return c2pHelper.applyCheckoutHandoff(request);
}
return request;
}
TranspayrentUIHelper.prototype.getAuthorizePaymentRequest = function (paymentMethodId) {
var request = authorizePaymentRequests[paymentMethodId];
if (paymentMethodId === 205) {
return c2pHelper.applyCheckoutHandoff(request);
}
return request;
}
/* ========== IMPLEMENT TRANSPAYRENT UI HELPER SDK METHODS END ========== */
</script>
Instantiate the Transpayrent SDK, Transpayrent UI Helper SDK, and Click-to-Pay helper
The code snippet below illustrates how to instantiate the Transpayrent SDK, the
Transpayrent UI Helper SDK, and the Click-to-Pay helper.
The Click-to-Pay helper is kept in its own variable (c2pHelper) — it is a different object from the UI Helper
(helper) used above and elsewhere in this tutorial; do not confuse the two.
<script>
// SDK configuration
const transpayrentConfig = {
merchantId: [UNIQUE MERCHANT ID ASSIGNED BY TRANSPAYRENT],
sessionId: [ID IN THE RESPONSE FROM "Create Payment Session"],
accessToken: '[x-transpayrent-access-token HTTP HEADER IN THE RESPONSE FROM "Create Payment Session"]'
};
const url = 'https://generator.[ENVIRONMENT].transpayrent.cloud/v1/'+ transpayrentConfig.merchantId +'/system/PAYMENT_GATEWAY/sdk/CLIENT';
// Instantiate SDK and UI Helper SDK
const sdk = new Transpayrent(url, transpayrentConfig);
const helper = new TranspayrentUIHelper(sdk, document.getElementById('container'), document.getElementById('loader') );
// Instantiate the Click-to-Pay helper (a thin wrapper around the Mastercard UCS SDK)
const c2pHelper = sdk.getClickToPayHelper({ debugLogging: false });
</script>
Recognize the consumer and render Click to Pay UI with Mastercard's SRC UI Kit
Every Click-to-Pay session starts the same way — check readiness, then init() followed by getCards() — and then
branches into one of three shapes depending on what Mastercard returns:
| Consumer state | What getCards() / idLookup() return |
What you show |
|---|---|---|
| Recognized | getCards() returns cards immediately |
Card list (<src-card-list>), then the Mastercard checkout popup on checkoutWithCard |
| Returning, no cards yet | getCards() empty, but idLookup() finds a profile (consumerPresent = true) |
Verify the consumer via either initiateValidation/validate or authenticate (see below), then the card list |
| New / no profile | idLookup() finds no profile (consumerPresent = false) |
Manual card entry; optionally enroll with encryptCard + checkoutWithNewCard, or pay without enrolling |
<src-loader id="c2pLoader" style="display: none;"></src-loader>
<script>
// Required by checkoutWithCard / checkoutWithNewCard - your merchant privacy notice and terms of use.
var complianceSettings = {
privacy: { acceptedVersion: 'LATEST', latestVersion: 'LATEST', latestVersionUri: 'https://merchant.example.com/privacy' },
tnc: { acceptedVersion: 'LATEST', latestVersion: 'LATEST', latestVersionUri: 'https://merchant.example.com/terms' }
};
/* ========== READINESS CHECK START ========== */
var readiness = c2pHelper.getReadiness();
if (!readiness.ready) {
console.warn('Click to Pay unavailable:', readiness.issues);
// Hide the Click to Pay entry point and fall back to standard card payment
}
/* ========== READINESS CHECK END ========== */
/* ========== RECOGNITION START ========== */
// A dedicated <src-loader id="c2pLoader"> - separate from the `loader` element passed to
// `new TranspayrentUIHelper(sdk, container, loader)`, which the UI Helper manages itself.
document.getElementById('c2pLoader').style.display = 'block';
var initRequest = {
srcDpaId: '{YOUR_SRC_DPA_ID}', // same id used in the Mastercard UCS script tag above
cardBrands: ['mastercard', 'maestro'], // brands your merchant account accepts
dpaData: { dpaName: 'My Merchant' },
dpaLocale: 'en_US'
};
c2pHelper.init(initRequest)
.then(() => c2pHelper.getCards())
.then(cards => {
document.getElementById('c2pLoader').style.display = 'none';
if (cards.length > 0) {
showCardList(cards); // Recognized consumer
}
else {
return c2pHelper.idLookup({ email: email })
.then(lookup => {
if (lookup.consumerPresent) {
// Returning consumer: verify via merchant-hosted OTP (startOtpValidation, below)
// or Mastercard-hosted authenticate() (see "authenticate: the Mastercard-hosted
// alternative", below) - pick one.
startOtpValidation();
}
else {
showManualCardEntry(); // New consumer, no Click to Pay profile
}
});
}
})
.catch(error => console.error('Click to Pay error:', error.api, error.status, error.messages));
/* ========== RECOGNITION END ========== */
</script>
Card list (<src-card-list>)
<src-card-list id="cardList"
card-brands="mastercard,maestro"
card-selection-type="radioButton"
display-sign-out="true"
display-add-card="true"
display-cancel-option="false"></src-card-list>
<script>
var selectedCardId = null;
function showCardList(cards) {
var cardList = document.getElementById('cardList');
cardList.loadCards(cards);
cardList.addEventListener('selectSrcDigitalCardId', event => {
selectedCardId = event.detail; // srcDigitalCardId to pass into checkoutWithCard
});
cardList.addEventListener('clickAddCardLink', () => showManualCardEntry() );
cardList.addEventListener('clickSignOutLink', () => {
c2pHelper.signOut().then(() => {
// Clear local card/session state, then re-run recognition for a different identity
});
});
}
function payWithSelectedCard(windowRef) {
return c2pHelper.checkoutWithCard({ srcDigitalCardId: selectedCardId,
windowRef: windowRef, // required: window/iframe opened for checkout
complianceSettings: complianceSettings, // required
recognitionTokenRequested: true });
}
</script>
OTP input (<src-otp-input>)
<src-otp-input id="otpInput"
display-remember-me="true"
display-cancel-option="false"></src-otp-input>
<script>
var currentOtp = '';
function startOtpValidation() {
c2pHelper.initiateValidation().then(result => {
document.getElementById('otpInput').loadSupportedValidationChannels(result.supportedValidationChannels);
});
var otpInput = document.getElementById('otpInput');
otpInput.addEventListener('otpChanged', event => { currentOtp = event.detail || ''; });
otpInput.addEventListener('continue', () => {
c2pHelper.validate({ value: currentOtp }).then(cards => showCardList(cards) );
});
otpInput.addEventListener('resendOtp', () => c2pHelper.initiateValidation() );
otpInput.addEventListener('notYouRequested', () => {
c2pHelper.signOut().then(() => { /* route back to identity entry */ });
});
}
</script>
authenticate: the Mastercard-hosted alternative
initiateValidation / validate above is the merchant-hosted approach — you own the OTP screen, rendered inline
with <src-otp-input> on your page. authenticate is the other option:
the Mastercard-hosted approach. You open a popup/iframe and hand it to Mastercard; Mastercard shows and drives
whatever challenge it decides is appropriate (OTP, passkey, etc.) inside that window, and resolves directly with
cards — there is no <src-otp-input> to build or wire up for this path.
Mastercard-hosted authenticate is less integration work
(no OTP UI at all) at the cost of sending the consumer into a Mastercard-controlled window instead of staying on your
page; merchant-hosted initiateValidation/validate keeps the consumer on your page but means you own the OTP screen,
error states, and resend flow yourself.
<script>
function authenticateWithPopup(identityValue, identityType, windowRef) {
// identityType: 'EMAIL_ADDRESS' or 'MOBILE_PHONE_NUMBER'
return c2pHelper.authenticate({
accountReference: { consumerIdentity: { identityType: identityType, identityValue: identityValue } },
windowRef: windowRef, // required for the Mastercard-hosted UI
requestRecognitionToken: true
}).then(result => {
if (result.cards) {
showCardList(result.cards);
}
});
}
</script>
Manual card entry and linking a new card
Whether the consumer has no Click-to-Pay profile at all, or is simply adding a card from the card list / OTP screen ("Add card"), the pattern is the same: show a plain card entry form, encrypt the card, then check out with it.
<script>
function showManualCardEntry() {
document.getElementById('manualCardEntryForm').style.display = 'block';
}
function linkNewCard(windowRef) {
var cardDetails = {
primaryAccountNumber: document.getElementById('cardNumber').value,
panExpirationMonth: document.getElementById('expiryMonth').value, // e.g. '09'
panExpirationYear: document.getElementById('expiryYear').value, // e.g. '2028'
cardSecurityCode: document.getElementById('cvv').value,
cardholderFirstName: document.getElementById('firstName').value,
cardholderLastName: document.getElementById('lastName').value
};
return c2pHelper.encryptCard(cardDetails)
.then(encrypted => c2pHelper.checkoutWithNewCard({ encryptedCard: encrypted.encryptedCard, // JWE string, not the whole response
cardBrand: encrypted.cardBrand, // required
windowRef: windowRef, // required
complianceSettings: complianceSettings, // required
recognitionTokenRequested: true }) );
}
</script>
encryptCard field validation errors (invalid PAN, expired card, etc.) reject with a Transpayrent-normalized error before
any Mastercard checkout window opens — show them next to the relevant form field.
Checkout and complete the payment
checkoutWithCard / checkoutWithNewCard return a normalized checkout result or throw a Transpayrent-normalized SDK error.
On checkoutActionCode === 'COMPLETE', the helper stores the checkout handoff automatically only when both
merchantTransactionId and srcFlowId are present — that stored handoff is what getAuthenticateConsumerRequest /
getAuthorizePaymentRequest apply via applyCheckoutHandoff further up this tutorial. Both payWithSelectedCard
(saved card) and linkNewCard (new card) converge on the same completion step:
<script>
// Shared by both the "Pay" button on the card list and the "Pay" button on the manual card entry form
function completeCheckout(checkoutPromise) {
var popup = window.open('', 'click-to-pay-checkout'); // Merchant-owned checkout window
return checkoutPromise(popup)
.then(checkoutResult => {
popup.close();
if (checkoutResult.checkoutActionCode !== 'COMPLETE') {
return; // CANCEL, CHANGE_CARD, or SWITCH_CONSUMER - return to the card list / identity screen
}
return helper.completePayment(205, false);
})
.catch(error => {
popup.close();
console.error('Click to Pay checkout failed:', error.api, error.status, error.messages);
});
}
// e.g. from the card list's "Pay" button:
completeCheckout(payWithSelectedCard);
// e.g. from the manual card entry form's "Pay" button:
completeCheckout(linkNewCard);
</script>
Access other account (sign out and switch identity)
When the consumer picks "not your cards" from the card list, or "not you" from the OTP screen, sign out of the current Click-to-Pay session and re-run recognition for a different identity:
<script>
function switchAccount(newEmail) {
return c2pHelper.signOut()
.then(() => c2pHelper.init(initRequest) ) // same request built during initial recognition, above
.then(() => c2pHelper.idLookup({ email: newEmail }) )
.then(lookup => lookup.consumerPresent ? startOtpValidation() : showManualCardEntry() );
}
</script>
Debug logging
Pass debugLogging: true when instantiating the Click-to-Pay helper (sdk.getClickToPayHelper({ debugLogging: true }))
when troubleshooting an integration. This logs Mastercard SDK request/response details to the browser console. Do not
enable it in normal merchant production usage unless you are intentionally debugging.
The CVV/security code is always hidden from these logs, regardless of this flag. Every other field — including the PAN — is logged in full, so treat any captured console output as sensitive when sharing it (screenshots, tickets, etc.).
c2pHelper.setDebugLogging(true);
Recognition storage
Opt in through sdk.getClickToPayHelper({ recognitionStorage: { ... } }). The helper then exposes recognitionStorage
for identity-scoped recognition tokens and remember-me preferences, so a recognized consumer can skip OTP on their next visit.
- When
recognitionStorageis omitted, the helper does not create browser storage (recognitionStorageisnull). - When
recognitionStorage: {}is passed, the helper uses defaultlocalStoragewith built-in key prefixes and normalizers.
<script>
const c2pHelper = sdk.getClickToPayHelper({
recognitionStorage: {
recognitionTokenKeyPrefix: 'recognitionToken:',
rememberMeKeyPrefix: 'c2p.rememberMe:',
identityNormalizer: identity => identity.trim().toLowerCase()
}
});
// Before init(): pass any stored token so a recognized consumer skips OTP
var storedToken = c2pHelper.recognitionStorage && c2pHelper.recognitionStorage.getRecognitionToken(email);
c2pHelper.init(Object.assign({}, initRequest, { recognitionToken: storedToken }));
// After a successful checkoutWithCard / checkoutWithNewCard, inside its .then(checkoutResult => { ... }):
if (c2pHelper.recognitionStorage && checkoutResult.recognitionToken) {
c2pHelper.recognitionStorage.setRecognitionToken(email, checkoutResult.recognitionToken);
c2pHelper.recognitionStorage.setRememberMe(email, true);
}
</script>
The helper never writes to recognition storage automatically. Read and update it from your merchant-owned Click-to-Pay
flow when needed — e.g. pass the stored token into init({ recognitionToken: token }) on the next visit.
Button rendering
sdk.displayPaymentButton(205, container, paymentMethodIds, { buttonText, onClick }) renders the SRC UI Kit <src-button>
when available. When it is not, a plain HTML button is used as a visual/click target fallback only. That fallback does
not indicate Mastercard runtime readiness; always call c2pHelper.getReadiness() before showing merchant-owned Click-to-Pay UI.
Flow options such as debugLogging and recognitionStorage belong in getClickToPayHelper config, not in the
displayPaymentButton config for payment method 205.
Not supported
Transpayrent.displayPaymentSheet(205, details) is not supported for Click to Pay — there is no native Mastercard payment
sheet to display. The SDK rejects it with PAYMENT_SHEET_NOT_SUPPORTED. Build the merchant-owned flow described above with
getClickToPayHelper instead.