cloudflare-api
Hit the Cloudflare REST API directly for operations that wrangler and MCP can't handle well. Bulk DNS, custom hostnames, email…
Add Stripe payments to a web app — Checkout Sessions, Payment Intents, subscriptions, webhooks, customer portal, and pricing pages. Covers the decision of which Stripe API to use, produces working integration code, and handles webhook verification. No MCP server needed — uses
Claude Code
$ npx -y skills add jezweb/claude-skills --skill stripe-payments --agent claude-code
Codex
$ npx skills add jezweb/claude-skills --skill stripe-payments -a codex -y
Cursor
$ npx skills add jezweb/claude-skills --skill stripe-payments -a cursor -y
Gemini CLI
$ npx skills add jezweb/claude-skills --skill stripe-payments -a gemini-cli -y
GitHub Copilot
$ npx skills add jezweb/claude-skills --skill stripe-payments -a github-copilot -y
OpenCode
$ npx skills add jezweb/claude-skills --skill stripe-payments -a opencode -y
Windsurf
$ npx skills add jezweb/claude-skills --skill stripe-payments -a windsurf -y
name: stripe-payments description: "Add Stripe payments to a web app — Checkout Sessions, Payment Intents, subscriptions, webhooks, customer portal, and pricing pages. Covers the decision of which Stripe API to use, produces working integration code, and handles webhook verification. No MCP server needed — uses Stripe npm package directly. Triggers: 'add payments', 'stripe', 'checkout', 'subscription', 'payment form', 'pricing page', 'billing', 'accept payments', 'stripe webhook', 'customer portal'." compatibility: claude-code-only allowed-tools: - Read - Write - Edit - Bash - Glob - Grep
Add Stripe payments to a web app. Covers the common patterns — one-time payments, subscriptions, webhooks, customer portal — with working code. No MCP server needed.
| You want to... | Use | Complexity | |----------------|-----|-----------| | Accept a one-time payment | Checkout Sessions | Low — Stripe hosts the payment page | | Embed a payment form in your UI | Payment Element + Payment Intents | Medium — you build the form, Stripe handles the card | | Recurring billing / subscriptions | Checkout Sessions (subscription mode) | Low-Medium | | Save a card for later | Setup Intents | Low | | Marketplace / platform payments | Stripe Connect | High | | Let customers manage billing | Customer Portal | Low — Stripe hosts it |
**Default recommendation**: Start with Checkout Sessions. It's the fastest path to accepting money. You can always add embedded forms later.
npm install stripe @stripe/stripe-js
# Get keys from: https://dashboard.stripe.com/apikeys # Test keys start with sk_test_ and pk_test_ # Live keys start with sk_live_ and pk_live_ # For Cloudflare Workers — store as secrets: npx wrangler secret put STRIPE_SECRET_KEY npx wrangler secret put STRIPE_WEBHOOK_SECRET # For local dev — .dev.vars: STRIPE_SECRET_KEY=sk_test_... STRIPE_WEBHOOK_SECRET=whsec_... STRIPE_PUBLISHABLE_KEY=pk_test_...
import Stripe from 'stripe'; // Cloudflare Workers const stripe = new Stripe(c.env.STRIPE_SECRET_KEY); // Node.js const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
The fastest way to accept payment. Stripe hosts the entire checkout page.
app.post('/api/checkout', async (c) => {
const { priceId, successUrl, cancelUrl } = await c.req.json();
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{ price: priceId, quantity: 1 }],
success_url: successUrl || `${new URL(c.req.url).origin}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: cancelUrl || `${new URL(c.req.url).origin}/pricing`,
});
return c.json({ url: session.url });
});async function handleCheckout(priceId: string) {
const res = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ priceId }),
});
const { url } = await res.json();
window.location.href = url;
}# Via Stripe CLI (recommended for setup) stripe products create --name="Pro Plan" --description="Full access" stripe prices create --product=prod_XXX --unit-amount=2900 --currency=aud --recurring[interval]=month # Or via Dashboard: https://dashboard.stripe.com/products
**Hardcode price IDs** in your code (they don't change):
const PRICES = {
pro_monthly: 'price_1234567890',
pro_yearly: 'price_0987654321',
} as const;Same as one-time but with `mode: 'subscription'`:
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{ price: PRICES.pro_monthly, quantity: 1 }],
success_url: `${origin}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${origin}/pricing`,
// Link to existing customer if known:
customer: customerId, // or customer_email: 'user@example.com'
});async function hasActiveSubscription(customerId: string): Promise<boolean> {
const subs = await stripe.subscriptions.list({
customer: customerId,
status: 'active',
limit: 1,
});
return subs.data.length > 0;
}Stripe sends events to your server when things happen (payment succeeded, subscription cancelled, etc.). **You must verify the webhook signature.**
app.post('/api/webhooks/stripe', async (c) => {
const body = await c.req.text();
const sig = c.req.header('stripe-signature')!;
let event: Stripe.Event;
try {
// Use constructEventAsync for Workers (no Node crypto)
event = await stripe.webhooks.constructEventAsync(
body,
sig,
c.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
console.error('Webhook signature verification failed:', err);
return c.json({ error: 'Invalid signature' }, 400);
}
switch (event.type) {
case 'checkout.session.completed': {
const session = event.data.object as Stripe.Checkout.Session;
// Fulfill the order — update database, send email, grant access
await handleCheckoutComplete(session);
break;
}
case 'customer.subscription.updated': {
const sub = event.data.object as Stripe.Subscription;
await handleSubscriptionChange(sub);
break;
}
case 'customer.subscription.deleted': {
const sub = event.data.object as Stripe.Subscription;
await handleSubscriptionCancelled(sub);
break;
}
case 'invoice.payment_failed': {
const invoice = event.data.object as Stripe.Invoice;
await handlePaymentFailed(invoice);
break;
}
}
return c.json({ received: true });
});Production workflow skills for Claude Code. Each skill guides Claude through a recipe to produce tangible output — scaffolded projects, generated assets, professional documents, deployed services. Ten plugins of practical, production-oriented skills.
Hit the Cloudflare REST API directly for operations that wrangler and MCP can't handle well. Bulk DNS, custom hostnames, email…
Scaffold and deploy Cloudflare Workers with Hono routing, Vite plugin, and Static Assets. Describe project, scaffold structure,…
Generate Drizzle ORM schemas for Cloudflare D1 databases with correct D1-specific patterns. Produces schema files, migration…
Cloudflare D1 migration workflow: generate with Drizzle, inspect SQL for gotchas, apply to local and remote, fix stuck…
Generate database seed scripts with realistic sample data. Reads Drizzle schemas or SQL migrations, respects foreign key…
Scaffold Hono API routes for Cloudflare Workers. Produces route files, middleware, typed bindings, Zod validation, error…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.