How payment apps get discovered

When a merchant starts a Web Payments transaction, the browser has to find the payment app the shopper wants to use. The discovery process relies on three pieces of metadata: a URL-based payment method identifier, a payment method manifest, and a web app manifest. This article explains how to serve each one so your payment app can be discovered and launched.

If you are new to Web Payments, you should first read about how payment apps work with the Payment Request API and what happens during a payment transaction. Browser support for Web Payments varies by feature, so check the current status before you build.

Discovery flow at a glance

The payment method identifier is a URL, for example Google Pay uses https://google.com/pay. As a payment app developer you can choose any URL you control, as long as you can serve content and HTTP headers from it. Merchants list the identifiers they accept in the supportedMethods property when they construct a PaymentRequest.

When the merchant initiates a transaction, the browser takes the following steps:

  1. It sends a request to the payment method identifier URL and fetches the payment method manifest.
  2. It reads the payment method manifest to find the web app manifest URL and fetches that file.
  3. It decides from the web app manifest whether to launch an OS-level payment app or a web-based payment app.

Step 1: Set up the payment method identifier and manifest

A payment method manifest is a JSON file that declares which payment apps are allowed to use a given payment method. The manifest has two fields: default_applications and supported_origins.

The identifier URL does not serve the manifest directly. Instead, the browser sends an HTTP HEAD request to the identifier URL, and the response must include a Link header pointing to the manifest. For example, if the manifest lives at https://bobbucks.dev/pay/payment-manifest.json, the response header looks like this:

Link: <https://bobbucks.dev/pay/payment-manifest.json>; rel="payment-method-manifest"

The manifest URL can be absolute or relative. You can inspect the response yourself with curl against the identifier URL.

The manifold itself is served from that URL in response to an HTTP GET request. Use default_applications to list the web app manifest URLs of the payment apps that support this method.

[payment handler] /payment-manifest.json

{
  "default_applications": ["https://bobbucks.dev/manifest.json"],
  "supported_origins": [
    "https://alicepay.friendsofalice.example"
  ]
}

Step 2: Serve a web app manifest

A web app manifest describes your payment app to the browser, just as it would for a Progressive Web App. The browser uses the name property to display the app in the Payment Request UI and the icons property for the app icon.

A typical manifest for a payment handler includes a serviceworker field with the SW URL and scope:

[payment handler] /manifest.json:

"serviceworker": {
  "src": "payment-handler.js"
}

Step 3: Chrome decides which kind of app to launch

Platform-specific app

Chrome launches a platform-specific payment app when all of these conditions hold:

  • The web app manifest specifies related_applications with an installed app whose package ID and signature match, and whose version is at least min_version.
  • prefer_related_applications is true.
  • The installed app has an intent filter for org.chromium.action.PAY and declares the payment method identifier in its org.chromium.default_payment_method_name property.

A manifest that enables this looks like the following:

[payment handler] /manifest.json

"prefer_related_applications": true,
"related_applications": [{
  "platform": "play",
  "id": "xyz.bobpay.app",
  "min_version": "1",
  "fingerprints": [{
    "type": "sha256_cert",
    "value": "92:5A:39:05:C5:B9:EA:BC:71:48:5F:F2:05:0A:1E:57:5F:23:40:E9:E3:87:14:EC:6D:A2:04:21:E0:FD:3B:D1"
  }]
}]

If those conditions are met, discovery stops here. Otherwise Chrome moves on to the web-based payment app.

Web-based app

To launch a web-based payment app, the browser fires a paymentrequest event at the service worker listed in the web app manifest. The service worker does not need to be registered in advance; Chrome can register it just-in-time.

Optimizations you should know about

Skipping the Payment Request UI

Normally, calling show() on a PaymentRequest displays the browser-provided Payment Request UI where the shopper selects an app and clicks Continue. Chrome can skip that UI and launch the payment app directly when:

  • show() is called with a user gesture (for example, a click).
  • Exactly one payment app supports the requested payment method identifier.

Just-in-time registration

If the Payment Request UI is shown, the service worker registers just-in-time and launches when the user clicks Continue. If the UI is skipped, registration and launch happen directly. Skipping the UI requires a user gesture to prevent unexpected registration of a cross-origin service worker.

Once your payment app is discoverable, you can move on to platform-specific development or building the web-based version. The guides for Android payment apps and web-based payment apps cover the details of each implementation path.