Example: Stripe Payment Element
This is an example of the PSP Integration Guide pattern, applied to Stripe Payment Element. Stripe Payment Element confirms payments client-side, so its cartridge needs targeted changes for Forter to get complete data.
Save pre-auth card data
Payment Element uses a secure iframe: card details never reach SFCC, so a pre-auth basket has no payment data to send. The client already receives Stripe's confirmation token, which includes card details in payment_method_preview. In app_stripe_sfra/cartridge/scripts/checkout/checkoutHelpers.js, inside validateBasketAndOrder, save it to the basket before the validateOrder hook call:
if (req.form && req.form.confirmationToken) {
Transaction.wrap(function () {
currentBasket.custom.forterPspAuthResult = req.form.confirmationToken;
});
}This requires forterPspAuthResult to exist as a custom attribute on the Basket object, not just Order (it ships on Order by default). Required for PRE_AUTH or PRE_AND_POST_AUTH timing.
Expand the PaymentIntent
Newer Stripe API versions return latest_charge and payment_method as string IDs instead of full objects, leaving Forter nothing to extract. Add expand: ['latest_charge', 'payment_method'] to every PaymentIntent creation call:
- buildPaymentIntentPayload in app_stripe_sfra/cartridge/scripts/checkout/checkoutHelpers.js
- StripeQuickCheckout in int_stripe_sfra/cartridge/controllers/StripePaymentsAPM.js
- createPaymentIntent in int_stripe_core/cartridge/scripts/stripe/helpers/checkoutHelper.js
stripe.paymentIntents.create({
// ...
expand: ['latest_charge', 'payment_method']
});This is safe on any API version.
Re-fire after 3DS
For cards that trigger 3DS, app.post.auth fires with the PaymentIntent still in requires_action state, before the charge exists. In int_stripe_sfra/cartridge/controllers/StripePaymentsCard.js, inside CardPaymentHandleRequiresAction, after the PaymentIntent is confirmed, overwrite forterPspAuthResult with the final response:
order.custom.forterPspAuthResult = JSON.stringify(paymentIntent);Fire the saved-card hook
Stripe saves cards through its own StripeWallet-AddNewCard endpoint, bypassing SFCC's standard PaymentInstruments-SavePayment route entirely, so Forter's controller hooks never fire for this flow. In app_stripe_sfra/cartridge/static/default/js/stripe.newcardform.js, send the full Stripe PaymentMethod object from the client alongside the payment method ID. Then, in int_stripe_sfra/cartridge/controllers/StripeWallet.js, inside the AddNewCard handler, fire app.payment.saved from the server before the card is attached:
var hookResult = hooksHelper('app.payment.saved', 'paymentSaved', {
paymentMethodId: request.httpParameterMap.payment_method_id.stringValue,
paymentMethodData: request.httpParameterMap.paymentMethodData.stringValue
}, require('*/cartridge/scripts/hooks/paymentSavedHandling').paymentSaved);
if (hookResult && hookResult.error) {
res.json({ success: false, error: hookResult.errorMessage });
return next();
}This same pattern applies to any PSP that bypasses PaymentInstruments-SavePayment.