Build This Now
Build This Now
Was ist der Claude Code?Claude Code installierenClaude Code Native InstallerDein erstes Claude Code-Projekt
Claude Code v2.1.122 Release NotesClaude Code Dynamic Workflows: 1.000 Subagents auf einer echten Codebase orchestrierenClaude Code Best PracticesClaude Opus 4.7 Best PracticesClaude Code auf einem VPSGit-IntegrationClaude Code ReviewClaude Code WorktreesClaude Code Remote ControlClaude Code ChannelsChannels, Routines, Teleport, DispatchGeplante Aufgaben mit Claude CodeClaude Code BerechtigungenClaude Code Auto-ModusStripe-Zahlungen mit Claude Code einbauenFeedback-LoopsTodo-WorkflowsClaude Code TasksProjekt-TemplatesClaude Code Preise und Token-NutzungClaude Code Preise: Was du wirklich zahlstClaude Code Ultra ReviewEine Next.js-App mit Claude Code bauenClaude Code With Supabase: Database, Auth, RLSVercel deepsec with Claude CodeAgentic Commerce: Wie du eine App baust, für die KI-Agents bezahlen könnenClaude Code 1M Context in Practice: When Bigger Isn't BetterClaude Code GitHub Actions Setup Guide (@claude + Cron)Claude Code Headless Mode: The Definitive Guide to claude -pClaude Code Max Plan vs API Cost: Break-Even GuideClaude Code Prompt Caching: The Token Discount Most People Never Turn OnRun a Team of AI Agents in Parallel with Git WorktreesPrompt Injection in Coding Agents: How to Not Get Pwned
speedy_devvkoen_salo
Blog/Handbook/Workflow/Adding Stripe Payments With Claude Code

Stripe-Zahlungen mit Claude Code einbauen

Verbinde Stripe Checkout, Webhooks und das Customer Portal in einer Next.js-App mit Claude Code. Vom ersten Prompt bis zur Live-Zahlung in einer Session.

Hören Sie auf zu konfigurieren. Fangen Sie an zu bauen.

SaaS-Builder-Vorlagen mit KI-Orchestrierung.

Published May 3, 20269 min readHandbook hubWorkflow index

Problem: Eine Stripe-Integration hat 7 bewegliche Teile: Checkout, Webhooks, das Customer Portal, Environment-Variablen, Test-Keys, Live-Keys und die CLI. Die meisten Tutorials decken drei davon ab und lassen dich den Rest um Mitternacht debuggen.

Quick Win: Füg den Stripe-MCP-Server mit einem einzigen Kommando zu Claude Code hinzu, damit Claude beim Bauen in Echtzeit Kunden, Preise und Abonnements nachschlagen kann:

claude mcp add --transport http stripe https://mcp.stripe.com/

Diese eine Zeile gibt Claude direkten Zugriff auf deinen Stripe-Account. Es kann Live-Daten lesen, prüfen, ob deine Produkte existieren, und Config-Fehler abfangen, bevor sie deinen Webhook-Handler erreichen.

Was du vorher brauchst

Drei Dinge müssen stehen.

Ein Stripe-Account mit mindestens einem angelegten Produkt und Preis. Du kannst Claude die über den MCP-Server anlegen lassen, ohne das Dashboard anzufassen. Sobald die MCP verbunden ist, reicht ein Prompt wie „create a product called Pro Plan with a $29/month recurring price".

Claude Code mit verbundener Stripe-MCP (Kommando oben). Die Alternative ist der Stripe-Best-Practices-Skill, der Stripe-Dokumentation in deine Session injiziert:

npx skills add https://docs.stripe.com --yes

Der MCP-Server ist für aktive Entwicklung die bessere Wahl. Claude kann ihn mitten in der Session aufrufen, um deine Preise aufzulisten, einen Kunden per E-Mail nachzuschlagen, den aktuellen Status eines Abonnements abzurufen oder zu prüfen, ob dein Webhook-Secret zu dem passt, was das Dashboard zeigt. Der Skill gibt dir nur Dokumentationskontext. Er fragt deinen Account nicht ab.

