Stripe

stripePayments32 lines

Card payments, subscriptions and billing for web checkout.

Current — as published in v1.3.2. Written by hand for Stripe, not generated.

The rule

Trust boundary

  • Never take an amount, price or currency from the client. Look the price up server-side from an id you control. A forged request body is trivial.
  • The secret key is server-side only. The publishable key is the only one that may reach a browser.
  • Landing on the success page is not proof of payment.

Webhooks are the source of truth

  • Verify every webhook signature against the raw body. A parsed body breaks the check; an unverified endpoint accepts forged "payment succeeded" events from anyone.
  • Idempotency is required, not optional. Stripe retries and delivers at-least-once: record the event id and ignore duplicates, or a retry grants access twice.
  • Handle the subscription lifecycle — updated and deleted — not only checkout completion.

Money

  • Amounts are integers in the smallest currency unit. Never use floats.
  • Store the Stripe customer and subscription ids against your own user.

Never

  • Never log a full card number, secret key or webhook payload containing personal data.
  • Never use Stripe for digital goods inside a mobile app — the stores reject it.
  • Never grant access from client state alone; re-check server-side.

As each tool receives it

The same guidance, in the shape each editor reads. Cursor and Claude Code are written separately by hand; the rest are derived from the Cursor rule.

.cursor/rules/stripe.mdchand-written for this tool
.cursor/rules/stripe.mdc
---
description: Stripe conventions
globs: ["server/**", "api/**", "app/api/**", "src/services/payments/**"]
alwaysApply: false
---

# Stripe

## Trust boundary

- **Never take an amount, price or currency from the client.** Look the price up
  server-side from an id you control. A forged request body is trivial.
- The secret key is server-side only. The publishable key is the only one that
  may reach a browser.
- Landing on the success page is not proof of payment.

## Webhooks are the source of truth

- Verify every webhook signature against the **raw** body. A parsed body breaks
  the check; an unverified endpoint accepts forged "payment succeeded" events
  from anyone.
- **Idempotency is required**, not optional. Stripe retries and delivers
  at-least-once: record the event id and ignore duplicates, or a retry grants
  access twice.
- Handle the subscription lifecycle — `updated` and `deleted` — not only
  checkout completion.

## Money

- Amounts are integers in the smallest currency unit. Never use floats.
- Store the Stripe customer and subscription ids against your own user.

## Never

- Never log a full card number, secret key or webhook payload containing
  personal data.
- Never use Stripe for digital goods inside a mobile app — the stores reject it.
- Never grant access from client state alone; re-check server-side.

What else this module writes

Selecting Stripe contributes more than a rule file — all of it merged with every other module you pick, with conflicts resolved rather than duplicated.

Environment
STRIPE_SECRET_KEYrequiredServer-side API key. Never ship in a client bundle.
STRIPE_WEBHOOK_SECRETrequiredVerifies webhook signatures. The endpoint is public without it.
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYoptionalBrowser-side key for Stripe.js. Safe to expose.
Dependencies
stripe^22.4.0@stripe/stripe-js^9.13.0
Folders
server/payments/src/features/billing/
Checklists
checklists/payments-web.md

Related

Put this in your repo

Adds Stripe to a project this tool generated, without starting over. Files you have hand-edited are left alone.