siteway

// stack · schnittstelle

Stripe.

Stripe ist der Zahlungsdienstleister, über den auf einer Website Geld fließt — und technisch vor allem eine API mit zwei Schlüsseln. Für siteway ist das eine klare Arbeitsteilung: Der Browser zeigt die Bezahlstrecke, entschieden wird auf dem Server. Diese Seite beschreibt die Anbindung — Zahlungsabsicht, Bezahlstrecke, Webhook — und die Zahlungsarten, die darüber laufen.

stack system: stripe · zahlungsabwicklung frontend: elements · gehostete seite server: paymentintent · webhook seit: 2006

// definition

Was ist Stripe?

Stripe ist ein Zahlungsdienstleister. Er nimmt die Zahlung entgegen, führt sie über Kartennetze, Banken und Wallet-Anbieter und zahlt das Geld an dich aus. Für Unternehmen im Europäischen Wirtschaftsraum ist Stripe Payments Europe, Limited die vertragschließende Gesellschaft. Verwaltet wird das Konto im Dashboard — Zahlungen, Auszahlungen, Rückerstattungen und die Frage, welche Zahlungsarten überhaupt angeboten werden.

Für eine Website ist Stripe vor allem ein Schlüsselpaar und ein Ablauf. Der veröffentlichbare Schlüssel beginnt mit pk_ und darf laut Dokumentation offen im Frontend liegen. Der geheime Schlüssel beginnt mit sk_, hat uneingeschränkte Berechtigungen für alle Stripe-APIs und gehört ausschließlich auf den Server. Daneben stehen eingeschränkte Schlüssel mit dem Präfix rk_, deren Berechtigungen du selbst festlegst — Stripe empfiehlt sie für neue Integrationen, weil ein abhandengekommener Schlüssel dann nur einen Ausschnitt öffnet.

Gebaut und getestet wird in einer Sandbox mit eigenen Test-Schlüsseln, scharf geschaltet im Live-Modus mit einem zweiten Satz. Beide Welten sind getrennt: Was in der einen entsteht, ist in der anderen nicht sichtbar. Das klingt nach einer Kleinigkeit, ist aber der Grund, warum eine Bezahlstrecke sich vollständig durchspielen lässt, bevor der erste echte Betrag fließt.

// praxis

Wie wir Stripe anbinden.

server entscheidet · nicht der browser

Die wichtigste Regel steht vor der ersten Zeile Code: Der Zahlungsstatus wird nie im Browser entschieden. Der Browser zeigt eine Oberfläche, mehr nicht. Betrag, Währung und die Absicht, diesen Betrag einzuziehen, entstehen auf dem Server — dort, wo niemand mit den Entwicklerwerkzeugen dazwischengeht.

Der Ablauf beginnt deshalb mit einem serverseitigen Endpunkt, der eine Zahlungsabsicht erzeugt — bei Stripe ein PaymentIntent. Die Dokumentation empfiehlt, ihn anzulegen, sobald der Betrag feststeht, damit auch abgebrochene Versuche erfasst werden. Zurück ins Frontend geht nur das Client-Secret dieser einen Zahlungsabsicht. Der geheime Schlüssel bleibt, wo er hingehört.

Im Frontend steht danach die Bezahlstrecke: entweder Stripe Elements, in das eigene Layout eingebaut, oder die von Stripe gehostete Bezahlseite. Beide Wege haben denselben Vorteil, und der ist kein Detail — die Zahlungsdaten gehen direkt an Stripe und laufen nicht über deinen Server. Stripe beschreibt genau das als risikoarme Integration; die PCI-Reichweite bleibt damit klein, statt eine dreistellige Zahl an Sicherheitsanforderungen ins eigene Haus zu holen.

Bestätigt wird über den Webhook. Stripe meldet Ereignisse wie payment_intent.succeeded und payment_intent.payment_failed an einen zweiten serverseitigen Endpunkt — und erst dieses Ereignis schaltet Bestellung, Zugang oder Rechnung frei. Die Doku rät ausdrücklich davon ab, die Abwicklung clientseitig zu behandeln: Kundinnen und Kunden können die Seite nach der Zahlung verlassen, bevor der Prozess überhaupt beginnt. Wiederholtes Abfragen ist möglich, laut Doku aber weitaus weniger zuverlässig.

