Claude Code Plugins

Community-maintained marketplace

Feedback

Stripe payment integration for SaaS. Use when implementing Stripe checkout, webhooks, subscriptions, or payment flows. Includes secure patterns for Next.js.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name stripe-integration
description Stripe payment integration for SaaS. Use when implementing Stripe checkout, webhooks, subscriptions, or payment flows. Includes secure patterns for Next.js.

Stripe Integration for SaaS

Setup

Environment Variables

STRIPE_SECRET_KEY=sk_...
STRIPE_PUBLISHABLE_KEY=pk_...
STRIPE_WEBHOOK_SECRET=whsec_...

Install

pnpm add stripe @stripe/stripe-js

Server Client

// lib/stripe.ts
import Stripe from 'stripe';

export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
  typescript: true,
});

Checkout Session

// app/api/checkout/route.ts
import { stripe } from '@/lib/stripe';
import { auth } from '@/lib/auth';

export async function POST(request: Request) {
  const user = await auth();
  if (!user) return new Response('Unauthorized', { status: 401 });

  const { priceId } = await request.json();

  // Validate price ID against allowed list
  const allowedPrices = ['price_xxx', 'price_yyy'];
  if (!allowedPrices.includes(priceId)) {
    return new Response('Invalid price', { status: 400 });
  }

  const session = await stripe.checkout.sessions.create({
    customer: user.stripeCustomerId,
    mode: 'subscription',
    line_items: [{ price: priceId, quantity: 1 }],
    success_url: `${process.env.NEXT_PUBLIC_URL}/dashboard?success=true`,
    cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
    subscription_data: {
      metadata: { userId: user.id },
    },
  });

  return Response.json({ url: session.url });
}

Webhook Handler (CRITICAL)

See templates/webhook_handler.ts for complete implementation.

Security Requirements

  1. ✅ Verify signature with stripe.webhooks.constructEvent()
  2. ✅ Use raw body (not parsed JSON)
  3. ✅ Return 200 quickly, process async
  4. ✅ Handle idempotency (check if already processed)
  5. ✅ Log webhook events for debugging

Event Types to Handle

  • checkout.session.completed - Initial purchase
  • customer.subscription.created - New subscription
  • customer.subscription.updated - Plan change
  • customer.subscription.deleted - Cancellation
  • invoice.payment_failed - Failed payment
  • invoice.paid - Successful payment

Testing

# Forward webhooks to local
stripe listen --forward-to localhost:3000/api/webhooks/stripe

# Trigger test events
stripe trigger checkout.session.completed
stripe trigger customer.subscription.updated
stripe trigger invoice.payment_failed

Common Errors

"No signatures found matching"

  • Check STRIPE_WEBHOOK_SECRET is correct
  • Ensure using raw body: await request.text()

"Webhook timeout"

  • Process heavy work async
  • Return 200 immediately, use queue for processing