web-payments
Stripe Checkout, subscriptions, webhooks, customer portal
Install
mkdir -p .claude/skills/web-payments && curl -L -o skill.zip "https://mcp.directory/api/skills/download/7650" && unzip -o skill.zip -d .claude/skills/web-payments && rm skill.zipInstalls to .claude/skills/web-payments
About this skill
Web Payments Skill (Stripe)
For integrating Stripe payments into web applications - one-time payments, subscriptions, and checkout flows.
Sources: Stripe Checkout | Payment Element Best Practices | Building Solid Stripe Integrations | Subscriptions
Setup
1. Create Stripe Account
- Go to https://dashboard.stripe.com/register
- Complete business verification
- Get API keys from https://dashboard.stripe.com/apikeys
2. Environment Variables
# .env
STRIPE_SECRET_KEY=sk_test_xxx # Server-side only
STRIPE_PUBLISHABLE_KEY=pk_test_xxx # Client-side safe
STRIPE_WEBHOOK_SECRET=whsec_xxx # For webhook verification
# Production
STRIPE_SECRET_KEY=sk_live_xxx
STRIPE_PUBLISHABLE_KEY=pk_live_xxx
3. Install SDK
# Node.js
npm install stripe @stripe/stripe-js
# Python
pip install stripe
Integration Options
| Method | Best For | Complexity |
|---|---|---|
| Checkout (Hosted) | Quick setup, Stripe-hosted page | Low |
| Checkout (Embedded) | Custom site, embedded form | Low |
| Payment Element | Full customization, complex flows | Medium |
| Custom Form | Complete control (rare) | High |
Recommendation: Start with Checkout, migrate to Payment Element if needed.
Stripe Checkout (Recommended)
Server: Create Checkout Session
Node.js / Next.js
// app/api/checkout/route.ts (Next.js App Router)
import Stripe from "stripe";
import { NextResponse } from "next/server";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(request: Request) {
const { priceId, mode = "payment" } = await request.json();
try {
const session = await stripe.checkout.sessions.create({
mode: mode as "payment" | "subscription",
payment_method_types: ["card"],
line_items: [
{
price: priceId,
quantity: 1,
},
],
success_url: `${process.env.NEXT_PUBLIC_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/canceled`,
// Optional: Link to existing customer
// customer: customerId,
// Optional: Collect shipping
// shipping_address_collection: { allowed_countries: ["US", "CA"] },
// Optional: Add metadata for tracking
metadata: {
userId: "user_123",
source: "pricing_page",
},
});
return NextResponse.json({ sessionId: session.id, url: session.url });
} catch (error) {
console.error("Stripe error:", error);
return NextResponse.json({ error: "Failed to create session" }, { status: 500 });
}
}
Python / FastAPI
# app/api/checkout.py
import stripe
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
import os
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
router = APIRouter()
class CheckoutRequest(BaseModel):
price_id: str
mode: str = "payment" # or "subscription"
@router.post("/api/checkout")
async def create_checkout_session(request: CheckoutRequest):
try:
session = stripe.checkout.Session.create(
mode=request.mode,
payment_method_types=["card"],
line_items=[{
"price": request.price_id,
"quantity": 1,
}],
success_url=f"{os.environ['APP_URL']}/success?session_id={{CHECKOUT_SESSION_ID}}",
cancel_url=f"{os.environ['APP_URL']}/canceled",
metadata={
"user_id": "user_123",
},
)
return {"session_id": session.id, "url": session.url}
except stripe.error.StripeError as e:
raise HTTPException(status_code=400, detail=str(e))
Client: Redirect to Checkout
// components/CheckoutButton.tsx
"use client";
import { loadStripe } from "@stripe/stripe-js";
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);
export function CheckoutButton({ priceId }: { priceId: string }) {
const handleCheckout = async () => {
const response = await fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ priceId }),
});
const { url } = await response.json();
// Redirect to Stripe Checkout
window.location.href = url;
};
return (
<button onClick={handleCheckout}>
Subscribe Now
</button>
);
}
Embedded Checkout
For keeping users on your site:
// components/EmbeddedCheckout.tsx
"use client";
import { useEffect, useState } from "react";
import { loadStripe } from "@stripe/stripe-js";
import {
EmbeddedCheckoutProvider,
EmbeddedCheckout,
} from "@stripe/react-stripe-js";
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);
export function EmbeddedCheckoutForm({ priceId }: { priceId: string }) {
const [clientSecret, setClientSecret] = useState("");
useEffect(() => {
fetch("/api/checkout/embedded", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ priceId }),
})
.then((res) => res.json())
.then((data) => setClientSecret(data.clientSecret));
}, [priceId]);
if (!clientSecret) return <div>Loading...</div>;
return (
<EmbeddedCheckoutProvider stripe={stripePromise} options={{ clientSecret }}>
<EmbeddedCheckout />
</EmbeddedCheckoutProvider>
);
}
Server endpoint for embedded:
// app/api/checkout/embedded/route.ts
export async function POST(request: Request) {
const { priceId } = await request.json();
const session = await stripe.checkout.sessions.create({
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
ui_mode: "embedded",
return_url: `${process.env.NEXT_PUBLIC_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
});
return NextResponse.json({ clientSecret: session.client_secret });
}
Webhooks (Critical)
Never trust client-side data. Always verify payments via webhooks.
Webhook Endpoint
// app/api/webhooks/stripe/route.ts
import Stripe from "stripe";
import { headers } from "next/headers";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;
export async function POST(request: Request) {
const body = await request.text();
const signature = headers().get("stripe-signature")!;
let event: Stripe.Event;
// Verify webhook signature
try {
event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
} catch (err) {
console.error("Webhook signature verification failed");
return new Response("Invalid signature", { status: 400 });
}
// Handle events
switch (event.type) {
case "checkout.session.completed": {
const session = event.data.object as Stripe.Checkout.Session;
await handleCheckoutComplete(session);
break;
}
case "customer.subscription.created":
case "customer.subscription.updated": {
const subscription = event.data.object as Stripe.Subscription;
await handleSubscriptionUpdate(subscription);
break;
}
case "customer.subscription.deleted": {
const subscription = event.data.object as Stripe.Subscription;
await handleSubscriptionCanceled(subscription);
break;
}
case "invoice.payment_failed": {
const invoice = event.data.object as Stripe.Invoice;
await handlePaymentFailed(invoice);
break;
}
default:
console.log(`Unhandled event type: ${event.type}`);
}
// Return 200 quickly - process async if needed
return new Response("OK", { status: 200 });
}
async function handleCheckoutComplete(session: Stripe.Checkout.Session) {
const userId = session.metadata?.userId;
const customerId = session.customer as string;
const subscriptionId = session.subscription as string;
// Update your database
await db.user.update({
where: { id: userId },
data: {
stripeCustomerId: customerId,
stripeSubscriptionId: subscriptionId,
subscriptionStatus: "active",
},
});
}
Python Webhook
# app/api/webhooks.py
import stripe
from fastapi import APIRouter, Request, HTTPException
router = APIRouter()
@router.post("/api/webhooks/stripe")
async def stripe_webhook(request: Request):
payload = await request.body()
sig_header = request.headers.get("stripe-signature")
try:
event = stripe.Webhook.construct_event(
payload, sig_header, os.environ["STRIPE_WEBHOOK_SECRET"]
)
except ValueError:
raise HTTPException(status_code=400, detail="Invalid payload")
except stripe.error.SignatureVerificationError:
raise HTTPException(status_code=400, detail="Invalid signature")
# Handle events
if event["type"] == "checkout.session.completed":
session = event["data"]["object"]
await handle_checkout_complete(session)
elif event["type"] == "customer.subscription.deleted":
subscription = event["data"]["object"]
await handle_subscription_canceled(subscription)
return {"status": "success"}
Key Webhook Events
| Event | When | Action |
|---|---|---|
checkout.session.completed | Payment successful | Provision access |
customer.subscription.created | New subscription | Store subscription ID |
customer.subscription.updated | Plan change | Update plan in DB |
customer.subscription.deleted | Canceled | Revoke access |
invoice.payment_failed | Payment failed | Notify user, retry |
invoice.paid | Renewal successful | Extend access |
Content truncated.
More by alinaqi
View all skills by alinaqi →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversIntegrate Stripe for seamless payment processing, credit card payments, and customer management in e-commerce and billin
Streamline billing with Paddle API tools. Manage products, prices, and subscriptions efficiently—an alternative to Strip
Dodo Payments — lightweight, serverless-ready API for AI-driven billing, subscriptions, and customer management.
Order online from Starbucks with Terminal.shop—browse coffee products, manage carts, and enjoy secure payments for subsc
Powerful MCP server for Slack with advanced API, message fetching, webhooks, and enterprise features. Robust Slack data
Bridge your workflow to Shopify using the Shopify API for seamless product, order, and customer management—all via the S
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.