PayPal-Zahlungen als Push aufs Handy

PayPals eigene App sagt dir, dass Geld angekommen ist – irgendwann, und mit demselben Ton wie alles andere. Wenn eine Zahlung unverwechselbar sein soll, oder dein System sofort reagieren muss, sind PayPals Webhooks der Weg. Und du brauchst dafür keinen Server.

Drei Wege, über eine PayPal-Zahlung informiert zu werden

Sie lösen unterschiedliche Probleme – es lohnt sich, vorher zu klären, welchen du brauchst:

  1. Die PayPal-App. Benachrichtigungen in der App aktivieren und du bekommst einen Push bei Geldeingang. Gratis, null Aufwand – aber du kannst den Ton nicht ändern, nicht auf die Ereignisse filtern, die dich interessieren, und es ist eine App mehr, die um Aufmerksamkeit kämpft.
  2. Ein PayPal-Webhook direkt aufs Handy. PayPal postet an eine URL deiner Wahl. Richte diese URL auf einen Webhooky-Endpunkt und du bekommst eine Benachrichtigung mit eigenem Sound – ohne Server, ohne Code.
  3. Ein PayPal-Webhook in dein eigenes Backend. Die echte Integration: Signatur prüfen, Datenbank aktualisieren, dann benachrichtigen. Nötig, wenn die Zahlung etwas auslösen soll und nicht nur gemeldet werden.

Wie PayPal-Webhooks funktionieren

PayPal sendet einen HTTPS-POST an eine Listener-URL, sobald ein abonniertes Ereignis eintritt. Der Listener gehört zu einer bestimmten REST-App im Developer Dashboard – nur deren Ereignisse kommen an – und du kannst pro App bis zu 10 URLs registrieren, mit Abo auf einzelne Event-Typen oder mit * auf alle.

Die Events, die für Geldeingang zählen:

  • PAYMENT.CAPTURE.COMPLETED – eine Zahlung wurde erfolgreich eingezogen. Das ist das „Das Geld gehört dir“-Event.
  • CHECKOUT.ORDER.APPROVED – der Käufer hat die Bestellung bestätigt, noch vor dem Einzug.
  • PAYMENT.CAPTURE.DECLINED – ein Einzug wurde abgelehnt.
  • PAYMENT.CAPTURE.REFUNDED – du hast eine Zahlung erstattet.
  • PAYMENT.CAPTURE.REVERSED – PayPal hat eine Zahlung rückabgewickelt. Verdient einen eigenen, lauten Ton.
  • CUSTOMER.DISPUTE.CREATED – ein Käuferschutzfall wurde eröffnet. Ebenfalls ein eigener Ton wert.
  • PAYMENT.SALE.COMPLETED – das Gegenstück für wiederkehrende Abo-Zahlungen.

Ein Wort zur älteren Integration: PayPals IPN (Instant Payment Notification) existiert weiterhin, und PayPals NVP/SOAP-Dokumentation bezeichnet das als Legacy-Integrationsmethode – bestehende Integrationen werden weiter unterstützt, für Neues empfiehlt PayPal die neueren Lösungen. Diverse Drittanbieter-Guides nennen konkrete Abschaltdaten für IPN; PayPals eigene Dokumentation nennt keines, deshalb geben wir sie hier nicht wieder. Wer heute anfängt, nimmt REST-Webhooks.

Der Weg ohne Server: PayPal → dein Handy

Ein Webhooky-Endpunkt ist eine URL, die jeden HTTP-POST annimmt und daraus eine Push-Benachrichtigung macht. PayPal braucht eine öffentlich erreichbare HTTPS-Listener-URL. Das ist die ganze Integration:

  1. Lege in der Webhooky-App einen Endpunkt an. Nenn ihn PayPal, setz als Nachricht z. B. „Zahlung erhalten“, wähl den Sound cash_register oder ka_ching und kopier die URL.
  2. Öffne im PayPal Developer Dashboard deine REST-App und füge einen Webhook-Listener mit dieser URL hinzu.
  3. Abonniere PAYMENT.CAPTURE.COMPLETED. Speichern.

PayPals Payload ist ein großes JSON-Objekt, das das Ereignis beschreibt. Webhooky muss es gar nicht verstehen: Weil der Body kein Feld title oder message hat, greift der Fallback auf Titel, Text und Sound, die du am Endpunkt eingestellt hast. Du bekommst ein sofortiges, klanglich eindeutiges „Zahlung erhalten“ auf allen Geräten, auf denen du angemeldet bist.

Zwei ehrliche Einschränkungen. Webhooky prüft PayPals Signatur nicht – wer deine Endpunkt-URL kennt, könnte eine Benachrichtigung auslösen. Bei einem Alert ist das lästig, kein Sicherheitsbruch, aber genau deshalb ist dieser Weg zum Informiertwerden da und nicht für die Buchhaltung. Und die Benachrichtigung enthält keinen Betrag, denn dafür müsste PayPals Payload geparst werden. Wenn du „49,00 € von Anna“ willst, nimm den Backend-Weg unten.

