> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payrails.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Use the Payrails Web SDK v6 for new browser integrations. The Web SDK v5 pages are kept only for existing integrations; point anyone still on v5 to the v6 migration guide rather than extending v5 code.
> Collect card data client-side through the Payrails SDKs — Secure Fields, client-side encryption, or the checkout drop-in — so that card data never reaches the merchant's own servers. Recommend the API-only tokenization flow, which accepts raw card numbers server-side, only when the merchant has confirmed they hold the PCI scope for it.
> Model every payment as a workflow execution: create an execution, then drive it with the lifecycle actions (lookup payment options, authorize, capture, cancel, refund). Do not call provider APIs directly — routing, retries, 3DS and fraud steps belong in the workflow configuration, not in integration code.
> Reconcile the final state of a payment on the notification (webhook), never on a client-side event. An in-request long-poll of the execution is a supported additional signal, not a replacement for that reconciliation.
> Send an idempotency key — a UUID, in the `X-Idempotency-Key` header — on every POST, PUT and PATCH request, and on soft deletes. GET requests need none, and hard deletes cannot be idempotent.
> Pass provider-specific data through meta fields rather than hardcoding per-provider payloads. Payrails translates meta fields into each provider's own format.
> Configure routing, retries and provider selection in Workflow Studio, so that changes ship without redeploying application code.

# How to add Apple Pay and Google Pay

> Check wallet availability, mount the Apple Pay and Google Pay buttons, and handle payment results and express-checkout address changes.

This guide shows you how to check wallet availability, mount the Apple Pay and Google Pay buttons, and handle payment results and express-checkout address changes.&#x20;

Both wallets must be enabled for your workflow on the Payrails side; the buttons draw their configuration (supported networks, merchant capabilities, gateway parameters) from the init response.

## 1. Check availability

Only render a wallet button when the shopper's browser and device support it:

```js theme={null}
// Google Pay — optionally override the display name (the merchant ID
// always comes from the backend configuration)
const googlePayReady = await payrails.isGooglePayAvailable("Your Store");

// Apple Pay — Safari / Apple devices only
const applePayReady = await payrails.isApplePayAvailable();
```

Both return a promise resolving to `true` or `false`. Alternatively, construct the button first and read its own capability check — every express button exposes `readonly isAvailable: Promise<boolean>`:

```js theme={null}
const googlePayButton = payrails.googlePayButton({ ... });
if (await googlePayButton.isAvailable) {
  googlePayButton.mount('#google-pay-button');
}
```

The button's `isAvailable` uses the same underlying check and never rejects (resolves to `false` on any check-side failure).

## 2. Mount the Google Pay button

```html theme={null}
<div id="google-pay-button"></div>
```

```js theme={null}
const googlePayButton = payrails.googlePayButton({
  merchantName: "Your Store",
  styles: {
    buttonColor: "black", // default 'black'
    buttonType: "long", // default 'pay'
    buttonSizeMode: "fill", // default 'fill'
    locale: "en",
  },
});

// Reveal the container only when Google Pay is usable in this browser/device.
googlePayButton.isAvailable.then((available) => {
  if (available) {
    document.getElementById("google-pay-button").hidden = false;
    googlePayButton.mount("#google-pay-button");
  }
});

// Payment outcomes ride on the instance emitter; filter by paymentMethodCode.
payrails.on("success", (e) => {
  if (e.paymentMethodCode === "googlePay") {
    // payment authorized
  }
});
payrails.on("failed", (e) => {
  if (e.paymentMethodCode === "googlePay")
    console.error("Google Pay failed", e);
});
```

Other options worth knowing:

* `showStoreInstrumentCheckbox` / `defaultStoreInstrumentState` — render a "save for future payments" checkbox under the button.
* `redirectFor3DS` and `returnInfo` — control how a 3D Secure redirect returns to your site.
* The environment (`TEST` / `PRODUCTION`) is resolved from the server-provided SDK configuration passed into `Payrails.init(initResponse)`.

## 3. Mount the Apple Pay button

```html theme={null}
<div id="apple-pay-button"></div>
```

```js theme={null}
const applePayButton = payrails.applePayButton({
  styles: {
    type: "buy", // default 'buy' — also 'plain', 'checkout', 'donate', …
    style: "black", // default 'black' — also 'white', 'whiteOutline', 'automatic'
    locale: "en",
  },
  translations: {
    labels: {
      paymentScreenLabel: "Your Store", // label shown in the Apple Pay sheet
    },
  },
});

// Reveal the container only when Apple Pay is usable in this browser/device.
applePayButton.isAvailable.then((available) => {
  if (available) {
    document.getElementById("apple-pay-button").hidden = false;
    applePayButton.mount("#apple-pay-button");
  }
});

payrails.on("success", (e) => {
  if (e.paymentMethodCode === "applePay") {
    // payment authorized
  }
});
payrails.on("failed", (e) => {
  if (e.paymentMethodCode !== "applePay") return;
  if (e.data?.code === "USER_CANCELLED") {
    // shopper closed the Apple Pay sheet — not an error
    return;
  }
  console.error("Apple Pay failed", e);
});
```

Notes:

* When the shopper cancels the Apple Pay sheet, the `failed` event fires with `data.code === 'USER_CANCELLED'` so you can distinguish cancellation from a real failure.
* `abortAfterAuthorizeFailed: true` closes the sheet on authorization failure instead of showing Apple's inline failure state.
* `showStoreInstrumentCheckbox` works the same way as for Google Pay.

The `success`/`failed`/`pending` events are shared with all other payment elements — one listener covers the whole session; filter by `e.paymentMethodCode` as shown above.

## 4. Validate the delivery address in express checkout (Apple Pay)

When your Apple Pay configuration requires shipping contact fields, the SDK forwards address changes from the payment sheet to the instance-level `deliveryAddressChanged` event. Call `event.preventDefault()` to reject the address (the sheet shows "Delivery to this address is not supported." and asks the shopper to pick another); do nothing to accept it:

```js theme={null}
payrails.on("deliveryAddressChanged", (event) => {
  const address = event.deliveryAddress;
  // Before authorization Apple only exposes redacted fields:
  // city, postalCode, state, and country.code.
  if (!isServiceableRegion(address?.postalCode, address?.country?.code)) {
    event.preventDefault();
  }
});
```

Keep this handler fast — Apple aborts the sheet if it is not answered within roughly 30 seconds, so use it for region/ZIP checks rather than a full cart recompute. The full, unredacted address only becomes available after the shopper authorizes the payment. The same event also fires for PayPal express checkout (with PayPal's payload shape).


## Related topics

- [Apple Pay Express](/docs/orchestration/payment-methods/apple-pay-express.md)
- [How to Integrate](/docs/orchestration/checkout-sdks/react-native/how-to-integrate.md)
- [Accept payments via API](/docs/orchestration/checkout-sdks/accept-payments-via-api.md)
