Chapter 1: Stripe Infrastructure Fundamentals and Developer Environment Setup
To become an engineer capable of building internationalized SaaS products, you must first deeply understand Stripe's underlying design philosophy. Unlike traditional payment systems (such as Taiwan's commonly used ECPay or Newebpay) which are centered around "orders," Stripe is built around "Object Models."
In Stripe's world, everything is an object: Customer, Product, Price, PaymentIntent, Subscription. This chapter will help you establish these fundamental concepts and complete your development environment setup.
๐ ๏ธ 1. Register and Activate Your Stripe Account
- Go to the Stripe website to register an account.
- Upon registration, you'll be in Test Mode. Notice the prominent orange "Test mode" label in the top-right corner of the Dashboard.
- Do not rush to switch to Live Mode yet. During development and testing, all our API calls and credit card transactions will occur in test mode. Stripe's test environment is incredibly powerful, allowing you to simulate various edge cases (e.g., insufficient card balance, expired cards, international issuer declines).
๐ 2. Understanding API Key Security Boundaries
In the Stripe Dashboard under Developers > API keys, you'll find two critical keys:
Publishable Key (starts with pk_test_...)
- Purpose: This key is publicly shareable.
- Usage: Typically used on the frontend (Client-side) to load Stripe.js, render Apple Pay buttons, or tokenize credit card numbers.
- Security: Even if this key is exposed, it's harmless because it can only initiate payment intents, not charge, refund, or access customer data.
- Environment Variable: In Next.js, we usually set it as
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY.
Secret Key (starts with sk_test_...)
- Purpose: This key is absolutely confidential!
- Usage: Must remain server-side only. It grants full access to your Stripe account for charging, refunding, creating customers, and viewing all financial reports.
- Security: If leaked, hackers could issue refunds to themselves or initiate malicious charges. Never include it in frontend code!
- Environment Variable: In Next.js, set as
STRIPE_SECRET_KEY(withoutNEXT_PUBLIC_).
๐จ Security Alert: If you accidentally push your
Secret Keyto GitHub, Stripe's security system typically detects it within seconds, automatically revokes the key, and emails you. Always keep these keys strictly in.env.local!
๐ฆ 3. Creating Products and Prices
In Stripe, "Products" and "Prices" are separate objects. Why this design? Because a SaaS product (e.g., Pro plan) might have:
- A $10/month price (Monthly Price)
- A $100/year price (Yearly Price)
- A Euro price for the European market
Hands-on: Create a Product in the Dashboard
- Click Product Catalog in the Dashboard sidebar.
- Click Add Product.
- Name: Enter
Vibe Tutor Pro (Global Pass). - Description:
Unlock all advanced courses and unlimited source code downloads. - Under Pricing:
- Pricing model: Select
Standard pricing. - Price: Enter
29.99. - Currency: Choose
USD - US Dollar(Hello, USD revenue!). - Billing period: Select
Monthly(this makes it a Recurring subscription price).
- Pricing model: Select
- After saving, you'll see a Price ID on the product details page (e.g.,
price_1PqX9a2eZvKYlo2...). Copy this Price IDโwe'll use it in the next chapter when coding!
๐จโ๐ป 4. Project Environment Setup
In your Next.js project, install Stripe's official SDKs:
# Install Stripe backend SDK
npm install stripe
# Install Stripe frontend SDK (if custom checkout UI is needed)
npm install @stripe/stripe-js
Then, add your keys to .env.local:
# Stripe Keys (Test Mode)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxxxxxxxxxx
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxx
# Webhook signing secret (covered later)
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxx
โ Chapter Summary
You've completed all foundational setups! You now have:
- A globally capable payment account
- Secure key management practices
- A USD-priced recurring product (Price ID) ready for automated monthly billing
In the next chapter, we'll dive into codingโteaching you how to call Stripe APIs in Next.js to create a polished checkout page!
More Stripe Examples
Subscription Flow
price = stripe.Price.create(product=prod.id, unit_amount=999, currency="usd", recurring={"interval": "monthly"})
sub = stripe.Subscription.create(customer=cus.id, items=[{"price": price.id}])
Webhook Security
- Verify signature with
stripe.Webhook.construct_event() - Process events asynchronously
- Return 200 quickly, do heavy work in background
- Idempotency keys to prevent duplicate processing
Stripe API Overview
Stripe provides a comprehensive REST API for payment processing. Key endpoints include:
| Endpoint | Purpose |
|----------|---------|
| POST /v1/charges | Create a charge (legacy) |
| POST /v1/payment_intents | Create a PaymentIntent (modern) |
| POST /v1/checkout/sessions | Create a Checkout Session |
| POST /v1/customers | Create a customer |
| POST /v1/products | Create a product |
| POST /v1/prices | Create a price |
| POST /v1/webhook_endpoints | Register a webhook |
| POST /v1/refunds | Issue a refund |
Development Workflow
1. Create Stripe account โ Get API keys
2. Install Stripe CLI (for webhook testing)
3. Set up your backend with Stripe SDK
4. Test with test mode (card number 4242...)
5. Implement webhook handling for async events
6. Switch to live mode after testing
Testing with Stripe CLI
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login
stripe login
# Forward webhooks to localhost
stripe listen --forward-to localhost:3000/api/webhooks
# Trigger test events
stripe trigger payment_intent.succeeded
stripe trigger payment_intent.payment_failed
stripe trigger customer.subscription.updated
Test Card Numbers
| Card Number | Scenario | |-------------|----------| | 4242424242424242 | Succeeds | | 4000000000000002 | Declined | | 4000000000003220 | Requires 3D Secure | | 4000002500003155 | Requires 3D Secure (different) | | 4000000000009995 | Insufficient funds | | 4000000000009987 | Lost card | | 4000000000009979 | Stolen card | | 4000000000000069 | Expired card | | 4000000000000127 | Incorrect CVC |
Handling Stripe Events
// Stripe sends webhook events for async notifications
// Important events to handle:
const events = {
'payment_intent.succeeded': handlePaymentSuccess,
'payment_intent.payment_failed': handlePaymentFailure,
'checkout.session.completed': handleCheckoutComplete,
'customer.subscription.created': handleSubscriptionCreated,
'customer.subscription.updated': handleSubscriptionUpdated,
'customer.subscription.deleted': handleSubscriptionDeleted,
'invoice.payment_succeeded': handleInvoicePaid,
'invoice.payment_failed': handleInvoiceFailed,
'charge.dispute.created': handleDisputeCreated,
'charge.refunded': handleRefunded,
};
Common Mistakes
| Mistake | Fix |
|---------|-----|
| Hardcoding API keys | Use environment variables |
| Not verifying webhook signatures | Always use stripe.webhooks.constructEvent() |
| Using live keys in development | Switch to test mode keys |
| Blocking on Stripe API calls | Make async calls, use webhooks |
| Not handling idempotency | Use idempotency keys for retries |
| Exposing secret keys to frontend | Only use publishable key on frontend |
Summary
Stripe provides a complete payment infrastructure. Use PaymentIntents for modern payments, Checkout Sessions for hosted payment pages, and webhooks for async event handling. Always test with test mode before switching to live.
Key takeaways:
- Sign up for Stripe and get API keys (test + live)
- Use Stripe SDK for your backend language
- PaymentIntent = modern way to accept payments
- Checkout Session = hosted payment page (fastest integration)
- Webhooks = async notifications for payment events
- Stripe CLI = test webhooks locally
- Always verify webhook signatures
- Test with 4242... card before going live
- Never hardcode API keys โ use environment variables
What's Next: Stripe Checkout Integration
The next chapter implements Stripe Checkout โ creating a hosted payment page with product details, quantity selection, and automatic redirect.