Comprehensive Python examples showing how to use Stripe for payments, subscriptions, invoicing, webhooks, and more. All code uses the official Stripe Python SDK.


Table of Contents


Setup

  1. Create a Stripe account
    Sign up at dashboard.stripe.com.

  2. Install dependencies

pip install -r requirements.txt

This installs: - stripe – official Stripe Python library - flask – optional, for the webhook server example - python-dotenv – optional, for loading .env

  1. Get your API keys
    In Developers → API keys: - Secret key (sk_test_... or sk_live_...) – used only on the server - Publishable key (pk_test_... or pk_live_...) – safe to use in browsers/apps

Use test keys while developing; they never move real money.


Configuration

Set your keys via environment variables or a .env file in the project root:

# .env (do not commit; add to .gitignore)
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxx
STRIPE_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxx

# Optional: for webhook signature verification (from Stripe CLI or Dashboard)
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx

# Optional: URLs for Checkout / Payment Links
SUCCESS_URL=https://yoursite.com/success
CANCEL_URL=https://yoursite.com/cancel
  • STRIPE_SECRET_KEY – Required for all server-side examples.
  • STRIPE_PUBLISHABLE_KEY – Used by frontend (Stripe.js, mobile SDKs); examples don’t call it directly.
  • STRIPE_WEBHOOK_SECRET – Required to verify webhook events (see Webhooks).

Project Structure

stripe_demo/
├── README.md                 # This file
├── requirements.txt         # Python dependencies
├── config.py                # Loads STRIPE_SECRET_KEY, etc.
├── run_examples.py           # Run selected examples
└── examples/
    ├── 00_error_handling.py  # How to catch Stripe errors
    ├── 01_customers.py       # Customers CRUD
    ├── 02_products_prices.py  # Products and Prices catalog
    ├── 03_payment_intents.py # One-time payments (Payment Intents)
    ├── 04_checkout_sessions.py # Hosted Checkout (payment / subscription / setup)
    ├── 05_subscriptions.py   # Subscriptions, items, schedules
    ├── 06_invoices.py       # Invoices and invoice items
    ├── 07_refunds.py        # Refunds
    ├── 08_coupons_promotion_codes.py # Coupons and promotion codes
    ├── 09_payment_links.py   # Payment Links (no-code style)
    ├── 10_webhooks.py        # Webhook verification and handling
    ├── 11_setup_intents.py   # Save payment method without charging
    ├── 12_balance_and_events.py # Balance, balance transactions, events
    ├── 13_customer_portal.py # Billing portal for customers
    ├── 14_payment_methods.py # List/attach/detach payment methods
    ├── 15_tax_rates.py       # Tax rates for invoices/checkout
    └── flask_webhook_server.py # Minimal Flask webhook server

Examples Overview

File What it demonstrates
00_error_handling Catching CardError, InvalidRequestError, etc.
01_customers Create, retrieve, update, list, delete, search customers
02_products_prices Products, one-time and recurring prices
03_payment_intents Create/confirm/cancel PaymentIntents for one-time payments
04_checkout_sessions Hosted Checkout for payment, subscription, or setup
05_subscriptions Create/cancel subscriptions, add/update items, schedules
06_invoices Draft invoices, line items, finalize, send, pay
07_refunds Full and partial refunds by charge or PaymentIntent
08_coupons_promotion_codes Percent/amount-off coupons and promotion codes
09_payment_links One-time and subscription Payment Links
10_webhooks Verify signature and handle event types
11_setup_intents Save a card for later (no charge)
12_balance_and_events Balance, balance transactions, events list
13_customer_portal Billing portal session and configuration
14_payment_methods List/attach/detach, set default payment method
15_tax_rates Create and use tax rates
flask_webhook_server Minimal Flask app that receives Stripe webhooks

Running Examples

Ensure STRIPE_SECRET_KEY is set, then:

# Run a specific example by number (e.g. customers)
python run_examples.py 01

# Run customers + products/prices (default)
python run_examples.py

# Run an example file directly
python examples/01_customers.py
python examples/03_payment_intents.py

Or from the examples/ directory:

cd examples
python 01_customers.py

Each file’s if __name__ == "__main__": block shows a small flow (create, retrieve, list, etc.). Edit IDs (e.g. customer_id, price_id) to match your Stripe test data.


Stripe Concepts

Customers

  • Represent buyers in your system.
  • Store email, name, address, and payment methods.
  • Required for subscriptions and for “charge saved card” flows.
  • Create with stripe.Customer.create(email=..., name=...).

Products & Prices

  • Product = what you sell (e.g. “Pro Plan”, “T‑shirt”).
  • Price = how much and how often: one-time or recurring (e.g. $10/month).
  • One product can have many prices. Checkout and Payment Links use Price IDs (price_xxx).