Die beiden schließen sich nicht aus. Manche Teams fahren beides: MCP für Live-Abfragen, Skill für Best-Practice-Anleitung. Die MCP mit einem eingeschränkten API-Key (rk_test_...) ist im Testmodus das sicherere Setup, weil eingeschränkte Keys begrenzen, welche Stripe-Objekte Claude anfassen kann.

Vier Environment-Variablen in deiner .env.local-Datei:

STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_URL=http://localhost:3000

STRIPE_SECRET_KEY berührt nie den Client. NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY darf offengelegt werden. STRIPE_WEBHOOK_SECRET kommt aus der Stripe CLI, wenn du das lokale Event-Forwarding startest (im Test-Abschnitt behandelt). NEXT_PUBLIC_URL speist deine success_url- und return_url-Parameter.

Checkout Sessions vs. Payment Intents

Zwei Stripe-APIs können eine Zahlung entgegennehmen. Die falsche zu wählen kostet dich Wochen Arbeit.

Checkout Sessions (stripe.checkout.sessions.create()) leiten den User auf eine von Stripe gehostete Seite oder ein eingebettetes Formular auf deiner Domain. Stripe kümmert sich um Karteneingabe, 3D Secure, Apple Pay, Währungsanzeige und Steuer. Für die meisten SaaS-Produkte ist das die richtige Wahl. Einmalkäufe und Abonnements laufen beide darüber.

Payment Intents (stripe.paymentIntents.create()) sind tiefergehend. Du baust das Formular selbst mit Stripe Elements, sammelst Kartendaten und rufst die API auf. Mehr Kontrolle, mehr Code, mehr Wartung. Nutz das nur, wenn du eine voll eigene Checkout-UI brauchst, die eine gehostete Seite nicht liefern kann.

Das 2026 bevorzugte Muster für Checkout Sessions ist Embedded Checkout: ui_mode: 'embedded' hält den User auf deiner Domain, nutzt die Komponenten EmbeddedCheckoutProvider und EmbeddedCheckout aus @stripe/react-stripe-js und kehrt zu einer return_url zurück, die du setzt. Hosted Checkout (Redirect zu stripe.com) funktioniert weiterhin, aber Embedded ist das, wozu Stripe neue Integrationen steuert.

Den Checkout-Flow bauen

Bitte Claude, die Route zu scaffolden, und prüf dann den mode-Parameter, bevor du auslieferst.

Ein nützlicher Prompt für Claude hier ist: „Build me a Stripe Checkout Sessions route in app/api/checkout/route.ts. Use mode: payment for one-time purchases, return the session URL as JSON, and read all URLs from environment variables."

Für einen Einmalkauf sieht die Route so aus:

// app/api/checkout/route.ts
import { NextResponse } from 'next/server'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
})

