phrazzld

billing-security

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

Install specific skill from multi-skill repository

# Description

|

# SKILL.md


name: billing-security
description: |
Apply billing and security best practices for payment/auth integrations.
Invoke when: setting up Stripe/Clerk/auth, debugging payment issues,
configuring webhooks, before prod deployment, after billing incidents.
keywords:
- stripe
- payment
- webhook
- billing
- checkout
- subscription
- customer_creation
- webhook_secret


Billing & Security Integration Patterns

"Configuration is not reality. Verification must be active, not passive."

This skill codifies lessons from 3 prod incidents (chrondle, bibliomnomnom, volume) where Stripe integrations failed despite passing code review.

Core Principle

Code reviews catch code bugs, not configuration bugs. External service integrations require:
1. Format validation (API key patterns, URL formats)
2. Reachability verification (can we actually reach the webhook URL?)
3. Cross-deployment parity (Vercel and Convex must have same config)
4. Runtime reconciliation (compare external state vs database state)


Critical Patterns

1. Environment Variable Hygiene

Always trim env vars:

// WRONG - trailing whitespace causes "Invalid character in header"
const key = process.env.STRIPE_SECRET_KEY;

// RIGHT - always trim
const key = process.env.STRIPE_SECRET_KEY?.trim();

Validate format before use:

const STRIPE_KEY_PATTERN = /^sk_(test|live)_[a-zA-Z0-9]+$/;
if (!STRIPE_KEY_PATTERN.test(key)) {
  throw new Error("Invalid STRIPE_SECRET_KEY format");
}

2. Webhook URL Validation

Stripe does NOT follow redirects for POST requests. If your webhook URL returns 3xx, webhooks silently fail.

# Check for redirects BEFORE configuring webhook
curl -s -o /dev/null -w "%{http_code}" -I -X POST "https://your-domain.com/api/webhooks/stripe"
# Must return 4xx or 5xx, NOT 3xx

Use canonical domain:
- If example.com redirects to www.example.com, configure webhook for www.example.com

3. Cross-Deployment Parity

When using Vercel + Convex (or similar split architectures):
- Env vars must be set on BOTH platforms
- Use --prod flag: npx convex env set --prod KEY value
- Verify parity: compare vercel env ls with npx convex env list --prod

4. Stripe Parameter Constraints

Mode-dependent parameters:
| Parameter | Valid Modes | Invalid Modes |
|-----------|-------------|---------------|
| customer_creation | payment, setup | subscription |
| subscription_data | subscription | payment, setup |

Common trap: Using customer_creation: "always" in subscription mode throws an error at checkout time, not at compile time.


Pre-Deployment Checklist

Before deploying any billing integration:

  • [ ] All env vars trimmed at read time
  • [ ] API key formats validated
  • [ ] Webhook URL returns non-3xx status
  • [ ] Vercel and Convex have matching config
  • [ ] Signature verification enabled
  • [ ] Error handling returns 200 (prevent Stripe infinite retries)

Debugging Workflow (OODA-V)

When billing integration fails:

  1. Observe - Check if request reaches server (look for logs)
  2. Orient - If no logs, it is network/redirect, not code
  3. Decide - Run curl -I on webhook URL
  4. Act - Fix configuration
  5. Verify - Resend event, watch pending_webhooks decrease

References

Scripts

  • scripts/verify-webhook-url.sh <url> - Check for redirects
  • scripts/verify-env-parity.sh - Compare Vercel/Convex config
  • scripts/audit-stripe-config.py - Full Stripe diagnostic

# 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.