Und dann das, was in Angeboten gern fehlt: der Fehlerfall. Jeder schreibende Aufruf an Stripe bekommt einen Idempotenz-Schlüssel, damit ein Netzwerkabbruch keine zweite Buchung erzeugt. Der Webhook-Endpunkt antwortet sofort mit einem 2xx-Status und arbeitet danach im Hintergrund weiter, weil Stripe im Live-Modus bis zu drei Tage lang erneut zustellt. Ereignis-IDs werden protokolliert, weil dieselbe Meldung mehrfach und in beliebiger Reihenfolge ankommen kann. Wie wir solche Anbindungen abnehmen und betreiben, steht in der Leistung Schnittstellenentwicklung.

// technik · 6 details

Die Technik im Detail.

belegt aus der doku

Was hier steht, stammt aus der öffentlichen Dokumentation unter docs.stripe.com — Schlüsselpräfixe, Statusnamen, Header und Ereignisnamen im Original. Was hier bewusst nicht steht: Gebühren und Konditionen. Die ändern sich, und die verbindliche Auskunft dazu gibt Stripe selbst.

// d-01zugang

Schlüssel & Zugriff.

Drei Schlüsselarten: pk_ fürs Frontend, sk_ mit uneingeschränkten Rechten nur serverseitig, rk_ mit selbst gesetzten Berechtigungen — für neue Integrationen empfohlen. Sandbox und Live-Modus haben getrennte Sätze. Die Doku verlangt einen Secrets-Tresor statt Quellcode in der Versionsverwaltung.

zweck: authentifizierung

// d-02ablauf

Die Zahlungsabsicht.

Ein PaymentIntent durchläuft requires_payment_method, requires_confirmation, requires_action, processing und endet in succeeded oder canceled. Scheitert eine Zahlung, fällt der Status zurück auf requires_payment_method — ein zweiter Versuch ist damit vorgesehen, kein Sonderfall.

zweck: zustand serverseitig

// d-03frontend

Bezahlstrecke im Frontend.

Stripe Elements sind vorgefertigte Eingabebausteine von Stripe.js; das Payment Element bündelt mehrere Zahlungsarten in einer Oberfläche. Alternative ist die von Stripe gehostete Bezahlseite. In beiden Fällen werden die Zahlungsdaten direkt an Stripe übermittelt, ohne den eigenen Server zu berühren.

zweck: eingabe ohne pci-last

// d-04bestätigung

Webhook & Signatur.

Jedes Ereignis kommt mit dem Header Stripe-Signature: ein Zeitstempel t und eine Signatur v1, gebildet per HMAC-SHA256 mit dem Endpoint-Secret. Verglichen wird in konstanter Zeit, der Zeitstempel nur innerhalb einer Toleranz von standardmäßig fünf Minuten akzeptiert — sonst ließen sich Ereignisse erfinden oder erneut einspielen.

zweck: verlässliche statusquelle

// d-05robustheit

Idempotenz & Wiederholung.

Der Header Idempotency-Key macht einen POST wiederholbar: Der zweite Aufruf mit demselben Schlüssel liefert das gespeicherte Ergebnis des ersten. Die Schlüssel werden mindestens 24 Stunden vorgehalten. In der Gegenrichtung garantiert Stripe weder Reihenfolge noch einmalige Zustellung — die Ereignis-ID ist der Schutz davor.

zweck: keine doppelbuchung

// d-06wiederkehrend

Abo & Rechnung.

Wiederkehrende Zahlungen setzen auf Customer, Product, Price, Subscription und Invoice auf. Das Abo trägt Zustände wie trialing, active, past_due und canceled; die Ereignisse invoice.paid, invoice.payment_failed und invoice.payment_action_required sagen der Website, ob ein Zugang bestehen bleibt.

abo & payment als komponente →

Was daraus auf der Website entsteht.

Aus dem Ablauf wird eine Strecke, die jemand tatsächlich durchläuft. Vorne steht das, was den Betrag festlegt — ein Warenkorb, ein Spendenbetrag, eine Formularstrecke mit Buchung am Ende. Dann die Bezahlseite, die nichts anderes tut, als die Zahlung entgegenzunehmen: keine Ablenkung, keine Nebenwege, klare Fehlermeldungen, wenn eine Karte abgelehnt wird.

