Selling online means moving money and state across three places: the browser where someone pays, your server where you enforce business rules, and Stripe where card networks and banks are orchestrated. Stripe is a payments platform: you create and update objects through its HTTP API (or Dashboard), Stripe handles compliance-sensitive steps such as card data collection, and your app reacts to webhooks when money actually moves.
This series walks through an Express app in JavaScript (ES modules). Examples keep your own user records in an in-memory Map so the focus stays on Stripe, not on picking a database.
What Stripe provides in a web stack
Your application still owns accounts, entitlements, and fulfillment. Stripe owns payment instruments, charge attempts, subscription billing cycles, and the ledger events that go with them.
| Layer | Your code | Stripe |
|---|---|---|
| Browser | Product pages, “Buy” buttons, optional custom forms | Stripe.js, Checkout hosted page, Payment Element |
| Server | Auth, carts, mapping userId → customerId |
REST API: Customers, Prices, Checkout Sessions, PaymentIntents, Subscriptions |
| After payment | Grant access, send email, update inventory | Webhooks: signed Event payloads |
Card numbers never touch your server when you use Checkout or the Payment Element with Stripe.js. That keeps you out of the heaviest PCI scope; you still must protect API keys and webhook endpoints.
Core API objects at a glance
Most integrations revolve around a small graph of objects. One-time sales usually flow through a Checkout Session or PaymentIntent; recurring revenue adds Subscription and Invoice.
flowchart TB Customer --> PaymentMethod Product --> Price Price --> CheckoutSession Customer --> CheckoutSession CheckoutSession --> PaymentIntent PaymentIntent --> PaymentMethod Customer --> Subscription Price --> Subscription Subscription --> Invoice StripeAPI[Stripe API] --> Event Event --> WebhookEndpoint[Your webhook handler]
- Customer — Identity in Stripe for a person or business; holds default payment methods and metadata you sync from your app.
- Product and Price — What you sell and how much it costs (one-time or recurring). Prices are versioned; you replace a price instead of editing amount in place.
- Checkout Session — Hosted or embedded checkout flow; recommended starting point for many web apps.
- PaymentIntent — Tracks a single payment attempt, including authentication (3D Secure) and status transitions.
- PaymentMethod — A saved card, wallet, or other instrument attached to a Customer.
- Subscription — Recurring billing for one or more Prices; generates Invoices on a schedule.
- Event — Something that happened in Stripe; delivered to your server as a webhook.
Later chapters go deep on each piece. For marketplaces and tax, Stripe also offers Connect, Tax, and other products—a short tour appears in Stripe beyond payments.
Test mode, live mode, and sandboxes
Every Stripe account has test mode and live mode keys. Test mode uses fake money and test card numbers; live mode moves real funds.
For new work, Stripe recommends sandboxes: isolated test environments with their own settings and data, separate from the account-wide test mode sandbox. Use different sandboxes for local development and CI when you can. Existing teams on the shared test mode sandbox can keep using it until migration makes sense.
Never mix keys: a test secret key against live objects (or the reverse) fails or creates confusing errors. The Dashboard and API keys page show which mode you are in.
Money amounts and currencies
Stripe amounts are integers in the smallest currency unit—cents for USD/EUR, whole yen for JPY (zero-decimal currencies). Sending 10.99 as a float is a common bug; send 1099 with currency: 'usd'.
Multi-currency catalogs use one Price per currency or separate Prices per market. Tax and presentment rules are product-specific; Stripe Tax can calculate tax when you enable it with proper registrations.
Where payments fit in the request flow
A typical one-time purchase looks like this:
- The user clicks Pay in your app.
- Your server creates a Checkout Session (or PaymentIntent for a custom form) and returns a URL or
client_secret. - The user completes payment on Stripe’s UI or your embedded form.
- Stripe sends a webhook (for example
checkout.session.completed) to your server. - Your webhook handler marks the order paid and unlocks the product.
The browser redirect to a “success” page is for UX only. Fulfillment belongs in the webhook handler, not in the success route, because the user can close the tab before your server runs or payment can complete asynchronously.
Check your understanding
Question 1 of 5
0 of 5 checked