phrazzld

fix-stripe

2
1
# Install this skill:
npx skills add phrazzld/claude-config --skill "fix-stripe"

Install specific skill from multi-skill repository

# Description

|

# SKILL.md


name: fix-stripe
description: |
Run /check-stripe, then fix the highest priority Stripe issue.
Creates one fix per invocation. Invoke again for next issue.
Use /log-stripe-issues to create issues without fixing.


/fix-stripe

Fix the highest priority Stripe integration issue.

What This Does

  1. Invoke /check-stripe to audit Stripe integration
  2. Identify highest priority issue
  3. Fix that one issue
  4. Verify the fix
  5. Report what was done

This is a fixer. It fixes one issue at a time. Run again for next issue. Use /stripe for full lifecycle.

Process

1. Run Primitive

Invoke /check-stripe skill to get prioritized findings.

2. Fix Priority Order

Fix in this order:
1. P0: Missing webhook secret, hardcoded keys
2. P1: Webhook verification, customer portal, subscription checks
3. P2: Idempotency, error handling
4. P3: Advanced features

3. Execute Fix

Missing webhook secret (P0):
Add to .env.local:

STRIPE_WEBHOOK_SECRET=whsec_...

Get from Stripe Dashboard or CLI:

stripe listen --print-secret

Hardcoded keys (P0):
Replace hardcoded keys with environment variables:

// Before
const stripe = new Stripe('sk_test_...', { apiVersion: '2024-12-18.acacia' });

// After
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2024-12-18.acacia' });

Webhook verification missing (P1):
Update webhook handler:

export async function POST(req: Request) {
  const body = await req.text();
  const signature = req.headers.get('stripe-signature')!;

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(
      body,
      signature,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err) {
    return new Response('Webhook signature verification failed', { status: 400 });
  }

  // Handle event...
}

No customer portal (P1):
Add billing portal endpoint:

// app/api/stripe/portal/route.ts
export async function POST(req: Request) {
  const { customerId } = await req.json();

  const session = await stripe.billingPortal.sessions.create({
    customer: customerId,
    return_url: `${process.env.NEXT_PUBLIC_APP_URL}/settings`,
  });

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

Subscription status not checked (P1):
Add subscription check middleware:

async function requireActiveSubscription(userId: string) {
  const subscription = await getSubscription(userId);
  if (!subscription || subscription.status !== 'active') {
    throw new Error('Active subscription required');
  }
}

4. Verify

After fix:

# Test webhook verification
stripe trigger checkout.session.completed

# Check portal works
curl -X POST http://localhost:3000/api/stripe/portal \
  -H "Content-Type: application/json" \
  -d '{"customerId": "cus_test"}'

5. Report

Fixed: [P0] Webhook signature not verified

Updated: app/api/webhooks/stripe/route.ts
- Added signature verification with constructEvent()
- Added error handling for invalid signatures

Verified: stripe trigger checkout.session.completed โ†’ verified

Next highest priority: [P1] No customer portal
Run /fix-stripe again to continue.

Branching

Before making changes:

git checkout -b fix/stripe-$(date +%Y%m%d)

Single-Issue Focus

Payment integrations are critical. Fix one thing at a time:
- Test each change thoroughly
- Easy to rollback specific fixes
- Clear audit trail for PCI

Run /fix-stripe repeatedly to work through the backlog.

  • /check-stripe - The primitive (audit only)
  • /log-stripe-issues - Create issues without fixing
  • /stripe - Full Stripe lifecycle
  • /stripe-health - Webhook diagnostics

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.