Danach die Bestätigungsseite — und die entscheidet nichts. Sie zeigt an, was der Server bereits weiß, und sie hält den Fall aus, dass das Webhook-Ereignis eine Sekunde später eintrifft als die Rückkehr aus der Bezahlstrecke. Erst am bestätigten Status hängen Freischaltung, Bestätigungsmail und Beleg. Wer diesen Schritt an den Browser hängt, baut sich eine Bestellung, die bezahlt aussieht, ohne bezahlt zu sein.

Und schließlich das Unauffällige: der Bestellstatus in der eigenen Datenbank. Er ist die Grundlage für Support, Buchhaltung und Auswertung — und dafür, dass niemand für eine simple Frage ins Stripe-Dashboard klettern muss. Rückerstattungen, Teilzahlungen und Zahlungsabbrüche bekommen dort ihren Platz, statt als Sonderfall im Postfach zu landen.

// zahlungsarten

Die Zahlungsarten dahinter.

im konto aktiviert · nicht einzeln gebaut

Kreditkarte, PayPal, Klarna, Apple Pay, Google Pay, WeChat Pay, Alipay: Das sind keine sieben Projekte. Sie werden nicht einzeln angebunden. Sie werden im Stripe-Konto aktiviert — in den Einstellungen unter Zahlungsmethoden — und erscheinen danach in derselben Bezahlstrecke, die schon steht. Die Dokumentation beschreibt das als dynamische Zahlungsmethoden: Die feste Liste im Code entfällt, Stripe wählt aus, was passt.

Was passt, entscheidet nicht die Website. Maßgeblich sind Land, Währung, Betrag und das eingesetzte Stripe-Produkt: Manche Verfahren gibt es nur in bestimmten Ländern, andere nur für bestimmte Währungen, wieder andere fallen unterhalb oder oberhalb bestimmter Beträge weg. Für die Umsetzung folgt daraus zweierlei — die Bezahlstrecke muss damit umgehen, dass die Auswahl für zwei Personen unterschiedlich aussieht, und sie muss den zusätzlichen Bestätigungsschritt aushalten, den manche Methoden auslösen. Beides ist Arbeit an der Strecke, nicht an sieben Integrationen.

// m-01karte

Kreditkarte & Debitkarte.

Der Standardweg, bei Stripe die Kategorie „Karten“. Die Daten werden in Elements oder auf der gehosteten Bezahlseite erfasst und gehen direkt an Stripe. Im europäischen Raum kommt bei Kartenzahlungen der zusätzliche Bestätigungsschritt über 3-D-Secure dazu.

kategorie: karten

// m-02wallet

PayPal.

Stripe führt PayPal als Wallet und nennt in der Dokumentation die europäischen Länder, in denen es für Stripe-Konten verfügbar ist — Deutschland gehört dazu. Aktiviert wird es im Dashboard, ohne Änderung am Code.

paypal im stack →

// m-03später bezahlen

Klarna.

In Stripes Systematik gehört Klarna zur Kategorie „Später bezahlen“. Für die Bezahlstrecke bedeutet das einen Umweg über die Oberfläche des Anbieters und eine Rückkehr auf die eigene Seite — der Status kommt trotzdem aus dem Webhook.

klarna im stack →

// m-04wallet

Apple Pay.

Ein Wallet: Bezahlt wird mit der im Gerät hinterlegten Karte, bestätigt per Gerätesperre. Der Knopf erscheint nur dort, wo Gerät und Browser ihn anbieten — die Bezahlstrecke braucht deshalb ohnehin einen zweiten, immer sichtbaren Weg.

apple pay im stack →

// m-05wallet

Google Pay.

Das Gegenstück auf der anderen Plattform, ebenfalls ein Wallet. Auch hier hängt die Anzeige an Gerät und Browser der Besucherin, nicht an einer Einstellung im CMS. Aktiviert wird es wie die übrigen Methoden im Stripe-Konto.

google pay im stack →

// m-06wallet

WeChat Pay & Alipay.

Beide führt Stripe als Wallets für den asiatischen Raum. Relevant, wenn ein Teil der Kundschaft von dort kommt — etwa im Tourismus oder im internationalen Vertrieb. Auch sie werden im Konto aktiviert, nicht im Code eingebaut.

