Signatur
Beschreibung
Einige Zahlungsmethoden, allen voran Apple Pay, verlangen vor dem Anzeigen des Zahlungsblatts, dass sich der Händler gegenüber dem Zahlungsdienstleister ausweist. Der Browser löst dazu am PaymentRequest das Ereignis merchantvalidation aus. Das Ereignisobjekt vom Typ MerchantValidationEvent enthält in validationURL die Adresse, an die der eigene Server eine signierte Anfrage schicken muss.
Die Antwort des Zahlungsdienstleisters (bei Apple Pay ein opakes „Merchant Session“-Objekt) wird anschließend mit complete() an den Browser zurückgereicht. Erst danach kann der Nutzer die Zahlung autorisieren. Statt der fertigen Daten darf auch ein Promise übergeben werden – das ist der übliche Weg, weil der Abruf über den eigenen Server asynchron ist.
Wichtig: complete() muss synchron innerhalb des Ereignis-Handlers aufgerufen werden. Ein await vor dem Aufruf ist daher falsch – stattdessen reicht man das noch ausstehende Promise direkt an complete() weiter.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $validationData Pflicht | object | Promise<object> | Die vom Zahlungsdienstleister gelieferten, händlerspezifischen Validierungsdaten oder ein Promise, das mit diesen Daten erfüllt wird. Das Format bestimmt die jeweilige Zahlungsmethode (bei Apple Pay: das Merchant-Session-Objekt). |
Beispiele
Händlervalidierung für Apple Pay mit Promise
const methods = [{
supportedMethods: 'https://apple.com/apple-pay',
data: {
version: 3,
merchantIdentifier: 'merchant.net.programmierung.shop',
merchantCapabilities: ['supports3DS'],
supportedNetworks: ['visa', 'masterCard'],
countryCode: 'DE'
}
}];
const details = {
total: { label: 'Mein Shop', amount: { currency: 'EUR', value: '19.99' } }
};
const request = new PaymentRequest(methods, details);
request.addEventListener('merchantvalidation', (event) => {
// Eigener Server fragt mit Händlerzertifikat bei validationURL an
const sessionPromise = fetch('/api/apple-pay/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ validationURL: event.validationURL })
}).then((res) => {
if (!res.ok) throw new Error(`Validierung fehlgeschlagen: ${res.status}`);
return res.json();
});
// Synchron aufrufen – das Promise wird direkt übergeben
event.complete(sessionPromise);
});
const pay = async () => {
try {
const response = await request.show();
await response.complete('success');
console.log('Zahlung abgeschlossen');
} catch (err) {
console.error('Zahlung abgebrochen:', err.name);
}
};
document.querySelector('#pay').addEventListener('click', pay);
Variante mit der onmerchantvalidation-Eigenschaft
const request = new PaymentRequest(
[{ supportedMethods: 'https://apple.com/apple-pay', data: { version: 3, merchantIdentifier: 'merchant.net.programmierung.shop', merchantCapabilities: ['supports3DS'], supportedNetworks: ['visa'], countryCode: 'DE' } }],
{ total: { label: 'Abo', amount: { currency: 'EUR', value: '4.99' } } }
);
const fetchMerchantSession = async (validationURL) => {
const res = await fetch(`/api/apple-pay/validate?url=${encodeURIComponent(validationURL)}`);
return res.json();
};
request.onmerchantvalidation = (event) => {
console.log('Validiere bei:', event.validationURL);
event.complete(fetchMerchantSession(event.validationURL));
};
Typischer Fehler: await vor complete()
request.onmerchantvalidation = async (event) => {
// FALSCH: Nach dem await ist der Handler bereits zurückgekehrt
// const data = await fetchMerchantSession(event.validationURL);
// event.complete(data);
// RICHTIG: Promise synchron übergeben
event.complete(fetchMerchantSession(event.validationURL));
};
// Wichtig · Fallstricke
- Veraltet und kaum unterstützt:
MerchantValidationEventwurde aus der Payment-Request-Spezifikation entfernt. Chrome, Edge und Firefox haben das Ereignis nie ausgeliefert, nur Safari unterstützt es für Apple Pay. Für Apple Pay im Web istApplePaySessionmitonvalidatemerchant/completeMerchantValidation()die verbreitetere Alternative. Vorher per'onmerchantvalidation' in PaymentRequest.prototypeprüfen. - InvalidStateError: Wird geworfen, wenn das Ereignis nicht vom Browser stammt (
isTrusted === false, z. B. selbst erzeugt pernew MerchantValidationEvent()) oder wenncomplete()für dasselbe Ereignis ein zweites Mal aufgerufen wird. - Synchron aufrufen:
complete()muss während der Ereignisverarbeitung aufgerufen werden, also vor jedemawait. Asynchrone Arbeit gehört in das übergebene Promise. - Sicherheit: Die Anfrage an
validationURLmuss vom Server aus gestellt werden, denn sie braucht das Händlerzertifikat samt privatem Schlüssel. Der Schlüssel darf niemals im Client landen. Auf dem Server außerdem prüfen, dassvalidationURLzu einer bekannten Domain des Zahlungsdienstleisters gehört (sonst droht Server-Side Request Forgery, kurz SSRF). - Die Payment Request API funktioniert nur in sicheren Kontexten (HTTPS).