Stripe Elements
With Stripe Elements you can offer multiple payment options like credit card, PayPal, iDEAL, SEPA debit and many more to your customers.
Stripe Elements provides an interface component (iFrame) that shows several payment options. The payment methods shown to your customer is determined by Stripe based on the currency, the customer’s location and the payment methods you have activated for your Stripe account.
To see which payment methods will be shown to your customers, you can use Stripe’s Payment Review.
You can also show only selected payment methods.
For detailed information on Stripe Elements, please read the Stripe Documentation Accept a payment.
Collect payment details
Learn how to create the Stripe Elements interface component, which is used to collect payment information.
Set up Stripe.js
Add a hidden field called payment_gateway with the value stripe-elements to the checkout form. This is used by Merx to complete the order.
Add the publishable key as a data attribute to the form element. The publishable key is required to initialize Stripe Elements.
<?php
$stripePublishableKey = option('wagnerwagner.merx.production') === true ? option('wagnerwagner.merx.stripe.live.publishable_key') : option('wagnerwagner.merx.stripe.test.publishable_key');
?>
<form id="checkout-form" action="<?= url('api/shop/checkout') ?>" method="post" data-stripe-publishable-key="<?= $stripePublishableKey ?>">
<!-- Other form fields -->
<input type="hidden" name="payment_gateway" value="stripe-elements">
<button>Submit order</button>
</form>
Add the stripe.js to the head of your HTML file. E.g. in a head snippet.
Stripe recommends including Stripe.js on every page of your site to leverage “Stripe’s advanced fraud functionality”. To accept payments, though, the checkout page is enough.
To learn more, see Including Stripe.js | Stripe JS Reference.
<?php if ($page->intendedTemplate()->name() === 'checkout'): ?>
<script src="https://js.stripe.com/clover/stripe.js"></script>
<?php endif ?>
To initialize the Stripe JavaScript API you need the publishable key from the checkout form.
const checkoutForm = document.getElementById('checkout-form');
const stripePublishableKey = checkoutForm.dataset.stripePublishableKey;
const stripe = Stripe(stripePublishableKey)
Add the Payment Element to your payment page
The Payment Element needs a place to live on your payment page. Create an empty DOM node (container) with a unique ID in your payment form:
<form id="checkout-form" action="<?= url('api/shop/checkout') ?>" method="post" data-stripe-publishable-key="<?= $stripePublishableKey ?>">
<!-- Other form fields -->
<div id="payment-element">
<!-- Elements will create form elements here -->
</div>
<button>Submit order</button>
</form>
Create and mount the Stripe elements
const elements = stripe.elements({
locale: document.querySelector('html').lang,
});
// Create and mount the Payment Element
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
See Elements Appearance API | Stripe Documentation to learn how to change the look of the elements.
Submit the payment to Stripe
As described in Validate checkout the personal data will be validated first against the personal data fields of the order blueprint. After that the payment data the customer entered into the elements is submitted to and validated by Stripe.
Retrieve the client secret
First, you need to retrieve the client secret of the payment intent. The payment intent is created server-side with the currency and the total of the cart. Use /shop/stripe-client-secret API endpoint to get the client secret of the payment intent. This secret is used to confirm the payment.
If you followed Validate checkout, replace window.location.href = json.redirectUrl; with the following.
const response = await fetch('/api/shop/stripe-client-secret');
const { clientSecret } = await response.json();
const {error} = await stripe.confirmPayment({
// `Elements` instance that was used to create the Payment Element
elements,
clientSecret,
confirmParams: {
return_url: json.redirectUrl,
},
});
if (error) {
// This point will only be reached if there is an immediate error when
// confirming the payment. Show error to your customer (for example, payment
// details incomplete)
checkoutForm.insertBefore(createErrorElement(error.message), event.submitter)
}
Fetch the client secret when the customer submits, as above, and not earlier. The payment intent is created with the cart total of that moment, and the cart stays editable until the checkout — a secret fetched on page load pays for a cart the customer has since changed. Merx refuses such a payment with error.merx.amountMismatch rather than shipping goods nobody paid for, so if you do cache the secret, fetch a new one whenever the cart changes.
After completing the payment the customer is redirected to the order page.
Most payment methods confirm the payment right away, so the stripe-elements gateway sets the datePaid field of the OrderPage to the current date in the background, and $orderPage->isPaid() returns true.
For some payment methods like SEPA Direct Debit, it can take up to 6 business days until the payment is confirmed. To ensure you don’t fulfill an order before payment clears, it’s recommended to use webhooks. You can set them up to automatically notify you, when payments are confirmed.
Optional: show only specific payment methods
By default Stripe shows the best payment methods. You can also define specific payment methods using the stripe.paymentIntentParameters option.
return [
'wagnerwagner.merx.stripe.paymentIntentParameters' => [
'payment_method_types' => ['card', 'ideal'],
'automatic_payment_methods' => ['enabled' => false],
'capture_method' => 'automatic_async',
'payment_method_options' => [
'card' => ['capture_method' => 'manual'],
],
],
];
See Stripe’s API reference Create a PaymentIntent to see all parameters. amount and currency are automatically added to by Merx.
Some payment methods don’t allow manual capturing (e.g. iDEAL). If you want to use such payment methods, you need to set capture_method to automatic_async. You can also set capture method for each payment using the payment_method_options
The default options and the options you set in the config.php are merged recursively, therefore you need to overwrite/disable automatic_payment_methods.