Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseUse Managed Payments
Use Payment Links
Use a prebuilt checkout page
Build a custom integration with Elements
    Overview
    Compare Checkout Sessions and PaymentIntents
    Quickstart guides
    Design an advanced integration
    Customize look and feel
    Manage payment methods
    Collect additional information
    Build a subscriptions integration
    Dynamic updates
      Shipping options
      Line items
      Trial durations
      Discounts
      Payment amounts
      Line item quantities
    Add discounts
    Collect taxes on your payments
    Let customers pay in their local currency
    Save and retrieve customer payment methods
    Send receipts and paid invoices
    Manually approve payments on your server
    Authorize and capture a payment separately
    Elements with Checkout Sessions API beta changelog
Build an in-app integration
Payment methods
Add payment methods
Manage payment methods
Faster checkout with Link
Payment interfaces
Payment Links
Checkout
Web Elements
In-app Payments
Payment scenarios
Handle multiple currencies
Custom payment flows
Flexible acquiring
Orchestration
In-person payments
Terminal
Beyond payments
Incorporate your company
Crypto
Financial Connections
Climate
Understand fraud
Radar fraud protection
Manage disputes
Verify identities
HomePaymentsBuild a custom integration with ElementsDynamic updates

Dynamically update payment amounts

Learn how to modify total amounts when customers change their selections during checkout.

Update the amount of a Checkout Session or Payment Intent when customers change what they’re buying or how much they pay. Recalculate the totals on your server, and then update the amount of the PaymentIntent.

Common use cases

  • Add or remove add-ons (such as gift wrap or a warranty).
  • Select a different shipping method or delivery speed.
  • Add additional services or charges.
  • Apply or remove a discount code or store credit.

Security best practices

  • Recalculate amounts on your server. Don’t trust client-provided prices or totals.
  • Authorize the update based on your business rules (for example, enforce max quantities).
  • Only update Sessions that are active and not completed or expired.

Constraints and behavior

  • You can update the amount while the Payment Intent or Checkout Session is awaiting payment (for example, requires_payment_method or requires_confirmation).
  • After confirmation, you generally can’t increase the amount.

Update the client SDK
Client-side

When using Elements with the Checkout Sessions API, wrap client calls to your server in runServerUpdate so the checkout state and totals refresh.

checkout.js
import {loadStripe} from '@stripe/stripe-js'; // Optional: include beta flags if your integration requires them const stripe = await loadStripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
, { betas: ['custom_checkout_server_updates_1'], }); const checkout = await stripe.initCheckout({ elementsOptions: {/* ... */}, }); // Example: Add additional service using price_data document .getElementById('add-service') .addEventListener('click', async () => { const updateOnServer = () => fetch('/update-custom-amount', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ checkout_session_id: checkout.session().id, product_id: 'gift_wrap', // Server looks up actual price }), }); const response = await checkout.runServerUpdate(updateOnServer); if (!response.ok) { // show error state } });

Create server endpoints
Server-side

Calculate amounts and validate inputs on your server. Then, you can update line_items with price_data to add ad-hoc charges.

Note

Updating the line_items or price_data recalculates the Session total and taxes.

Node
Python
No results
import express from 'express'; import Stripe from 'stripe'; const app = express(); app.use(express.json()); const stripe = new Stripe(
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
); // Product catalog with prices - store this securely server-side const PRODUCTS = { gift_wrap: { name: 'Gift Wrap', price: 500 }, // $5.00 express_shipping: { name: 'Express Shipping', price: 1500 }, // $15.00 warranty: { name: 'Extended Warranty', price: 2000 }, // $20.00 }; app.post('/update-custom-amount', async (req, res) => { try { const {checkout_session_id, product_id} = req.body; const session = await stripe.checkout.sessions.retrieve(checkout_session_id); if (session.status === 'complete' || session.expires_at * 1000 < Date.now()) { return res.status(400).json({error: 'Session is no longer updatable.'}); } // Look up product price server-side const product = PRODUCTS[product_id]; if (!product) { return res.status(400).json({error: 'Invalid product ID'}); } // Add the additional product via price_data const updated = await stripe.checkout.sessions.update(checkout_session_id, { line_items: [ { price_data: { currency: 'usd', product_data: {name: product.name}, unit_amount: product.price, }, quantity: 1, }, ], }); return res.json({id: updated.id, amount_total: updated.amount_total}); } catch (err) { return res.status(400).json({error: err.message}); } }); app.listen(4242, () => console.log('Server running on port 4242'));
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Join our early access program.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc