# Payments

> Payment Request API, Apple Pay, Google Pay, and provider SDKs in a PWA: which engine supports which method, by version, and what the browser requires first.

import CompatTable from '@components/CompatTable.astro';

A PWA takes payment with the same three layers as any web page: the browser's Payment Request
API, a wallet that plugs into it (Apple Pay in Safari, Google Pay in Chromium and others), and a
payment provider's JavaScript SDK that falls back to a hosted form. Which layer works depends
on the engine and its version, not on whether the page is installed.

## How it works

The browser owns the checkout sheet. Your code describes the methods it accepts and the total,
and the engine decides which wallets it can show; a provider SDK sits on top and chooses between
that sheet and its own form.

### Payment Request API

`new PaymentRequest(methods, details)` followed by `show()` opens the browser's sheet. The
compat data (BCD `api.PaymentRequest`) places it in Chrome 60 on desktop and Chrome 53 on
Android, Edge 15, Safari 11.1 on macOS and iOS, Samsung Internet following Chrome for Android,
and Android WebView 136. Firefox 55 contains an implementation that is disabled by default
behind `dom.payments.request.enabled` and a `dom.payments.request.supportedRegions` country
list, so a Firefox user sees no sheet. The API is limited to secure contexts, and a cross-origin
`<iframe>` gets it only with the `allowpaymentrequest` attribute.

<CompatTable feature="payment-request" />

Detection has two steps, because a browser can expose the constructor and still support none
of your methods:

```js
async function startCheckout(methods, details) {
  if (!('PaymentRequest' in window)) return openProviderForm();
  const request = new PaymentRequest(methods, details);
  if (!(await request.canMakePayment())) return openProviderForm();
  try {
    const response = await request.show();
    await response.complete('success');
  } catch (err) {
    if (err.name === 'AbortError') return; // the user closed the sheet
    return openProviderForm();
  }
}
```

### Apple Pay

In Safari the only method behind Payment Request is Apple Pay; the sheet is the same one
Apple Pay JS opens. Apple's planning page states that merchants anywhere can accept Apple Pay
"as long as their payment service provider supports Apple Pay", that "in China mainland, Apple
Pay on the web is supported in Safari on iOS only", and that platforms register merchant
websites through the Apple Pay Web Merchant Registration API. Web content shown in an
`SFSafariViewController` can use Apple Pay as in Safari; a `WKWebView` cannot, and Apple
directs those apps to move the request into native code.

### Google Pay

Google's setup guide lists the browsers in which the Google Pay API for web runs: "Google
Chrome, Mozilla Firefox, Apple Safari, Microsoft Edge, Opera, or UCWeb UC Browser", and requires
"an HTTPS webpage with a TLS domain-validated certificate". The API returns a payment token for
the chosen method, which your backend forwards to the processor. Google lists Firefox and Safari
although Payment Request does not surface Google Pay in either engine.

### Provider SDKs

A provider SDK is ordinary JavaScript and loads in a PWA as in a tab. Stripe's Payment Request
Button, which wrapped `PaymentRequest` to show Apple Pay, Google Pay, or Link, is marked
deprecated in Stripe's documentation in favour of the Express Checkout Element. The question an
installed PWA adds is navigation: a redirect-based 3-D Secure or bank flow that leaves the
manifest `scope` runs under the browser's out-of-scope UI (Microsoft documents a URL and
title bar for Store-installed Edge PWAs), so prefer
providers whose authentication runs in a popup or inline frame when you ship a standalone app.

| Layer | Where it works | Precondition |
|---|---|---|
| Payment Request API | Chrome 60 / 53 Android, Edge 15, Safari 11.1, Samsung Internet, WebView 136 | Secure context; transient user activation for `show()` |
| Apple Pay | Safari (macOS, iOS); `SFSafariViewController` | Merchant registration; PSP that supports Apple Pay |
| Google Pay | Chrome, Firefox, Safari, Edge, Opera, UC Browser | HTTPS with TLS domain-validated certificate |
| Provider SDK | Any engine the SDK supports | Provider account; fallback form for unsupported wallets |

## Observed behaviour

:::observed
`PaymentRequest.show()` does not throw; it rejects. MDN documents the names: `NotSupportedError`
"if the user agent does not support the payment methods specified when the `PaymentRequest`
constructor was called", `SecurityError` "if the call to `show()` was not in response to a user
action, such as a `click` or `keyup` event", `AbortError` when the user cancels or a sheet is
already open, and `InvalidStateError` when the same request is shown twice. The same page notes
that Firefox allows more than one active payment request at a time although the specification
forbids it.
:::

## See also

- [Payment Request API](https://www.w3.org/TR/payment-request/) (w3.org)
- [PaymentRequest: show() method](https://developer.mozilla.org/en-US/docs/Web/API/PaymentRequest/show) (developer.mozilla.org)
- [Set up Google Pay API for web](https://developers.google.com/pay/api/web/guides/setup) (developers.google.com)
- [Payment Request API compatibility](/compatibility/payment-request/)
- [Payment Request API reference](/reference/capabilities/payment-request/)
- [Monetization](/ecosystem/monetization/)
- [Digital Goods API](/reference/capabilities/digital-goods/)

← Back to the [Ecosystem](/ecosystem/) overview.