kategorie: wallets

// integration

Stripe in deine Website integrieren.

drei systeme · ein muster

Der Weg ist in jedem System derselbe, und er ist erfreulich kurz zu beschreiben. Die Bezahlstrecke liegt im CMS — als eigene Seite oder als letzter Schritt einer Formularstrecke, mit den Texten, dem Layout und den Rechtstexten, die dort ohnehin gepflegt werden. Ein serverseitiger Endpunkt erzeugt die Zahlungsabsicht, hält den geheimen Schlüssel und gibt nur das Client-Secret ins Frontend. Ein zweiter Endpunkt nimmt den Webhook entgegen, prüft die Signatur und bestätigt den Zahlungseingang. Erst dieser bestätigte Status schaltet frei, versendet und stellt in Rechnung. Der Zahlungsstatus wird nie im Browser entschieden — die Bestätigungsseite zeigt nur an, was der Server bereits weiß.

Was sich je System unterscheidet, ist nicht diese Logik, sondern ihr Ort: wie eine eigene Route entsteht, wo der Schlüssel abgelegt wird und womit das Frontend rendert. Deshalb bauen wir die Anbindung in jedem der drei Systeme selbst, mit dessen eigenen Bordmitteln — als eigene Extension, als eigenes Plugin oder als eigene Route samt Controller. Der Bestellstatus liegt danach in der Datenbank der Website und nicht nur im Stripe-Dashboard; daran hängen Freischaltung, Beleg und Support. Und weil der Webhook-Endpunkt von außen erreichbar sein muss, gilt für ihn dieselbe Sorgfalt wie für jede andere offene Route: HTTPS, Signaturprüfung, keine Ausnahme.

// cms-01typo3

Stripe in TYPO3.

Wir bauen die Anbindung als eigene Extension. Zwei Controller-Routen tragen die Sache: eine erzeugt die Zahlungsabsicht und gibt das Client-Secret zurück, die zweite nimmt den Webhook entgegen und prüft die Signatur, bevor irgendetwas verarbeitet wird. Der geheime Schlüssel liegt in der Extension-Konfiguration oder — sauberer, weil je Umgebung anders — in einer Umgebungsvariable. Bestellungen und Zahlungsstatus werden als Records geführt, die Ausgabe übernehmen Fluid-Templates: Bezahlseite, Bestätigung, Beleg. Die Redaktion pflegt Texte und Rechtshinweise im Backend, ohne die Strecke anzufassen.

typo3 im stack →

// cms-02wordpress

Stripe in WordPress.

In WordPress entsteht die Anbindung als eigenes Plugin und nicht als Theme-Code — so überlebt sie einen Theme-Wechsel. Zwei eigene REST-Routen bilden den Ablauf ab: eine für die Zahlungsabsicht, eine für den Webhook samt Signaturprüfung. Die Schlüssel liegen in der wp-config.php oder in Umgebungsvariablen, nie im Beitragstext und nie im Frontend. Bestellungen und Zahlungsstatus bekommen eine eigene Ablage statt eines Sammelfelds. Fürs Frontend kommen Template-Dateien und Blöcke dazu, damit die Redaktion Bezahlstrecke und Bestätigung dort platziert, wo sie hingehören.

wordpress im stack →

// cms-03statamic

Stripe in Statamic.

Statamic läuft auf Laravel, und das macht die Sache hier besonders geradlinig: Route plus Controller für die Zahlungsabsicht, Route plus Controller für den Webhook, die Signaturprüfung als Middleware davor. Die Schlüssel stehen in der .env und damit außerhalb der Versionsverwaltung. Bestellungen liegen in der Datenbank, nicht im Dateibaum der Inhalte. Antlers oder Blade rendern Bezahlseite, Bestätigung und Beleg — und beim Static Caching bleiben genau diese Seiten außen vor, weil sie personenbezogen sind.

statamic im stack →

// sicherheit

Sicherheit & Datenschutz.

schlüssel · transport · daten

Schlüssel und Transport.

