# Prebuilt subscription page with Stripe Checkout
# Prebuilt subscription page with Stripe Checkout
Incorporate your own test data into our sample app to run a full, working subscription integration using [Stripe Billing](https://docs.stripe.com/billing.md) and [Stripe Checkout](https://docs.stripe.com/payments/checkout.md).
The sample app demonstrates redirecting your customers from your site to a prebuilt payment page hosted on Stripe. The Stripe Billing APIs create and manage subscriptions, invoices, and recurring payments, while Checkout provides the prebuilt, secure, Stripe-hosted UI for collecting payment details.
Click each step to see the corresponding sample code. As you interact with the steps, such as adding pricing data, the builder updates the sample code.
Download and customize the sample app locally to test your integration.
### Add your products and prices
Create new *Products* and *Prices* that you can use in this sample.
### Add features to your product
Create features, such as an annual birthday gift, and associate them with your subscription to [entitle](https://docs.stripe.com/billing/entitlements.md) new subscribers to them. Listen to the [active entitlements summary events](https://docs.stripe.com/billing/entitlements.md#webhooks) for your [event destination](https://docs.stripe.com/event-destinations.md), and use the [list active entitlements API](https://docs.stripe.com/api/entitlements/active-entitlement/list.md) for a given customer to fulfill your customer’s entitlements.
### Enable payment methods
Use your [Dashboard](https://dashboard.stripe.com/settings/payment_methods) to enable [supported payment methods](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) that you want to accept in addition to cards. Checkout dynamically displays your enabled payment methods in order of relevance, based on the customer’s location and other characteristics.
### Add a pricing preview page
Add a page to your site that displays your product and allows your customers to subscribe to it. Clicking **Checkout**, redirects them to a Stripe-hosted [Checkout](https://docs.stripe.com/payments/checkout.md) page, which finalizes the order and prevents further modification.
Consider embedding a [pricing table](https://docs.stripe.com/payments/checkout/pricing-table.md) to dynamically display your pricing information through the Dashboard. Clicking a pricing option redirects your customer to the checkout page.
### Add a checkout button
The button on your order preview page redirects your customer to the Stripe-hosted Checkout page and uses your product’s `lookup_key` to retrieve the `price_id` from the server.
### Add a success page
Create a success page to display order confirmation messaging or order details to your customer. Associate this page with the Checkout Session `success_url`, which Stripe redirects to after the customer successfully completes the checkout.
### Add a customer portal button
Add a button to redirect to the customer portal to allow customers to manage their subscription. Clicking this button redirects your customer to the Stripe-hosted customer portal page.
### Add a cancel page
Add a page to associate with the Checkout Session `cancel_url`, which Stripe redirects to when the customer clicks the back button in Checkout.
### Redirect to the customer portal session
Make a request to the endpoint on your server to redirect to a new customer portal session. This sample uses the `session_id` from the [Checkout session](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-id) to demonstrate retrieving the `customer_id`. In a production environment, you typically store this value alongside the authenticated user in your database.
### Install the Stripe Node library
Install the package and import it in your code. Alternatively, if you’re starting from scratch and need a package.json file, download the project files using the Download link in the code editor.
Install the library:
Or download the stripe-node library source code directly
[from GitHub](https://github.com/stripe/stripe-node).
### Install the Stripe Ruby library
Install the Stripe ruby gem and require it in your code. Alternatively, if you’re starting from scratch and need a Gemfile, download the project files using the link in the code editor.
Install the gem:
Add this line to your Gemfile:
Or download the stripe-ruby gem source code directly
[from GitHub](https://github.com/stripe/stripe-ruby).
### Install the Stripe Java library
Add the dependency to your build and import the library. Alternatively, if you’re starting from scratch and need a sample pom.xml file (for Maven), download the project files using the link in the code editor.
Add the following dependency to your POM and replace {VERSION} with the version number you want to use.
Add the dependency to your build.gradle file and replace {VERSION} with the version number you want to use.
Download the JAR directly
[from GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Install the Stripe Python package
Install the Stripe package and import it in your code. Alternatively, if you’re starting from scratch and need a requirements.txt file, download the project files using the link in the code editor.
Install the package via pip:
Download the stripe-python library source code directly
[from GitHub](https://github.com/stripe/stripe-python/releases).
### Install the Stripe PHP library
Install the library with composer and initialize with your secret API key. Alternatively, if you’re starting from scratch and need a composer.json file, download the files using the link in the code editor.
Install the library:
Or download the stripe-php library source code directly
[from GitHub](https://github.com/stripe/stripe-php).
### Set up your server
Add the dependency to your build and import the library. Alternatively, if you’re starting from scratch and need a go.mod file, download the project files using the link in the code editor.
Make sure to initialize with Go Modules:
Or download the stripe-go module source code directly
[from GitHub](https://github.com/stripe/stripe-go).
### Install the Stripe.net library
Install the package with .NET or NuGet. Alternatively, if you’re starting from scratch, download the files which contains a configured .csproj file.
Install the library:
Install the library:
Or download the Stripe.net library source code directly
[from GitHub](https://github.com/stripe/stripe-dotnet).
### Install the Stripe libraries
Install the packages and import them in your code. Alternatively, if you’re starting from scratch and need a `package.json` file, download the project files using the link in the code editor.
Install the libraries:
### Create a Checkout Session
The [Checkout Session](https://docs.stripe.com/api/checkout/sessions.md) controls what your customer sees in the Stripe-hosted payment page such as line items, the order amount and currency, and acceptable payment methods.
### Get the price from lookup key
Pass the lookup key you defined for your product in the [Price](https://docs.stripe.com/api/prices/list.md) endpoint to apply its price to the order.
### Define the line items
Always keep sensitive information about your product inventory, such as price and availability, on your server to prevent customer manipulation from the client. Pass in the predefined price ID retrieved above.
### Set the mode
Set the mode to `subscription`. Checkout also supports [payment](https://docs.stripe.com/checkout/quickstart.md) and [setup](https://docs.stripe.com/payments/save-and-reuse.md) modes for non-recurring payments.
### Supply success and cancel URLs
Specify publicly accessible URLs that Stripe can redirect customers after success or cancellation. You can provide the same URL for both properties. Add the `session_id` query parameter at the end of your URL so you can retrieve the customer later and so Stripe can generate the customer’s hosted Dashboard.
### Redirect from Checkout
After creating the session, redirect your customer to the URL returned in the response (either the success or cancel URL).
### Create a customer portal session
Initiate a secure, Stripe-hosted [customer portal session](https://docs.stripe.com/api/customer_portal/sessions/create.md) that lets your customers manage their subscriptions and billing details.
### Redirect to customer portal
After creating the portal session, redirect your customer to the URL returned in the response.
### Fulfill the subscription
Create a `/webhook` endpoint and obtain your webhook secret key in the [Webhooks](https://dashboard.stripe.com/webhooks) tab in Workbench to listen for events related to subscription activity. After a successful payment and redirect to the success page, verify that the subscription status is `active` and grant your customer access to the products and features they subscribed to.
### Run the server
Start your server and navigate to [http://localhost:4242/](http://localhost:4242/)
### Run the server
Start your server. It automatically opens a browser window to [http://localhost:3000/checkout](http://localhost:3000/checkout)
### Run the server
Start your server and navigate to [http://localhost:4242/](http://localhost:4242/)
### Run the server
Start your server. It automatically opens a browser window to [http://localhost:3000/checkout](http://localhost:3000/checkout)
### Run the server
Start your server and navigate to [http://localhost:4242/](http://localhost:4242/)
### Run the server
Start your server. It automatically opens a browser window to [http://localhost:3000/checkout](http://localhost:3000/checkout)
### Run the server
Start your server and navigate to [http://localhost:4242/](http://localhost:4242/)
### Run the server
Start your server. It automatically opens a browser window to [http://localhost:3000/checkout](http://localhost:3000/checkout)
### Run the server
Start your server and navigate to [http://localhost:4242/](http://localhost:4242/)
### Run the server
Start your server. It automatically opens a browser window to [http://localhost:3000/checkout](http://localhost:3000/checkout)
### Run the server
Start your server and navigate to [http://localhost:4242/](http://localhost:4242/)
### Run the server
Start your server. It automatically opens a browser window to [http://localhost:3000/checkout](http://localhost:3000/checkout)
### Run the server
Start your server and navigate to [http://localhost:4242/](http://localhost:4242/)
### Run the server
Start your server. It automatically opens a browser window to [http://localhost:3000/checkout](http://localhost:3000/checkout)
### Try it out
Click the checkout button. In the Stripe Checkout page, use any of these test cards to simulate a payment.
| Scenario | Card Number |
| ------------------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment requires authentication | 4000002500003155 |
| Payment is declined | 4000000000009995 |
## Add customization features
If you successfully subscribed to your product in your test, you have a working, basic subscriptions checkout integration. Use the toggles below to see how to customize this sample with additional features.
### Add trials
Attach a trial period to a Checkout session.
### Add a trial period
Use `subscription_data` to add an integer representing the number of `trial_period_days` before charging the customer for the first time. This must be at least `1`.
If you start a free trial without a payment method, set the `trial_settings[end_behavior][missing_payment_method]` field to `pause` or `cancel` so the subscription doesn’t continue if the trial ends with no payment method. Pass this parameter into `subscription_data` when you create a Checkout session, or update it on the subscription at another time. See [Use trial periods](https://docs.stripe.com/billing/subscriptions/trials.md#create-free-trials-without-payment) for more information.
### Set billing cycle date
Specify a billing cycle anchor when creating a Checkout session.
### Anchor the subscription billing cycle
Use `subscription_data` to set a `billing_cycle_anchor` timestamp for a subscription’s next billing date. See [Setting the billing cycle date in Checkout](https://docs.stripe.com/payments/checkout/billing-cycle.md) for more information.
### Automate tax collection
Calculate and collect the right amount of tax on your Stripe transactions. Learn more about [Stripe Tax](https://docs.stripe.com/tax.md) and [how to add it to Checkout](https://docs.stripe.com/tax/checkout.md). [Activate Stripe Tax](https://dashboard.stripe.com/tax) in the Dashboard before integrating.
### Add the automatic tax parameter
Set the `automatic_tax` parameter to `enabled: true`.
```html
Subscribe to a cool new product
Starter plan
$20.00 / month
```
```html
Thanks for your order!
Subscription to Starter plan successful!
```
```html
Checkout canceled
Picked the wrong subscription? Shop around then come back to pay!
);
export default function App() {
let [message, setMessage] = useState('');
let [success, setSuccess] = useState(false);
let [sessionId, setSessionId] = useState('');
useEffect(() => {
// Check to see if this is a redirect back from Checkout
const query = new URLSearchParams(window.location.search);
if (query.get('success')) {
setSuccess(true);
setSessionId(query.get('session_id'));
}
if (query.get('canceled')) {
setSuccess(false);
setMessage(
"Order canceled -- continue to shop around and checkout when you're ready."
);
}
}, [sessionId]);
if (!success && message === '') {
return ;
} else if (success && sessionId !== '') {
return ;
} else {
return ;
}
}
const Logo = () => (
);
```
```json
{
"name": "stripe-sample",
"version": "0.1.0",
"dependencies": {
"@stripe/react-stripe-js": "^3.5.1",
"@stripe/stripe-js": "^6.1.0",
"express": "^4.17.1",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-scripts": "^3.4.0",
"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.5.1",
"@stripe/stripe-js": "^6.1.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-scripts": "^3.4.0"
},
"homepage": "http://localhost:3000/checkout",
"proxy": "http://localhost: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"
]
}
}
```
```css
body {
display: flex;
justify-content: center;
align-items: center;
background: #242d60;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
'Helvetica Neue', 'Ubuntu', sans-serif;
height: 100vh;
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
section {
background: #ffffff;
display: flex;
flex-direction: column;
width: 400px;
height: 112px;
border-radius: 6px;
justify-content: space-between;
}
.product {
display: flex;
flex: 1;
}
.description {
display: flex;
flex-direction: column;
justify-content: center;
}
p {
font-style: normal;
font-weight: 500;
font-size: 14px;
line-height: 20px;
letter-spacing: -0.154px;
color: #242d60;
height: 100%;
width: 100%;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
img, svg {
border-radius: 6px;
margin: 10px;
width: 54px;
height: 57px;
}
h3,
h5 {
font-style: normal;
font-weight: 500;
font-size: 14px;
line-height: 20px;
letter-spacing: -0.154px;
color: #242d60;
margin: 0;
}
h5 {
opacity: 0.5;
}
button {
height: 36px;
background: #556cd6;
color: white;
width: 100%;
font-size: 14px;
border: 0;
font-weight: 500;
cursor: pointer;
letter-spacing: 0.6;
border-radius: 0 0 6px 6px;
transition: all 0.2s ease;
box-shadow: 0px 4px 5.5px 0px rgba(0, 0, 0, 0.07);
}
button:hover {
opacity: 0.8;
}
```
```javascript
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(, document.getElementById("root"));
```
```html
Stripe sample
```
```javascript
const stripe = require('stripe')('<>');
const express = require('express');
const app = express();
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const YOUR_DOMAIN = 'http://localhost:4242';
app.post('/create-checkout-session', async (req, res) => {
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 metered billing, do not pass quantity
quantity: 1,
},
],
mode: 'subscription',
success_url: `${YOUR_DOMAIN}/success.html?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${YOUR_DOMAIN}/cancel.html`,
success_url: `${YOUR_DOMAIN}/?success=true&session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${YOUR_DOMAIN}?canceled=true`,
discounts: [{
coupon: '{{COUPON_ID}}',
}],
customer: 'cus_123',
subscription_data: {
trial_period_days: 7,
},
subscription_data: {
billing_cycle_anchor: 1672531200,
},
automatic_tax: { enabled: true },
});
res.redirect(303, session.url);
});
app.post('/create-portal-session', async (req, res) => {
// For demonstration purposes, we're using the Checkout session to retrieve the customer ID.
// Typically this is stored alongside the authenticated user in your database.
const { session_id } = req.body;
const checkoutSession = await stripe.checkout.sessions.retrieve(session_id);
// 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,
});
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();
}
);
app.listen(4242, () => console.log('Running on port 4242'));
```
```json
{
"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": "^8.202.0"
}
}
{
"name": "stripe-sample",
"version": "0.1.0",
"dependencies": {
"@stripe/react-stripe-js": "^1.0.0",
"@stripe/stripe-js": "^1.0.0",
"concurrently": "^6.2.1",
"express": "^4.17.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "^4.0.3",
"stripe": "^8.202.0"
},
"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"
]
}
}
```
```ruby
require 'stripe'
require 'sinatra'
Stripe.api_key = '<>'
set :static, true
set :port, 4242
YOUR_DOMAIN = 'http://localhost:4242'
post '/create-checkout-session' do
prices = Stripe::Price.list(
lookup_keys: [params['lookup_key']],
expand: ['data.product']
)
begin
session = Stripe::Checkout::Session.create({
mode: 'subscription',
line_items: [{
quantity: 1,
price: prices.data[0].id
}],
success_url: YOUR_DOMAIN + '/success.html?session_id={CHECKOUT_SESSION_ID}',
cancel_url: YOUR_DOMAIN + '/cancel.html',
success_url: YOUR_DOMAIN + '?success=true&session_id={CHECKOUT_SESSION_ID}',
cancel_url: YOUR_DOMAIN + '?canceled=true',
subscription_data: {
trial_period_days: 7
},
subscription_data: {
billing_cycle_anchor: 1672531200
},
customer: 'cus_JyTTNqVDAoRYE1',
discounts: [{
coupon: 'gBY6sFUf'
}]
automatic_tax: {
enabled: true
},
})
rescue StandardError => e
halt 400,
{ 'Content-Type' => 'application/json' },
{ 'error': { message: e.error.message } }.to_json
end
redirect session.url, 303
end
post '/create-portal-session' do
content_type 'application/json'
# For demonstration purposes, we're using the Checkout session to retrieve the customer ID.
# Typically this is stored alongside the authenticated user in your database.
checkout_session_id = params['session_id']
checkout_session = Stripe::Checkout::Session.retrieve(checkout_session_id)
# This is the URL to which users will be redirected after they're done
# managing their billing.
return_url = YOUR_DOMAIN
session = Stripe::BillingPortal::Session.create({
customer: checkout_session.customer,
return_url: return_url
})
redirect session.url, 303
end
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
```
```
source 'https://rubygems.org/'
gem 'sinatra'
gem 'stripe'
```
```python
\#! /usr/bin/env python3.6
"""
server.py
Stripe Sample.
Python 3.6 or newer required.
"""
import os
from flask import Flask, redirect, jsonify, json, request, current_app
import stripe
stripe.api_key = '<>'
app = Flask(__name__,
static_url_path='',
static_folder='public')
YOUR_DOMAIN = 'http://localhost:4242'
@app.route('/', methods=['GET'])
def get_index():
return current_app.send_static_file('index.html')
@app.route('/create-checkout-session', methods=['POST'])
def create_checkout_session():
try:
prices = stripe.Price.list(
lookup_keys=[request.form['lookup_key']],
expand=['data.product']
)
checkout_session = stripe.checkout.Session.create(
line_items=[
{
'price': prices.data[0].id,
'quantity': 1,
},
],
mode='subscription',
success_url=YOUR_DOMAIN +
'/success.html?session_id={CHECKOUT_SESSION_ID}',
cancel_url=YOUR_DOMAIN + '/cancel.html',
success_url=YOUR_DOMAIN +
'?success=true&session_id={CHECKOUT_SESSION_ID}',
cancel_url=YOUR_DOMAIN + '?canceled=true',
subscription_data={
'trial_period_days': 7
},
subscription_data={
'billing-cycle-anchor': 1672531200
},
discounts=[
{
'coupon': '{{COUPON_ID}}'
}
],
customer='cus_123',
automatic_tax={
'enabled': True
},
)
return redirect(checkout_session.url, code=303)
except Exception as e:
print(e)
return "Server error", 500
@app.route('/create-portal-session', methods=['POST'])
def customer_portal():
# For demonstration purposes, we're using the Checkout session to retrieve the customer ID.
# Typically this is stored alongside the authenticated user in your database.
checkout_session_id = request.form.get('session_id')
checkout_session = stripe.checkout.Session.retrieve(checkout_session_id)
# This is the URL to which the customer will be redirected after they're
# done managing their billing with the portal.
return_url = YOUR_DOMAIN
portalSession = stripe.billing_portal.Session.create(
customer=checkout_session.customer,
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 = stripe.Webhook.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'})
if __name__ == '__main__':
app.run(port=4242)
```
```
blinker==1.8.2
certifi==2024.8.30
charset-normalizer==3.4.0
click==8.1.7
Flask==3.0.3
idna==3.10
itsdangerous==2.2.0
Jinja2==3.1.4
MarkupSafe==3.0.1
requests==2.32.3
stripe==11.1.0
typing_extensions==4.12.2
urllib3==2.2.3
Werkzeug==3.0.4
```
```php
$checkout_session->customer,
'return_url' => $return_url,
]);
header("HTTP/1.1 303 See Other");
header("Location: " . $session->url);
} catch (Error $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
```
```php
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';
}
```
```php
>';
```
```php
[$_POST['lookup_key']],
'expand' => ['data.product']
]);
$checkout_session = \Stripe\Checkout\Session::create([
'line_items' => [[
'price' => $prices->data[0]->id,
'quantity' => 1,
]],
'mode' => 'subscription',
'success_url' => $YOUR_DOMAIN . '/success.html?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => $YOUR_DOMAIN . '/cancel.html',
'success_url' => $YOUR_DOMAIN . '?success=true&session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => $YOUR_DOMAIN . '?canceled=true',
'subscription_data' => [
'trial_period_days' => 7,
],
'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);
} catch (Error $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
```
```json
{
"require": {
"stripe/stripe-php": "^7.56.0"
}
}
```
```csharp
using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Stripe;
using Stripe.Checkout;
public class StripeOptions
{
public string option { get; set; }
}
namespace server.Controllers
{
public class Program
{
public static void Main(string[] args)
{
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://0.0.0.0:4242")
.UseWebRoot("public")
.UseStartup()
.Build()
.Run();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddNewtonsoftJson();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
StripeConfiguration.ApiKey = "<>";
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
app.UseRouting();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseEndpoints(endpoints => endpoints.MapControllers());
}
}
[Route("create-checkout-session")]
[ApiController]
public class CheckoutApiController : Controller
{
[HttpPost]
public ActionResult Create()
{
var domain = "http://localhost:4242";
var priceOptions = new PriceListOptions
{
LookupKeys = new List {
Request.Form["lookup_key"]
}
};
var priceService = new PriceService();
StripeList prices = priceService.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}",
CancelUrl = domain + "/cancel.html",
SuccessUrl = domain + "?success=true&session_id={CHECKOUT_SESSION_ID}",
CancelUrl = domain + "?canceled=true",
SubscriptionData = new SessionSubscriptionDataOptions
{
TrialPeriodDays = 7,
},
SubscriptionData = new SessionSubscriptionDataOptions
{
BillingCycleAnchor = 1672531200,
},
AutomaticTax = new SessionAutomaticTaxOptions { Enabled = true },
Customer = "cus_123",
};
var service = new SessionService();
Session session = service.Create(options);
Response.Headers.Add("Location", session.Url);
return new StatusCodeResult(303);
}
}
[Route("create-portal-session")]
[ApiController]
public class PortalApiController : Controller
{
[HttpPost]
public ActionResult Create()
{
// For demonstration purposes, we're using the Checkout session to retrieve the customer ID.
// Typically this is stored alongside the authenticated user in your database.
var checkoutService = new SessionService();
var checkoutSession = checkoutService.Get(Request.Form["session_id"]);
// This is the URL to which your customer will return after
// they're done managing billing in the Customer Portal.
var returnUrl = "http://localhost:4242";
var options = new Stripe.BillingPortal.SessionCreateOptions
{
Customer = checkoutSession.CustomerId,
ReturnUrl = returnUrl,
};
var service = new Stripe.BillingPortal.SessionService();
var session = service.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();
}
}
}
}
```
```xml
net8.0StripeExample
```
```go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"github.com/stripe/stripe-go/v82"
portalsession "github.com/stripe/stripe-go/v82/billingportal/session"
"github.com/stripe/stripe-go/v82/checkout/session"
"github.com/stripe/stripe-go/v82/price"
"github.com/stripe/stripe-go/v82/webhook"
)
func main() {
stripe.Key = "<>"
http.Handle("/", http.FileServer(http.Dir("public")))
http.HandleFunc("/create-checkout-session", createCheckoutSession)
http.HandleFunc("/create-portal-session", createPortalSession)
http.HandleFunc("/webhook", handleWebhook)
addr := "localhost:4242"
log.Printf("Listening on %s", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
func createCheckoutSession(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
r.ParseForm()
lookup_key := r.PostFormValue("lookup_key")
domain := "http://localhost:4242"
params := &stripe.PriceListParams{
LookupKeys: stripe.StringSlice([]string{
lookup_key,
}),
}
i := price.List(params)
if !i.Front() {
log.Printf(">>>>>>>>>>>>>>>>>>>>>>>>>>> Add a price lookup key to checkout.html line 27 for the demo <<<<<<<<<<<<<<<<<<<<<<<<")
}
var price *stripe.Price
for i.Next() {
p := i.Price()
price = p
}
checkoutParams := &stripe.CheckoutSessionParams{
Mode: stripe.String(string(stripe.CheckoutSessionModeSubscription)),
LineItems: []*stripe.CheckoutSessionLineItemParams{
&stripe.CheckoutSessionLineItemParams{
Price: stripe.String(price.ID),
Quantity: stripe.Int64(1),
},
},
SubscriptionData: &stripe.CheckoutSessionSubscriptionDataParams{
TrialPeriodDays: stripe.Int64(7),
},
SubscriptionData: &stripe.CheckoutSessionSubscriptionDataParams{
BillingCycleAnchor: stripe.Int64(1672531200),
},
Discounts: []*stripe.CheckoutSessionDiscountParams{
&stripe.CheckoutSessionDiscountParams{
Coupon: stripe.String("gBY6sFUf"),
},
},
SuccessURL: stripe.String(domain + "/success.html?session_id={CHECKOUT_SESSION_ID}"),
CancelURL: stripe.String(domain + "/cancel.html"),
SuccessURL: stripe.String(domain + "?success=true&session_id={CHECKOUT_SESSION_ID}"),
CancelURL: stripe.String(domain + "?canceled=true"),
AutomaticTax: &stripe.CheckoutSessionAutomaticTaxParams{Enabled: stripe.Bool(true)},
}
s, err := session.New(checkoutParams)
if err != nil {
log.Printf("session.New: %v", err)
}
http.Redirect(w, r, s.URL, http.StatusSeeOther)
}
func createPortalSession(w http.ResponseWriter, r *http.Request) {
domain := "http://localhost:4242"
// For demonstration purposes, we're using the Checkout session to retrieve the customer ID.
// Typically this is stored alongside the authenticated user in your database.
r.ParseForm()
sessionId := r.PostFormValue("session_id")
fmt.Print(sessionId)
s, err := session.Get(sessionId, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("session.Get: %v", err)
return
}
// Authenticate your user.
params := &stripe.BillingPortalSessionParams{
Customer: stripe.String(s.Customer.ID),
ReturnURL: stripe.String(domain),
}
ps, _ := portalsession.New(params)
log.Printf("ps.New: %v", ps.URL)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("ps.New: %v", err)
return
}
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 := webhook.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)
}
func writeJSON(w http.ResponseWriter, v interface{}) {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(v); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("json.NewEncoder.Encode: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
if _, err := io.Copy(w, &buf); err != nil {
log.Printf("io.Copy: %v", err)
return
}
}
```
```
module stripe.com/docs/payments/checkout
go 1.13
require github.com/stripe/stripe-go/v82 v82.0.0
```
```java
package com.stripe.sample;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import static spark.Spark.post;
import static spark.Spark.port;
import static spark.Spark.staticFiles;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.google.gson.JsonSyntaxException;
import com.stripe.Stripe;
import com.stripe.net.ApiResource;
import com.stripe.model.Event;
import com.stripe.model.EventDataObjectDeserializer;
import com.stripe.exception.SignatureVerificationException;
import com.stripe.net.Webhook;
import com.stripe.model.StripeObject;
import com.stripe.model.checkout.Session;
import com.stripe.param.checkout.SessionCreateParams;
import com.stripe.model.Price;
import com.stripe.param.PriceListParams;
import com.stripe.model.PriceCollection;
import com.stripe.model.Discount;
import com.stripe.model.Subscription;
public class Server {
private static Gson gson = new Gson();
public static void main(String[] args) {
port(4242);
Stripe.apiKey = "<>";
// 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
String endpointSecret = "whsec_12345";
final String YOUR_DOMAIN = "http://localhost:4242";
staticFiles.externalLocation(Paths.get("public").toAbsolutePath().toString());
post("/create-checkout-session", (request, response) -> {
PriceListParams priceParams = PriceListParams.builder().addLookupKeys(request.queryParams("lookup_key")).build();
PriceCollection prices = Price.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}")
.setCancelUrl(YOUR_DOMAIN + "/cancel.html")
.setSuccessUrl(YOUR_DOMAIN + "?success=true&session_id={CHECKOUT_SESSION_ID}")
.setCancelUrl(YOUR_DOMAIN + "?canceled=true")
.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setTrialPeriodDays(7L).build())
.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setBillingCycleAnchor(1672531200).build())
.addDiscount(SessionCreateParams.Discount.builder().setCoupon("{{COUPON_ID}}").build())
.setCustomer("cus_JyTTNqVDAoRYE1")
.setAutomaticTax(
SessionCreateParams.AutomaticTax.builder()
.setEnabled(true)
.build())
.build();
Session session = Session.create(params);
response.redirect(session.getUrl(), 303);
return "";
});
post("/create-portal-session", (request, response) -> {
// For demonstration purposes, we're using the Checkout session to retrieve the
// customer ID.
// Typically this is stored alongside the authenticated user in your database.
// Deserialize request from our front end.
Session checkoutSession = Session.retrieve(request.queryParams("session_id"));
// Authenticate your user.
com.stripe.param.billingportal.SessionCreateParams params = new com.stripe.param.billingportal.SessionCreateParams.Builder()
.setReturnUrl(YOUR_DOMAIN).setCustomer(checkoutSession.getCustomer()).build();
com.stripe.model.billingportal.Session portalSession = com.stripe.model.billingportal.Session.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 = Webhook.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 "";
});
}
}
```
```xml
4.0.0com.stripe.samplestripe-payment1.0.0-SNAPSHOTorg.slf4jslf4j-simple2.0.3com.sparkjavaspark-core2.9.4com.google.code.gsongson2.9.1org.projectlomboklombok1.18.20providedcom.stripestripe-java22.5.1sampleorg.apache.maven.pluginsmaven-compiler-plugin3.10.11.81.8maven-assembly-pluginpackagesinglejar-with-dependenciesServer
```
```md
\# Prebuilt checkout page with subscriptions
Explore a full, working code sample of an integration with Stripe Checkout and the customer portal. The client- and server-side code redirects to a prebuilt payment page hosted on Stripe. Included are some basic build and run scripts you can use to start up the application.
## Running the sample
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)
```
## See Also
#### [Update subscription prices](https://docs.stripe.com/billing/subscriptions/change-price.md)
Update subscriptions to handle customers upgrading or downgrading their subscription plan.
#### [Apply prorations](https://docs.stripe.com/billing/subscriptions/prorations.md)
Learn how to adjust a customer’s invoice to accurately reflect mid-cycle pricing changes.
#### [Offer upsells](https://docs.stripe.com/payments/checkout/upsells.md)
Incentivize customers with discounts for committing to longer billing intervals.
#### [More features](https://docs.stripe.com/billing/subscriptions/features.md)
Review the features to further customize your integration to offer discounts, pause payment collection, and more.