Payment Request API : consentement et solutions de repli
Utilisez PaymentRequest avec activation explicite, contexte sécurisé, annulation visible et solution de paiement sans collecte de secrets.
BotBrowser Team
Vous voulez la documentation structurée pour Plateforme ?
Cet article fait partie de la bibliothèque éditoriale. Pour les étapes de configuration, la référence et les mises à jour continues, passez directement à la section docs.
Payment Request peut ouvrir une feuille de paiement contrôlée par le navigateur, mais la fin de show() ne prouve ni l'autorisation ni la réception des fonds par le marchand. BotBrowser peut rejouer ses propres fixtures et vérifier les états visibles ; il ne peut pas fournir d'instrument réel, approuver les opérations bancaires ou traiter les identifiants de paiement. Pose des limites nettes : lance la demande depuis une action explicite dans un contexte sécurisé, ne confonds pas indication de capacité et consentement, traite séparément annulation et délai d'attente, réserve complete() à l'état final de la feuille et garde un checkout classique quand l'API ou les données de paiement sont indisponibles.
Résumé
new PaymentRequest(methodData, details, options)décrit les méthodes et les détails de la transaction ; il ne demande pas de secret et ne garantit pas qu'une méthode existe.canMakePayment()n'est qu'une indication de capacité.truene signifie ni consentement, ni autorisation, ni fonds disponibles, et ne garantit pas la réussite deshow().- Appelle
show()depuis un clic visible ou une action clavier dans un contexte sécurisé. TraiteAbortError,NotAllowedError, les délais et les méthodes absentes comme des états ordinaires du produit. - Après validation de la réponse, ferme la feuille avec
complete('success'),complete('fail')oucomplete('unknown').complete()décrit l'interface, pas le règlement. - Ne journalise jamais les identifiants de paiement, la réponse, les données de carte ni les exceptions complètes. Garde un formulaire manuel, une demande de facture ou une autre voie sans PaymentRequest.
Sommaire
Séparer capacité et consentement
Payment Request API permet de décrire les moyens de paiement et de demander au navigateur d'intermédier le choix de l'utilisateur. Elle ne remplace pas le processeur et ne sert pas à lire une carte ou un portefeuille. Le navigateur affiche la feuille et la personne décide ; le marchand doit toujours gérer l'autorisation serveur, l'idempotence, l'antifraude et le résultat de règlement du fournisseur.
canMakePayment() peut aider à afficher une entrée de paiement rapide. Le navigateur peut renvoyer false, true ou un rejet selon ses politiques, les méthodes enregistrées, la confidentialité et l'implémentation ; le résultat peut varier d'une visite à l'autre. Ne l'utilise pas pour masquer le checkout complet, déduire le portefeuille ou construire un profil stable. Demande-le quand la personne choisit la voie de paiement et garde le résultat peu longtemps.
La détection de fonctionnalité doit rester bornée :
const paymentSupported = window.isSecureContext && 'PaymentRequest' in window;
if (!paymentSupported) showCheckoutFallback('unsupported');
La présence du constructeur ne signifie pas que chaque méthode est prise en charge. Le document peut perdre le focus, se trouver dans un frame soumis à une politique restrictive ou ne plus avoir l'activation transitoire. Une mise à jour du navigateur peut modifier les méthodes sans changer le code. Considère chaque essai comme une observation nouvelle, jamais comme une propriété permanente de l'utilisateur.
Pour une limite de consentement voisine, Web Share et ses solutions de repli rappelle qu'un transfert terminé ne prouve pas l'acceptation par le destinataire ; les limites des permissions Web Share montrent aussi le rôle du contexte et d'une activation récente. Payment Request peut exposer une réponse au marchand, mais le serveur et le processeur restent responsables du règlement. Le guide des contextes sécurisés présente le socle HTTPS commun aux fonctions puissantes du navigateur.
Construire une requête étroite
Garde les données de méthode et les détails de transaction minimaux. L'identifiant indique au navigateur quel type de paiement le marchand sait traiter. details fournit un total visible et des lignes facultatives, mais ce n'est pas une source de vérité. À la réception, le serveur doit recalculer le montant final : prix, taxes, stock et devise ne sont pas fiables côté page.
const methodData = [
{
supportedMethods: 'https://example.test/pay',
data: { version: 1 },
},
];
const details = {
id: 'order-2026-1042',
total: { label: 'Example order', amount: { currency: 'USD', value: '19.00' } },
displayItems: [{ label: 'Item', amount: { currency: 'USD', value: '19.00' } }],
};
const options = { requestPayerName: false, requestPayerEmail: false };
const request = new PaymentRequest(methodData, details, options);
Ne place pas de numéro de carte, token de portefeuille, secret ou identifiant personnel dans methodData ou l'URL. Des options comme requestPayerEmail demandent seulement des données et ne valident pas la valeur retournée. Demande les champs nécessaires à la commande, explique pourquoi, puis cesse de les conserver après réception du token autorisé par le processeur.
Associe chaque objet request à un seul essai de checkout. Si le panier change, crée une nouvelle requête avec un details.id et une version de commande serveur différents. Ne réutilise pas l'ancien objet après un délai ou une navigation. Un token d'opération bref permet à l'interface de refuser les réponses tardives d'un ancien panier.
Lancer show avec activation
request.show() ouvre la feuille de paiement et renvoie une promesse contenant PaymentResponse. Lance-le directement depuis un bouton visible ou une activation clavier. Ne l'appelle pas au chargement, dans un minuteur ou un callback analytique, et n'attends pas d'abord un travail qui pourrait consommer l'activation transitoire. Le contexte sécurisé, les politiques, les limites d'iframe ou les règles de la plate-forme peuvent aussi bloquer la feuille.
let activeAttempt = 0;
async function beginPayment() {
const attempt = ++activeAttempt;
if (!window.isSecureContext || !('PaymentRequest' in window)) {
showCheckoutFallback('unsupported');
return;
}
const request = buildRequest();
showPaymentState('opening');
try {
const response = await request.show();
if (attempt !== activeAttempt) return;
await handlePaymentResponse(response, request, attempt);
} catch (error) {
if (attempt !== activeAttempt) return;
showPaymentState(error?.name === 'AbortError' ? 'cancelled' : 'rejected');
showCheckoutFallback(error?.name === 'AbortError' ? 'cancelled' : 'rejected');
}
}
payButton.addEventListener('click', beginPayment);
Tu peux désactiver les activations répétées pendant l'ouverture, mais garde une solution visible. Après annulation ou refus, rends le focus au bouton d'origine. Annonce opening, cancelled et fallback dans une live region sans exposer la réponse, afin que la personne comprenne la suite sans voir une erreur du navigateur.
Un checkout intégré demande une décision de déploiement explicite. Une politique supérieure ou un attribut d'iframe peut décider si le navigateur autorise le paiement, mais la délégation ne contourne pas les permissions et ne donne pas le consentement. Teste séparément l'origine supérieure et le parcours intégré ; ce qui marche dans un onglet peut être indisponible dans un frame d'une autre origine.
Valider la réponse et compléter la feuille
PaymentResponse contient les données du moyen, les champs payer demandés et complete(). Après validation de sa forme, envoie au serveur uniquement le token approuvé par le processeur via un canal authentifié. Ne traite jamais la réponse comme un reçu : le processeur peut refuser, retarder ou révoquer l'autorisation.
async function handlePaymentResponse(response, request, attempt) {
showPaymentState('validating');
let outcome = 'unknown';
try {
const result = await postPaymentToken({
methodName: response.methodName,
details: response.details,
orderId: request.id,
attempt,
});
outcome = result.authorized === true ? 'success' : 'fail';
} catch {
outcome = 'unknown';
}
try {
await response.complete(outcome);
} catch {
// The payment sheet may already have closed; keep the server outcome.
}
showPaymentState(outcome);
}
N'appelle complete() qu'une fois par réponse. success demande au navigateur d'afficher un état terminé, fail décrit un essai échoué et unknown s'utilise quand le serveur n'a pas de résultat. Aucune de ces valeurs ne prouve un débit, un remboursement ou une livraison ; l'état de référence vient de la réponse serveur du processeur et du journal idempotent de la commande.
response.complete() peut être rejeté si la réponse est déjà fermée, si le navigateur a terminé la feuille ou si le document n'est plus pertinent. Ne transforme pas ce rejet en second débit. Garde le résultat serveur, propose un nouvel essai de commande et n'envoie jamais deux fois le même token.
Classer annulation, refus et délai
Une annulation n'est pas un échec de carte. La personne peut fermer la feuille, changer d'avis ou refuser une méthode. AbortError indique souvent une annulation sans en donner la raison. Sépare cancelled, rejected, unsupported et processor-failed; conserve le panier et offre un formulaire manuel sans demander de secret dans les diagnostics.
Un délai doit avoir un responsable clair. La page peut fixer une échéance pour l'appel serveur, mais un minuteur ne prouve pas ce que la feuille a fait. Si l'appel expire après réception d'une réponse, marque unknown, arrête les renvois et vérifie la commande auprès du processeur avant de réessayer. Un callback tardif ne doit pas écraser un nouvel essai.
Les erreurs de méthode diffèrent de celles du navigateur. Une méthode absente peut faire rejeter show() avant l'ouverture de la feuille ; une politique ou une activation bloquée peut produire NotAllowedError. Une réponse mal formée relève de la validation, tandis que le refus du processeur relève du serveur. Conserve ces étapes dans l'interface et le support afin de ne pas redemander la carte à cause d'une politique d'iframe.
Utilise une séquence bornée : idle, opening, shown, response-received, authorizing, success, fail, unknown, cancelled, rejected, unsupported et fallback. Enregistre seulement la première étape en échec de chaque essai. Ne relance pas automatiquement show() après la fermeture et n'appelle pas abort() depuis une tâche d'arrière-plan, sauf si le produit possède explicitement cette action d'annulation.
Données et solution de repli
La réponse de paiement peut contenir un token sensible, des données payer, une référence de facturation ou une valeur opaque qui devient un secret lorsqu'elle est rejouée. N'insère pas response.details, l'e-mail payer, un fragment de carte ni une exception complète dans les journaux, URL, captures, replays, rapports d'incident ou dimensions analytiques. La désidentification doit aussi couvrir les intégrations hors de l'appel PaymentRequest.
{
"api": "PaymentRequest",
"attempt": "pay-7f31",
"capability": "available",
"outcome": "cancelled",
"methodNamePresent": true,
"paymentDetailsRetained": false,
"settlement": "not-asserted"
}
Cet enregistrement suffit à savoir si la feuille s'est ouverte et quel résultat la page a affiché, mais pas si la personne possède un compte ni si le processeur a débité. Les tokens doivent être aléatoires et courts ; les exports de diagnostic doivent expirer et toute capture de support doit être explicite et vérifiable. Hacher un token ne le rend pas inoffensif : une valeur stable peut relier plusieurs sessions.
Préserver un repli et séparer le règlement.
Garde la solution de repli dès le premier écran. Si PaymentRequest est absent, si canMakePayment() est rejeté, si show() est annulé, si la méthode est absente ou si la réponse du processeur est inconnue, laisse un formulaire classique, une demande de facture, un lien de paiement ou un contact. Le repli doit conserver panier, clavier, libellés, validation et instructions suivantes.
Ne désactive pas le repli parce que canMakePayment() renvoie true. Sans résultat autoritatif du processeur côté serveur, n'affiche pas « paiement terminé » après complete('success'). Ne confonds pas la feuille avec Web Share, Credential Management ou l'interface d'un portefeuille. Payment Request est un checkout intermédiaire du navigateur, pas un coffre de secrets ni un contournement du processeur.
Dans les fixtures contrôlées, utilise des identifiants de méthode synthétiques et des montants fictifs. Vérifie qu'aucun champ secret n'est journalisé, que le focus revient après annulation, qu'un résultat serveur inconnu appelle complete('unknown') et que la voie manuelle reste disponible. Les identifiants réels et les endpoints du fournisseur ne doivent pas entrer dans les fixtures automatisées.
Tableau de décision.
| Étape observée | Ce qu'elle prouve | Suite sûre |
|---|---|---|
| API absente ou contexte non sécurisé | Payment Request ne peut pas démarrer | Garde le checkout manuel ou la facture |
canMakePayment() vaut false ou rejette | Aucune indication utile cette fois | Garde le checkout principal, sans déduire le portefeuille |
show() rejette avec AbortError | La feuille a été annulée ou fermée | Garde le panier, journalise cancelled et attends une nouvelle action |
| Politique ou activation bloquée | Le navigateur a refusé l'essai | Vérifie contexte sécurisé, focus, politique du frame et responsable du geste |
| Une réponse arrive | Le navigateur a rendu les données de méthode | Valide strictement et envoie seulement le token autorisé |
| Autorisation refusée par le serveur | Le processeur n'a pas autorisé l'essai | Appelle complete('fail'), explique le repli et évite les doublons |
| Délai du résultat serveur | Le règlement est inconnu | Si possible, appelle complete('unknown') et vérifie avant de réessayer |
complete('success') se termine | La feuille a accepté la demande d'interface | Affiche seulement l'état serveur de la commande |
Capacité et limite de BotBrowser.
Un contexte contrôlé BotBrowser peut rejouer une fixture PaymentRequest du même origin avec une méthode synthétique, exercer les branches de capacité et d'activation, simuler annulation ou délai, puis vérifier un résultat visible désidentifié et le repli. La documentation des capacités avancées décrit les limites propres à la page. BotBrowser ne fournit pas d'instrument réel, n'approuve aucune transaction bancaire ou de portefeuille, ne prouve pas le règlement et ne collecte pas d'identifiants pour tester.
Conserve un enregistrement déterministe de la fixture :
{
"api": "PaymentRequest",
"secureContext": true,
"userActivation": true,
"canMakePayment": "hint-only",
"show": "cancelled",
"complete": "unknown",
"paymentDetailsRetained": false,
"fallback": "manual-checkout"
}
Répète le test en ne changeant qu'une variable : version du navigateur, origin supérieur, politique d'iframe, moment d'activation, méthode synthétique, délai serveur ou branche d'annulation. Compare la première différence visible. Une fixture prouve seulement le traitement de l'état de page, pas l'autorisation ni le mouvement de fonds.
Sources
- W3C Payment Request API
- MDN:Payment Request API
- MDN:PaymentRequest.show()
- MDN:PaymentRequest.canMakePayment()
- MDN:PaymentResponse.complete()
- MDN : contextes sécurisés
- BotBrowser : capacités avancées
Conclusion pratique
BotBrowser peut rejouer un fixture PaymentRequest synthétique et vérifier l'activation, l'indice de capacité, l'annulation et le repli, mais il ne fournit pas d'instrument réel et ne prouve pas le règlement.
BotBrowser peut rejouer un fixture PaymentRequest synthétique et vérifier l'activation, l'indice de capacité, l'annulation et le repli, mais il ne fournit pas d'instrument réel et ne prouve pas le règlement.
Considère PaymentRequest uniquement comme une interface de consentement intermédiaire du navigateur. Construis une demande minimale, appelle show() depuis une action utilisateur récente dans un contexte sécurisé, valide la réponse côté serveur et réserve complete() à l'état de la feuille, sans affirmer le règlement. Distingue annulation, refus, délai et méthode absente, journalise des résultats désidentifiés et conserve un checkout complet sans PaymentRequest. Une fixture BotBrowser contrôlée démontre des branches visibles, pas un débit réel.
Cet article fait partie du guide : Surfaces de la plateforme web : carte de revue
Articles Connexes
Web Share API : limites des permissions et replis sûrs
PlateformeWeb Share API et partage déclenché par la personne
PlateformePresentation API : limites d écran et de session
PlateformeWeb MIDI API : permission et confidentialité des appareils
PlateformeEyeDropper API : activation et confidentialité des couleurs
PlateformeIdle Detection API : contrôle, permissions et confidentialité
Faites passer BotBrowser de la recherche à la production
Utilisez ces guides pour comprendre le modèle, puis passez à la validation multi-plateforme, aux contextes isolés et au déploiement navigateur prêt pour l'échelle.