Kit enthält ein vollständiges Zahlungssystem, das auf Lemon Squeezy als Merchant of Record aufbaut. Das System unterstützt zwei Preismodelle — credit-basiert für KI-intensive Anwendungen und klassisches SaaS für traditionelle Abonnement-Stufen — umschaltbar mit einer einzigen Umgebungsvariable.
Diese Seite behandelt die Architektur und die grundlegenden Konzepte. Für Einrichtungsanweisungen siehe Lemon Squeezy Setup. Für die Plan-Konfiguration siehe Abonnement-Pläne.
Duale Preisarchitektur
Kit unterstützt zwei unterschiedliche Preismodelle, die zur Deployment-Zeit über die Umgebungsvariable
NEXT_PUBLIC_PRICING_MODEL ausgewählt werden:NEXT_PUBLIC_PRICING_MODEL
|
|--- "credit_based" ──> Nutzer kaufen Credits, die pro KI-Operation verbraucht werden
| Monatliche Credit-Zuteilung pro Stufe
| Bonus-Credit-Käufe als Aufladung
| Kostenerfassung pro Operation
|
|--- "classic_saas" ──> Traditionelle Abonnement-Stufen
Monatliche und jährliche Abrechnungszeiträume
Feature-Gates pro Stufe
Unterstützung für Testzeiträume
Es ist immer nur ein Modell aktiv. Das Preiskonfigurationssystem prüft beim Start, ob alle erforderlichen Umgebungsvariablen für das aktive Modell vorhanden sind:
src/lib/pricing/config.ts — Dual Model Header
/**
* Pricing Configuration - DUAL Model
*
* Central configuration system for the dual pricing model.
* Supports both credit-based and classic SaaS pricing.
*
* IMPORTANT: Only ONE model can be active at a time based on NEXT_PUBLIC_PRICING_MODEL env var.
*/
Das Preismodell wird einmalig beim Deployment deiner Anwendung festgelegt. Das Wechseln zwischen den Modellen erfordert eine Neukonfiguration deiner Lemon Squeezy-Produkte und Variant-IDs. Beide Modelle teilen sich dieselbe Abonnement-Infrastruktur (Stufen, Webhooks, Datenbank) — nur die Abrechnungslogik und die Benutzeroberfläche unterscheiden sich.
Credit-basiertes Modell
Designed für KI-intensive Anwendungen, bei denen die Nutzung pro Nutzer variiert. Jede Stufe enthält eine monatliche Credit-Zuteilung (Free: 500, Basic: 1.500, Pro: 5.000, Enterprise: 15.000). Credits werden pro KI-Operation mit atomaren Datenbanktransaktionen abgezogen. Nutzer können Bonus-Credits als Aufladung kaufen. Nur monatliche Abrechnung — keine jährliche Option.
Klassisches SaaS-Modell
Traditionelles Abonnement-Pricing mit monatlichen und jährlichen Abrechnungszeiträumen. Jede Stufe schaltet eine Reihe von Features frei. Enthält Unterstützung für Testzeiträume mit einem
hasUsedTrial-Flag zur Missbrauchsverhinderung. Die jährliche Abrechnung bietet einen Rabatt. Die Enterprise-Stufe ist nur auf Anfrage erhältlich (kein Self-Service-Checkout).Zahlungsfluss
Jede Zahlung in Kit folgt diesem Ablauf — vom Checkout-Button bis zur Datenbankaktualisierung:
Nutzer klickt "Abonnieren"
|
v
Checkout-URL (von Lemon Squeezy gehostet)
|--- custom_data: { userId: "db_user_id" }
|--- variant_id: ausgewählte Plan-Variante
|
v
Lemon Squeezy verarbeitet die Zahlung
|--- Übernimmt die Steuerberechnung (Merchant of Record)
|--- Verwaltet die Zahlungsmethode
|--- Erstellt das Abonnement
|
v
Webhook POST an /api/webhooks/lemonsqueezy
|
|--- 1. HMAC-SHA256-Signatur verifizieren
|--- 2. Event-Typ parsen (subscription_created, etc.)
|--- 3. userId aus custom_data extrahieren
|--- 4. An Event-Handler weiterleiten
|
v
Datenbank aktualisiert
|--- Abonnement-Datensatz erstellt/aktualisiert
|--- Nutzer-Stufe synchronisiert
|--- Credits initialisiert (credit-basiertes Modell)
|--- Willkommens-E-Mail versandt (nicht-blockierend)
Das entscheidende Detail ist
custom_data — beim Generieren der Checkout-URL übergibt Kit die Datenbank-Nutzer-ID. So weiß der Webhook-Handler, welchem Nutzer das Abonnement gehört.Lemon Squeezy-Integration
Kit verwendet Lemon Squeezy als Zahlungsanbieter aus einem bestimmten Grund: Es fungiert als Merchant of Record. Das bedeutet, Lemon Squeezy übernimmt die gesamte Steuerberechnung, -erhebung und -abführung — du musst dir keine Gedanken über Mehrwertsteuer, Umsatzsteuer oder steuerliche Compliance in verschiedenen Ländern machen.
Die Integration verwendet das offizielle
@lemonsqueezy/lemonsqueezy.js SDK mit Lazy Initialization:src/lib/payments/lemonsqueezy-client.ts — API Client
import {
lemonSqueezySetup,
listProducts,
listVariants,
getProduct,
getVariant,
getSubscription,
updateSubscription,
cancelSubscription,
createCheckout,
type Variant,
type Product,
type Subscription,
type Checkout,
type NewCheckout,
} from '@lemonsqueezy/lemonsqueezy.js'
import crypto from 'crypto'
// Initialize Lemon Squeezy client lazily
let isInitialized = false
const initializeLemonSqueezy = () => {
if (isInitialized) return
const apiKey = process.env.LEMONSQUEEZY_API_KEY
if (!apiKey) {
throw new Error('LEMONSQUEEZY_API_KEY is not set in environment variables')
}
lemonSqueezySetup({
apiKey,
onError: (error) => {
console.error('Lemon Squeezy API error:', error)
},
})
isInitialized = true
}
Der Client kapselt alle SDK-Funktionen mit einem
ensureInitialized-Guard, sodass der API-Key nur aus der Umgebung gelesen wird, wenn die erste Zahlungsoperation stattfindet — nicht beim Import. Dies verhindert Build-Fehler, wenn Umgebungsvariablen noch nicht gesetzt sind.Aktiviere während der Entwicklung den Test-Modus im Lemon Squeezy-Dashboard. Der Test-Modus verwendet separate Produkte, Varianten und Webhook-Secrets. Kit erkennt den Test-Modus automatisch über
process.env.NODE_ENV === 'development' oder LEMONSQUEEZY_TEST_MODE=true.Kernkonzepte
Varianten
Lemon Squeezy verwendet Varianten, um verschiedene Preisoptionen innerhalb eines Produkts darzustellen. In Kit ist jede Kombination aus Stufe + Abrechnungszeitraum eine separate Variante:
- Klassisches SaaS: 6 Varianten (Basic/Pro/Enterprise × Monatlich/Jährlich)
- Credit-basiert: 3 Varianten (Basic/Pro/Enterprise × nur Monatlich)
Jede Variante hat eine eindeutige ID aus dem Lemon Squeezy-Dashboard, die als Umgebungsvariablen gespeichert wird.
Abonnements
Ein Abonnement verbindet einen Nutzer mit einer Variante. Kit speichert Abonnements in der Datenbank mit der Lemon Squeezy-Abonnement-ID, der Variant-ID, dem Status und den Abrechnungszeitraum-Daten. Der Abonnement-Status steuert den Feature-Zugriff in der gesamten Anwendung.
Stufen
Kit definiert vier Stufen — Free, Basic, Pro und Enterprise. Jeder Nutzer startet auf der Free-Stufe. Die Stufe wird anhand der Variant-ID des Abonnements mithilfe der zentralen Funktionen
getTierLevel() und getTierName() bestimmt. Stufenwechsel lösen im credit-basierten Modell Credit-Anpassungen aus.Checkout-URLs
Der Checkout wird vollständig von der gehosteten Checkout-Seite von Lemon Squeezy abgewickelt. Kit generiert Checkout-URLs mit der korrekten Variant-ID und übergibt
custom_data mit der Datenbank-ID des Nutzers. Nach der Zahlung leitet Lemon Squeezy zurück zu deiner Anwendung und sendet Webhook-Events.Verzeichnisstruktur
Das Zahlungssystem erstreckt sich über mehrere Verzeichnisse:
apps/boilerplate/src/
├── lib/
│ ├── payments/
│ │ ├── config.ts # Variant-ID-Mapping, Stufen-Erkennung
│ │ ├── lemonsqueezy-client.ts # API-Client mit Lazy Init
│ │ ├── subscription.ts # Abonnement-Verwaltung, Kundenportal
│ │ └── types.ts # Gemeinsame Zahlungstypen
│ ├── pricing/
│ │ ├── config.ts # Konfiguration des dualen Preismodells
│ │ └── types.ts # Preistypen (PricingModel, PricingConfig)
│ ├── credits/
│ │ ├── config.ts # Credit-System-Feature-Flag, Stufen-Standardwerte
│ │ ├── credit-manager.ts # Atomare Abbuchungen, Rückerstattungen, Resets
│ │ ├── credit-costs.ts # Kostendefinitionen pro Operation
│ │ └── initialization.ts # Lazy Credit-Initialisierung
│ └── webhooks/
│ └── credit-helpers.ts # Credit-Update-Logik für Webhooks
├── app/
│ ├── api/
│ │ └── webhooks/
│ │ └── lemonsqueezy/
│ │ ├── route.ts # Webhook-Endpunkt mit Signaturverifizierung
│ │ ├── handlers/ # 11 modulare Event-Handler
│ │ ├── lib/ # Signaturverifizierung, Hilfsfunktionen
│ │ └── types.ts # Webhook-Payload-Typen
│ └── (dashboard)/
│ └── dashboard/
│ └── billing/ # Abrechnungs-UI (Planauswahl, Portal)
Umgebungsvariablen
| Variable | Erforderlich | Modell | Zweck |
|---|---|---|---|
LEMONSQUEEZY_API_KEY | Ja | Beide | Serverseitiger API-Key für das Lemon Squeezy SDK |
LEMONSQUEEZY_STORE_ID | Ja | Beide | Dein Lemon Squeezy Store-Bezeichner |
LEMONSQUEEZY_WEBHOOK_SECRET | Ja | Beide | HMAC-Secret zur Webhook-Signaturverifizierung |
NEXT_PUBLIC_PRICING_MODEL | Ja | Beide | credit_based oder classic_saas |
NEXT_PUBLIC_LEMONSQUEEZY_BASIC_MONTHLY_VARIANT_ID | Ja | Classic | Basic-Stufe monatliche Variant-ID |
NEXT_PUBLIC_LEMONSQUEEZY_BASIC_YEARLY_VARIANT_ID | Ja | Classic | Basic-Stufe jährliche Variant-ID |
NEXT_PUBLIC_LEMONSQUEEZY_PRO_MONTHLY_VARIANT_ID | Ja | Classic | Pro-Stufe monatliche Variant-ID |
NEXT_PUBLIC_LEMONSQUEEZY_PRO_YEARLY_VARIANT_ID | Ja | Classic | Pro-Stufe jährliche Variant-ID |
NEXT_PUBLIC_LEMONSQUEEZY_ENTERPRISE_MONTHLY_VARIANT_ID | Ja | Classic | Enterprise-Stufe monatliche Variant-ID |
NEXT_PUBLIC_CREDIT_BASIC_MONTHLY_VARIANT_ID | Ja | Credit | Basic-Stufe Credit-Variant-ID |
NEXT_PUBLIC_CREDIT_PRO_MONTHLY_VARIANT_ID | Ja | Credit | Pro-Stufe Credit-Variant-ID |
NEXT_PUBLIC_CREDIT_ENTERPRISE_MONTHLY_VARIANT_ID | Ja | Credit | Enterprise-Stufe Credit-Variant-ID |
CURRENCY | Nein | Beide | Währungscode (Standard: EUR) |
Die vollständige Referenz der Umgebungsvariablen einschließlich credit-spezifischer Variablen findest du unter Umgebungsvariablen.
Wichtige Dateien
| Datei | Zweck |
|---|---|
apps/boilerplate/src/lib/payments/config.ts | Variant-ID-Mapping, getTierLevel(), getTierName(), getBillingPeriod() |
apps/boilerplate/src/lib/payments/lemonsqueezy-client.ts | API-Client, Signaturverifizierungs-Helper, Test-Modus-Erkennung |
apps/boilerplate/src/lib/payments/subscription.ts | Abonnement-Abfragen, getSubscriptionTier(), Kundenportal-URL |
apps/boilerplate/src/lib/pricing/config.ts | Dualer Pricing-Config-Loader mit Validierung und Caching |
apps/boilerplate/src/lib/credits/config.ts | Credit-System-Feature-Flag (isCreditSystemEnabled()) |
apps/boilerplate/src/lib/credits/credit-manager.ts | Atomare Credit-Abbuchungen mit SELECT FOR UPDATE |
apps/boilerplate/src/lib/credits/credit-costs.ts | Kostentabelle pro Operation (17 Operationstypen) |
apps/boilerplate/src/app/api/webhooks/lemonsqueezy/route.ts | Webhook-Endpunkt — Signaturverifizierung und Event-Routing |
apps/boilerplate/src/app/api/webhooks/lemonsqueezy/handlers/ | 11 modulare Event-Handler (eine Datei pro Event) |