Die Dokumentation ist an dieser Stelle unmissverständlich: Vertrauliche Schlüssel gehören in einen Secrets-Tresor der Hosting-Plattform, nicht in Quellcode oder Konfigurationsdateien, die in die Versionsverwaltung eingecheckt werden — und nicht per E-Mail oder Chat über den Tisch. Wir vergeben je Aufgabe einen eigenen, eingeschränkten Schlüssel und tauschen ihn aus, wenn Personen oder Systeme wechseln. Bezahlseiten und der Webhook-Endpunkt laufen über TLS 1.2 oder höher; für den Endpunkt nennt die Doku zusätzlich die Beschränkung auf Stripes veröffentlichte IP-Adressen und die Zeitstempel-Toleranz, die ein erneutes Einspielen alter Ereignisse verhindert.

SCA und 3-D-Secure.

Im europäischen Raum ist die starke Kundenauthentifizierung vorgeschrieben — als Teil der PSD2-Regulierung, in Kraft seit September 2019. Bei Kartenzahlungen wird die Anforderung über 3-D-Secure erfüllt: Die Bank verlangt einen zusätzlichen Bestätigungsschritt. Für die Umsetzung ist das kein Nebensatz, sondern eine Anforderung an die Strecke. Der PaymentIntent geht dafür in den Status requires_action, das Ergebnis steht erst danach fest, und getestet wird beides — die erfolgreiche und die gescheiterte Authentifizierung. Ob im Einzelfall eine Ausnahme greift, entscheiden Bank und Regelwerk, nicht die Website.

Welche Daten anfallen.

Die Zahlungsdaten selbst laufen bei Elements und gehosteter Bezahlseite nicht über deinen Server; zurück kommen unkritische Angaben wie Kartenmarke, letzte vier Ziffern und Ablaufdatum, die sich laut Doku speichern lassen. Alles andere ist Datensparsamkeit: Für Zahlung, Rechnung und Support braucht es bestimmte Felder — und keins mehr. Wo Stripe personenbezogene Daten im Auftrag verarbeitet, gehören Verträge und ein Abschnitt in der Datenschutzerklärung dazu; die rechtliche Einordnung trifft deine Rechtsberatung, wir liefern die technische Grundlage und die Dokumentation der Datenflüsse. Mehr dazu im Stack unter Sicherheit & Datenschutz.

// faq

Häufige Fragen.

Was ist Stripe?

Stripe ist ein Zahlungsdienstleister: Über eine dokumentierte API wickelt er Zahlungen für Websites und Anwendungen ab. Für Unternehmen im Europäischen Wirtschaftsraum ist Stripe Payments Europe, Limited die vertragschließende Gesellschaft. Technisch besteht die Anbindung aus zwei Teilen — einem veröffentlichbaren Schlüssel, der im Frontend liegen darf, und einem geheimen Schlüssel, der ausschließlich auf dem Server arbeitet. Alles, was Geld bewegt, passiert auf der Serverseite.

Wie läuft eine Zahlung über Stripe technisch ab?

In vier Schritten. Erstens erzeugt ein serverseitiger Endpunkt eine Zahlungsabsicht, sobald der Betrag feststeht — Stripe nennt das einen PaymentIntent. Zweitens bekommt das Frontend nur das dazugehörige Client-Secret und zeigt die Bezahlstrecke, entweder mit Stripe Elements im eigenen Layout oder auf der von Stripe gehosteten Bezahlseite. Drittens bestätigt die Kundin oder der Kunde die Zahlung; bei Bedarf schiebt sich ein zusätzlicher Bestätigungsschritt der Bank dazwischen. Viertens meldet Stripe das Ergebnis per Webhook an einen zweiten serverseitigen Endpunkt — und erst dieses Ereignis schaltet Bestellung, Zugang oder Rechnung frei.

Was ist der Unterschied zwischen Publishable Key und Secret Key?

Der veröffentlichbare Schlüssel beginnt mit pk_ und darf laut Dokumentation offen im Frontend liegen. Der geheime Schlüssel beginnt mit sk_ und hat uneingeschränkte Berechtigungen für alle Stripe-APIs; er gehört in einen Secrets-Tresor der Hosting-Plattform und niemals in Quellcode oder Konfigurationsdateien, die in die Versionsverwaltung eingecheckt werden. Daneben gibt es eingeschränkte Schlüssel mit dem Präfix rk_, deren Berechtigungen du selbst festlegst; Stripe empfiehlt sie für neue Integrationen. Sandbox und Live-Modus haben jeweils eigene Schlüsselsätze.

