Start · Sprachen · JavaScript · Referenz · ServiceWorkerGlobalScope: paymentrequest

ServiceWorkerGlobalScope: paymentrequest

Ereignis

Wird im Service Worker einer Zahlungs-App ausgelöst, sobald eine Händlerseite über <code>PaymentRequest.show()</code> einen Zahlungsvorgang mit dieser App startet.

seit JavaScript Experimentell: Chromium-Browser (Chrome/Edge 70+), Kategorie: webapi

Signatur

self.addEventListener("paymentrequest", handler)

Beschreibung

Das Ereignis paymentrequest gehört zur Payment Handler API. Es wird im ServiceWorkerGlobalScope einer webbasierten Zahlungs-App ausgelöst, wenn eine Händler-Website new PaymentRequest(...).show() aufruft und der Nutzer diese Zahlungs-App auswählt. Oft wird sie auch direkt gestartet, wenn sie die einzige passende App ist. Der Handler bekommt ein PaymentRequestEvent mit allen Angaben zur Transaktion, zum Beispiel methodData, total, modifiers, paymentRequestOrigin, topOrigin und paymentRequestId.

Normalerweise öffnet die Zahlungs-App im Handler mit event.openWindow(url) ein eigenes Fenster, etwa für Anmeldung, Bestätigung oder 3-D-Secure. Außerdem ruft sie event.respondWith(promise) auf. Das übergebene Promise muss mit einem Objekt erfüllt werden, das dem PaymentHandlerResponse-Dictionary entspricht, mindestens mit methodName und details. Dieses Objekt landet auf der Händlerseite als PaymentResponse.

Damit das Ereignis überhaupt ausgelöst wird, muss der Service Worker als Zahlungs-App bekannt sein. Dafür gibt es zwei Wege: über ein Web-App-Manifest mit Payment-Method-Manifest (Just-in-Time-Installation) oder über registration.paymentManager. Die Zahlungsmethode, die die Händlerseite angibt, meist eine URL wie https://pay.example/, muss zu dieser App passen.

Als On-Property steht zusätzlich self.onpaymentrequest = handler zur Verfügung. Das Ereignis lässt sich nicht abbrechen und steigt nicht auf (kein Bubbling).

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignistyp, immer "paymentrequest".
$handler Pflicht (event: PaymentRequestEvent) => void Callback, der ein PaymentRequestEvent bekommt. Wichtige Mitglieder: respondWith(), openWindow(), changePaymentMethod(), changeShippingAddress(), changeShippingOption(), total, methodData, paymentRequestId, paymentRequestOrigin, topOrigin, instrumentKey (veraltet).
$options boolean|AddEventListenerOptions false Die üblichen Optionen von addEventListener, zum Beispiel { once: true }.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Das Ergebnis der Zahlung liefert man über event.respondWith() als Promise, das mit einem PaymentHandlerResponse erfüllt wird.

Beispiele

Minimaler Handler im Service Worker (addEventListener)

// sw.js der Zahlungs-App
self.addEventListener('paymentrequest', (event) => {
  console.log('Zahlung angefragt von:', event.paymentRequestOrigin);
  console.log('Betrag:', event.total.value, event.total.currency);

  // Ohne UI direkt antworten (nur zu Demo-Zwecken)
  event.respondWith(Promise.resolve({
    methodName: 'https://pay.example/',
    details: { token: 'demo-token-123' }
  }));
});
Zahlung angefragt von: https://shop.example Betrag: 49.90 EUR

Zahlungsfenster öffnen und Ergebnis per postMessage abwarten

// sw.js
let resolver = null;
let paymentEvent = null;

self.addEventListener('paymentrequest', (event) => {
  paymentEvent = event;

  const antwort = new Promise((resolve, reject) => {
    resolver = { resolve, reject };
  });
  event.respondWith(antwort);

  // Eigene Bestätigungsseite der Zahlungs-App öffnen
  event.openWindow('/checkout.html').then((client) => {
    if (!client) resolver.reject(new Error('Fenster konnte nicht geöffnet werden'));
  }).catch((err) => resolver.reject(err));
});

self.addEventListener('message', (e) => {
  if (!resolver) return;
  if (e.data.type === 'READY') {
    // Transaktionsdaten an das Fenster schicken
    e.source.postMessage({ total: paymentEvent.total, origin: paymentEvent.topOrigin });
  } else if (e.data.type === 'PAID') {
    resolver.resolve({ methodName: 'https://pay.example/', details: { token: e.data.token } });
    resolver = null;
  } else if (e.data.type === 'CANCEL') {
    resolver.reject(new DOMException('Vom Nutzer abgebrochen', 'AbortError'));
    resolver = null;
  }
});

Variante mit on-Property und Händlerseite

// sw.js – alternative Registrierung über die On-Property
self.onpaymentrequest = (event) => {
  event.respondWith((async () => ({
    methodName: 'https://pay.example/',
    details: { id: event.paymentRequestId, status: 'ok' }
  }))());
};

// shop.js – auf der Händlerseite
const kaufen = async () => {
  const request = new PaymentRequest(
    [{ supportedMethods: 'https://pay.example/' }],
    { total: { label: 'Summe', amount: { currency: 'EUR', value: '49.90' } } }
  );
  const response = await request.show(); // löst paymentrequest im SW aus
  console.log(response.methodName, response.details);
  await response.complete('success');
};
document.querySelector('#buy').addEventListener('click', kaufen);
https://pay.example/ { id: "…", status: "ok" }

// Wichtig · Fallstricke

  • Kompatibilität: Das Ereignis ist experimentell und nur in Chromium-Browsern verfügbar (Chrome, Edge, Opera, Samsung Internet). Firefox und Safari unterstützen die Payment Handler API nicht. Prüfen lässt sich die Unterstützung mit 'PaymentRequestEvent' in self oder 'paymentManager' in registration.
  • Sicherer Kontext: Es funktioniert nur über HTTPS und in einem registrierten Service Worker, der als Zahlungs-App installiert ist. Zur Installation gehören ein Payment-Method-Manifest und ein Web-App-Manifest.
  • respondWith synchron aufrufen: event.respondWith() muss synchron im Handler aufgerufen werden, also vor dem ersten await. Sonst wirft der Aufruf einen InvalidStateError. Asynchrone Arbeit gehört in das übergebene Promise.
  • openWindow: event.openWindow() ist nur im Kontext dieses Ereignisses erlaubt und darf nur Seiten desselben Ursprungs öffnen. Das Promise kann mit null erfüllt werden.
  • Sicherheit: Der Service Worker darf den Angaben des Händlers (total, methodData) nicht blind vertrauen. Er sollte topOrigin und paymentRequestOrigin prüfen und Beträge serverseitig verifizieren. Nachrichten aus message-Ereignissen sollte man auf den Absender (e.source/Ursprung) prüfen, bevor man ein Zahlungs-Token herausgibt.
  • Wird das Promise abgelehnt, erhält die Händlerseite bei show() einen AbortError bzw. OperationError.
  • Die Eigenschaft instrumentKey ist veraltet und sollte nicht mehr benutzt werden.