PAS7 Studio
Illustration von Bun.js, Stripe Webhook und PostgreSQL Ledger
Technologie27. Aug. 2026·3 Min. Lesezeit·Aktualisiert 27. Aug. 2026

Bun.js + Stripe Webhooks + Drizzle: Zahlungen ohne Duplikate

Stripe-Webhooks mit Bun.js sicher verarbeiten: Signaturprüfung, PostgreSQL-Event-Ledger, Idempotenz und transaktionssichere Geschäftslogik.

Full-Stack-EntwicklerSaaS- und Ecommerce-TeamsBackend-Teams für Zahlungen

Bun liest den Raw Body, das Stripe SDK prüft die Signatur und PostgreSQL speichert die Event-ID vor der Geschäftslogik. Ein Duplikat wird im Ledger erkannt und als No-op beendet.

Signaturen gegen den unveränderten Raw Body prüfen.
Die eindeutige Event-ID als Idempotency-Key verwenden.
Geschäftsänderung und Processed-Marker atomar committen.
Xin

Warum ein Webhook kein normaler Callback ist

Stripe kann Zustellung wiederholen, Events in anderer Reihenfolge liefern oder nach einem temporären Serverfehler erneut senden.

01

Stripe sendet ein signiertes Event

Der Payload enthält Stripe-Signature. Vor der Prüfung darf JSON nicht vertraut werden.

02

Bun prüft den Raw Body

request.text() statt request.json() lesen: Parsing kann signierte Bytes verändern.

03

Das Ledger erkennt Duplikate

Eine eindeutige event.id verhindert doppelte Geschäftsoperationen.

04

Eine Transaktion ändert die Domain

Payment-Status oder Entitlement ändern und Event atomar als verarbeitet markieren.

Die doppelte Zustellung stoppt bei Idempotency; der Business-Job läuft erst nach der Prüfung.

Screenshot des Abschnitts architecture

Schritt 1: SDK und Secrets

01

SDK installieren

BASH
bun add stripe drizzle-orm postgres
bun add -d drizzle-kit
02

Secrets konfigurieren

ENV
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
DATABASE_URL=postgres://app:app@localhost:5432/payments

Das Secret der Stripe CLI und das Production-Secret sind verschieden.

03

Event-Ledger anlegen

TS
export const stripeEvents = pgTable("stripe_events", {
  id: text("id").primaryKey(),
  type: text("type").notNull(),
  processedAt: timestamp("processed_at", { withTimezone: true }),
  receivedAt: timestamp("received_at", { withTimezone: true }).defaultNow().notNull(),
});

Der Primary Key ist die letzte Schutzschicht gegen Duplikate.

Schritt 2: Raw Body signieren

Rufe request.json() nicht vor constructEvent auf. Nach dem Parsing können die Bytes vom signierten Payload abweichen.

TS
import Stripe from "stripe";
const stripe = new Stripe(Bun.env.STRIPE_SECRET_KEY!);
export async function verifyStripeRequest(request: Request) {
  const signature = request.headers.get("stripe-signature");
  if (!signature) throw new Response("Missing signature", { status: 400 });
  const rawBody = await request.text();
  return stripe.webhooks.constructEvent(rawBody, signature, Bun.env.STRIPE_WEBHOOK_SECRET!);
}

constructEvent prüft HMAC-Signatur und Zeitfenster. Alles andere ablehnen.

Schritt 3: idempotenter Drizzle-Handler

Füge das Event zuerst ein. Ein Conflict bedeutet eine erneute Zustellung — die Geschäftslogik darf nicht erneut laufen.

TS
export async function processEvent(event: Stripe.Event) {
  const inserted = await db.insert(stripeEvents).values({ id: event.id, type: event.type }).onConflictDoNothing().returning();
  if (inserted.length === 0) return { duplicate: true };
  await db.transaction(async (tx) => {
    if (event.type === "checkout.session.completed") {
      const session = event.data.object as Stripe.Checkout.Session;
      // Bestellung auf paid setzen, z. B. mit tx.update(...).
    }
    await tx.update(stripeEvents).set({ processedAt: new Date() }).where(eq(stripeEvents.id, event.id));
  });
  return { duplicate: false };
}

Schritt 4: Endpoint und Retry-Policy

Gib 2xx erst zurück, wenn das Event geprüft und verarbeitet wurde oder schon im Ledger steht. Bei einem temporären Datenbankfehler muss Stripe mit 500 erneut senden.