Wozu braucht es einen Webhook, wenn der Browser den Erfolg doch schon anzeigt?

Weil der Browser nicht verlässlich ist. Die Dokumentation rät ausdrücklich davon ab, die Abwicklung clientseitig zu behandeln, weil Kundinnen und Kunden die Seite nach Abschluss der Zahlung verlassen können, bevor der Abwicklungsprozess beginnt. Stattdessen empfiehlt Stripe, auf das Ereignis payment_intent.succeeded zu hören und den Abschluss asynchron zu verarbeiten. Wiederholtes Abfragen des Status ist zwar möglich, laut Dokumentation aber weitaus weniger zuverlässig. Der Webhook ist damit die verlässliche Statusquelle — und er wird nur angenommen, wenn die Signatur im Header Stripe-Signature stimmt.

Welche Zahlungsarten laufen über Stripe?

Kreditkarte und Debitkarte, PayPal, Klarna, Apple Pay, Google Pay, WeChat Pay und Alipay gehören dazu; Stripe ordnet sie den Kategorien Karten, Wallets und Später bezahlen zu. Wichtig für die Umsetzung ist, dass diese Methoden nicht einzeln angebunden werden. Sie werden im Stripe-Konto aktiviert und erscheinen danach in derselben Bezahlstrecke — sofern sie zu Land, Währung, Betrag und dem eingesetzten Stripe-Produkt passen. Die Auswahl kann deshalb für zwei Personen unterschiedlich aussehen, ohne dass am Code etwas geändert wurde.

Was bedeutet SCA oder 3-D-Secure für die Bezahlstrecke?

SCA steht für starke Kundenauthentifizierung und ist im europäischen Raum als Teil der PSD2-Regulierung vorgeschrieben, in Kraft seit September 2019. Bei Kartenzahlungen wird die Anforderung über 3-D-Secure erfüllt: Die Bank verlangt einen zusätzlichen Bestätigungsschritt, bevor die Zahlung durchgeht. Für die Umsetzung heißt das, dass die Bezahlstrecke diesen Zwischenschritt aushalten muss — der PaymentIntent geht dafür in den Status requires_action, und erst danach steht das Ergebnis fest. Getestet wird deshalb beides: die erfolgreiche und die gescheiterte Authentifizierung.

Lässt sich Stripe in TYPO3, WordPress oder Statamic einbinden?

Ja, und die Logik ist in allen drei Systemen dieselbe: Bezahlstrecke im CMS, ein serverseitiger Endpunkt für die Zahlungsabsicht, ein zweiter für den Webhook. Unterschiedlich ist nur, wo das liegt. In TYPO3 bauen wir eine eigene Extension mit Controller-Routen für Zahlungsabsicht und Webhook, dem geheimen Schlüssel in der Extension-Konfiguration oder einer Umgebungsvariable und Fluid im Frontend. In WordPress entsteht ein eigenes Plugin statt Theme-Code, mit eigenen REST-Routen und den Schlüsseln in der wp-config.php oder in Umgebungsvariablen. In Statamic liegt Laravel darunter: Route plus Controller, Schlüssel in der .env, Ausgabe über Antlers oder Blade.

Wie verhindert ihr Doppelbuchungen?

Auf zwei Ebenen. Beim Aufruf an Stripe setzen wir einen Idempotency-Key: Bricht eine Anfrage durch einen Netzwerkfehler ab und wird wiederholt, liefert Stripe das gespeicherte Ergebnis des ersten Aufrufs zurück, statt einen zweiten Vorgang anzulegen — die Schlüssel werden laut Dokumentation mindestens 24 Stunden vorgehalten. In die andere Richtung gilt dasselbe für eingehende Webhooks: Stripe garantiert weder eine Reihenfolge noch eine einmalige Zustellung, deshalb protokollieren wir die Ereignis-ID und verarbeiten jedes Ereignis nur einmal. Der Endpunkt bestätigt sofort mit einem 2xx-Status, die eigentliche Arbeit läuft danach im Hintergrund.

// womit das zusammenhängt

Womit das zusammenhängt.

methoden, systeme & leistung

// Zahlungen über Stripe auf deiner Website?

Projekt anfragen