export async function POST(request: Request) {
  const { priceId } = await request.json()

  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    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}/pricing`,
  })

  return NextResponse.json({ url: session.url })
}

Für ein Abonnement änderst du genau eine Sache. Setz mode: 'subscription' statt mode: 'payment'. Deine priceId muss auf einen wiederkehrenden Preis zeigen (nicht auf einen Einmalpreis) in Stripe. Alles andere in der Route bleibt identisch.

Um auf Embedded Checkout umzustellen, füg ui_mode: 'embedded' hinzu und ersetz success_url durch return_url. Die Antwort gibt session.client_secret zurück statt session.url, das der EmbeddedCheckoutProvider im Frontend nutzt.

Webhooks: Der Teil, den alle falsch machen

Webhooks sind, wo Stripe zu deiner App zurückspricht. Jede Bereitstellungsentscheidung (Zugriff gewähren, Zugriff entziehen, eine Quittung senden) sollte im Webhook-Handler leben, nicht im Checkout-Success-Redirect. User schließen Tabs und drücken den Zurück-Button. Der Redirect ist unzuverlässig. Der Webhook feuert immer.

Das kritische Problem im Next.js App Router ist das Parsen des Raw Body. Stripes Signaturprüfung (stripe.webhooks.constructEvent) braucht den rohen Request-Body als String. Der App Router parst den Body, bevor dein Handler ihn sieht. Wenn du request.json() aufrufst, wird der Stream verbraucht, und die Prüfung scheitert jedes Mal.

Gib Claude die exakte Vorgabe: „Build a Stripe webhook handler at app/api/stripe-webhook/route.ts. It must use request.text() for the raw body, not request.json(), and verify the signature before processing any events."

Nutz stattdessen request.text():

// app/api/stripe-webhook/route.ts
import { NextResponse } from 'next/server'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
})

export async function POST(request: Request) {
  const rawBody = await request.text()
  const sig = request.headers.get('stripe-signature')!

  let event: Stripe.Event

  try {
    event = stripe.webhooks.constructEvent(
      rawBody,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET!
    )
  } catch (err) {
    return NextResponse.json(
      { error: 'Webhook signature verification failed' },
      { status: 400 }
    )
  }

  switch (event.type) {
    case 'checkout.session.completed': {
      const session = event.data.object as Stripe.Checkout.Session
      // Provision access, send welcome email
      await grantAccess(session.customer as string)
      break
    }
    case 'customer.subscription.updated': {
      const sub = event.data.object as Stripe.Subscription
      // Update tier in DB
      await updateSubscription(sub.customer as string, sub.status)
      break
    }
    case 'customer.subscription.deleted': {
      const sub = event.data.object as Stripe.Subscription
      // Revoke access
      await revokeAccess(sub.customer as string)
      break
    }
    case 'invoice.payment_failed': {
      const invoice = event.data.object as Stripe.Invoice
      // Send dunning email, flag in DB
      await handleFailedPayment(invoice.customer as string)
      break
    }
  }

  return NextResponse.json({ received: true })
}

Die vier Events, die du mindestens behandeln solltest, stehen in der Tabelle unten. Den Rest kannst du hinzufügen, wenn deine Billing-Logik wächst.

EventWann es feuertAktion
checkout.session.completedZahlung oder Abo gestartetZugriff bereitstellen, Willkommens-E-Mail senden
customer.subscription.updatedPlan-Wechsel, Verlängerung, Trial-EndeDB-Tier aktualisieren
customer.subscription.deletedKündigungZugriff entziehen
invoice.payment_failedWiederkehrende Belastung fehlgeschlagenDunning-E-Mail senden, in DB markieren

Noch eine Sache: Diese Route muss von jeder Next.js-Middleware ausgenommen werden, die den Body liest, und sie darf nicht in die Auth-Checks deiner App gehüllt sein. Stripe postet als unauthentifizierter Request dorthin. Schütz sie nur über die Signaturprüfung.

Customer Portal einrichten

Das Customer Portal lässt User ihr eigenes Abonnement verwalten: kündigen, Zahlungsinfos aktualisieren, Rechnungen ansehen. Ein Schritt bringt die meisten Entwickler aus dem Tritt.

Du musst das Portal im Stripe-Dashboard konfigurieren, bevor du irgendwelche Portal-Sessions erstellst. Ohne gespeicherte Konfiguration gibt jeder billingPortal.sessions.create()-Aufruf einen Fehler zurück. Die Konfigurations-URL für den Testmodus ist https://dashboard.stripe.com/test/settings/billing/portal. Der Live-Modus hat seine eigene, separate URL unter https://dashboard.stripe.com/settings/billing/portal. Beide brauchen vor dem Deploy eine Konfiguration.

Der Konfigurationsschritt ist, wo du entscheidest, welche Aktionen User vornehmen dürfen: ihr Abonnement kündigen, ihre Zahlungsmethode aktualisieren, Pläne wechseln, Rechnungen herunterladen. Setz diese Optionen im Dashboard, speichere die Konfiguration, und dann funktionieren deine API-Aufrufe.

Einmal konfiguriert, ist die Route zum Erstellen einer Session kurz:

// app/api/portal/route.ts
import { NextResponse } from 'next/server'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
})

export async function POST(request: Request) {
  const { customerId } = await request.json()

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

  return NextResponse.json({ url: session.url })
}

Dein Frontend leitet auf session.url weiter. Der User sieht seine Stripe-Billing-Seite, nimmt Änderungen vor und kehrt zu /account zurück, wenn er fertig ist. Die Änderungen feuern als customer.subscription.updated- oder customer.subscription.deleted-Events, die dein Webhook-Handler bereits abdeckt.

Hinweis: Test- und Live-Modus-Portal-Konfigurationen sind komplett getrennt. Das Portal im Testmodus zu konfigurieren richtet es nicht für den Live-Modus ein. Geh dieselben Konfigurationsschritte in beiden Umgebungen durch, bevor du live gehst.

Den kompletten Flow testen

Die Stripe CLI leitet Live-Events von Stripe an deinen lokalen Server weiter. Führ das in einem separaten Terminal aus, bevor du irgendwelche Zahlungen testest:

stripe listen --forward-to localhost:3000/api/stripe-webhook

Die CLI gibt beim Start ein Webhook-Signing-Secret aus. Dieser Wert kommt in STRIPE_WEBHOOK_SECRET in deiner .env.local. Er ändert sich jedes Mal, wenn du den Listener neu startest — hardcode ihn also nicht.

Um ein bestimmtes Event auszulösen, ohne dich durch ein Zahlungsformular zu klicken, nutz stripe trigger:

stripe trigger checkout.session.completed
stripe trigger customer.subscription.deleted
stripe trigger invoice.payment_failed

Testkarten für verschiedene Szenarien:

SzenarioKartennummer
Erfolgreiche Zahlung4242 4242 4242 4242
Abgelehnt4000 0000 0000 0002
3D Secure erforderlich4000 0025 0000 3155
Unzureichende Deckung4000 0000 0000 9995

Nimm ein beliebiges zukünftiges Ablaufdatum, einen beliebigen dreistelligen CVC und eine beliebige PLZ. Die Kartennummer ist der einzige Wert, der das Ergebnis ändert.

Die empfohlene Test-Sequenz ist: Starte den CLI-Listener, öffne deine Checkout-Seite, schließ eine Zahlung mit Karte 4242 4242 4242 4242 ab, beobachte, wie das checkout.session.completed-Event in deinem Terminal eintrifft, und prüf, ob dein Handler lief (check die DB oder die Logs). Dann löse stripe trigger invoice.payment_failed aus, um zu bestätigen, dass dein Dunning-Pfad funktioniert, ohne auf eine echte fehlgeschlagene Belastung zu warten. Die 3D-Secure-Karte (4000 0025 0000 3155) deck zuletzt ab. Stripe leitet durch einen Authentifizierungsschritt, den dein Frontend behandeln muss. Wenn der Redirect still scheitert, wird die Session nie abgeschlossen und kein Webhook feuert.

Going-Live-Checkliste

Der Wechsel von Test- zu Live-Modus sind vier Schritte, nicht ein Key-Tausch.

Erstens: Ersetz deine Test-Keys (sk_test_, pk_test_) durch Live-Keys (sk_live_, pk_live_) in deinen Production-Environment-Variablen.

Zweitens: Konfigurier das Customer Portal im Live-Modus unter https://dashboard.stripe.com/settings/billing/portal. Test- und Live-Modus haben komplett getrennte Portal-Konfigurationen. Was du im Testmodus setzt, wird nicht übernommen.

Drittens: Setz deinen Webhook-Endpoint im Stripe-Dashboard auf deine Production-URL. Geh zu Developers > Webhooks > Add endpoint und zeig auf https://yourdomain.com/api/stripe-webhook. Kopier das Live-Webhook-Signing-Secret und setz es als STRIPE_WEBHOOK_SECRET in Production.

Viertens: Bestätige deine Preis-IDs. Test-Modus-Preise (price_test_...) existieren im Live-Modus nicht. Alle hartcodierten Preis-IDs müssen auf Live-Preis-IDs aktualisiert oder aus Environment-Variablen gelesen werden.

Führ eine echte Zahlung mit einer echten Karte durch (und erstatte sie dann), bevor du die Integration für fertig erklärst. Der CLI-Trigger ist gut zum Testen von Handlern, aber nichts bestätigt den kompletten Pfad so wie eine tatsächliche Belastung.

Was Build This Now vorgebaut ausliefert

Diesen Flow zu schreiben und zu debuggen kostet die meisten Entwickler einen ganzen Tag. Stripes Checkout-Edge-Function, der Webhook-Handler, die Customer-Portal-Route und alle vier Environment-Variablen sind in Build This Now vom ersten Tag an vorverdrahtet. Die Integration deployt auf Supabase Edge Functions, getestet und funktionierend, bevor du dein erstes eigenes Feature schreibst.

Stripe ist nicht der schwere Teil. Jedes Stück in der richtigen Reihenfolge verbunden zu bekommen, schon. Hast du es einmal gemacht, weißt du, wo die Lücken sind.

Continue in Workflow

  • Agentic Commerce: Wie du eine App baust, für die KI-Agents bezahlen können
    Ein Guide in einfachem Deutsch zu Agentic Commerce im Jahr 2026: Was x402, ACP und das Machine Payments Protocol tun, plus eine Wochenend-Anleitung, um eine bezahlte API auszuliefern, von der KI-Agents kaufen können.
  • Claude Code Best Practices
    Fünf Gewohnheiten trennen Entwickler, die mit Claude Code liefern: PRDs, modulare CLAUDE.md-Regeln, Custom-Slash-Commands, /clear-Resets und eine System-Evolutions-Denkweise.
  • Claude Code Auto-Modus
    Ein zweites Sonnet-Modell prüft jeden Claude Code-Tool-Aufruf, bevor er ausgeführt wird. Was der Auto-Modus blockiert, was er erlaubt, und die Erlaubnisregeln, die er in deine Einstellungen schreibt.
  • Channels, Routines, Teleport, Dispatch
    Die vier Claude-Code-Features, die Anthropic im März und April 2026 ausgeliefert hat und die die CLI in eine ereignisgesteuerte Koordinationsschicht über Handy, Web und Desktop verwandeln.
  • Claude Code 1M Context in Practice: When Bigger Isn't Better
    The 1M-token context window is GA at flat pricing, but bigger isn't always better. A decision framework, token-cost math, and when to use /compact, subagents, and dynamic workflows instead.
  • Claude Code Channels
    Claude Code per Plugin-MCP-Server in Telegram, Discord oder iMessage einbinden. Setup-Anleitungen und die asynchronen Mobil-Workflows, die das Einrichten lohnenswert machen.

More from Handbook

  • Grundlagen für Agenten
    Fünf Möglichkeiten, spezialisierte Agenten in Claude Code zu erstellen: Aufgaben-Unteragenten, .claude/agents YAML, benutzerdefinierte Slash-Befehle, CLAUDE.md Personas und perspektivische Aufforderungen.
  • Agent-Harness-Engineering
    Der Harness ist jede Schicht rund um deinen KI-Agenten, außer dem Modell selbst. Lern die fünf Steuerungshebel, das Constraint-Paradoxon und warum das Harness-Design die Performance des Agenten mehr bestimmt als das Modell.
  • Agenten-Muster
    Orchestrator, Fan-out, Validierungskette, Spezialistenrouting, Progressive Verfeinerung und Watchdog. Sechs Orchestrierungsformen, um Claude Code Sub-Agenten zu verdrahten.
  • Agent Teams Best Practices
    Bewährte Muster für Claude Code Agent Teams. Kontextreiche Spawn-Prompts, richtig bemessene Aufgaben, Datei-Eigentümerschaft, Delegate-Modus und Fixes für v2.1.33-v2.1.45.

Hören Sie auf zu konfigurieren. Fangen Sie an zu bauen.

SaaS-Builder-Vorlagen mit KI-Orchestrierung.

Claude Code Auto-Modus

Ein zweites Sonnet-Modell prüft jeden Claude Code-Tool-Aufruf, bevor er ausgeführt wird. Was der Auto-Modus blockiert, was er erlaubt, und die Erlaubnisregeln, die er in deine Einstellungen schreibt.

Feedback-Loops

Gib Claude Code einen einzigen Prompt, der Code schreibt, deinen Test- oder Dev-Befehl ausführt, die Ausgabe liest, alles Kaputte behebt und schleift, bis die Suite grün ist.

On this page

Was du vorher brauchst
Checkout Sessions vs. Payment Intents
Den Checkout-Flow bauen
Webhooks: Der Teil, den alle falsch machen
Customer Portal einrichten
Den kompletten Flow testen
Going-Live-Checkliste
Was Build This Now vorgebaut ausliefert

Hören Sie auf zu konfigurieren. Fangen Sie an zu bauen.

SaaS-Builder-Vorlagen mit KI-Orchestrierung.