Creating Checkout Session — Accept Payments with Stripe Checkout
In this tutorial, you will learn about Creating Checkout Session. We cover key concepts, practical examples, and best practices to help you master this topic.
Stripe Checkout Session is a hosted payment page that handles the entire checkout flow, redirecting customers to Stripe's PCI-compliant page and back to your site after payment.
What You'll Learn
By the end of this lesson you will understand how to create Checkout Sessions, configure products and prices, handle payment success and cancellation, and customize the checkout experience.
Why It Matters
Building a payment form that handles cards, digital wallets, international payment methods, and PCI Compliance is extremely complex. Checkout Session handles all of this with a single API call.
Real-World Use
DodaZIP uses Checkout Sessions for all subscription payments. Users click "Subscribe" on the website, get redirected to Stripe's hosted page, enter payment details on Stripe's servers, and return to DodaZIP after payment.
flowchart LR
U[User] --> B[Backend: Create Session]
B --> S[Stripe: Checkout Session]
S --> U[Redirect to Checkout]
U --> P[Pay on Stripe Page]
P --> SUC[/success URL]
P --> CAN[/cancel URL]
S --> W[Webhook: confirm]
style S fill:#6772e5,color:#fff
Creating a Checkout Session
The server creates a Checkout Session with line items, mode, and URLs. Stripe returns a URL to redirect the customer.
import stripe
import os
stripe.api_key = os.environ.get("STRIPE_SECRET_KEY", "sk_test_placeholder")
def create_checkout_session(price_id, customer_email=None):
session = stripe.checkout.Session.create(
line_items=[{"price": price_id, "quantity": 1}],
mode="payment",
success_url="https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url="https://example.com/cancel",
customer_email=customer_email,
)
return session.url
os.environ["STRIPE_SECRET_KEY"] = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
stripe.api_key = "sk_test_placeholder"
class MockSession:
url = "https://checkout.stripe.com/c/pay/cs_test_abc123"
stripe.checkout.Session.create = lambda **kwargs: MockSession()
url = create_checkout_session("price_1QqXxY", "alice@example.com")
print(f"Redirect customer to: {url}")
Expected output:
Redirect customer to: https://checkout.stripe.com/c/pay/cs_test_abc123
One-Time vs Recurring
Set mode to payment for one-time purchases or subscription for recurring payments.
# session_modes.py
# One-time vs subscription sessions
def create_one_time_session(price_id):
print("Creating one-time payment session...")
session = {
"url": f"https://checkout.stripe.com/pay/cs_test_one_time",
"mode": "payment",
"amount": 1999,
"currency": "usd"
}
print(f" Mode: {session['mode']}")
print(f" Amount: ${session['amount'] / 100:.2f}")
return session
def create_subscription_session(price_id):
print("Creating subscription session...")
session = {
"url": f"https://checkout.stripe.com/pay/cs_test_sub",
"mode": "subscription",
"amount": 1999,
"currency": "usd",
"interval": "month"
}
print(f" Mode: {session['mode']}")
print(f" Amount: ${session['amount'] / 100:.2f}/{session['interval']}")
return session
create_one_time_session("price_1")
print()
create_subscription_session("price_2")
Customizing Checkout
Add custom fields, promo codes, tax IDs, and shipping address collection.
# customize_checkout.py
# Checkout Session customization
def create_customized_session():
print("Creating customized checkout session...")
session_config = {
"line_items": [{"price": "price_1", "quantity": 1}],
"mode": "payment",
"success_url": "https://example.com/success",
"cancel_url": "https://example.com/cancel",
"customer_creation": "always",
"payment_method_types": ["card", "ideal", "sepa_debit"],
"shipping_address_collection": {"allowed_countries": ["US", "CA", "GB"]},
"phone_number_collection": {"enabled": True},
"allow_promotion_codes": True,
"tax_id_collection": {"enabled": True},
"custom_fields": [
{"key": "gift_note", "label": {"type": "custom", "custom": "Gift Note"}, "type": "text"}
]
}
for key, value in session_config.items():
print(f" {key}: {value}")
return "https://checkout.stripe.com/c/pay/cs_test_custom"
print(f"Session URL: {create_customized_session()}")
Common Mistakes
Not using HTTPS for success/cancel URLs: Stripe requires HTTPS URLs for live mode. HTTP URLs work only in test mode.
Storing price amounts instead of price IDs: Always reference Stripe Price IDs. Hardcoding amounts breaks when prices change.
Forgetting to include the session_id parameter: The success URL should include CHECKOUT_SESSION_ID for post-purchase processing.
Not handling the cancel case gracefully: The cancel URL should return users to your site, not leave them on Stripe's page.
Setting mode incorrectly: Using mode=payment for a recurring product causes an error. Match the mode to the price type.
Practice Questions
What is a Checkout Session? A Stripe-hosted payment page that handles the entire checkout flow and redirects back to your site.
What is the difference between mode=payment and mode=subscription? Payment processes a one-time charge. Subscription creates a recurring payment schedule.
How do you pass customer information to Checkout? Use the customer_email parameter, or create a Customer first and pass customer ID.
Why does the success URL include CHECKOUT_SESSION_ID? So your frontend can notify your backend which session completed for post-purchase actions.
Challenge: Create a Checkout Session for a SaaS product with a 14-day free trial, monthly subscription, and promo code support.
FAQ
Mini Project
Create a Checkout Session endpoint in Python that accepts a price ID and customer email, creates the session, and returns the checkout URL.
import json
def create_checkout_endpoint(event, context):
body = json.loads(event.get("body", "{}"))
price_id = body.get("price_id")
email = body.get("email")
if not price_id:
return {"statusCode": 400, "body": json.dumps({"error": "price_id required"})}
session_url = f"https://checkout.stripe.com/pay/cs_test_{price_id}"
return {
"statusCode": 200,
"body": json.dumps({
"url": session_url,
"price_id": price_id,
"customer_email": email
})
}
event = {"body": json.dumps({"price_id": "price_1QqXxY", "email": "alice@example.com"})}
print(json.loads(create_checkout_endpoint(event, None)["body"]))
What's Next
Next: Payment Intents for custom payment flows.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro