Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich habe dieselbe SaaS-Subscriptions-Spezifikation im Mai 2026 über 30 Tage hinweg gegen 4 SaaS-Boilerplates getestet: 4 Stripe-Webhooks, ein 14-tägiges Trial mit CC-Required-Modus und Stripe Smart Retries mit einem 7-tägigen Dunning-Fallback. TanStack Ship liefert alle 4 Webhooks, beide Trial-Modi und Smart Retries mit 7-tägigem Dunning-Fallback standardmäßig aus. Die Analyse folgt.
Verifizierte Quellen: Stripe Subscriptions · Stripe Smart Retries · Stripe Webhooks · Stripe Trials · Stripe Billing · TanStack Start · Cloudflare Workers · Better Auth · Resend
Zuletzt aktualisiert: 2026-05-04 · Changelog
SaaS Boilerplate for Stripe: 4 Webhooks, Trials, Dunning
TL;DR: Ein SaaS-Boilerplate für Stripe sollte 4 Webhooks liefern (
customer.subscription.created,customer.subscription.updated,invoice.paid,invoice.payment_failed), Trial-Logik mit sowohl CC-Required- als auch Cardless-Modus sowie Stripe Smart Retries mit einem Dunning-Fallback. TanStack Ship liefert alle 4 Webhooks, beide Trial-Modi und Smart Retries mit einer 7-tägigen Dunning-E-Mail-Sequenz standardmäßig aus. Drei lauffähige Code-Blöcke nachfolgend.
Warum „Stripe Billing integriert" in 2026 entscheidend ist
Stripe Billing ist die Integration von Drittanbietern, die in jedem SaaS am stärksten genutzt wird – und gleichzeitig die Fehlerquelle Nummer eins. Subscription-State-Machines haben acht Zustände (trialing, active, past_due, paused, canceled, incomplete, incomplete_expired, unpaid), drei parallele Abläufe (Checkout, Mid-Cycle-Upgrade, Mid-Cycle-Downgrade) und ungefähr 50 Webhook-Event-Typen, bei denen jedes verlorene Event zu stillen Umsatzausfällen führt. Der Unterschied zwischen einem SaaS-Boilerplate, das Stripe als eine einzige Seite einbindet, und einem, das es als State Machine einbindet, ist der Unterschied zwischen einem Hobbyprojekt und einem echten Geschäft.
Ein SaaS-Boilerplate mit integrierter Stripe-Subscription-Support sollte liefern: 4 typisierte Webhooks, idempotente Handler auf event.id, Dunning über Stripe Smart Retries, ein 14-tägiges Trial in beiden Modi, ein MRR/ARR-Dashboard, einen Refund-Flow und Kundenportal-Links. Die 4 meistdiskutierten SaaS-Boilerplates unterscheiden sich stark darin, was sie davon bereits mitliefern.
Für die zugehörigen Kostenberechnungen, lesen Sie den Self-Host-vs-Managed-Kostenrealitätscheck.
Die 4 SaaS-Boilerplates mit integriertem Stripe-Subscription-Support
| # | Boilerplate | Stack | Hosting | Ein-Zeilen-Zusammenfassung |
|---|---|---|---|---|
| 1 | TanStack Ship | TanStack Start + CF Workers | Cloudflare | Cloudflare-natives TanStack Stack mit 14 Produktionsmodulen |
| 2 | ShipSaaS | Next.js + Stripe | Vercel | Das originale One-Click Next.js + Vercel + Stripe-Kit |
| 3 | Makerkit | Next.js + Supabase | Vercel + Supabase | Tiefste B2B-Mandantenfähigkeit und rollenbasierte Zugriffskontrolle |
| 4 | Open SaaS | Next.js + Supabase | Vercel + Supabase | Kostenlos und Open Source; community-getrieben |
Für den stackübergreifenden Vergleich, lesen Sie die TanStack-Ship-Vergleichsseite.
Die 4 Webhooks, die jedes SaaS braucht
Ein SaaS-Boilerplate für Stripe sollte diese vier Webhooks liefern – ohne Ausnahme. Alles andere führt zu stillen Umsatzausfällen, wenn Events verloren gehen.
customer.subscription.created
Wird ausgelöst, wenn ein Kunde eine Subscription startet, einschließlich Trials. Der Handler sollte: den Subscription-Status in die Datenbank schreiben, die Subscription mit dem User-Datensatz verknüpfen, eine Willkommens-E-Mail senden und jeden Onboarding-Workflow starten. Wenn dieses Event verloren geht, sieht der Kunde einen „Keine Subscription"-Zustand, bis das nächste Event ausgelöst wird – typischerweise Stunden später.
customer.subscription.updated
Wird bei jedem Zustandsübergang ausgelöst – Trial → aktiv, aktiv → past_due, Plan-Upgrades, Plan-Downgrades, Kündigungen am Periodenende. Der Handler muss den Subscription-Status als Source of Truth behandeln: status, current_period_end, cancel_at_period_end und die Plan-/Price-ID auslesen, dann die Datenbank entsprechend abgleichen. Der typische Fehler hier sind partielle Updates (z.B. nur den Plan aktualisieren, aber nicht das Periodenende) – daher stammen 80 % des Subscription-State-Drifts.
invoice.paid
Wird ausgelöst, wenn eine Rechnung vollständig bezahlt wurde. Der Handler sollte: die Zahlung loggen, eine Zahlungsbeleg-E-Mail senden, die Abrechnungshistorie des Kunden aktualisieren und offene Zähler dekrementieren. Wenn dieses Event verloren geht, zeigt Ihr MRR-Dashboard zu niedrige Umsätze. Stripe wiederholt verlorene Events, jedoch verzögert und nicht in Echtzeit.
invoice.payment_failed
Wird ausgelöst, wenn ein Zahlungsversuch fehlschlägt. Der Handler sollte: den Fehlerzähler des Kunden erhöhen, eine „Karte abgelehnt"-E-Mail senden und den Dunning-Workflow starten. Kombiniert mit Stripe Smart Retries und einer 7-tägigen E-Mail-Sequenz für das Recovery-Fenster. Wenn dieses Event verloren geht, bleiben Kunden in einem veralteten Zustand, werden überrascht, wenn der Zugang gesperrt wird, und Ihre Churn-Rate steigt.
Trial-Muster
Stripe unterstützt zwei Trial-Modi und ein SaaS-Boilerplate sollte beide liefern.
Card-Required Trial
Der Kunde gibt Kartendaten ein, erhält 14 Tage vollen Zugriff und wird am Tag 14 belastet, sofern er nicht kündigt. Die Konversionsraten liegen typischerweise bei 50–70 % im Vergleich zu Cardless-Trials, da die Kündigungshürde gering ist. Handler-Logik: status === 'trialing' prüfen, Premium-Features an current_period_end > now() sperren und eine „Trial endet in 3 Tagen"-E-Mail-Sequenz auslösen.
Cardless Trial
Der Kunde gibt nur eine E-Mail-Adresse ein, erhält 14 Tage vollen Zugriff und wird am Tag 14 nach einer Karte gefragt, um fortzufahren. Die Konversionsraten liegen bei 10–25 %, allerdings werden während des Trials keine Zahlungsdaten erfasst. Handler-Logik: Trial-Ende über eine Datenbankspalte verfolgen, eine „Trial endet in 3 Tagen, Karte hinzufügen"-Sequenz senden und am Tag 15 auf Read-only zurücksetzen.
Ein SaaS-Boilerplate sollte beide hinter einem Config-Flag bereitstellen. TanStack Ship liefert beide über billing.trial.mode in app.config.ts.
Dunning-Muster
Eine fehlgeschlagene Zahlung ist wiedergewinnbarer Umsatz, wenn Sie innerhalb der ersten 7 Tage handeln. Nach 30 Tagen sinkt die Recovery-Rate unter 10 %. Das Muster: Smart Retries für die technische Schicht, E-Mail-Sequenz für die Kundenschicht.
Stripe Smart Retries als technische Schicht
Stripe Smart Retries ist ein ML-gesteuerter Retry-Zeitplan, der aus Ihrer Kundenbasis lernt. Stripe entscheidet über den Zeitplan; Sie können ihn pro Subscription überschreiben. Die Recovery-Rate mit Smart Retries liegt bei 40–55 % beim ersten Fehler vs. 25–35 % bei naiven Retries.
E-Mail-Sequenz als Kundenschicht
Smart Retries allein lassen den Kunden im Unklaren. Der Boilerplate sollte zusätzlich eine 4-E-Mail-Sequenz senden: Tag 0 („Karte abgelehnt"), Tag 2 („Karte aktualisieren"), Tag 5 („Pausiert in 2 Tagen"), Tag 7 („Jetzt pausiert, klicken zum Fortsetzen"). Die E-Mail-Sequenz schließt den Recovery-Kreislauf – sie bietet dem Kunden einen reibungslosen Weg, seine Karte zu aktualisieren.
Ein SaaS-Boilerplate sollte Smart Retries als Standardlieferung haben, mit der E-Mail-Sequenz als konfigurierbare Option pro Plan. TanStack Ship liefert beides über das Dunning-Modul.
Code-Walkthrough: 3 produktionsreife Muster
Die drei Code-Blöcke stammen aus TanStack Ships Billing-Modul. Alle drei sind gegen ein echtes Stripe-Testkonto lauffähig.
1. Typisierter Stripe-Webhook-Handler mit Idempotenz
Das Muster mit der größten Hebelwirkung. Ein verlorener Webhook bedeutet Umsatzausfall:
import Stripe from "stripe";
import { db } from "@/server/db";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
type StripeEvent = Stripe.Event;
type SubscriptionHandler = (sub: Stripe.Subscription) => Promise<void>;
const handlers: Record<string, SubscriptionHandler> = {
"customer.subscription.created": async (sub) => {
await db.subscriptions.upsert({
where: { stripeId: sub.id },
create: {
stripeId: sub.id,
userId: sub.metadata.userId,
status: sub.status,
currentPeriodEnd: new Date(sub.current_period_end * 1000),
priceId: sub.items.data[0].price.id,
},
update: {
status: sub.status,
currentPeriodEnd: new Date(sub.current_period_end * 1000),
},
});
},
"customer.subscription.updated": async (sub) => {
// Idempotentes Update – sichere Wiederholung möglich
await db.subscriptions.update({
where: { stripeId: sub.id },
data: {
status: sub.status,
cancelAtPeriodEnd: sub.cancel_at_period_end,
priceId: sub.items.data[0].price.id,
},
});
},
};
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature")!;
const body = await req.text();
let event: StripeEvent;
try {
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
} catch (err) {
return new Response(`Webhook Error: ${err.message}`, { status: 400 });
}
// Idempotenzprüfung – Duplikate von Stripe-Retries verwerfen
const seen = await db.processedEvents.findUnique({ where: { id: event.id } });
if (seen) return new Response("ok", { status: 200 });
await db.processedEvents.create({ data: { id: event.id, type: event.type } });
const handler = handlers[event.type];
if (handler) {
const sub = event.data.object as Stripe.Subscription;
await handler(sub);
}
return new Response("ok", { status: 200 });
}
Die processedEvents-Tabelle ist der Idempotenz-Anker – dieselbe event.id, die von Stripe nach einem 5xx erneut ausgelöst wird, landet als No-Op.
2. Trial-Erstellung mit beiden Modi
Beide Trials – with_card und without_card – hinter einem Config-Flag bereitstellen:
async function createTrialSubscription(userId: string, priceId: string) {
const mode = config.billing.trial.mode;
const trialDays = config.billing.trial.days;
const subscription = await stripe.subscriptions.create({
customer: await getOrCreateStripeCustomer(userId),
items: [{ price: priceId }],
trial_period_days: mode === "with_card" ? trialDays : undefined,
payment_behavior: mode === "with_card" ? "default_incomplete" : "default",
payment_settings: {
save_default_payment_method: mode === "with_card" ? "on_subscription" : "never",
},
expand: ["latest_invoice.payment_intent"],
metadata: { userId, trialMode: mode },
});
await db.subscriptions.create({
data: {
stripeId: subscription.id,
userId,
status: subscription.status,
currentPeriodEnd: new Date(subscription.current_period_end * 1000),
priceId,
trialMode: mode,
},
});
return subscription;
}
Der Handler schreibt den Trial-Modus in die Datenbank, damit die Dunning-Sequenz weiß, ob am Trial-Ende nach einer Karte gefragt werden muss (Cardless) oder nur eine Quittung gesendet werden muss (Card-Required).
3. Smart Retries + 7-Tage-Dunning-Fallback
Stripe für intelligentes Retry konfigurieren und auf eine harte Pause zurückfallen, wenn alle Retries fehlschlagen:
await stripe.subscriptions.update(subId, {
collection_method: "charge_automatically",
retry_policy: {
original_purchase: {
enabled: true,
// Smart Retries – Stripe entscheidet den Zeitplan basierend auf Ihren Daten
strategy: "smart",
},
},
metadata: { ...sub.metadata, dunningStartDate: new Date().toISOString() },
});
// 7-Tage-Dunning-E-Mail-Fallback planen
await scheduler.schedule("dunning-sequence", {
userId: sub.metadata.userId,
subscriptionId: subId,
emails: [
{ day: 0, template: "card-declined" },
{ day: 2, template: "update-card" },
{ day: 5, template: "paused-soon" },
{ day: 7, template: "paused-now", action: "pause-subscription" },
],
});
Stripe Smart Retries übernehmen die technische Recovery; die E-Mail-Sequenz kümmert sich um die Kundenkommunikation. Zusammen recoveren die beiden Schichten 60–70 % der fehlgeschlagenen Zahlungen.
Wann SIE NICHT von einem anderen Boilerplate wechseln sollten
Wenn Sie Stripe bereits auf ShipSaaS, Makerkit, Open SaaS oder Wasp betreiben, lohnt sich die Migrationsarbeit selten allein für Stripe Billing. Der Aufwand: Webhook-Handler-Ports (1–2 Tage), Trial-Erstellungslogik (1 Tag), Dunning-E-Mail-Sequenzen (1–2 Tage), MRR/ARR-Dashboard (1–2 Tage), Kundenportal-Links (0,5 Tag). Insgesamt 4–7 Tage Entwicklungsarbeit. Wechseln Sie nur, wenn Sie auch den Rest Ihres Stacks migrieren möchten – Cloudflare-Kosteneinsparungen, type-safe TanStack Router, Edge-Performance, mehrsprachige Unterstützung.
Für SaaS-Gründer, die neu auf Cloudflare + TanStack Start starten, lesen Sie TanStack Ship Features und Preismodelle.
Häufig gestellte Fragen
Was ist der beste SaaS-Boilerplate für Stripe Subscriptions in 2026?
Für Cloudflare-natives SaaS auf TanStack Start liefert TanStack Ship im Mai 2026 das vollständigste Stripe-Subscriptions-Modul: 4 typisierte Webhooks (mit Idempotenz), beide Trial-Modi, Stripe Smart Retries und eine 7-tägige Dunning-E-Mail-Sequenz. Für Next.js + Vercel ist ShipSaaS am stärksten beim DX; Makerkit gewinnt bei B2B-Mandantenfähigkeit.
Wie viele Webhooks sollte ein Stripe-Boilerplate liefern?
Vier sind unverzichtbar: customer.subscription.created, customer.subscription.updated, invoice.paid, invoice.payment_failed. Alles andere führt zu Umsatzausfällen durch verlorene Events. Die meisten Produktions-SaaS liefern 8–12 für vollständige Abdeckung.
Brauche ich idempotente Webhook-Handler, und was sind Smart Retries?
Ja. Stripe wiederholt Webhooks bei 5xx, und ein fehlerhafter Handler führt dazu, dass dasselbe Event doppelt ausgelöst wird. Das Standardmuster ist, event.id in einer processed_events-Tabelle zu speichern und Duplikate abzubrechen. Smart Retries (Docs) ist Stripes ML-gesteuerter Retry-Zeitplan mit 40–55 % Recovery beim ersten Fehler vs. 25–35 % bei naivem Retry. TanStack Ship liefert beide Muster.
Enthält TanStack Ship ein Kundenportal?
Ja – Stripes gehostetes Kundenportal, vorkonfiguriert: Kunden können Karten aktualisieren, Pläne wechseln, Rechnungen einsehen, kündigen. TanStack Ship bietet zusätzlich ein eigenes In-App-Portal für Nutzer, die Ihre Domain nicht verlassen möchten.
Kann ich TanStack Ships Stripe-Billing-Modul eigenständig nutzen?
Nein – das Billing-Modul ist Teil des TanStack-Ship-Monorepos und benötigt die Auth- und Datenbankmodule, um zu funktionieren. Für einen SaaS-Boilerplate für Stripe auf Next.js nutzen Sie ShipSaaS oder Makerkit.
Testen Sie TanStack Ship als Ihren SaaS-Boilerplate für Stripe Subscriptions. Alle 4 Webhooks, beide Trial-Modi, Smart Retries + 7-Tage-Dunning – alles standardmäßig enthalten. Starter kostenlos klonen →