The MerchantValidationEvent interface

Merchant validation is the process by which a payment handler validates the identity of a merchant against some |value| (usually some cryptographic challenge response). Validated merchants are allowed to interface with a payment handler. Details of how actual validation is performed is outside the scope of this specification.

This feature was removed from [[[Payment-Request]]] due to lack of interoperable support. However, as it is implemented by at least one browser engine, the Working Group decided to publish this document as a Working Group Note.

Extensions to the `PaymentRequest` interface

        partial interface PaymentRequest {
          attribute EventHandler onmerchantvalidation;

onmerchantvalidation attribute

A {{PaymentRequest}}'s {{PaymentRequest/onmerchantvalidation}} attribute is an {{EventHandler}} for a {{MerchantValidationEvent}} named "merchantvalidation".

MerchantValidationEvent interface

          [SecureContext, Exposed=Window]
          interface MerchantValidationEvent : Event {
            constructor(DOMString type, optional MerchantValidationEventInit eventInitDict = {});
            readonly attribute DOMString methodName;
            readonly attribute USVString validationURL;
            undefined complete(Promise<any> merchantSessionPromise);

Internal Slots

Instances of {{MerchantValidationEvent}} are created with the internal slots in the following table:

Internal Slot Description (non-normative)
[[\waitForUpdate]] A boolean indicating whether a {{PaymentResponse/complete()}}-initiated update is currently in progress.

`MerchantValidationEvent` constructor

The event constructing steps, which take a {{MerchantValidationEvent}} |event:MerchantValidationEvent|, are as follows:

  1. Let |base:URL| be the [=context object|event=]’s relevant settings object’s [=environment settings object/api base URL=].
  2. Let |validationURL:URL| be the result of [=URL parser|URL parsing=] |eventInitDict:MerchantValidationEventInit|.{{MerchantValidationEventInit/validationURL}} and |base|.
  3. If |validationURL| is failure, throw a {{TypeError}}.
  4. Initialize |event|.{{MerchantValidationEvent/validationURL}} attribute to |validationURL|.
  5. If |eventInitDict|.{{MerchantValidationEventInit/methodName}} is not the empty string, run the steps to validate a payment method identifier with |eventInitDict|.{{MerchantValidationEventInit/methodName}}. If it returns false, then throw a {{RangeError}} exception. Optionally, inform the developer that the payment method identifier is invalid.
  6. Initialize |event|.{{MerchantValidationEvent/methodName}} attribute to |eventInitDict|.{{MerchantValidationEventInit/methodName}}.
  7. Initialize |event|.{{MerchantValidationEvent/[[waitForUpdate]]}} to false.

methodName attribute

When getting, returns the value it was initialized with. See {{MerchantValidationEvent/methodName}} member of {{MerchantValidationEventInit}} for more information.

validationURL attribute

A URL from which a developer can fetch payment handler-specific verification data. By then passing that data (or a promise that resolves with that data) to {{PaymentResponse/complete()}}, the user agent can verify that the payment request is from an authorized merchant.

When getting, returns the value it was initialized with.

complete() method

The {{MerchantValidationEvent}}'s complete(|merchantSessionPromise|) method MUST act as follows:

  1. Let |event:MerchantValidationEvent| be [=this=].
  2. If |event|'s {{Event/isTrusted}} attribute is false, then [=exception/throw=] an {{"InvalidStateError"}} {{DOMException}}.
  3. If |event|.{{MerchantValidationEvent/[[waitForUpdate]]}} is true, then [=exception/throw=] an {{"InvalidStateError"}} {{DOMException}}.
  4. Let |request:PaymentRequest| be |event|'s [=Event/target=].
  5. If |request|.`[[state]` is not `"interactive"`, then [=exception/throw=] an {{"InvalidStateError"}} {{DOMException}}.
  6. If |request|.`[[updating]]` is true, then [=exception/throw=] an {{"InvalidStateError"}} {{DOMException}}.
  7. Set |event|'s [=Event/stop propagation flag=] and [=Event/stop immediate propagation flag=].
  8. Set |event|.{{MerchantValidationEvent/[[waitForUpdate]]}} to true.
  9. Run the validate merchant's details algorithm with |merchantSessionPromise| and |request|.

MerchantValidationEventInit dictionary

            dictionary MerchantValidationEventInit : EventInit {
              DOMString methodName = "";
              USVString validationURL = "";
methodName member
A payment method identifier representing the payment handler that is requiring merchant validation.
validationURL member
A URL from which a developer would fetch payment handler-specific verification data.

Request merchant validation algorithm

For payment handlers that support merchant validation, the user agent runs the request merchant validation algorithm. The algorithm takes a {{USVString}} |merchantSpecificURL|, provided by the payment handler:

  1. Let |request:PaymentRequest| be the {{PaymentRequest}} object that the user is interacting with.
  2. Let |validationURL:URL| be a absolute-URL string from which a developer can fetch payment handler-specific verification data.
  3. Let |methodName:URL or String| be the payment method identifier for the payment handler that is requiring merchant validation.
  4. Queue a task on the user interaction task source to run the following steps:
    1. Assert: |request|.`[[updating]]` is false.
    2. Assert: |request|.`[[state]` is `"interactive"`.
    3. Let |eventInitDict:MerchantValidationEventInit| be an new {{MerchantValidationEventInit}} dictionary.
    4. Set |eventInitDict|.{{MerchantValidationEventInit/validationURL}}] to |validationURL|.
    5. Set |eventInitDict|.{{MerchantValidationEventInit/methodName}} to |methodName|.
    6. Let |event:MerchantValidationEvent| be the result of calling the [=Event/constructor=] of {{MerchantValidationEvent}} with "merchantvalidation" and |eventInitDict|.
    7. Initialize |event|’s {{Event/isTrusted}} attribute to true.
    8. Dispatch |event| to |request|.

Validate merchant's details algorithm

The validate merchant's details algorithm takes a {{Promise}} |opaqueDataPromise| and a {{PaymentRequest}} |request|. The steps are conditional on the |opaqueDataPromise| settling. If |opaqueDataPromise| never settles then the payment request is blocked. The user agent SHOULD provide the user with a means to abort a payment request. Implementations MAY choose to implement a timeout for pending updates if |opaqueDataPromise| doesn't settle in a reasonable amount of time. If an implementation chooses to implement a timeout, they MUST execute the steps listed below in the "upon rejection" path. Such a timeout is a fatal error for the payment request.

  1. Set |request|.`[[updating]]` to true.
  2. In parallel, disable the user interface that allows the user to accept the payment request. This is to ensure that the payment is not accepted until the user interface is updated with any new details.
  3. Upon rejection of |opaqueDataPromise|:
    1. Abort the update with |request| and an {{"AbortError"}} {{DOMException}}.
  4. Upon fulfillment of |opaqueDataPromise| with value |opaqueData|:
    1. Validate the merchant using |opaqueData|.
    2. If |opaqueData| is invalid, as per the validation rules of the payment handler, abort the update with |request| and an appropriate exception and return.
    3. Otherwise, set |request|.`[[updating]]` to false.
    4. Enable the user interface, allowing the request for payment to proceed.

Privacy considerations

It is important that the {{MerchantValidationEvent/validationURL}} in a {{MerchantValidationEvent}} does not expose personally identifying information to unauthorized parties.

Events Summary

Event name Interface Dispatched when… Target
merchantvalidation {{MerchantValidationEvent}} The user agent requires the merchant to perform merchant validation. {{PaymentRequest}}