Stripe Integration mit Claude Code: Payments, Subscriptions & Webhooks 2026
Stripe ist die mächtigste Payment-Plattform — aber auch eine der komplexesten zu integrieren. Checkout Sessions, Subscription-Lifecycle, Proration, Webhooks, Customer Portal: Claude Code generiert jeden Teil korrekt und erklärt die Fallstricke.
Der Stripe-Integration-Flow
- Stripe-Kunde anlegen bei Registration — Stripe Customer ID in DB speichern
- Checkout Session erstellen — Nutzer zur Stripe-Seite leiten
- Webhook empfangen:
checkout.session.completed→ Subscription aktivieren - Subscription-Lifecycle managen: Upgrade, Downgrade, Cancel, Reaktivierung
- Customer Portal: Self-Service für Nutzer (Zahlungsmethode, Kündigung)
- Rechnungen und Invoices: automatisch, konfigurierbar
Claude Code Prompt-Strategie: Stripe-Integrationen sind komplex weil viele Randfälle existieren. Prompt-Tipp: "Implementiere Stripe Subscriptions. Berücksichtige: failed payments, dunning, trial periods, proration bei Plan-Wechsel, und Webhook-Idempotency." So bekommt man produktionsreife Code.
Checkout Session: One-Time und Subscription
CheckoutSession erstellen
# Prompt: "Erstelle Stripe Checkout für Subscription mit Trial"
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
export async function createCheckoutSession({
customerId, priceId, userId, successUrl, cancelUrl
}) {
const session = await stripe.checkout.sessions.create({
customer: customerId,
mode: 'subscription',
line_items: [{ price: priceId, quantity: 1 }],
// 14-Tage-Trial
subscription_data: {
trial_period_days: 14,
metadata: { userId }
},
// Success: nach Checkout weiterleiten
success_url: `${successUrl}?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: cancelUrl,
// Automatische Steuern (Stripe Tax)
automatic_tax: { enabled: true },
// Metadata für Webhook
metadata: { userId }
});
return session.url;
}
# One-Time Payment (statt Subscription):
# mode: 'payment' statt 'subscription'
# line_items: [{ price: oneTimePriceId, quantity: 1 }]
Webhook-Handler: Der kritische Teil
WebhooksAlle relevanten Events abfangen
# Die wichtigsten Stripe-Webhook-Events für SaaS:
| Event | Wann | Action |
|---|---|---|
checkout.session.completed |
Kauf abgeschlossen | Plan in DB aktivieren |
customer.subscription.updated |
Plan-Wechsel, Trial-Ende | Plan + Status updaten |
customer.subscription.deleted |
Kündigung wirksam | Auf FREE downgraden |
invoice.payment_failed |
Zahlung fehlgeschlagen | User informieren, Dunning |
invoice.paid |
Rechnung bezahlt | Zugang verlängern |
# Webhook-Handler (Next.js App Router)
export async function POST(req) {
const body = await req.text();
const sig = req.headers.get('stripe-signature');
let event;
try {
event = stripe.webhooks.constructEvent(
body, sig, process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
return Response.json({ error: 'Invalid signature' }, { status: 400 });
}
// Idempotency: Events können mehrfach kommen!
const processed = await db.webhookEvents.findUnique({
where: { stripeEventId: event.id }
});
if (processed) return Response.json({ received: true });
await db.webhookEvents.create({ data: { stripeEventId: event.id } });
switch (event.type) {
case 'customer.subscription.updated':
case 'customer.subscription.created': {
const sub = event.data.object;
await syncSubscription(sub);
break;
}
case 'customer.subscription.deleted':
await cancelSubscription(event.data.object);
break;
case 'invoice.payment_failed':
await handleFailedPayment(event.data.object);
break;
}
return Response.json({ received: true });
}
Webhook-Idempotency ist Pflicht! Stripe kann dasselbe Event mehrfach senden (Netzwerkfehler, Retries). Immer prüfen ob das Event bereits verarbeitet wurde — sonst wird der User doppelt upgegraded oder downgraded.
Subscription-Management
SubscriptionPlan-Wechsel mit Proration
# Upgrade von BASIC zu PRO — anteilige Abrechnung
async function upgradeSubscription(subscriptionId, newPriceId) {
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
const updated = await stripe.subscriptions.update(subscriptionId, {
items: [{
id: subscription.items.data[0].id,
price: newPriceId
}],
// Sofort upgraden, anteilig berechnen
proration_behavior: 'create_prorations',
// Alternativ: 'none' (keine Proration) oder 'always_invoice' (sofort Rechnung)
});
return updated;
}
# Kündigung zum Periodenende (nicht sofort):
async function cancelAtPeriodEnd(subscriptionId) {
return stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true
});
// User behält Zugang bis Abo-Ende → dann subscription.deleted Event
}
Customer Portal: Self-Service
PortalStripe Customer Portal einbinden
# Customer Portal: Stripe managed UI für Zahlungen, Pläne, Kündigung
# Setup: Stripe Dashboard → Billing → Customer Portal → Configure
export async function createPortalSession(customerId, returnUrl) {
const session = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: returnUrl // Wohin nach Portal-Exit
});
return session.url;
}
# In der App: Button → redirect zu Portal
# User kann selbst: Zahlungsmethode ändern, Abo kündigen, Plan wechseln
# Du bekommst Webhook-Events für alle Änderungen → syncSubscription()
Customer Portal = Pflicht für SaaS. Ohne Portal musst du jeden Support-Case manuell bearbeiten. Mit Portal: User löst 90% selbst. Setup dauert 10 Minuten, spart Stunden pro Woche.
Testing: Stripe CLI und Test-Karten
# Stripe CLI: Webhooks lokal testen
stripe listen --forward-to localhost:3000/api/webhooks/stripe
# Webhook-Secret für lokale Tests:
# STRIPE_WEBHOOK_SECRET=whsec_xxx (aus stripe listen Output)
# Test-Karten:
# Erfolg: 4242 4242 4242 4242
# Declined: 4000 0000 0000 0002
# 3D-Secure: 4000 0025 0000 3155
# SCA: 4000 0027 6000 3184
# Events triggern ohne echten Checkout:
stripe trigger payment_intent.succeeded
stripe trigger customer.subscription.deleted
Payment-Integration im Kurs
Im Claude Code Mastery Kurs: vollständige Stripe-Integration mit Checkout, Webhooks, Customer Portal, Subscription-Lifecycle und Testing — direkt in eine funktionierende SaaS-App eingebaut.
14 Tage kostenlos testen →