Die Anforderung klingt überschaubar: Ein neuer Zahlungsanbieter soll integriert werden. PayPal, Klarna, oder ein lokaler PSP – die technische Dokumentation des Anbieters ist vorhanden, es gibt eine SDK oder eine REST-API, und der Checkout soll in vier Wochen fertig sein. Was dann folgt, ist in gewachsenen PHP-Systemen oft ein Moment der Ernüchterung: Der Checkout-Prozess verteilt sich über sechs Controller, die Bestelllogik ist untrennbar mit der Template-Ausgabe verwoben, und Zahlungsstatus wird in einer Spalte gespeichert, die niemand mehr vollständig versteht.

Warum Payment-Integration in Legacy-Systemen besonders ist

Zahlungsflüsse sind nicht wie andere Features. Sie haben externe Abhängigkeiten mit strengen Timeout-Anforderungen, sie müssen auditierbar sein, und ein Fehler im falschen Moment bedeutet Umsatzverlust. In sauber strukturierten Systemen gibt es dafür klare Grenzen: ein Payment-Service, ein Webhook-Handler, eine State-Machine. In gewachsenen Systemen existieren diese Grenzen oft nicht.

Wer einen neuen Zahlungsanbieter integriert, bevor er versteht, wie der alte angebunden ist, löst kein Problem – er verdoppelt es.

Der Schnitt, bevor die Integration beginnt

Bevor eine Zeile Anbieter-Code geschrieben wird, lohnt sich eine Bestandsaufnahme des bestehenden Zahlungsflusses. Dabei geht es nicht darum, ihn sofort zu refaktorieren – sondern ihn zu verstehen und zu isolieren:

  • Wo wird der Zahlungsstatus gesetzt, gelesen und ausgewertet?
  • Welche Systemteile sprechen mit dem aktuellen Zahlungsanbieter?
  • Wie werden Webhooks und asynchrone Rückmeldungen heute verarbeitet?
  • Gibt es Retry-Logik oder manuelle Eingriffe für fehlgeschlagene Zahlungen?

Diese Fragen zu beantworten ist die eigentliche Vorarbeit. Die Integration danach ist Handwerk.

Integration ohne Umbau: Adapter statt Neubau

In Legacy-Systemen ist der pragmatische Weg meist ein Adapter, der die neue Payment-API hinter einer einfachen internen Schnittstelle verbirgt. Der bestehende Checkout-Code ruft nicht den PSP direkt auf, sondern einen lokalen PaymentHandler, der intern austauschbar ist. So bleibt der Checkout-Code unverändert, und der neue Anbieter wird hinter der Adapter-Schicht implementiert.

Webhooks – also asynchrone Statusrückmeldungen des Anbieters – sollten in einem eigenen Endpunkt landen, der nichts außer Logging und Queue-Einspeisung macht. Die eigentliche Statusverarbeitung gehört in einen separaten Job, der idempotent ist und erneut ausgeführt werden kann.

Fazit

Payment-Integration in gewachsenen PHP-Systemen ist machbar, ohne das Fundament anzufassen – wenn der Scope klar ist und die Integration hinter einem Adapter liegt. Was dabei entsteht, ist oft mehr als nur ein neuer Zahlungsanbieter: ein erster, sauberer Schnitt im Checkout-Bereich, der spätere Arbeiten erheblich erleichtert.