skills_all/nextjs-stripe-integration/SKILL.md
Add Stripe payment processing to Next.js projects. Implement checkout sessions, payment handling, subscriptions, webhooks, and customer management. Use when adding Stripe to a Next.js project, building payment flows, implementing subscriptions, or integrating payment processing.
npx skillsauth add activer007/ordinary-claude-skills nextjs-stripe-integrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This Skill teaches Claude how to implement Stripe payment processing in Next.js projects, including one-time payments, subscriptions, webhooks, and customer management. Based on real-world implementation experience with modern Stripe APIs and authentication frameworks.
stripe.redirectToCheckout() is DEPRECATED and no longer works!
Modern Stripe implementations use the checkout session URL directly:
// ❌ OLD (BROKEN)
const { error } = await stripe.redirectToCheckout({ sessionId });
// ✅ NEW (CORRECT)
const session = await stripe.checkout.sessions.create({...});
window.location.href = session.url; // Use the URL directly!
When implementing Stripe in a Next.js project:
stripe and @stripe/stripe-jsNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY and STRIPE_SECRET_KEY to .env.localunauthenticatedPaths if using auth middleware# .env.local
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
CRITICAL: Access environment variables inside API route functions, NOT at module initialization:
// ❌ WRONG - Fails at build/startup
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST() { ... }
// ✅ CORRECT - Variables loaded at runtime
export async function POST(request: NextRequest) {
const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
if (!stripeSecretKey) {
return NextResponse.json({ error: 'API key not configured' }, { status: 500 });
}
const stripe = new Stripe(stripeSecretKey);
// ... rest of function
}
Important: Only use NEXT_PUBLIC_ prefix for publishable keys. Secret keys stay server-side only.
API Route (app/api/checkout/route.ts):
mode: 'payment'// ✅ CORRECT: Load env vars inside function
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const session = await stripe.checkout.sessions.create({...});
return NextResponse.json({ url: session.url }); // Return URL directly
Client Side (Simplified):
session.url directly from responseDifferences from one-time payments:
mode: 'subscription' when creating checkout sessionsKey workflow:
customer.subscription.created webhookCritical security requirements:
payment_intent.succeeded — one-time payment confirmedcustomer.subscription.created — new subscriptioncustomer.subscription.updated — subscription changescustomer.subscription.deleted — cancellationinvoice.payment_succeeded — renewal paymentWebhook endpoint (app/api/webhooks/stripe/route.ts):
stripe.webhooks.constructEvent(body, signature, secret)When using WorkOS or similar auth frameworks, explicitly allow payment routes:
// middleware.ts
export default authkitMiddleware({
eagerAuth: true,
middlewareAuth: {
enabled: true,
unauthenticatedPaths: [
'/',
'/sign-in',
'/sign-up',
'/api/checkout', // Allow unauthenticated checkout
'/api/webhooks/stripe', // Allow webhook delivery
'/payment-success',
'/payment-cancel',
],
},
});
Why: Without this, auth middleware intercepts payment routes, causing CORS errors when the frontend tries to call them.
Enable users to manage subscriptions without custom code:
npm install stripe @stripe/stripe-js
.env.local.env.local to .gitignoreCreate app/api/checkout/route.ts:
Create checkout page:
response.url directlyCreate success page:
session_id query parameterCreate product in Stripe Dashboard (recurring pricing)
Create app/api/subscriptions/list/route.ts:
Create app/api/checkout-subscription/route.ts:
mode: 'subscription'Create subscriptions page:
Create app/api/customer-portal/route.ts:
Create app/api/webhooks/stripe/route.ts:
export const config = { api: { bodyParser: false } }stripe.webhooks.constructEvent(body, signature, webhookSecret)Test locally with Stripe CLI:
stripe listen --forward-to localhost:3000/api/webhooks/stripe
stripe trigger payment_intent.succeeded
Deploy webhook endpoint to production
Add webhook endpoint URL in Stripe Dashboard → Webhooks
Use production secret key for production webhooks
NEXT_PUBLIC_ only for publishable keys// Query your database for customer's subscription status
const subscription = await db.subscriptions.findFirst({
where: { userId, status: 'active' }
});
return subscription !== null;
Listen for invoice.payment_failed webhook and:
Stripe handles this automatically when updating subscriptions via the API. Use proration_behavior to control how changes are billed.
app/
├── api/
│ ├── checkout/route.ts # One-time payment sessions
│ ├── checkout-subscription/route.ts
│ ├── subscriptions/
│ │ └── list/route.ts # Get available tiers
│ ├── customer-portal/route.ts # Manage subscriptions
│ └── webhooks/
│ └── stripe/route.ts # Webhook handler
├── checkout/
│ └── page.tsx # Checkout form
├── success/
│ └── page.tsx # Success page
└── subscriptions/
└── page.tsx # Subscription tiers
tools
Generate typed TypeScript SDKs for AI agents to interact with MCP servers. Converts verbose JSON-RPC curl commands to clean function calls (docs.createDocument() vs curl). Auto-detects MCP tools from server modules, generates TypeScript types and client methods, creates runnable example scripts. Use when: building MCP-enabled applications, need typed programmatic access to MCP tools, want Claude Code to manage apps via scripts, eliminating manual JSON-RPC curl commands, validating MCP inputs/outputs, or creating reusable agent automation.
testing
Generate structured task lists from specs or requirements. IMPORTANT: After completing ANY spec via ExitSpecMode, ALWAYS ask the user: "Would you like me to generate a task list for this spec?" Use when user confirms or explicitly requests task generation from a plan/spec/PRD.
tools
Create compelling story-format summaries using UltraThink to find the best narrative framing. Support multiple formats - 3-part narrative, n-length with inline links, abridged 5-line, or comprehensive via Foundry MCP. USE WHEN user says 'create story explanation', 'narrative summary', 'explain as a story', or wants content in Daniel's conversational first-person voice.
testing
Navigate through the original three-world shamanic technology. Deploy when soul retrieval, power animal guidance, or journey between realms emerges. Deeply respectful of Tungus, Buryat, Yakut, Evenki traditions. Use for consciousness navigation, NOT cultural appropriation.