TS
export async function POST(request: Request) {
  try {
    const event = await verifyStripeRequest(request);
    await processEvent(event);
    return new Response("ok", { status: 200 });
  } catch (error) {
    console.error("stripe webhook failed", error);
    return new Response("retry", { status: 500 });
  }
}

Langsame Jobs nach dem Commit in eine Queue stellen; keine unbegrenzten Network Calls im Webhook-Request.

Lokal mit der Stripe CLI testen

01

Events weiterleiten

BASH
stripe listen --forward-to http://localhost:3000/api/stripe/webhook
02

Event auslösen

BASH
stripe trigger checkout.session.completed
03

Duplikat prüfen

Dasselbe Event zweimal senden: eine Geschäftsänderung und danach { duplicate: true }. Signaturprüfung niemals in CI deaktivieren.

Production-Checkliste

Signatur und Zeitstempel prüfen

Frontend-Daten oder Event-Typ allein beweisen keine Zahlung.

Payload schützen

JSON nur für Audit speichern, Zugriffe begrenzen und Secrets aus Logs entfernen.

Webhook-Secrets rotieren

Separate Secrets pro Umgebung und definierte Rotation verwenden.

Fehler überwachen

Auf 5xx, steigende Duplikate und unverarbeitete Ledger-Zeilen alarmieren.

FAQ

FAQ

Kann ich einen Stripe Webhook mit request.json() parsen?

Nicht vor der Signaturprüfung. Zuerst request.text() lesen, mit dem Stripe SDK prüfen und erst dann Event-Daten verwenden.

Was soll ein doppeltes Event zurückgeben?

In der Regel 200, weil es bereits verarbeitet wurde. Bei einem temporären Datenbankfehler 500 zurückgeben, damit Stripe erneut zustellt.

Geprüft: 27. Aug. 2026Gilt für: Bun 1.3+Gilt für: Stripe Node SDKGilt für: Drizzle ORMGilt für: PostgreSQL 16+Getestet mit: Bun runtimeGetestet mit: stripeGetestet mit: drizzle-ormGetestet mit: Stripe CLI

Fazit

Beschreiben Sie die Aufgabe — die ersten 15 Minuten der Beratung sind kostenlos.

Verwandte Artikel

AI Assistant Entwicklung Kosten 2026: RAG, Knowledge Base, Integrationen und Support
ai-assistants

AI Assistant Entwicklung Kosten 2026: RAG, Knowledge Base, Integrationen und Support

Praktischer Leitfaden zu Kosten fuer AI Assistants: RAG, Knowledge Base, Channels, Tool Use, Guardrails, Evaluations, Monitoring und Support.

KI fur Landingpage-Entwicklung: wo sie Launches beschleunigt und wo sie Conversion schadet
blogs

KI fur Landingpage-Entwicklung: wo sie Launches beschleunigt und wo sie Conversion schadet

Eine praxisnahe Analyse zur Nutzung von KI fur Landingpages: v0, Webflow AI, Builder.io, Framer-ahnliche Builder, UX-Generierung, Copy, SEO, Personalisierung, A/B-Tests, Template-Risiken, Accessibility, Security und technischer Schuldenaufbau.

AI SEO / GEO im Jahr 2026: Ihre nächsten Kunden sind nicht Menschen — sondern Agents
growth

AI SEO / GEO im Jahr 2026: Ihre nächsten Kunden sind nicht Menschen — sondern Agents

Suche verschiebt sich von Klicks zu Antworten. Bots und AI-Agents crawlen, zitieren, empfehlen — und kaufen zunehmend. Erfahren Sie, was AI SEO / GEO bedeutet, warum klassisches SEO nicht mehr reicht und wie PAS7 Studio Marken im agentischen Web sichtbar macht.

Der leistungsstärkste Chip von Apple? M5 Pro und M5 Max brechen Rekorde
blogs

Der leistungsstärkste Chip von Apple? M5 Pro und M5 Max brechen Rekorde

Eine Analyse zu Apple M5 Pro und M5 Max im März 2026. Wir zeigen, warum diese Chips als die stärksten professionellen Laptop-SoCs von Apple gelten können, wie sie sich gegen M4 Pro, M4 Max, M1 Pro, M1 Max schlagen und was der Vergleich mit aktuellen Intel- und AMD-Chips zeigt.

Professionelle Entwicklung für Ihr Geschäft

Wir erstellen moderne Web-Lösungen und Bots für Unternehmen. Erfahren Sie, wie wir Ihnen helfen können, Ihre Ziele zu erreichen.