Tutorials Search / Backend integrations / Set up Stripe API keys
📝 Written ● Beginner Updated 2026-05-13

How do I set up Stripe API keys correctly?

TL;DR: Stripe gives you four keys: pk_test, sk_test, pk_live, sk_live. Publishable (pk) goes in client code, secret (sk) goes in env vars only — never client code. Use test keys until launch, then swap to live keys in one place (env vars), not in code.

Stripe gives you four keys — publishable and secret, test and live. They look similar; they are not interchangeable. The five-minute walk through this tutorial saves you from the two Stripe accidents that hurt: leaking a secret key to the public, and accidentally charging real cards in test mode.

Every credential system has a unique mental model, and Stripe's is one of the better-designed ones — once you understand it. There are two axes. The first axis is visibility: publishable keys are safe to ship in the frontend (browser, mobile app); secret keys are only safe on your backend server. The second axis is environment: test keys hit a sandbox where charges are fake and no money moves; live keys hit production where every transaction is real money. Multiply the two: pk_test_…, sk_test_…, pk_live_…, sk_live_….

What goes wrong with developers new to Stripe almost always traces back to confusing these. A secret key committed to GitHub is the classic accident — public repos get scraped within minutes of secret keys being pushed. A live secret used by accident during a demo is the other — somebody's card gets a real charge instead of a test one. Both are recoverable (Stripe lets you rotate keys; refunds are quick) but both are avoidable.

This tutorial covers fetching the keys, understanding which one to use where, and putting them in your project in a way that doesn't accidentally publish them. The companion tutorial on webhooks covers what your server actually does with the keys.

What you'll learn

Step 1: Create a Stripe account

1

Test mode works before you submit business details

Sign up at dashboard.stripe.com. The signup is fast — email, password, basic business info. You'll be in test mode immediately, with full API access and test keys. You don't need to submit verification documents to start integrating.

Live mode (real charges) requires Stripe to verify your business: business name, address, tax ID, bank account. That can wait until you're ready to accept real payments. For now, test mode is the whole game.

Step 2: Find the keys

2

Developers → API Keys

In the Stripe dashboard, click Developers in the top nav (or in the menu), then API keys. You'll see two keys for whatever mode you're currently in:

  • Publishable key — starts with pk_. Shown in full. Safe to put in frontend code, ship in your JavaScript bundle, expose in URLs. It can identify your Stripe account but can't read sensitive data or move money on its own.
  • Secret key — starts with sk_. Hidden by default; click "Reveal" to see. NEVER put this anywhere a non-trusted party could see — that includes frontend code, public repos, error logs, JSON responses to clients. Anyone with this key can charge cards, refund payments, create customers, and read every transaction.

The test-mode keys have test in their name (pk_test_…, sk_test_…). The live-mode keys (visible after you switch toggle and complete verification) have live (pk_live_…, sk_live_…).

Step 3: Understand the test/live toggle

3

The single most important Stripe UI element

Top-right of every Stripe dashboard page is a toggle that says either Test mode (orange) or Live mode (default). The toggle controls:

  • Which keys appear on the API Keys page.
  • Which webhooks fire (test and live have separate endpoint configs).
  • Which customers and charges you see — they're separate stores.
  • What test cards work (test mode accepts 4242 4242 4242 4242; live doesn't).

If you're seeing "your customer doesn't exist" errors in development, you're probably in live mode looking at a test customer (or vice versa). Check the toggle first; nine times out of ten that's the bug.

The orange test-mode banner is your friend. Stripe shows an orange banner across the top of every page when you're in test mode. Train yourself to glance at it. If you don't see it and you're about to do something destructive (refund, cancel, etc.), you're in live mode — slow down.

Step 4: Put the keys in your project

4

Environment variables, not source files

Three rules:

  1. Never hard-code secret keys. Use environment variables. In Node: process.env.STRIPE_SECRET_KEY. In Python: os.environ["STRIPE_SECRET_KEY"]. Same pattern everywhere.
  2. Never commit your .env file. Add .env to .gitignore. Use .env.example with placeholder values to document what env vars exist, and commit that.
  3. Use the test key in development, the live key in production. Your production server needs STRIPE_SECRET_KEY=sk_live_…; your dev box has sk_test_…. Same variable name; different values per environment.

For frontend code, the publishable key can live in the bundle but should still come from an env var at build time (NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, VITE_STRIPE_PUBLISHABLE_KEY, etc.). This is mostly for cleanliness — the value isn't secret, but you don't want to rebuild to swap from test to live.

Step 5: Confirm it works

5

One curl, one assertion

From your backend (or a terminal where the env var is set):

curl https://api.stripe.com/v1/charges \
  -u "$STRIPE_SECRET_KEY:" \
  -d amount=2000 \
  -d currency=usd \
  -d "source=tok_visa" \
  -d "description=test charge"

If the key works, you get a JSON response with a charge object. If it doesn't, you get a 401 with a clear error message. tok_visa is a Stripe test token; the charge is fake; nothing moves.

Step 6: When (not if) you leak a key

6

Rotation is fast; assume the worst

Sooner or later you (or a teammate) will leak a secret key — committed to a public repo, pasted in a Slack channel that was screen-shared, in a browser dev-tools dump someone screenshotted. The fix:

  1. In the Stripe dashboard, Developers → API keys → Roll secret key. The old key is immediately invalid; Stripe issues a new one.
  2. Update STRIPE_SECRET_KEY in every environment that uses the key (production, staging, dev) and redeploy.
  3. Audit your account for any suspicious activity in the window between leak and rotation. Stripe's logs make this easy.

Don't be ashamed of having to rotate. Everyone does it eventually. The mature response is "rotate, audit, move on" — not "panic, delete account, start over."

GitHub scans for leaked keys. If you push a secret key to a public repo, Stripe usually invalidates it within minutes — GitHub notifies Stripe, Stripe rolls the key automatically. This is helpful (the worst-case window is short) but it's not a substitute for not leaking. Don't rely on the safety net.

Step 7: Restricted keys (production hygiene)

7

The "full secret key" isn't the only option

For production, consider creating restricted keys — keys scoped to specific resources (e.g., "can create charges, can't read customers"). In the dashboard: Developers → API keys → Restricted keys → Create.

If your app only ever creates Checkout Sessions, a restricted key with just that permission is safer than the full secret key. The fallout from leaking is bounded by what the key can do.

What's next