Payment Intents

  • Model a single payment (card, etc.) and its lifecycle.
  • You create a PaymentIntent on the server, then the frontend uses client_secret with Stripe.js or Mobile SDKs to confirm.
  • Status flow: requires_payment_method → requires_confirmation → requires_action (e.g. 3DS) → succeeded (or requires_capture for manual capture).

Checkout Sessions

  • Hosted payment pages. You create a session with line_items, success_url, cancel_url; Stripe returns a url to redirect the customer.
  • Modes: payment (one-time), subscription, setup (save card only).
  • No need to build your own payment form; Stripe hosts it.

Subscriptions

  • Recurring billing tied to a Customer and one or more Prices (recurring).
  • Create with stripe.Subscription.create(customer=..., items=[{"price": "price_xxx", "quantity": 1}]).
  • Stripe creates Invoices and PaymentIntents for each billing cycle.

Invoices

  • Invoices can be created by subscriptions (automatic) or manually.
  • For manual: create a draft, add line items with stripe.InvoiceItem.create(...), then stripe.Invoice.finalize_invoice(...) and optionally stripe.Invoice.send_invoice(...).

Webhooks

  • Stripe sends events (e.g. payment_intent.succeeded, customer.subscription.deleted) to your endpoint via HTTP POST.
  • You must verify the signature using Stripe-Signature and your webhook secret, then handle event.type and event.data.object.

Idempotency

  • For create/update operations that change money or state, send an Idempotency-Key header (unique value per “logical” request) so retries don’t double-charge. The Python SDK can accept idempotency_key='...' on create/update calls.

API Quick Reference

All examples use the same pattern: stripe.api_key = STRIPE_SECRET_KEY (or set via config), then call the resource.

Resource Create Retrieve List Update Delete / Cancel
Customers stripe.Customer.create(...) stripe.Customer.retrieve(id) stripe.Customer.list(...) stripe.Customer.modify(id, ...) stripe.Customer.delete(id)
Products stripe.Product.create(...) stripe.Product.retrieve(id) stripe.Product.list(...) stripe.Product.modify(id, ...) —
Prices stripe.Price.create(...) stripe.Price.retrieve(id) stripe.Price.list(...) stripe.Price.modify(id, ...) —
PaymentIntents stripe.PaymentIntent.create(...) stripe.PaymentIntent.retrieve(id) stripe.PaymentIntent.list(...) stripe.PaymentIntent.modify(id, ...) stripe.PaymentIntent.cancel(id)
Checkout Sessions stripe.checkout.Session.create(...) stripe.checkout.Session.retrieve(id) stripe.checkout.Session.list(...) stripe.checkout.Session.modify(id, ...) stripe.checkout.Session.expire(id)
Subscriptions stripe.Subscription.create(...) stripe.Subscription.retrieve(id) stripe.Subscription.list(...) stripe.Subscription.modify(id, ...) stripe.Subscription.delete(id) or modify(..., cancel_at_period_end=True)
Invoices stripe.Invoice.create(...) stripe.Invoice.retrieve(id) stripe.Invoice.list(...) — stripe.Invoice.void_invoice(id)
Refunds stripe.Refund.create(...) stripe.Refund.retrieve(id) stripe.Refund.list(...) stripe.Refund.modify(id, ...) stripe.Refund.cancel(id) (pending only)

Amounts in the API are in the smallest currency unit (e.g. cents for USD). So $19.99 = 1999.


Testing

  • Use test keys (sk_test_..., pk_test_...) so no real charges occur.
  • Test cards: Stripe test cards, e.g. 4242 4242 4242 4242 for success.
  • Trigger test events: Stripe CLI – e.g. stripe trigger payment_intent.succeeded.
  • Forward webhooks to your machine: stripe listen --forward-to localhost:4242/webhook (use the printed webhook secret in .env as STRIPE_WEBHOOK_SECRET).

Webhooks

  1. Local testing - Run the Flask webhook server: flask --app examples/flask_webhook_server run --port 4242 - In another terminal: stripe listen --forward-to localhost:4242/webhook - Use the whsec_... secret from the CLI output as STRIPE_WEBHOOK_SECRET in your env.

  2. Verify signatures - Always verify using the raw request body and Stripe-Signature with stripe.Webhook.construct_event(payload, sig_header, secret).

  3. Respond quickly - Return 2xx immediately, then process the event in a background job/queue so the endpoint doesn’t time out.

  4. Idempotency - Stripe may send the same event more than once. Track processed event.id (or data.object.id + type) to avoid duplicate work.


Security & Best Practices

  • Never put your secret key in client-side code or in version control.
  • Use HTTPS in production for all endpoints, including webhooks.
  • Prefer Stripe.js or official mobile SDKs on the frontend so card data never touches your server (PCI scope reduction).
  • Use Checkout or Payment Element when possible; they handle SCA, 3DS, and local methods.
  • Restrict API keys (e.g. Restricted keys) to the minimum needed.
  • Rotate webhook signing secrets periodically and when you suspect exposure.