# Make line item quantities adjustable Learn how to allow your customers to adjust the quantity of items during checkout. The line items for each [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) keep track of what your customer is purchasing. You can configure the Checkout Session so customers can adjust line item quantities during checkout. > #### Payment Intents API > > If you use the Payment Intents API, you must manually track line item updates and modify the payment amount, or by creating a new PaymentIntent with adjusted amounts. ## Enable adjustable quantities [Server-side] > Other line item updates, such as adding new line items, aren’t supported for this integration. Set [adjustable_quantity](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-adjustable_quantity) on your [line_items](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items) when creating a Checkout Session to allow your customers to update the quantity of an item during checkout. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "line_items[0][price_data][currency]=usd" \ -d "line_items[0][price_data][product_data][name]=T-shirt" \ -d "line_items[0][price_data][unit_amount]=2000" \ -d "line_items[0][quantity]=1" \ -d "line_items[0][adjustable_quantity][enabled]=true" \ -d "line_items[0][adjustable_quantity][maximum]=100" \ -d "line_items[0][adjustable_quantity][minimum]=0" \ -d mode=payment \ -d ui_mode=elements \ -d return_url={{RETURN_URL}} ``` You can customize the default settings for the minimum and maximum quantities allowed by setting [adjustable_quantity.minimum](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-adjustable_quantity-minimum) and [adjustable_quantity.maximum](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-adjustable_quantity-maximum). By default, an item’s minimum adjustable quantity is 0 and the maximum adjustable quantity is 99. You can specify a value of up to 999999 for `adjustable_quantity.maximum`. Checkout prevents the customer from removing an item if it’s the only item remaining. ## Update line item quantities [Client-side] Use [updateLineItemQuantity](https://docs.stripe.com/js/custom_checkout/update_line_item_quantity) to change a line item’s quantity in response to customer interaction, such as a button to increment the quantity. Pass the [line item ID](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-lineItems-id) and the new quantity: #### HTML + JS ```html ``` ```js const checkout = stripe.initCheckoutElementsSdk({clientSecret}); const button = document.querySelector('.increment-quantity-button'); const lineItem = button.getAttribute("data-line-item"); checkout.loadActions().then((loadActionsResult) => { if (loadActionsResult.type === 'success') { const {actions} = loadActionsResult; const session = loadActionsResult.getSession(); const quantity = session.lineItems.find((li) => li.id === lineItem).quantity; button.addEventListener('click', () => {actions.updateLineItemQuantity({ lineItem, quantity: quantity + 1, }) }); } else { const {error} = loadActionsResult; } }); ``` #### React ```jsx import React from 'react'; import {useCheckout} from '@stripe/react-stripe-js/checkout'; const IncrementLineItemButton = (props) => { const checkoutState = useCheckout(); if (checkoutState.type === 'loading') { return (
Loading...
); } else if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } const {updateLineItemQuantity} = checkoutState.checkout; const handleClick = () => {updateLineItemQuantity({ lineItem: props.lineItem, quantity: props.quantity + 1, }); }; return ; }; export default IncrementLineItemButton; ``` ## Handle completed transactions [Server-side] After the payment completes, you can make a request for the finalized [line items](https://docs.stripe.com/api/checkout/sessions/line_items.md) and their quantities. If your customer removes a line item, it’s also removed from the line items response. See the [Fulfillment guide](https://docs.stripe.com/checkout/fulfillment.md) to learn how to create an event handler to handle completed Checkout Sessions. > To test your event handler, [install the Stripe CLI](https://docs.stripe.com/stripe-cli.md) and use `stripe listen --forward-to localhost:4242/webhook` to [forward events to your local server](https://docs.stripe.com/webhooks.md#test-webhook). #### Ruby ```ruby # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/apikeys Stripe.api_key = "<>" require 'sinatra' # You can find your endpoint's secret in your webhook settings endpoint_secret = 'whsec_...' post '/webhook' do event = nil # Verify webhook signature and extract the event # See https://stripe.com/docs/webhooks#verify-events for more information. begin sig_header = request.env['HTTP_STRIPE_SIGNATURE'] payload = request.body.read event = Stripe::Webhook.construct_event(payload, sig_header, endpoint_secret) rescue JSON::ParserError => e # Invalid payload return status 400 rescue Stripe::SignatureVerificationError => e # Invalid signature return status 400 end if event['type'] == 'checkout.session.completed' checkout_session = event['data']['object'] line_items = Stripe::Checkout::Session.list_line_items(checkout_session['id'], {limit: 100}) # Fulfill the purchase... begin fulfill_order(checkout_session, line_items) rescue NotImplementedError => e return status 400 end end status 200 end def fulfill_order(checkout_session, line_items) # TODO: Remove error and implement... raise NotImplementedError.new(<<~MSG) Given the Checkout Session "#{checkout_session.id}" load your internal order from the database here. Then you can reconcile your order's quantities with the final line item quantity purchased. You can use `checkout_session.metadata` and `price.metadata` to store and later reference your internal order and item ids. MSG end ```