This chapter follows What is Stripe?.
Stripe authenticates API requests with API keys. Treat them like passwords: leak a secret key and someone can move money or refund charges in your account. The Node.js SDK wraps Stripe’s REST API with typed helpers, automatic retries for network blips, and webhook signature verification.
Publishable, secret, and restricted keys
| Key | Prefix (test) | Where it lives | Purpose |
|---|---|---|---|
| Publishable | pk_test_ |
Browser, mobile app, server-rendered pages | Initialize Stripe.js; safe to expose |
| Secret | sk_test_ |
Server only | Full API access for that mode |
| Restricted | rk_test_ |
Server only | Scoped permissions (preferred over broad secret keys) |
Live keys use pk_live_, sk_live_, and rk_live_. The Dashboard Developers → API keys page lists keys for the active mode or sandbox.
Never commit keys to git. Load them from the environment—see Env vars, process and globals in NodeJS.
Loading keys in Node.js
Use two variables in development:
STRIPE_SECRET_KEY=sk_test_...STRIPE_PUBLISHABLE_KEY=pk_test_...Your Express app reads the secret key at startup. Templates or a small /config.js endpoint can expose the publishable key to the browser for Stripe.js—never send the secret key to the client.
Installing the stripe package and creating a client
Install the current major SDK (for example stripe@23 on npm) alongside Express:
npm install stripe expressCreate one shared module that constructs a Stripe client instance. Do not use the deprecated pattern of setting a global API key on the module.
import Stripe from 'stripe';
if (!process.env.STRIPE_SECRET_KEY) { throw new Error('Missing STRIPE_SECRET_KEY');}
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2026-09-30.endive',});Import stripe from that file in route handlers. Pinning apiVersion keeps behavior stable when Stripe ships new API versions; upgrade deliberately after reading the changelog.
A minimal health route proves the key format without charging money:
import { stripe } from '../stripe-client.js';
export async function getBalance(_req, res) { const balance = await stripe.balance.retrieve(); res.json({ available: balance.available });}API version and idempotency
Every response includes the API version Stripe used. Your client’s apiVersion parameter requests a specific version on each call.
Idempotency keys let you safely retry POST requests without creating duplicate objects. Pass a unique key per logical operation (often your internal order id):
import { stripe } from '../stripe-client.js';
export async function createCustomer(req, res) { const customer = await stripe.customers.create( { email: req.body.email, metadata: { appUserId: req.body.userId } }, { idempotencyKey: `customer-${req.body.userId}` }, ); res.json({ customerId: customer.id });}Stripe stores idempotency results for about 24 hours. Reuse the same key with a different body returns an error.
Errors and retries
Failed calls throw Stripe.errors.StripeError subclasses. Branch on error.type:
| type | Meaning | Typical action |
|---|---|---|
StripeCardError |
Card declined | Show message to customer |
StripeInvalidRequestError |
Bad parameters | Fix code, log details |
StripeAuthenticationError |
Wrong or missing key | Fix configuration |
StripeRateLimitError |
Too many requests | Back off and retry |
StripeAPIError |
Stripe server issue | Retry with idempotency key |
The SDK retries idempotent GETs and some network failures automatically. For POSTs you initiate, combine idempotency keys with your own retry policy.
Rotating keys safely
Rotation limits blast radius if a key leaks:
- Create a new restricted key in the Dashboard with the same permissions.
- Deploy the new key to your secrets store and restart servers.
- Monitor traffic; disable the old key once nothing uses it.
For publishable keys, update front-end config and CDN caches after rotation. Webhook signing secrets are separate from API keys; rotate them in the webhook endpoint settings and update STRIPE_WEBHOOK_SECRET before disabling the old secret.
Next: Customers in Stripe.
Check your understanding
Question 1 of 6
0 of 6 checked