> ## Documentation Index
> Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt
> Use this file to discover all available pages before exploring further.

# stripe

> Configure the Stripe payment method in WEBSALE: required settings, related modules and integration steps for the Stripe checkout in the frontend.

## Configurations

The following settings are relevant for configuring the Stripe payment method:

***

## Modules

The following modules are relevant for integrating the Stripe payment method in the checkout process:

* [\$wsStripe](/en/frontend/referenz/module/wsstripe) - Stripe payment methods module
* [\$wsCheckout](/en/frontend/referenz/module/wscheckout) - Checkout state, addresses, shipping, payment, problems, totals
* [\$wsActions](/en/frontend/referenz/module/wsactions) - Generate and evaluate actions
* [\$wsAccount](/en/frontend/referenz/module/wsAccount) - Login status, email, addresses, loadAddress()
* [\$wsViews](/en/frontend/referenz/module/wsviews) - Current URL, destination pages, view URLs
* [\$wsBasket](/en/frontend/referenz/module/wsbasket) - Basket and order overview
* [\$wsConfig](/en/frontend/referenz/module/wsconfig) - Configuration values, for example salutations and currency

***

## Actions

The following actions are relevant for the integration of the Stripe payment method:

***

## Additionally relevant information

The following additional content must be integrated for the payment method.

### Frontend integration

Stripe provides its own JavaScript SDK that must be embedded in the template. It handles the display of the payment fields and the communication with Stripe.

**HTML structure**<br />The following HTML block must be placed in the template:

* `#wsStripePaymentElement` is the container in which Stripe automatically embeds the payment fields (e.g., credit card number, PayPal button, etc.)
* The form submits the payment process when "Pay with Stripe" is clicked

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<div id="wsStripePaymentElement">
    
</div>
<form method="post" action="{{= $wsViews.current.url() }}" id="wsCheckoutStripeConfirmForm">
    <input type="hidden" name="wsact" value="{{= $cActionCheckoutConfirm.id }}">
    <input type="hidden" name="wscsrf" value="{{= $cActionCheckoutConfirm.csrf }}">
    <input type="hidden" name="wstarget" value="{{= $wsViews.viewUrl('confirm.htm') }}">
    <button class="btn btn-success btn-block wsStripeOrderBtn" {{if not $wsCheckout.isValid}}disabled{{/if}}>
      Pay with Stripe
    </button>