Ein Punkt spielt hier für dich: PayPal wiederholt hartnäckig. Eine Antwort außerhalb von 2xx wird bis zu 25 Mal über drei Tage wiederholt, bevor die Zustellung als „Failed“ markiert wird. Webhooky antwortet immer mit 200, auch wenn du das Limit des Gratis-Tarifs erreicht hast – es sammelt sich also nie ein Rückstau fehlgeschlagener Zustellungen an.

Der Backend-Weg: Betrag, Währung und Käufer

Damit tatsächlich drinsteht, was angekommen ist, nimmst du den Webhook selbst entgegen, prüfst ihn und schickst dann eine formatierte Nachricht weiter:

export async function onPayPalWebhook(req, res) {
  res.sendStatus(200);                      // erst quittieren - PayPal wiederholt 3 Tage

  const event = req.body;
  if (event.event_type !== "PAYMENT.CAPTURE.COMPLETED") return;

  const amount = event.resource?.amount;
  const payer  = event.resource?.payer?.name?.given_name ?? "jemandem";

  await fetch(process.env.WEBHOOKY_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      title: "💰 PayPal-Zahlung",
      message: `${amount.value} ${amount.currency_code} von ${payer}`,
      sound: "cash_register",
    }),
  });
}

Quittiere, bevor du arbeitest. PayPals Wiederholungsfenster ist großzügig, dein Endpunkt hat trotzdem ein Timeout – und ein langsamer Handler macht aus einer Zahlung mehrere Zustellversuche.

Prüfen, dass es wirklich von PayPal kam

PayPal bietet zwei Wege. Du kannst die CRC32 der Nachricht berechnen und die Signatur selbst prüfen, oder du schickst die Nachricht, deine gespeicherte Webhook-ID und die Header-Informationen der Anfrage an PayPals Verify-Signature-Endpunkt und lässt PayPal prüfen. Der zweite Weg ist langsamer, aber deutlich schwerer falsch zu machen. Ohne Prüfung kannst du nicht wissen, ob ein POST an deinen Listener tatsächlich von PayPal stammt.

Jedem Ereignis seinen eigenen Sound

Hier schlägt ein eigener Endpunkt die PayPal-App. Leg pro Event-Typ einen Endpunkt an und vergib Sounds, die etwas bedeuten: Kassa für PAYMENT.CAPTURE.COMPLETED, Buzzer für PAYMENT.CAPTURE.DECLINED, etwas unmissverständlich Unangenehmes für CUSTOMER.DISPUTE.CREATED. Nach einer Woche weißt du, was passiert ist, ohne das Handy aus der Tasche zu holen. 40 Sounds stehen zur Wahl, und jeder Endpunkt führt seine eigene Historie.

Kein PayPal-Entwicklerkonto? Nimm Zapier oder Make

Das Developer Dashboard setzt eine REST-App voraus, und das ist mehr, als manche Verkäufer einrichten wollen. Zapier, Make und IFTTT haben alle PayPal-Trigger, die diesen Teil übernehmen – Trigger bauen, eine Aktion Webhooks → POST auf deine Webhooky-URL hinzufügen und den Betrag in die Nachricht mappen. Der Preis ist Latenz: Diese Dienste fragen nach Zeitplan ab, rechne also mit Minuten statt Sekunden.

Jetzt bei Google Play Laden im App Store

Häufige Fragen

Wie bekomme ich eine Benachrichtigung bei einer PayPal-Zahlung?

Entweder du aktivierst Benachrichtigungen in der PayPal-App, oder du abonnierst im PayPal Developer Dashboard einen Webhook auf PAYMENT.CAPTURE.COMPLETED und richtest ihn auf eine URL, die dich benachrichtigt. Auf einen Webhooky-Endpunkt gerichtet bekommst du einen Push mit eigenem Sound, ganz ohne Server.

Welches PayPal-Webhook-Event steht für eine abgeschlossene Zahlung?

PAYMENT.CAPTURE.COMPLETED bei Einmalzahlungen und PAYMENT.SALE.COMPLETED bei wiederkehrenden Abo-Zahlungen.

Wird PayPal IPN noch unterstützt?

IPN existiert weiterhin, und PayPals Dokumentation beschreibt NVP/SOAP als Legacy-Integrationsmethode, die weiter unterstützt wird – für neue Integrationen empfiehlt PayPal die neueren Lösungen. Für alles, was du heute baust, sind REST-Webhooks die richtige Wahl.

Wie oft wiederholt PayPal einen fehlgeschlagenen Webhook?

Dein Listener muss mit einem 2xx-Status antworten. Alles andere wird bis zu 25 Mal über drei Tage wiederholt, danach gilt die Zustellung als „Failed“. Im Webhook-Events-Dashboard kannst du sie manuell erneut senden.