Stripe schnell integrieren. DATEV automatisch füttern.

Du bist SaaS-Gründer:in oder baust Subscriptions? Hier lernst du die Stripe-Integration in React/Next.js/React Native – und warum danach die eigentliche Arbeit in der Buchhaltung startet. finHero übernimmt sie.

🇩🇪DATEV ist der quasi Standard für Steuerkanzleien in Deutschland. Der Export lohnt sich besonders, wenn dein Unternehmen in Deutschland sitzt oder deine Kanzlei in Deutschland arbeitet.

Stripe-Integration: Step-by-Step

Drei typische Setups mit realistischen Defaults (inkl. productId/priceId & Subscription).

1) Checkout-Session (Subscription) – API Route

code
// app/api/checkout/session/route.ts
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: "2023-10-16" });

export async function POST(req: Request) {
  const { email, productId, priceId, customerId } = await req.json();

  // Falls nur productId vorhanden → zu Price (recurring) auflösen
  let resolvedPriceId = priceId;
  if (!resolvedPriceId && productId) {
    const prices = await stripe.prices.list({ product: productId, active: true, limit: 10 });
    resolvedPriceId = prices.data.find(p => p.recurring)?.id || prices.data[0]?.id;
  }
  if (!resolvedPriceId) {
    return Response.json({ error: "Kein Price gefunden." }, { status: 400 });
  }

  // Customer wiederverwenden/erstellen
  const customer = customerId ? customerId : (await stripe.customers.create({ email })).id;

  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    customer,
    line_items: [{ price: resolvedPriceId, quantity: 1 }],
    success_url: `${process.env.NEXT_PUBLIC_APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.NEXT_PUBLIC_APP_URL}/cancel`,
    allow_promotion_codes: true,
    metadata: { source: "pre-landing", plan_hint: productId || "n/a" },
  });

  return Response.json({ sessionId: session.id });
}

2) Client – Redirect zu Checkout

code
// app/(marketing)/subscribe/page.tsx
"use client";
import { loadStripe } from "@stripe/stripe-js";
import { useState } from "react";

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);

export default function SubscribePage() {
  const [loading, setLoading] = useState(false);

  async function handleSubscribe() {
    setLoading(true);
    const res = await fetch("/api/checkout/session", {
      method: "POST",
      body: JSON.stringify({
        email: "kunde@example.com",
        // eines von beiden:
        productId: "prod_ABC123", // → Server löst zu recurring price auf
        // priceId: "price_123",
      }),
    });

    const { sessionId } = await res.json();
    const stripe = await stripePromise;
    await stripe?.redirectToCheckout({ sessionId });
    setLoading(false);
  }

  return (
    <button className="btn btn-primary" onClick={handleSubscribe} disabled={loading}>
      {loading ? "Weiterleiten…" : "Abo starten"}
    </button>
  );
}

3) Webhook – Ereignisse verarbeiten (Basis)

code
// app/api/stripe/webhook/route.ts
import Stripe from "stripe";

export const config = { api: { bodyParser: false } }; // nur Pages Router; App Router liefert raw body

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: "2023-10-16" });

export async function POST(req: Request) {
  const sig = req.headers.get("stripe-signature")!;
  const raw = await req.text();

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(raw, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  } catch (err: any) {
    return new Response(`Webhook Error: ${err.message}`, { status: 400 });
  }

  if (event.type === "checkout.session.completed") {
    const session = event.data.object as Stripe.Checkout.Session;
    // TODO: Onboarding, Feature-Freischaltung …
  }

  if (event.type === "invoice.paid") {
    const invoice = event.data.object as Stripe.Invoice;
    // TODO: Rechnungsdaten für finHero/DATEV vorbereiten
  }

  return new Response("ok");
}

Warum Stripe ≠ Buchhaltung

Stripe macht Billing leicht – die Finanzbuchhaltung aber nicht automatisch. Du brauchst saubere Belege, korrekte Buchungssätze, SKR-Konfiguration und (bei Subscriptions) pRAP/Abgrenzung.

Ereignisse vs. Buchung

„paid“ in Stripe heißt nicht automatisch Geldeingang in der Fibu (Refunds, Disputes, Fees …).

Belege & IDs

Rechnungen, Gutschriften, Stornos müssen sauber mit Transaktions-IDs verknüpft werden – das liebt DATEV.

SKR03/SKR04 & pRAP

Abos erfordern periodengerechte Abgrenzung.
Manuell = fehleranfällig → automatisiert = sorgenfrei.

So funktioniert’s

In drei Schritten zur automatisierten Buchhaltung.

  • 1 — Stripe verbinden
  • 2 — Konten definieren
  • 3 — Automatisch exportieren

1. Stripe verbinden

Verbinde dein Stripe-Konto – in wenigen Klicks, ohne technisches Vorwissen.

2. Konten definieren

Hinterlege optional Konten & Buchungsschlüssel. Kompatibel mit SKR03, SKR04 und individuellen Regeln.

3. Automatisch exportieren

Monatliche, fertige DATEV-Exports – einfach an den Steuerberater senden & Zeit sparen.

Kurz FAQ

In drei Schritten zur automatisierten Buchhaltung.

Brauche ich productId oder priceId?

Für Subscriptions buchst du mit priceId. Wenn du nur productId hast, löst das Backend (siehe API-Beispiel) automatisch den passenden recurring-Price.

Wie kommen Belege nach DATEV?

finHero exportiert Belege (Rechnungen, Stornos, Gutschriften) inklusive Verknüpfung zu den Buchungssätzen – fertig für deine Steuerberater/Kanzlei.

Funktioniert das auch ohne deutschen Sitz?

Ja, Exporte sind auch außerhalb von DATEV möglich. Für deutsche Kanzleien/Steuerberater ist DATEV aber der Standard.

Wo finde ich weitere Unterstützung?

Schau gerne kurz in unserem Hilfe-Center vorbei

Help-Center

Bereit, deine Buchhaltung zu entlasten?

Erlebe selbst, wie einfach der Export von Stripe zu DATEV sein kann. Teste finHero 7 Tage lang kostenlos – ohne Risiko.

Kostenlos testen