---
title: Example: Stripe Payment Element
slug: extensions/example-stripe-payment-element
docTags: 
createdAt: 2026-09-22T18:20:22.602Z
---

This is an example of the [PSP Integration Guide](https://docs.forter.com/extensions/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:

```javascript
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`

```javascript
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:

```javascript
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:

```javascript
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`.