</form>
```

**JavaScript**<br />The following script block must be inserted directly after the HTML block. It must be enclosed in `{{ autoescape "js" }}` so that template variables in the JavaScript context are processed correctly.

The flow in the script is as follows:

1. **Initialize Stripe** - The SDK is started with the credentials from [\$wsStripe.configuration](/en/frontend/referenz/module/wsstripe)
2. **Display payment fields** - Stripe renders the payment selection (credit card, PayPal, etc.) into the `#wsStripePaymentElement` container. The Stripe address input fields are disabled because the customer's address is already known in the shop and is passed automatically.
3. **Trigger payment** - When the form is submitted, the entered payment data is sent to Stripe together with the billing address from [\$wsAccount](/en/frontend/referenz/module/wsAccount). Stripe returns a confirmation token for this.
4. **Send token to the shop** - The token is transmitted to the shop, which uses it to start the actual payment process with Stripe.
5. **Process result** - If the payment fails, an error message is displayed. If an additional confirmation is required (e.g., 3D Secure), Stripe handles this automatically.
6. **Redirect** - After a successful payment, the customer is redirected to the order confirmation page.

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ autoescape "js" }}
<script>
    {{ var $stripeConfig = $wsStripe.configuration }}
    const stripe = Stripe("{{= $stripeConfig.publishableKey }}", {
        stripeAccount: "{{= $stripeConfig.targetAccount }}"
    });

    const appearance = {
        theme: 'stripe', // Appearance customizable, see Stripe Appearance API
    };

    const options = {
        mode: 'payment',
        amount: {{= $wsCheckout.getAmountInSmallestUnit($wsCheckout.sum.total) }},
        currency: '{{= lower($wsCheckout.sum.currency) }}',
        paymentMethodCreation: 'manual',
        appearance,
    };

    const elements = stripe.elements(options);

    // Disable Stripe address input fields – the address is
    // passed automatically below from $wsAccount when submitting
    const paymentElement = elements.create('payment', {
        fields: {
            billingDetails: {
                name: 'never',
                email: 'never',
                phone: 'never',
                address: {
                    line1: 'never',
                    line2: 'never',
                    city: 'never',
                    state: 'auto', // State is not present in our addresses
                    country: 'never',
                    postalCode: 'never'
                }
            }
        }
    });
    paymentElement.mount("#wsStripePaymentElement");

    document
        .querySelector("#wsCheckoutStripeConfirmForm")
        .addEventListener("submit", handleSubmit);

    async function handleSubmit(e) {
        e.preventDefault();
        setLoading(true);

        // Check whether the payment inputs are complete
        const {error: submitError} = await elements.submit();
        if (submitError) {
            showMessage(submitError.message);
            return;
        }

        // Send payment data + billing address to Stripe,
        // Stripe returns a confirmation token for this
        const {error, confirmationToken} = await stripe.createConfirmationToken({
            elements,
            params: {
                payment_method_data: {
                    billing_details: {
                        {{ foreach $addr in $wsAccount.addresses }}
                            {{if $addr.id==$wsCheckout.selectedBillAddress}}
                        address: {
                            city: "{{=$addr.city}}",
                            country: "{{=$addr.country}}",
                            line1: "{{=$addr.street}}",
                            line2: "",
                            postal_code: "{{=$addr.zip}}",
                        },
                        email: "{{ if $wsCheckout.guestMail }}{{= $wsCheckout.guestMail }}{{ else }}{{= $wsAccount.email }}{{ /if }}",
                        name: "{{=$addr.firstName}} {{=$addr.lastName}}",
                        phone: "{{= $addr.phone }}",
                            {{ /if }}
                        {{ /foreach }}
                    }
                }
            }
        });

        if (error) {
            showMessage(error.message);
            return;
        }

        // Send the confirmation token to the shop, which uses it to start the payment process
        var action = $('#confirmForm').attr('action');
        var payload = $('#confirmForm').serialize();
        payload += `&confirmationToken=${confirmationToken.id}`;

        const response = await fetch(action, {
            method: 'post',
            body: payload
        });

        const dataContentType = response.headers.get("content-type");
        if (dataContentType && !dataContentType.includes("application/json")) {
            // Response is not JSON (e.g., if the terms and conditions were not accepted) – reload the page
            return;
        }

        const data = await response.json();
        const { success } = data;

        if (success === false) {
            // Payment declined – error details at: https://docs.stripe.com/testing#declined-payments
            const {error_code, decline_code} = data;
            showMessage(`Payment failed: ${error_code} ${decline_code}`);
            setLoading(false);
            return;
        }

        // If an additional confirmation is required (e.g., 3D Secure),
        // Stripe handles this automatically
        const { clientSecret, status } = data;
        if (status === "requires_action") {
            const { error } = await stripe.handleNextAction({ clientSecret });
            if (error) {
                showMessage(error.message);
                setLoading(false);
                return;
            }
        }

        setLoading(false);
        // Payment successful – redirect to the order confirmation
        window.location.href = "{{= $wsViews.viewUrl('confirm.htm', {wsPayment: 'stripe', stripe_action: 'return'}) }}";
    }

    // ------- UI helper functions -------

    function showMessage(messageText) {
        // TODO: display error message
    }

    function setLoading(isLoading) {
        let wsStripeOrderBtn = document.querySelectorAll(".wsStripeOrderBtn");
        wsStripeOrderBtn.forEach(btn => btn.disabled = isLoading);
        // TODO: show/hide loading indicator
    }
</script>
{{ /autoescape }}
```

***

## Further links

* General documentation for the Stripe frontend: [https://docs.stripe.com/js](https://docs.stripe.com/js)
