Photo by chansu shin on Unsplash

On this page

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:

Terminal window
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:

Terminal window
npm install stripe express

Create one shared module that constructs a Stripe client instance. Do not use the deprecated pattern of setting a global API key on the module.

stripe-client.js
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:

routes/health.js
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):

routes/create-customer.js
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:

  1. Create a new restricted key in the Dashboard with the same permissions.
  2. Deploy the new key to your secrets store and restart servers.
  3. 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

  1. 1. Which key type does the article recommend for server-side API access when you can configure permissions?

Search articles

Type a word to search published articles.

Open the search page