# Créer une page d'abonnement préconfigurée avec Stripe Checkout
# Page d’abonnement préconfigurée avec Stripe Checkout
Commencez à utiliser notre exemple d’application pour exécuter une intégration d’abonnement complète et fonctionnelle à l’aide de [Stripe Billing](https://docs.stripe.com/billing.md) et [Stripe Checkout](https://docs.stripe.com/payments/checkout.md).
L’application test montre comment rediriger vos clients depuis votre site vers une page de paiement prédéfinie hébergée sur Stripe. Les API Stripe Billing permettent de créer et de gérer des abonnements, des factures et des paiements récurrents, tandis que Checkout fournit l’interface utilisateur préconfigurée, sécurisée et hébergée par Stripe pour collecter les informations du paiement.
Vous pouvez modéliser les clients dans votre intégration soit sous forme d’objets [Account configurés comme clients](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) à l’aide de l’API Accounts v2 (recommandé dans la plupart des cas), soit sous forme d’objets [Customer](https://docs.stripe.com/api/customers/object.md) à l’aide de l’API Customers v1. Pour en savoir plus sur les différences entre ces options, consultez la rubrique [Utiliser les comptes comme clients](https://docs.stripe.com/connect/use-accounts-as-customers.md).
Cliquez après chaque étape pour voir l’exemple de code correspondant. Au fur et à mesure des étapes, par exemple lorsque vous ajoutez des données de tarification, l’outil met à jour l’exemple de code.
Téléchargez et personnalisez l’application test localement pour tester votre intégration.
### Ajouter vos produits et tarifs
Créez de nouveaux *produits* (Products represent what your business sells—whether that's a good or a service) and *tarifs* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) à utiliser dans cet exemple.
> Connectez-vous à votre compte Stripe pour configurer vos produits et tarifs.
### Ajouter des fonctionnalités à votre produit
Créez des fonctionnalités, par exemple un cadeau d’anniversaire annuel, et associez-les à votre abonnement pour y [donner droit](https://docs.stripe.com/billing/entitlements.md) aux nouveaux abonnés. Écoutez les [événements récapitulatifs des droits actifs](https://docs.stripe.com/billing/entitlements.md#webhooks) pour votre [destination d’événement](https://docs.stripe.com/event-destinations.md) et utilisez l’[API List Active Entitlements](https://docs.stripe.com/api/entitlements/active-entitlement/list.md) pour un client donné afin de satisfaire aux droits de votre client.
### (Facultatif) Activer les moyens de paiement
Utilisez votre [Dashboard](https://dashboard.stripe.com/settings/payment_methods) pour activer les [moyens de paiement pris en charge](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) que vous souhaitez accepter en plus des cartes. Checkout affiche dynamiquement les moyens de paiement activés par ordre de pertinence, en fonction de la localisation du client et d’autres caractéristiques.
### Ajouter une page d’aperçu des tarifs
Ajoutez à votre site une page qui affiche votre produit et permet à vos clients de s’y abonner. Lorsqu’il clique sur **Paiement**, le client est redirigé vers une page [Checkout](https://docs.stripe.com/payments/checkout.md) hébergée par Stripe, ce qui finalise la commande et empêche toute modification ultérieure.
Envisagez d’intégrer une [grille tarification](https://docs.stripe.com/payments/checkout/pricing-table.md) pour afficher dynamiquement vos informations tarification via le Dashboard. En cliquant sur une option tarification, votre client est redirigé vers la page de paiement.
### Ajouter un bouton de paiement
Le bouton de la page d’aperçu de votre commande redirige votre client vers la page de paiement hébergée par Stripe et utilise le `lookup_key` de votre produit pour récupérer le `price_id` sur le serveur.
### Ajouter une page de confirmation de paiement
Créez une page de confirmation de commande pour présenter le message de confirmation de commande ou les détails de la commande à votre client. Associez cette page à la `success_url` de la session Checkout, vers laquelle Stripe redirige le client une fois qu’il a terminé le paiement.
### Ajouter un bouton destiné au portail client
Ajoutez un bouton de redirection vers le portail client pour permettre aux clients de gérer leur abonnement. Lorsque les clients cliquent sur ce bouton, ils sont redirigés vers la page du portail client hébergée par Stripe.
### Rediriger vers la session du portail client
Envoyez une requête à l’endpoint de votre serveur afin de créer une redirection vers une nouvelle session du portail client. Cet exemple utilise le `session_id` de la [session Checkout](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-id) pour illustrer la récupération du `customer_id`. Dans un environnement de production, nous vous recommandons de sauvegarder cette valeur avec l’utilisateur authentifié dans votre base de données.
### Installer la bibliothèque Node de Stripe
Installez le package et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier package.json, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### npm
Installez la bibliothèque :
```bash
npm install --save stripe
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Node de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-node).
### Installer la bibliothèque Ruby de Stripe
Installez le gem Ruby de Stripe et exigez-le dans votre code. Si vous partez de zéro et avez besoin d’un Gemfile, téléchargez les fichiers du projet à l’aide du lien dans l’éditeur de code.
#### Terminal
Installez le gem :
```bash
gem install stripe
```
#### Bundler
Ajoutez cette ligne à votre Gemfile :
```bash
gem 'stripe'
```
#### GitHub
Vous pouvez sinon télécharger le code source du gem Ruby de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-ruby).
### Installer la bibliothèque Java
Ajoutez la dépendance à votre build et importez la bibliothèque. Ou bien, si vous partez de zéro et avez besoin d’un exemple de fichier pom.xml (pour Maven), téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Maven
Ajoutez la dépendance suivante à votre POM et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Ajoutez la dépendance à votre fichier build.gradle et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Téléchargez le fichier JAR directement [depuis GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Installer le package Python de Stripe
Installez le package Stripe et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier requirements.txt, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### pip
Installez le package via pip :
```bash
pip3 install stripe
```
#### GitHub
Téléchargez le code source de la bibliothèque stripe-python directement [depuis GitHub](https://github.com/stripe/stripe-python).
### Installer la bibliothèque PHP
Installez la bibliothèque avec composer et initialisez-la avec votre clé API secrète. Si vous partez de zéro et que vous avez besoin d’un fichier composer.json, vous pouvez également télécharger les fichiers à l’aide du lien de téléchargement dans l’éditeur de code.
#### Composer
Installez la bibliothèque :
```bash
composer require stripe/stripe-php
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque php de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-php).
### Configurer votre serveur
Ajoutez la dépendance à votre build et importez la bibliothèque. Si vous partez de zéro et avez besoin d’un fichier go.mod, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Go
Veillez à initialiser avec des modules Go :
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Go de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-go).
### Installer la bibliothèque Stripe.net
Installez le package avec .NET ou NuGet. Si vous partez de zéro, vous pouvez également télécharger les fichiers qui contiennent un fichier .csproj configuré.
#### .NET
Installez la bibliothèque :
```bash
dotnet add package Stripe.net
```
#### NuGet
Installez la bibliothèque :
```bash
Install-Package Stripe.net
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque .NET de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-dotnet).
### Installer les bibliothèques Stripe
Installez les packages et importez-les dans votre code. Si vous partez de zéro et qu’il vous faut un fichier `package.json`, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
Installez les bibliothèques :
```bash
npm install --save stripe @stripe/stripe-js next
```
### Créer une session Checkout
La [session Checkout](https://docs.stripe.com/api/checkout/sessions.md) détermine ce que votre client voit sur la page de paiement hébergée par Stripe, notamment les postes de factures, le montant et la devise de la commande, ainsi que les moyens de paiement acceptés.
### Obtenir le prix à partir de la clé de recherche
Transmettez la clé de recherche que vous avez définie pour votre produit dans l’endpoint [Price](https://docs.stripe.com/api/prices/list.md) afin d’appliquer son tarif à la commande.
### Définir les postes de facture
Conservez toujours sur votre serveur les informations sensibles relatives à l’inventaire de vos produits, notamment leur prix et leur disponibilité, pour éviter toute manipulation de la part du client. Transmettez l’ID du prix prédéfini récupéré ci-dessus.
### Définir le mode
Définissez le mode sur `subscription`. Checkout prend également en charge les modes [paiement](https://docs.stripe.com/checkout/quickstart.md) et [configuration](https://docs.stripe.com/payments/save-and-reuse.md) pour les paiements non récurrents.
### URL de confirmation de fourniture
Indiquez une URL accessible au public vers laquelle Stripe peut rediriger les clients après une opération réussie. Ajoutez le paramètre de requête `session_id` à la fin de votre URL afin de pouvoir récupérer le client ultérieurement et permettre à Stripe de générer le Dashboard hébergé du client.
### Rediriger depuis Checkout
Après avoir créé la session, redirigez votre client vers l’URL renvoyée dans la réponse (l’URL de réussite ou d’annulation).
### Créer une session de portail client
Lancez une [session de portail client](https://docs.stripe.com/api/customer_portal/sessions/create.md) sécurisée et hébergée par Stripe, qui permettra à vos clients de gérer leurs abonnements et leurs informations de facturation.
### Rediriger vers le portail client
Après avoir créé la session du portail, redirigez votre client vers l’URL renvoyée dans la réponse.
### Traiter l’abonnement
Créez un endpoint `/webhook` et obtenez votre clé secrète de webhook dans l’onglet [Webhooks](https://dashboard.stripe.com/webhooks) de Workbench pour écouter les événements liés à l’activité des abonnements. Après un paiement réussi et une redirection vers la page de confirmation, vérifiez que l’état de l’abonnement est `active` et accordez à votre client l’accès aux produits et fonctionnalités auxquels il s’est abonné.
### Exécuter le serveur
Démarrez votre serveur et accédez à
```bash
npm start
```
### Exécuter le serveur
Démarrez votre serveur. Il ouvre automatiquement une fenêtre de navigateur à l’adresse
```bash
npm start
```
### Exécuter le serveur
Démarrez votre serveur et accédez à
```bash
ruby server.rb
```
### Exécuter le serveur
Démarrez votre serveur. Il ouvre automatiquement une fenêtre de navigateur à l’adresse
```bash
ruby server.rb
```
### Exécuter le serveur
Démarrez votre serveur et accédez à
```bash
python3 -m flask run --port=4242
```
### Exécuter le serveur
Démarrez votre serveur. Il ouvre automatiquement une fenêtre de navigateur à l’adresse
```bash
python3 -m flask run --port=4242
```
### Exécuter le serveur
Démarrez votre serveur et accédez à
```bash
php -S 127.0.0.1:4242 --docroot=public
```
### Exécuter le serveur
Démarrez votre serveur. Il ouvre automatiquement une fenêtre de navigateur à l’adresse
```bash
php -S 127.0.0.1:4242 --docroot=public
```
### Exécuter le serveur
Démarrez votre serveur et accédez à
```bash
dotnet run
```
### Exécuter le serveur
Démarrez votre serveur. Il ouvre automatiquement une fenêtre de navigateur à l’adresse
```bash
dotnet run
```
### Exécuter le serveur
Démarrez votre serveur et accédez à
```bash
go run server.go
```
### Exécuter le serveur
Démarrez votre serveur. Il ouvre automatiquement une fenêtre de navigateur à l’adresse
```bash
go run server.go
```
### Exécuter le serveur
Démarrez votre serveur et accédez à
```bash
java -cp target/sample-jar-with-dependencies.jar com.stripe.sample.Server
```
### Exécuter le serveur
Démarrez votre serveur. Il ouvre automatiquement une fenêtre de navigateur à l’adresse
```bash
java -cp target/sample-jar-with-dependencies.jar com.stripe.sample.Server
```
### Faire un essai
Cliquez sur le bouton de paiement. Sur la page de paiement hébergée par Stripe, utilisez l’une de ces cartes bancaires de test pour simuler un paiement.
| Scenario | Card Number |
| ----------------------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment requires 3DS authentication | 4000002500003155 |
| Payment is declined | 4000000000009995 |
## Ajouter des fonctionnalités de personnalisation
Si vous avez réussi à vous abonner à votre produit lors de votre test, votre intégration de paiement par abonnement est fonctionnelle. Utilisez les boutons ci-dessous pour voir comment personnaliser cet exemple à l’aide de fonctionnalités supplémentaires.
### Ajouter des périodes d’essai
Associez une période d’essai à une session Checkout.
### Ajouter une période d’essai
Utilisez `subscription_data` pour ajouter un nombre entier représentant le nombre de `trial_period_days` avant de débiter le client pour la première fois. La valeur doit être supérieure ou égale à `1`.
Si vous démarrez un essai gratuit sans moyen de paiement, définissez `les paramètres_d’essai[end_behavior][missing_payment_method]` sur `suspendre` ou `annuler` afin que l’abonnement ne se poursuive pas si l’essai se termine sans moyen de paiement. Transmettez ce paramètre dans `abonnement_données` lorsque vous créez une Checkout Session , ou la mettez à jour sur l’abonnement à un autre moment. Consultez la page [Utilisez des périodes d’essai](https://docs.stripe.com/billing/subscriptions/trials/free-trials.md#create-free-trials-without-payment) pour en savoir plus.
### Définir la date de début de cycle de facturation
Spécifiez une date de début du cycle de facturation lors de la création d’une session Checkout.
### Définir la date de début du cycle de facturation des abonnements
Utilisez `subscription_data` afin de définir un horodatage `billing_cycle_anchor` pour la prochaine date de facturation d’un abonnement. Pour en savoir plus, consultez la page [Définir la date de début de cycle de facturation dans Checkout](https://docs.stripe.com/payments/checkout/billing-cycle.md).
### Automatiser la perception des taxes
Calculez et percevez le montant de taxes approprié sur les transactions Stripe. En savoir plus sur [Stripe Tax](https://docs.stripe.com/tax.md) et la [manière de l’intégrer à Checkout](https://docs.stripe.com/tax/checkout.md). [Activez Stripe Tax](https://dashboard.stripe.com/tax) dans le Dashboard avant l’intégration.
### Ajouter le paramètre automatic_tax
Définissez le paramètre `automatic_tax` sur `enabled: true`.
{{PRODUCT_NAME}}
{{FORMATTED_RECURRING_PRICE}}
Subscription to Starter plan successful!
Picked the wrong subscription? Shop around then come back to pay!
{{PRODUCT_NAME}}
{{FORMATTED_RECURRING_PRICE}}
Subscription to {{PRODUCT_NAME}} successful!
{
"name": "stripe-sample",
"version": "0.1.0",
"dependencies": {
"@stripe/react-stripe-js": "^3.7.0",
"@stripe/stripe-js": "^7.3.0",
"express": "^4.17.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1",
"stripe": "^8.202.0"
},
"devDependencies": {
"concurrently": "4.1.2"
},
"homepage": "http://localhost:3000/checkout",
"proxy": "http://127.0.0.1:4242",
"scripts": {
"start-client": "react-scripts start",
"start-server": "node server.js",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"start": "concurrently \"yarn start-client\" \"yarn start-server\""
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@stripe/react-stripe-js": "^3.7.0",
"@stripe/stripe-js": "^7.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1"
},
"homepage": "http://localhost:3000/checkout",
"proxy": "http://127.0.0.1:4242",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
// This is a public sample test API key.
// Don’t submit any personally identifiable information in requests made with this key.
// Sign in to see your own test API key embedded in code samples.
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
const stripe = require('stripe')('<>');
const YOUR_DOMAIN = "http://localhost:4242";
const YOUR_DOMAIN = "http://localhost:3000";
const prices = await stripe.prices.list({
lookup_keys: [req.body.lookup_key],
expand: ['data.product'],
});
const session = await stripe.checkout.sessions.create({
billing_address_collection: 'auto',
line_items: [
{
price: prices.data[0].id,
// For usage-based billing, don't pass quantity
quantity: 1,
},
],
mode: 'subscription',
success_url: `${YOUR_DOMAIN}/success.html?session_id={CHECKOUT_SESSION_ID}`,
success_url: `${YOUR_DOMAIN}/?success=true&session_id={CHECKOUT_SESSION_ID}`,
discounts: [{
coupon: '{{COUPON_ID}}',
}],
customer: 'cus_123',
customer_account: 'acct_123',
subscription_data: {
trial_period_days: 7,
billing_cycle_anchor: 1672531200,
},
subscription_data: {
billing_cycle_anchor: 1672531200,
},
automatic_tax: { enabled: true },
});
res.redirect(303, session.url);
// This is the url to which the customer will be redirected when they're done
// managing their billing with the portal.
const returnUrl = YOUR_DOMAIN;
const portalSession = await stripe.billingPortal.sessions.create({
customer: checkoutSession.customer,
return_url: returnUrl,
});
// This is the url to which the customer will be redirected when they're done
// managing their billing with the portal.
const returnUrl = YOUR_DOMAIN;
const portalSession = await stripe.billingPortal.sessions.create({
customer_account: checkoutSession.customer_account,
return_url: returnUrl,
});
res.redirect(303, portalSession.url);
app.post(
'/webhook',
express.raw({ type: 'application/json' }),
(request, response) => {
let event = request.body;
// Replace this endpoint secret with your endpoint's unique secret
// If you are testing with the CLI, find the secret by running 'stripe listen'
// If you are using an endpoint defined with the API or dashboard, look in your webhook settings
// at https://dashboard.stripe.com/webhooks
const endpointSecret = 'whsec_12345';
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with JSON.parse
if (endpointSecret) {
// Get the signature sent by Stripe
const signature = request.headers['stripe-signature'];
try {
event = stripe.webhooks.constructEvent(
request.body,
signature,
endpointSecret
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`, err.message);
return response.sendStatus(400);
}
}
let subscription;
let status;
// Handle the event
switch (event.type) {
case 'customer.subscription.trial_will_end':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription trial ending.
// handleSubscriptionTrialEnding(subscription);
break;
case 'customer.subscription.deleted':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription deleted.
// handleSubscriptionDeleted(subscriptionDeleted);
break;
case 'customer.subscription.created':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription created.
// handleSubscriptionCreated(subscription);
break;
case 'customer.subscription.updated':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription update.
// handleSubscriptionUpdated(subscription);
break;
case 'entitlements.active_entitlement_summary.updated':
subscription = event.data.object;
console.log(`Active entitlement summary updated for ${subscription}.`);
// Then define and call a method to handle active entitlement summary updated
// handleEntitlementUpdated(subscription);
break;
default:
// Unexpected event type
console.log(`Unhandled event type ${event.type}.`);
}
// Return a 200 response to acknowledge receipt of the event
response.send();
}
);
{
"name": "stripe-sample",
"version": "1.0.0",
"description": "A sample Stripe implementation",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"author": "stripe-samples",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"stripe": "^21.0.1"
}
}
{
"name": "stripe-sample",
"version": "0.1.0",
"dependencies": {
"@stripe/react-stripe-js": "^3.7.0",
"@stripe/stripe-js": "^7.3.0",
"express": "^4.17.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1",
"stripe": "21.0.1"
},
"devDependencies": {
"concurrently": "4.1.2"
},
"homepage": "http://localhost:3000/checkout",
"proxy": "http://localhost:4242",
"scripts": {
"start-client": "react-scripts start",
"start-server": "node server.js",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"start": "concurrently \"yarn start-client\" \"yarn start-server\""
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
\# This is a public sample test API key.
# Don’t submit any personally identifiable information in requests made with this key.
# Sign in to see your own test API key embedded in code samples.
\# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
client = Stripe::StripeClient.new('<>')
prices = client.v1.prices.list(
lookup_keys: [params['lookup_key']],
expand: ['data.product']
)
session = client.v1.checkout.sessions.create({
mode: 'subscription',
line_items: [{
quantity: 1,
price: prices.data[0].id
}],
success_url: YOUR_DOMAIN + '/success.html?session_id={CHECKOUT_SESSION_ID}',
success_url: YOUR_DOMAIN + '?success=true&session_id={CHECKOUT_SESSION_ID}',
subscription_data: {
trial_period_days: 7,
billing_cycle_anchor: 1672531200
},
subscription_data: {
billing_cycle_anchor: 1672531200
},
customer: 'cus_JyTTNqVDAoRYE1',
customer_account: 'acct_123',
discounts: [{
coupon: 'gBY6sFUf'
}],
automatic_tax: {
enabled: true
},
})
redirect session.url, 303
session = client.v1.billing_portal.sessions.create({
customer: checkout_session.customer,
return_url: return_url
})
session = client.v1.billing_portal.sessions.create({
customer_account: checkout_session.customer_account,
return_url: return_url
})
redirect session.url, 303
post '/webhook' do
\# Replace this endpoint secret with your endpoint's unique secret
# If you are testing with the CLI, find the secret by running 'stripe listen'
# If you are using an endpoint defined with the API or dashboard, look in your webhook settings
# at https://dashboard.stripe.com/webhooks
webhook_secret = 'whsec_12345'
payload = request.body.read
if !webhook_secret.empty?
# Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured.
sig_header = request.env['HTTP_STRIPE_SIGNATURE']
event = nil
begin
event = Stripe::Webhook.construct_event(
payload, sig_header, webhook_secret
)
rescue JSON::ParserError => e
# Invalid payload
status 400
return
rescue Stripe::SignatureVerificationError => e
# Invalid signature
puts '⚠️ Webhook signature verification failed.'
status 400
return
end
else
data = JSON.parse(payload, symbolize_names: true)
event = Stripe::Event.construct_from(data)
end
# Get the type of webhook event sent - used to check the status of PaymentIntents.
event_type = event['type']
data = event['data']
data_object = data['object']
if event.type == 'customer.subscription.deleted'
# handle subscription canceled automatically based
# upon your subscription settings. Or if the user cancels it.
# puts data_object
puts "Subscription canceled: #{event.id}"
end
if event.type == 'customer.subscription.updated'
# handle subscription updated
# puts data_object
puts "Subscription updated: #{event.id}"
end
if event.type == 'customer.subscription.created'
# handle subscription created
# puts data_object
puts "Subscription created: #{event.id}"
end
if event.type == 'customer.subscription.trial_will_end'
# handle subscription trial ending
# puts data_object
puts "Subscription trial will end: #{event.id}"
end
if event.type == 'entitlements.active_entitlement_summary.updated'
# handle active entitlement summary updated
# puts data_object
puts "Active entitlement summary updated: #{event.id}"
end
content_type 'application/json'
{
status: 'success'
}.to_json
end
import stripe
\# This is a public sample test API key.
# Don’t submit any personally identifiable information in requests made with this key.
# Sign in to see your own test API key embedded in code samples.
\# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
client = stripe.StripeClient('<>')
try:
prices = client.v1.prices.list(params={
'lookup_keys': [request.form['lookup_key']],
'expand': ['data.product'],
})
checkout_session = client.v1.checkout.sessions.create(params={
'line_items': [
{
'price': prices.data[0].id,
'quantity': 1,
},
],
'mode': 'subscription',
'success_url': YOUR_DOMAIN +
'/success.html?session_id={CHECKOUT_SESSION_ID}',
'success_url': YOUR_DOMAIN +
'?success=true&session_id={CHECKOUT_SESSION_ID}',
'subscription_data': {
'trial_period_days': 7,
'billing_cycle_anchor': 1672531200,
},
'subscription_data': {
'billing_cycle_anchor': 1672531200,
},
'discounts': [
{
'coupon': '{{COUPON_ID}}'
}
],
'customer': 'cus_123',
'customer_account': 'acct_123',
'automatic_tax': {
'enabled': True
},
})
return redirect(checkout_session.url, code=303)
portalSession = client.v1.billing_portal.sessions.create(params={
'customer': checkout_session.customer,
'return_url': return_url,
})
portalSession = stripe.billing_portal.Session.create(
customer_account=checkout_session.customer_account,
return_url=return_url,
)
return redirect(portalSession.url, code=303)
@app.route('/webhook', methods=['POST'])
def webhook_received():
\# Replace this endpoint secret with your endpoint's unique secret
# If you are testing with the CLI, find the secret by running 'stripe listen'
# If you are using an endpoint defined with the API or dashboard, look in your webhook settings
# at https://dashboard.stripe.com/webhooks
webhook_secret = 'whsec_12345'
request_data = json.loads(request.data)
if webhook_secret:
# Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured.
signature = request.headers.get('stripe-signature')
try:
event = client.construct_event(
payload=request.data, sig_header=signature, secret=webhook_secret)
data = event['data']
except Exception as e:
return e
# Get the type of webhook event sent - used to check the status of PaymentIntents.
event_type = event['type']
else:
data = request_data['data']
event_type = request_data['type']
data_object = data['object']
print('event ' + event_type)
if event_type == 'checkout.session.completed':
print('🔔 Payment succeeded!')
elif event_type == 'customer.subscription.trial_will_end':
print('Subscription trial will end')
elif event_type == 'customer.subscription.created':
print('Subscription created %s', event.id)
elif event_type == 'customer.subscription.updated':
print('Subscription created %s', event.id)
elif event_type == 'customer.subscription.deleted':
# handle subscription canceled automatically based
# upon your subscription settings. Or if the user cancels it.
print('Subscription canceled: %s', event.id)
elif event_type == 'entitlements.active_entitlement_summary.updated':
# handle active entitlement summary updated
print('Active entitlement summary updated: %s', event.id)
return jsonify({'status': 'success'})
certifi==2026.1.4
chardet==5.2.0
click==8.3.1
Flask==3.1.2
idna==3.11
itsdangerous==2.2.0
Jinja2==3.1.6
MarkupSafe==3.0.3
requests==2.32.5
stripe==15.0.0
toml==0.10.2
Werkzeug==3.1.5
$session = $stripe->billingPortal->sessions->create([
'customer' => $checkout_session->customer,
'return_url' => $return_url,
]);
$session = $stripe->billingPortal->sessions->create([
'customer_account' => $checkout_session->customer_account,
'return_url' => $return_url,
]);
header("HTTP/1.1 303 See Other");
header("Location: " . $session->url);
// Replace this endpoint secret with your endpoint's unique secret
// If you are testing with the CLI, find the secret by running 'stripe listen'
// If you are using an endpoint defined with the API or dashboard, look in your webhook settings
// at https://dashboard.stripe.com/webhooks
$endpoint_secret = 'whsec_12345';
$payload = @file_get_contents('php://input');
$event = null;
try {
$event = \Stripe\Event::constructFrom(
json_decode($payload, true)
);
} catch(\UnexpectedValueException $e) {
// Invalid payload
echo '⚠️ Webhook error while parsing basic request.';
http_response_code(400);
exit();
}
// Handle the event
switch ($event->type) {
case 'customer.subscription.trial_will_end':
$subscription = $event->data->object; // contains a \Stripe\Subscription
// Then define and call a method to handle the trial ending.
// handleTrialWillEnd($subscription);
break;
case 'customer.subscription.created':
$subscription = $event->data->object; // contains a \Stripe\Subscription
// Then define and call a method to handle the subscription being created.
// handleSubscriptionCreated($subscription);
break;
case 'customer.subscription.deleted':
$subscription = $event->data->object; // contains a \Stripe\Subscription
// Then define and call a method to handle the subscription being deleted.
// handleSubscriptionDeleted($subscription);
break;
case 'customer.subscription.updated':
$subscription = $event->data->object; // contains a \Stripe\Subscription
// Then define and call a method to handle the subscription being updated.
// handleSubscriptionUpdated($subscription);
break;
case 'entitlements.active_entitlement_summary.updated':
$subscription = $event->data->object; // contains a \Stripe\Subscription
// Then define and call a method to handle active entitlement summary updated.
// handleEntitlementUpdated($subscription);
break;
default:
// Unexpected event type
echo 'Received unknown event type';
}
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
$stripeSecretKey = '<>';
$stripe = new \Stripe\StripeClient($stripeSecretKey);
$prices = $stripe->prices->all([
// retrieve lookup_key from form data POST body
'lookup_keys' => [$_POST['lookup_key']],
'expand' => ['data.product']
]);
$checkout_session = $stripe->checkout->sessions->create([
'line_items' => [[
'price' => $prices->data[0]->id,
'quantity' => 1,
]],
'mode' => 'subscription',
'success_url' => $YOUR_DOMAIN . '/success.html?session_id={CHECKOUT_SESSION_ID}',
'success_url' => $YOUR_DOMAIN . '?success=true&session_id={CHECKOUT_SESSION_ID}',
'subscription_data' => [
'trial_period_days' => 7,
'billing_cycle_anchor' => 1672531200,
],
'subscription_data' => [
'billing_cycle_anchor' => 1672531200,
],
'discounts' => [[
'coupon' => '{{COUPON_ID}}',
]],
'customer' => 'cus_123',
'automatic_tax' => [
'enabled' => true,
],
]);
header("HTTP/1.1 303 See Other");
header("Location: " . $checkout_session->url);
// This is a public sample test API key.
// Don’t submit any personally identifiable information in requests made with this key.
// Sign in to see your own test API key embedded in code samples.
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
services.AddSingleton(new StripeClient("<>"));
var priceOptions = new PriceListOptions
{
LookupKeys = new List {
Request.Form["lookup_key"]
}
};
StripeList prices = _client.V1.Prices.List(priceOptions);
var options = new SessionCreateOptions
{
LineItems = new List
{
new SessionLineItemOptions
{
Price = prices.Data[0].Id,
Quantity = 1,
},
},
Mode = "subscription",
SuccessUrl = domain + "/success.html?session_id={CHECKOUT_SESSION_ID}",
SuccessUrl = domain + "?success=true&session_id={CHECKOUT_SESSION_ID}",
SubscriptionData = new SessionSubscriptionDataOptions
{
TrialPeriodDays = 7,
BillingCycleAnchor = 1672531200,
},
SubscriptionData = new SessionSubscriptionDataOptions
{
BillingCycleAnchor = 1672531200,
},
Customer = "cus_123",
CustomerAccount: stripe.String("acct_123"),
AutomaticTax = new SessionAutomaticTaxOptions { Enabled = true },
CustomerAccount = "acct_123",
};
Session session = _client.V1.Checkout.Sessions.Create(options);
Response.Headers.Add("Location", session.Url);
return new StatusCodeResult(303);
var options = new Stripe.BillingPortal.SessionCreateOptions
{
Customer = checkoutSession.CustomerId,
ReturnUrl = returnUrl,
};
var session = _client.V1.BillingPortal.Sessions.Create(options);
var options = new Stripe.BillingPortal.SessionCreateOptions
{
CustomerAccount = checkoutSession.CustomerAccount,
ReturnUrl = returnUrl,
};
var session = _client.V1.BillingPortal.Sessions.Create(options);
Response.Headers.Add("Location", session.Url);
return new StatusCodeResult(303);
[Route("webhook")]
[ApiController]
public class WebhookController : Controller
{
[HttpPost]
public async Task Index()
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
// Replace this endpoint secret with your endpoint's unique secret
// If you are testing with the CLI, find the secret by running 'stripe listen'
// If you are using an endpoint defined with the API or dashboard, look in your webhook settings
// at https://dashboard.stripe.com/webhooks
const string endpointSecret = "whsec_12345";
try
{
var stripeEvent = EventUtility.ParseEvent(json);
var signatureHeader = Request.Headers["Stripe-Signature"];
stripeEvent = EventUtility.ConstructEvent(json,
signatureHeader, endpointSecret);
// If on SDK version < 46, use class Events instead of EventTypes
if (stripeEvent.Type == EventTypes.CustomerSubscriptionDeleted)
{
var subscription = stripeEvent.Data.Object as Subscription;
Console.WriteLine("A subscription was canceled.", subscription.Id);
// Then define and call a method to handle the successful payment intent.
// handleSubscriptionCanceled(subscription);
}
else if (stripeEvent.Type == EventTypes.CustomerSubscriptionUpdated)
{
var subscription = stripeEvent.Data.Object as Subscription;
Console.WriteLine("A subscription was updated.", subscription.Id);
// Then define and call a method to handle the successful payment intent.
// handleSubscriptionUpdated(subscription);
}
else if (stripeEvent.Type == EventTypes.CustomerSubscriptionCreated)
{
var subscription = stripeEvent.Data.Object as Subscription;
Console.WriteLine("A subscription was created.", subscription.Id);
// Then define and call a method to handle the successful payment intent.
// handleSubscriptionUpdated(subscription);
}
else if (stripeEvent.Type == EventTypes.CustomerSubscriptionTrialWillEnd)
{
var subscription = stripeEvent.Data.Object as Subscription;
Console.WriteLine("A subscription trial will end", subscription.Id);
// Then define and call a method to handle the successful payment intent.
// handleSubscriptionUpdated(subscription);
}
else if (stripeEvent.Type == EventTypes.ActiveEntitlementSummaryUpdated)
{
var summary = stripeEvent.Data.Object as ActiveEntitlementSummary;
Console.WriteLine("Active entitlement summary updated for customer", summary.Customer);
// Then define and call a method to handle active entitlement summary updated.
// handleEntitlementUpdated($subscription);
}
else
{
Console.WriteLine("Unhandled event type: {0}", stripeEvent.Type);
}
return Ok();
}
catch (StripeException e)
{
Console.WriteLine("Error: {0}", e.Message);
return BadRequest();
}
}
"github.com/stripe/stripe-go/v85"
"github.com/stripe/stripe-go/v85/webhook"
// This is a public sample test API key.
// Don’t submit any personally identifiable information in requests made with this key.
// Sign in to see your own test API key embedded in code samples.
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
sc = stripe.NewClient("<>")
params := &stripe.PriceListParams{
LookupKeys: stripe.StringSlice([]string{
lookup_key,
}),
}
var price *stripe.Price
for p, err := range sc.V1Prices.List(context.TODO(), params).All(context.TODO()) {
if err != nil {
log.Printf("sc.V1Prices.List: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
price = p
break
}
if price == nil {
log.Printf(">>>>>>>>>>>>>>>>>>>>>>>>>>> Add a price lookup key to checkout.html for the demo <<<<<<<<<<<<<<<<<<<<<<<<")
return
}
checkoutParams := &stripe.CheckoutSessionCreateParams{
Mode: stripe.String(stripe.CheckoutSessionModeSubscription),
LineItems: []*stripe.CheckoutSessionCreateLineItemParams{
&stripe.CheckoutSessionCreateLineItemParams{
Price: stripe.String(price.ID),
Quantity: stripe.Int64(1),
},
},
SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{
TrialPeriodDays: stripe.Int64(7),
BillingCycleAnchor: stripe.Int64(1672531200),
},
SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{
BillingCycleAnchor: stripe.Int64(1672531200),
},
Discounts: []*stripe.CheckoutSessionCreateDiscountParams{
&stripe.CheckoutSessionCreateDiscountParams{
Coupon: stripe.String("gBY6sFUf"),
},
},
SuccessURL: stripe.String(domain + "/success.html?session_id={CHECKOUT_SESSION_ID}"),
SuccessURL: stripe.String(domain + "?success=true&session_id={CHECKOUT_SESSION_ID}"),
Customer: stripe.String("cus_123"),
CustomerAccount: stripe.String("acct_123"),
AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{
Enabled: stripe.Bool(true),
},
}
s, err := sc.V1CheckoutSessions.Create(context.TODO(), checkoutParams)
http.Redirect(w, r, s.URL, http.StatusSeeOther)
// Authenticate your user.
params := &stripe.BillingPortalSessionCreateParams{
Customer: stripe.String(s.Customer.ID),
ReturnURL: stripe.String(domain),
}
ps, _ := sc.V1BillingPortalSessions.Create(context.TODO(), params)
log.Printf("sc.V1BillingPortalSessions.Create: %v", ps.URL)
// Authenticate your user.
params := &stripe.BillingPortalSessionCreateParams{
CustomerAccount: stripe.String(s.CustomerAccount),
ReturnURL: stripe.String(domain),
}
ps, _ := sc.V1BillingPortalSessions.Create(context.TODO(), params)
log.Printf("sc.V1BillingPortalSessions.Create: %v", ps.URL)
http.Redirect(w, r, ps.URL, http.StatusSeeOther)
func handleWebhook(w http.ResponseWriter, req *http.Request) {
const MaxBodyBytes = int64(65536)
bodyReader := http.MaxBytesReader(w, req.Body, MaxBodyBytes)
payload, err := ioutil.ReadAll(bodyReader)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
// Replace this endpoint secret with your endpoint's unique secret
// If you are testing with the CLI, find the secret by running 'stripe listen'
// If you are using an endpoint defined with the API or dashboard, look in your webhook settings
// at https://dashboard.stripe.com/webhooks
endpointSecret := "whsec_12345"
signatureHeader := req.Header.Get("Stripe-Signature")
event, err := sc.ConstructEvent(payload, signatureHeader, endpointSecret)
if err != nil {
fmt.Fprintf(os.Stderr, "⚠️ Webhook signature verification failed. %v\n", err)
w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature
return
}
// Unmarshal the event data into an appropriate struct depending on its Type
switch event.Type {
case "customer.subscription.deleted":
var subscription stripe.Subscription
err := json.Unmarshal(event.Data.Raw, &subscription)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Subscription deleted for %d.", subscription.ID)
// Then define and call a func to handle the deleted subscription.
// handleSubscriptionCanceled(subscription)
case "customer.subscription.updated":
var subscription stripe.Subscription
err := json.Unmarshal(event.Data.Raw, &subscription)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Subscription updated for %d.", subscription.ID)
// Then define and call a func to handle the successful attachment of a PaymentMethod.
// handleSubscriptionUpdated(subscription)
case "customer.subscription.created":
var subscription stripe.Subscription
err := json.Unmarshal(event.Data.Raw, &subscription)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Subscription created for %d.", subscription.ID)
// Then define and call a func to handle the successful attachment of a PaymentMethod.
// handleSubscriptionCreated(subscription)
case "customer.subscription.trial_will_end":
var subscription stripe.Subscription
err := json.Unmarshal(event.Data.Raw, &subscription)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Subscription trial will end for %d.", subscription.ID)
// Then define and call a func to handle the successful attachment of a PaymentMethod.
// handleSubscriptionTrialWillEnd(subscription)
case "entitlements.active_entitlement_summary.updated":
var subscription stripe.Subscription
err := json.Unmarshal(event.Data.Raw, &subscription)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Active entitlement summary updated for %d.", subscription.ID)
// Then define and call a func to handle active entitlement summary updated.
// handleEntitlementUpdated(subscription)
default:
fmt.Fprintf(os.Stderr, "Unhandled event type: %s\n", event.Type)
}
w.WriteHeader(http.StatusOK)
}
require github.com/stripe/stripe-go/v85 v85.0.0
// This is a public sample test API key.
// Don’t submit any personally identifiable information in requests made with this key.
// Sign in to see your own test API key embedded in code samples.
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
StripeClient client = new StripeClient("<>");
PriceListParams priceParams = PriceListParams.builder().addLookupKey(request.queryParams("lookup_key")).build();
StripeCollection prices = client.v1().prices().list(priceParams);
SessionCreateParams params = SessionCreateParams.builder()
.addLineItem(
SessionCreateParams.LineItem.builder().setPrice(prices.getData().get(0).getId()).setQuantity(1L).build())
.setMode(SessionCreateParams.Mode.SUBSCRIPTION)
.setSuccessUrl(YOUR_DOMAIN + "/success.html?session_id={CHECKOUT_SESSION_ID}")
.setSuccessUrl(YOUR_DOMAIN + "?success=true&session_id={CHECKOUT_SESSION_ID}")
.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setTrialPeriodDays(7L).setBillingCycleAnchor(1672531200).build())
.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setBillingCycleAnchor(1672531200).build())
.addDiscount(SessionCreateParams.Discount.builder().setCoupon("{{COUPON_ID}}").build())
.setCustomer("cus_JyTTNqVDAoRYE1")
.setCustomerAccount("acct_123")
.setAutomaticTax(
SessionCreateParams.AutomaticTax.builder()
.setEnabled(true)
.build())
.build();
Session session = client.v1().checkout().sessions().create(params);
response.redirect(session.getUrl(), 303);
com.stripe.param.billingportal.SessionCreateParams params = new com.stripe.param.billingportal.SessionCreateParams.Builder()
.setCustomer(checkoutSession.getCustomer())
.setReturnUrl(YOUR_DOMAIN).build();
com.stripe.model.billingportal.Session portalSession = client.v1().billingPortal().sessions().create(params);
com.stripe.param.billingportal.SessionCreateParams params = new com.stripe.param.billingportal.SessionCreateParams.Builder()
.setCustomerAccount(checkoutSession.getCustomerAccount())
.setReturnUrl(YOUR_DOMAIN).build();
com.stripe.model.billingportal.Session portalSession = client.v1().billingPortal().sessions().create(params);
response.redirect(portalSession.getUrl(), 303);
return "";
post("/webhook", (request, response) -> {
String payload = request.body();
Event event = null;
try {
event = ApiResource.GSON.fromJson(payload, Event.class);
} catch (JsonSyntaxException e) {
// Invalid payload
System.out.println("⚠️ Webhook error while parsing basic request.");
response.status(400);
return "";
}
String sigHeader = request.headers("Stripe-Signature");
if (endpointSecret != null && sigHeader != null) {
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with GSON.
try {
event = client.constructEvent(payload, sigHeader, endpointSecret);
} catch (SignatureVerificationException e) {
// Invalid signature
System.out.println("⚠️ Webhook error while validating signature.");
response.status(400);
return "";
}
}
// Deserialize the nested object inside the event
EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer();
StripeObject stripeObject = null;
if (dataObjectDeserializer.getObject().isPresent()) {
stripeObject = dataObjectDeserializer.getObject().get();
} else {
// Deserialization failed, probably due to an API version mismatch.
// Refer to the Javadoc documentation on `EventDataObjectDeserializer` for
// instructions on how to handle this case, or return an error here.
}
// Handle the event
Subscription subscription = null;
switch (event.getType()) {
case "customer.subscription.deleted":
subscription = (Subscription) stripeObject;
// Then define and call a function to handle the event
// customer.subscription.deleted
// handleSubscriptionTrialEnding(subscription);
case "customer.subscription.trial_will_end":
subscription = (Subscription) stripeObject;
// Then define and call a function to handle the event
// customer.subscription.trial_will_end
// handleSubscriptionDeleted(subscriptionDeleted);
case "customer.subscription.created":
subscription = (Subscription) stripeObject;
// Then define and call a function to handle the event
// customer.subscription.created
// handleSubscriptionCreated(subscription);
case "customer.subscription.updated":
subscription = (Subscription) stripeObject;
// Then define and call a function to handle the event
// customer.subscription.updated
// handleSubscriptionUpdated(subscription);
case "entitlements.active_entitlement_summary.updated":
subscription = (Subscription) stripeObject;
// Then define and call a function to handle the event
// entitlements.active_entitlement_summary.updated
// handleEntitlementUpdated(subscription);
// ... handle other event types
default:
System.out.println("Unhandled event type: " + event.getType());
}
response.status(200);
return "";
});
1. Build the server
~~~
pip3 install -r requirements.txt
~~~
1. Build the server
~~~
bundle install
~~~
1. Build the server
~~~
composer install
~~~
1. Build the server
~~~
dotnet restore
~~~
1. Build the server
~~~
mvn package
~~~
2. Run the server
~~~
export FLASK_APP=server.py
python3 -m flask run --port=4242
~~~
2. Run the server
~~~
ruby server.rb -o 0.0.0.0
~~~
2. Run the server
~~~
php -S 127.0.0.1:4242 --docroot=public
~~~
2. Run the server
~~~
dotnet run
~~~
2. Run the server
~~~
java -cp target/sample-jar-with-dependencies.jar com.stripe.sample.Server
~~~
3. Build the client app
~~~
npm install
~~~
4. Run the client app
~~~
npm start
~~~
5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
3. Build the client app
~~~
npm install
~~~
4. Run the client app
~~~
npm start
~~~
5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
3. Build the client app
~~~
npm install
~~~
4. Run the client app
~~~
npm start
~~~
5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
3. Build the client app
~~~
npm install
~~~
4. Run the client app
~~~
npm start
~~~
5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
3. Build the client app
~~~
npm install
~~~
4. Run the client app
~~~
npm start
~~~
5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
1. Run the server
~~~
go run server.go
~~~
2. Build the client app
~~~
npm install
~~~
3. Run the client app
~~~
npm start
~~~
4. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
1. Run the server
~~~
go run server.go
~~~
2. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
1. Build the application
~~~
npm install
~~~
2. Run the application
~~~
npm start
~~~
3. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
1. Build the server
~~~
npm install
~~~
2. Run the server
~~~
npm start
~~~
3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
## Prochaines étapes
#### [Modifier le tarif des abonnements](https://docs.stripe.com/billing/subscriptions/change-price.md)
Modifiez les Abonnement pour gérer les clients qui passent à une offre tarifaire supérieure ou inférieure.
#### [Appliquer les calculs au prorata](https://docs.stripe.com/billing/subscriptions/prorations.md)
Découvrez comment ajuster la facture d’un client pour qu’elle reflète correctement les changements de tarif en milieu de cycle.
#### [Proposer des abonnements supérieurs](https://docs.stripe.com/payments/checkout/upsells.md)
Incitez les clients à prendre un abonnement sur une plus longue période en leur accordant des réductions.