# Mettre à jour dynamiquement les montants des paiements Apprenez à modifier les montants totaux lorsque les clients changent leur sélection lors du paiement. Mettez à jour le montant d’une [ Checkout-Session ](https://docs.stripe.com/api/checkout/sessions.md) ou d’un[ PaymentIntent ](https://docs.stripe.com/api/payment_intents.md) lorsque les clients modifient leurs achats ou le montant de leur paiement. Recalculez les totaux sur votre serveur, puis mettez à jour le montant du PaymentIntent. #### Cas d’usage fréquents - Ajouter ou supprimer des produits additionnels (tels qu’un emballage cadeau ou une garantie). - Sélectionnez un autre mode de livraison ou un autre délai de livraison. - Ajoutez des services ou des débits supplémentaires. - Appliquer ou supprimer un code de réduction ou un crédit magasin avant taxes. #### Bonnes pratiques en matière de sécurité : - Recalculez les montants sur votre serveur. Ne vous fiez pas aux prix ou aux totaux fournis par le client. - Autorisez la mise à jour en fonction de vos règles d’entreprise (par exemple, imposez des quantités maximales). - Ne mettez à jour que les sessions qui sont actives et non terminées ou expirées. #### Contraintes et comportement - Vous pouvez mettre à jour le montant lorsque le Payment Intent ou la session Checkout est en attente de paiement (par exemple, `requires_payment_method` ou `requires_confirmation`). - Après confirmation, vous ne pouvez généralement pas augmenter le montant. # API Checkout Sessions > This is a API Checkout Sessions for when payment-ui is embedded-components. View the full page at https://docs.stripe.com/payments/advanced/dynamically-update-amounts?payment-ui=embedded-components. ## Mettre à jour le SDK client [Côté client] Lorsque vous utilisez Elements avec l’API Checkout Sessions, encapsulez les appels client à votre serveur dans `runServerUpdate` afin que l’état du paiement et les totaux soient actualisés. Encapsulez les appels `runServerUpdate` dans des blocs `try`/`catch` pour gérer les erreurs provenant de votre serveur et de `runServerUpdate` lui-même (par exemple, les délais d’expiration). `response.type === 'error'` couvre les échecs lors de la récupération interne par Stripe de la session mise à jour. Les erreurs renvoyées par votre propre serveur (telles que les réponses 4xx ou 5xx) ne sont pas reflétées dans `response`, car l’[API Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) se résout pour toute réponse HTTP complète, quel que soit le code d’état. Vérifiez `response.ok` dans votre fonction de mise à jour et levez une exception en cas d’échec pour que le bloc `catch` soit atteint. #### HTML + JS ```javascript import {loadStripe} from '@stripe/stripe-js'; // Optional: include beta flags if your integration requires them const stripe = await loadStripe('<>', { betas: ['custom_checkout_server_updates_1'], }); const checkout = stripe.initCheckoutElementsSdk({ clientSecret, elementsOptions: {/* ... */}, }); // Example: Add additional service using price_data const loadActionsResult = await checkout.loadActions(); if (loadActionsResult.type === 'success') { const actions = loadActionsResult.actions; const session = actions.getSession(); document .getElementById('add-service') .addEventListener('click', async () => { const updateOnServer = async () => { const response = await fetch('/update-custom-amount', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ checkout_session_id: session.id, product_id: 'gift_wrap', // Server looks up actual price }), }); if (!response.ok) { const body = await response.json(); throw new Error(body.message); } }; try { const response = await actions.runServerUpdate(updateOnServer); if (response.type === 'error') { // Handle Stripe API errors (for example, session retrieval failure) } } catch (error) { // Handle promise rejection from your server (4xx/5xx errors) or // from runServerUpdate itself (for example, timeouts). // error.message contains the message thrown from your update function. } }); } ``` #### React ```jsx import React from 'react'; import {useCheckoutElements} from '@stripe/react-stripe-js'; export const AddServiceButton = () => { const checkoutState = useCheckoutElements(); if (checkoutState.type === 'loading') { return (
Loading...
); } else if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } const {runServerUpdate, id} = checkoutState; const addService = async () => { const updateOnServer = async () => { const response = await fetch('/update-custom-amount', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ checkout_session_id: id, product_id: 'gift_wrap', // Server looks up actual price }), }); if (!response.ok) { const body = await response.json(); throw new Error(body.message); } }; try { const res = await runServerUpdate(updateOnServer); if (res.type === 'error') { // Handle Stripe API errors (for example, session retrieval failure) } } catch (error) { // Handle promise rejection from your server (4xx/5xx errors) or // from runServerUpdate itself (for example, timeouts). // error.message contains the message thrown from your update function. } }; return ( ); }; ``` ## Créer des endpoints de serveur [Côté serveur] Calculez les montants et validez les entrées sur votre serveur. Ensuite, vous pouvez mettre à jour `line_items` avec [price_data ](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-line_items-price_data) pour ajouter des débits ad hoc. > La mise à jour de `line_items` ou `price_data` recalcule le total de la session et les taxes. #### Node ```node import express from 'express'; import Stripe from 'stripe'; const app = express(); app.use(express.json()); // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. const stripe = new Stripe('<>'); // 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')); ``` # API Payment Intents > This is a API Payment Intents for when payment-ui is elements. View the full page at https://docs.stripe.com/payments/advanced/dynamically-update-amounts?payment-ui=elements. ## Recalculer et mettre à jour le total sur le serveur [Côté serveur] Pour mettre à jour le montant total : 1. Récupérez les modifications apportées par le client au panier ou à la sélection 1. Recalculez le nouveau montant total sur votre serveur. 1. Mettre à jour le PaymentIntent avec le nouveau montant. 1. Renvoyez le PaymentIntent (ou son `client_secret`) au client. #### Node ```node import express from 'express'; import Stripe from 'stripe'; const app = express(); app.use(express.json()); // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. const stripe = new Stripe('<>'); function computeOrderAmount(items, options = {}) { // ToDo: Your logic to compute an order total } app.post('/update-payment-intent', async (req, res) => { try { const {payment_intent_id, items, shipping_cents, service_cents, discount_cents} = req.body; // Compute amount on server const amount = computeOrderAmount(items, {shipping_cents, service_cents, discount_cents}); // Update the amount if the PaymentIntent can be updated const pi = await stripe.paymentIntents.update(payment_intent_id, { amount, }); return res.json({id: pi.id, amount: pi.amount, client_secret: pi.client_secret}); } catch (err) { return res.status(400).json({error: err.message}); } }); app.listen(4242, () => console.log('Server running on port 4242')); ``` ## Mettez à jour le client et confirmez [Côté client] > Vous êtes responsable de la synchronisation entre le client et le serveur. Après avoir actualisé le montant du PaymentIntent sur le serveur, actualisez l’interface utilisateur et confirmez lorsque le client est prêt.