Signatur
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
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' }
}));
});
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);
// 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 selfoder'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 erstenawait. Sonst wirft der Aufruf einenInvalidStateError. 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 mitnullerfüllt werden. - Sicherheit: Der Service Worker darf den Angaben des Händlers (
total,methodData) nicht blind vertrauen. Er solltetopOriginundpaymentRequestOriginprüfen und Beträge serverseitig verifizieren. Nachrichten ausmessage-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()einenAbortErrorbzw.OperationError. - Die Eigenschaft
instrumentKeyist veraltet und sollte nicht mehr benutzt werden.