# Mettre à jour dynamiquement les réductions Apprenez à appliquer et à modifier les codes de réduction lors du paiement. > #### Version bêta privée > > Les réductions dynamiques sont en version bêta privée. Découvrez comment ajouter ou supprimer dynamiquement des réductions sur une [session Checkout](https://docs.stripe.com/api/checkout/sessions/object.md). ### Cas d’usage Ce guide vous explique comment intégrer votre système de réductions interne pour créer des remises dynamiques, mais vous pouvez également appliquer : - **Des remises de fidélité** : appliquez automatiquement des remises en fonction du niveau de fidélité du client ou de l’historique d’achat. - **Promotions basées sur la valeur du panier :** ajoutez des remises lorsque le montant total de la commande dépasse certains seuils (par exemple, 10 USD de remise pour toute commande supérieure à 100 USD). - **Des offres à durée limitée** : appliquez des remises promotionnelles à durée limitée ou supprimez les codes de réduction expirés. - **Des remises basées sur la localisation** : appliquez des remises spécifiques à chaque région en fonction de l’adresse de livraison du client. - **Des offres spécifiques aux clients** : créez des montants de remise personnalisés en fonction de certains segments de clientèle ou comportements d’achat passés. > #### API Payment Intents > > Si vous utilisez l’API Payment Intents, vous pouvez appliquer des remises en calculant et en modifiant manuellement le montant du paiement, ou en créant un nouveau PaymentIntent avec des montants réajustés. ## Configurer le SDK [Côté serveur] Utilisez nos bibliothèques officielles pour accéder à l’API Stripe depuis votre application : #### Ruby ```bash gem install stripe -v 15.1.0-beta.2 ``` ## Mettre à jour le SDK du serveur [Côté serveur] Pour utiliser cette fonctionnalité de prévisualisation, mettez d’abord à jour votre SDK afin d’utiliser l’en-tête de version bêta : `checkout_server_update_beta=v1`. #### Ruby ```ruby # Don't put any keys in code. Use a secrets vault or environment # variable to supply keys to your integration. This example # shows how to set a secret key for illustration purposes only. # # See https://docs.stripe.com/keys-best-practices and find your # keys at https://dashboard.stripe.com/apikeys. Stripe.api_key = '<>' Stripe.api_version = '2025-03-31.basil; checkout_server_update_beta=v1;' ``` ## Configurer les autorisations de mise à jour pour la session Checkout [Côté serveur] Lorsque vous créez une session de paiement, transmettez l’option [ permissions.update_discounts=server_only ](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-permissions-update_discounts) pour désactiver l’application des réductions côté client et permettre la mise à jour des réductions à partir de votre serveur. ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -H "Stripe-Version: 2025-03-31.basil; checkout_server_update_beta=v1;" \ -d ui_mode=custom \ -d "permissions[update_discounts]"=server_only \ -d "line_items[0][price]"="{{PRICE_ID}}" \ -d "line_items[0][quantity]"=1 \ -d mode=payment \ --data-urlencode return_url="https://example.com/return" ``` ## Mettre à jour dynamiquement les réductions [Côté serveur] Créez un endpoint sur votre serveur pour appliquer les réductions pendant la session Checkout. Vous l’appellerez à partir de l’interface dans une étape ultérieure. > Le code côté client s’exécute dans un environnement contrôlé par l’utilisateur. Un utilisateur malveillant peut contourner votre validation côté client, intercepter et modifier des requêtes, ou créer de nouvelles requêtes vers votre serveur. Lors de la création d’un endpoint, nous vous recommandons ce qui suit : - Créez des endpoints pour des interactions spécifiques avec les clients au lieu de les rendre génériques. Par exemple, « appliquer une remise de fidélité » au lieu d’une action générale de « mise à jour ». Des endpoints spécifiques peuvent faciliter l’écriture et la maintenance de la logique de validation. - Ne transmettez pas les [ données de session](https://docs.stripe.com/js/custom_checkout/session_object) directement du client à votre endpoint. Des clients malveillants peuvent modifier les données de requête, ce qui en fait une source peu fiable pour déterminer l’état d’une session de paiement. Au lieu de cela, transmettez l’[identifiant de session](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-id) à votre serveur et utilisez-le pour récupérer en toute sécurité les données à partir de l’API Stripe. #### Ruby ```ruby require 'sinatra' require 'json' require 'stripe' set :port, 4242 # 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 = "<>" # Return a boolean indicating whether the discounts are valid. def validate_discounts(discounts, session # Basic validation - ensure we only have one discount if any return true if discounts.empty? || discounts == "" # Ensure only one discount is being applied return false if discounts.is_a?(Array) && discounts.length > 1 # Add your own validation logic here # For example, validate promo codes against your internal system true end # Return an array of the updated discounts or the original ones if no update is needed. def recompute_discounts(discounts, session) # If removing discounts, return empty return [] if discounts.empty? || discounts == "" # Example: Access your internal discounts system # This could be based on customer ID, promo codes, cart value, and so on customer_id = session.customer || session.client_reference_id cart_total = session.amount_total # Example internal discount calculation discount_amount = calculate_customer_discount(customer_id, cart_total) if discount_amount > 0 # Create a dynamic discount using coupon_data [{ coupon_data: { name: "Customer Discount", amount_off: discount_amount, currency: session.currency || 'usd' } }] else # No discount applicable [] end end # Example function to integrate with your internal discounts system def calculate_customer_discount(customer_id, cart_total) # Example logic - replace with your actual discount system # This could check: # - Customer loyalty tier # - Active promotions # - Cart value thresholds # - Seasonal discounts # Example: 10% off for carts over 100 USD, max 20 USD discount if cart_total > 10000 # 100 USD in cents discount = [cart_total * 0.1, 2000].min # Max 20 USD discount discount.to_i else 0 end end post '/update-discounts' do content_type :json request.body.rewind request_data = JSON.parse(request.body.read) checkout_session_id = request_data['checkout_session_id'] discounts = request_data['discounts'] # 1. Retrieve the Checkout Session session = Stripe::Checkout::Session.retrieve(checkout_session_id) # 2. Validate the discounts if !validate_discounts(discounts, session) return { type: 'error', message: 'Your discounts are invalid. Please refresh your session.' }.to_json end # 3. Recompute the discounts with your custom logic discounts = recompute_discounts(discounts, session) # 4. Update the Checkout Session with the new discounts if discounts Stripe::Checkout::Session.update(checkout_session_id, { discounts: discounts, }) return { type: 'object', value: { succeeded: true } }.to_json else return { type: 'error', message: "We could not update your discounts. Please try again." }.to_json end end ``` ## Mettre à jour le SDK client [Côté client] #### HTML + JS Initialisez Stripe.js avec l’en-tête `custom_checkout_server_updates_1` beta. ```javascript const stripe = Stripe('<>', { betas: ['custom_checkout_server_updates_1'], }); ``` #### React Passez l’en-tête `custom_checkout_server_updates_1` bêta lors de l’initialisation de l’instance `stripe`. ```javascript import {loadStripe} from '@stripe/stripe-js'; const stripe = loadStripe("<>", { betas: ['custom_checkout_server_updates_1'], }); ``` ## Requête de mise à jour du serveur [Côté client] #### HTML + JS À partir de votre interface, envoyez une requête de mise à jour à votre serveur et encapsulez-la dans [ runServerUpdate ](https://docs.stripe.com/js/custom_checkout/run_server_update). Une requête réussie met à jour l’objet [ Session ](https://docs.stripe.com/js/custom_checkout/session_object) avec la nouvelle remise. ```html ``` ```javascript document.getElementById('apply-customer-discount') .addEventListener("click", async (event) => { const updateCheckout = () => { return fetch("/apply-customer-discount", { method: "POST", headers: { "Content-type": "application/json", }, body: JSON.stringify({ checkout_session_id: actions.getSession().id, }) }); }; const response = await checkout.runServerUpdate(updateCheckout); if (!response.ok) { // Handle error state return; } // Update UI to reflect the applied discount event.target.textContent = "Discount Applied!"; event.target.disabled = true; }); ``` #### React À partir de votre interface, envoyez une requête de mise à jour à votre serveur et encapsulez-la dans [ runServerUpdate ](https://docs.stripe.com/js/custom_checkout/run_server_update). Une requête réussie met à jour l’objet [ Session ](https://docs.stripe.com/js/custom_checkout/session_object) avec la nouvelle remise. ```jsx import React from 'react'; import {useCheckout} from '@stripe/react-stripe-js/checkout'; const ApplyDiscountButton = () => { const [isDiscountApplied, setIsDiscountApplied] = React.useState(false); const checkoutState = useCheckout(); if (checkoutState.type === 'loading') { return (
Loading...
); } else if (checkoutState.type === 'error') { return (
Error: {checkoutState.error.message}
); } const {runServerUpdate, id} = checkoutState.checkout; const updateCheckout = () => fetch("/apply-customer-discount", { method: "POST", headers: { 'Content-type': 'application/json', }, body: JSON.stringify({ checkout_session_id: id, }) }); const handleClick = async () => {const response = await runServerUpdate(updateCheckout); if (!response.ok) { // set error state return; } // Update UI to reflect the applied discount setIsDiscountApplied(true); }; return ( ); }; ``` ## Tester l’intégration Suivez ces étapes pour tester votre intégration et vous assurer que vos remises dynamiques fonctionnent correctement. 1. Configurez un environnement de test qui reflète votre configuration en mode production. Utilisez les clés API d’environnement de test Stripe pour cet environnement. 1. Simulez différents scénarios de remise pour vérifier que votre fonction `recomputeDiscounts` gère correctement les différents scénarios. 1. Vérifiez la logique côté serveur en utilisant des outils de journalisation ou de débogage pour vous assurer que votre serveur : - Récupère la [session Checkout](https://docs.stripe.com/api/checkout/sessions/object.md). - Valide les demandes de réduction. - Recalcule les réductions mises à jour en fonction de votre logique métier. - Mets à jour la [session Checkout](https://docs.stripe.com/api/checkout/sessions/object.md) avec les nouvelles réductions lorsque vos conditions personnalisées sont remplies. Assurez-vous que la réponse de mise à jour contient les nouvelles réductions. Par défaut, la réponse ne contient pas le champ discounts, sauf si la requête [développe](https://docs.stripe.com/api/expanding_objects.md) l’objet. 1. Vérifiez la logique côté client en effectuant plusieurs fois le processus de paiement dans votre navigateur. Observez la façon dont l’interface utilisateur se met à jour après l’application d’une réduction. Assurez-vous que : - La fonction [runServerUpdate](https://docs.stripe.com/js/custom_checkout/run_server_update) est appelée comme prévu. - Les remises s’appliquent correctement en fonction de votre logique métier. - Le total du paiement est mis à jour pour refléter la réduction appliquée. - Les messages d’erreur s’affichent correctement lorsqu’une application de réduction a échoué. 1. Testez divers scénarios de réduction, y compris des demandes de remise non valides, ou simulez des erreurs de serveur pour tester la gestion des erreurs, tant du côté serveur que du côté client.