Changing product quantity in Stripe embedded components [closed]

1 week ago 23
ARTICLE AD BOX

I have successfully implemented Stripe using their Embedded Components API. As I understand correctly, for maximum security products are set server-site in advance. This absolutely makes sense for a multi-page checkout process.

However, now I have a dashboard with user data already present, where the client can choose from a list of just 2 products and add them to his booking. The Stripe payment button is placed directly below the list. For everything else I used the template from Stripe's documentation.

checkout.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <script src="https://js.stripe.com/clover/stripe.js"></script> <script src="checkout.js" defer></script> </head> <body> <!-- Display a payment form --> <form id="payment-form"> <div class="product"> <label>Product 1 ($10)</label> <input type="number" id="p1" value="0" min="0"> </div> <div class="product"> <label>Product 2 ($20)</label> <input type="number" id="p2" value="0" min="0"> </div> <label> Email <input type="email" id="email"/> </label> <div id="email-errors"></div> <h4>Payment</h4> <div id="payment-element"> <!--Stripe.js injects the Payment Element--> </div> <button id="submit"> <span id="button-text">Pay now</span> </button> <div id="payment-message" class="hidden"></div> </form> </body> </html>

checkout.js

const stripe = Stripe("pk_test_***"); let checkout; let actions; initialize(); const emailInput = document.getElementById("email"); const emailErrors = document.getElementById("email-errors"); const validateEmail = async (email) => { const updateResult = await actions.updateEmail(email); const isValid = updateResult.type !== "error"; return { isValid, message: !isValid ? updateResult.error.message : null }; }; document .querySelector("#payment-form") .addEventListener("submit", handleSubmit); // Fetches a Checkout Session and captures the client secret async function initialize() { const promise = fetch('/create.php', { method: 'POST', headers: {'Content-Type': 'application/json'}, }) .then((r) => r.json()) .then((r) => r.clientSecret); const appearance = { theme: 'stripe', }; checkout = stripe.initCheckout({ clientSecret: promise, elementsOptions: { appearance }, }); checkout.on('change', (session) => { // Handle changes to the checkout session }); const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { actions = loadActionsResult.actions; const session = loadActionsResult.actions.getSession(); document.querySelector("#button-text").textContent = `Pay ${ session.total.total.amount } now`; } emailInput.addEventListener("input", () => { // Clear any validation errors emailErrors.textContent = ""; emailInput.classList.remove("error"); }); emailInput.addEventListener("blur", async () => { const newEmail = emailInput.value; if (!newEmail) { return; } const { isValid, message } = await validateEmail(newEmail); if (!isValid) { emailInput.classList.add("error"); emailErrors.textContent = message; } }); const paymentElement = checkout.createPaymentElement(); paymentElement.mount("#payment-element"); } async function handleSubmit(e) { e.preventDefault(); setLoading(true); const email = document.getElementById("email").value; const { isValid, message } = await validateEmail(email); if (!isValid) { emailInput.classList.add("error"); emailErrors.textContent = message; showMessage(message); setLoading(false); return; } const { error } = await actions.confirm(); showMessage(error.message); setLoading(false); } // ------- UI helpers ------- function showMessage(messageText) { const messageContainer = document.querySelector("#payment-message"); messageContainer.classList.remove("hidden"); messageContainer.textContent = messageText; setTimeout(function () { messageContainer.classList.add("hidden"); messageContainer.textContent = ""; }, 4000); }

create.php

<?php require_once '../vendor/autoload.php'; require_once '../secrets.php'; $stripe = new \Stripe\StripeClient([ "api_key" => $stripeSecretKey, "stripe_version" => "2025-11-17.clover" ]); header('Content-Type: application/json'); $checkout_session = $stripe->checkout->sessions->create([ 'ui_mode' => 'custom', 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'unit_amount' => 1000, 'product_data' => [ 'name' => 'Product 1', 'description' => 'Product 1 is what you need', ] ], 'adjustable_quantity' => [ 'enabled' => true, 'minimum' => 0, 'maximum' => 10, ], 'quantity' => 1 ], [ 'price_data' => [ 'currency' => 'usd', 'unit_amount' => 2000, 'product_data' => [ 'name' => 'Product 2', 'description' => 'You also need product 2', ] ], 'adjustable_quantity' => [ 'enabled' => true, 'minimum' => 0, 'maximum' => 10, ], 'quantity' => 1 ], ], 'mode' => 'payment', 'return_url' => $_SERVER['HTTP_REFERER'] . '/complete.html?session_id={CHECKOUT_SESSION_ID}', ]); echo json_encode(array('clientSecret' => $checkout_session->client_secret)); ?>

How can the product quantity of the Payment Intent be changed in this environment?

Thanks a lot in advance!

Read Entire Article