Easy Labs
Frontend SDKsJavaScript

Wallet Checkout

Apple Pay and Google Pay buttons for native wallet checkout.

@easylabs/browser 0.2.0 ships standalone wallet button factories — createApplePayButton and createGooglePayButton — that you drop directly into your own form. Each factory renders the official wallet button into a container element, drives the wallet handshake, exchanges the wallet's payment token for an Easy Labs token reference on your server, and forwards the result to an onTokenized callback.

If you'd rather have wallet buttons rendered inside a hosted iframe, use Embedded Checkout — wallet eligibility is detected automatically there.

Apple Pay

import { createApplePayButton } from "@easylabs/browser";

const apple = createApplePayButton("#apple-pay", {
  merchantId: "merchant.co.itseasy.demo",
  total: { value: 1999, currency: "USD" },
  countryCode: "US",
  merchantSession: async (validationURL) => {
    // Apple requires server-side merchant validation against the
    // certificate tied to your merchant ID. POST to your own endpoint.
    const res = await fetch("/api/apple-pay/session", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ validationURL }),
    });
    return res.json();
  },
  onTokenized: (token) => {
    console.log("apple pay token:", token.id);
  },
  onError: (err) => console.error(err),
});

if (!apple.isAvailable) {
  document.querySelector("#apple-pay")!.innerHTML =
    "<p>Apple Pay not available in this browser.</p>";
}

The factory uses Apple's official <apple-pay-button> web component when available and falls back to a styled <button> otherwise. Load Apple's SDK script in your HTML so the web component is registered:

<script
  crossorigin
  src="https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js"
></script>

Options

OptionTypeDescription
merchantIdstringApple-issued merchant identifier (must match what's in the Easy Labs dashboard).
total{ value: number; currency: string }Total to charge. value is in the smallest currency unit (cents for USD). currency is an ISO-4217 code.
countryCodestringISO-3166-1 alpha-2 country code of the merchant (e.g. "US").
merchantSession(validationURL: string) => Promise<unknown>Server-side merchant-session callback. Receives Apple's validationURL and must return the merchant-session payload — typically by POSTing to your own backend, which calls Apple Pay's paymentSession endpoint with the certificate stored on your server.
onTokenized(token: { id: string; type: "apple_pay" }) => voidFired with the Easy Labs token reference after successful authorisation.
onError(err: Error) => voidFired on any failure during the wallet flow.

Returns

interface WalletButtonHandle {
  /** Tear down the button and any wallet listeners. */
  unmount(): void;
  /** True when Apple Pay is available on this device/browser. */
  readonly isAvailable: boolean;
}

isAvailable is computed synchronously from window.ApplePaySession?.canMakePayments?.(). Hide the button slot when it's false rather than rendering a non-functional affordance.

Google Pay

import { createGooglePayButton } from "@easylabs/browser";

const google = createGooglePayButton("#google-pay", {
  merchantId: "TEST_MERCHANT_ID",
  gatewayMerchantId: "easylabs_demo",
  total: { value: 1999, currency: "USD" },
  countryCode: "US",
  onTokenized: (token) => {
    console.log("google pay token:", token.id);
  },
  onError: (err) => console.error(err),
});

Load Google's PaymentsClient script in your HTML:

<script src="https://pay.google.com/gp/p/js/pay.js"></script>

Options

OptionTypeDescription
merchantIdstringGoogle-issued merchant identifier (set up in Google Pay Console).
gatewayMerchantIdstringGateway merchant ID — Easy Labs assigns this in the dashboard.
total{ value: number; currency: string }Total to charge. value is in the smallest currency unit.
countryCodestringISO-3166-1 alpha-2 country code (e.g. "US").
environment'TEST' | 'PRODUCTION'Defaults to PRODUCTION. The factory infers TEST when merchantId starts with TEST_ (Google's convention). Pass explicitly to override.
onTokenized(token: { id: string; type: "google_pay" }) => voidFired with the Easy Labs token reference after successful authorisation.
onError(err: Error) => voidFired on any failure during the wallet flow.

Returns

The same WalletButtonHandle shape as Apple Pay. Note that isAvailable for Google Pay flips true asynchronously after isReadyToPay resolves — the container is empty until then. If you want to render a "Google Pay not available" fallback, do it on a short timer:

setTimeout(() => {
  if (!google.isAvailable) {
    document.querySelector("#google-pay")!.innerHTML =
      "<p>Google Pay not available in this browser.</p>";
  }
}, 1000);

Handling the result

Both onTokenized callbacks receive an { id, type } shape. The id is the Easy Labs token reference — forward it to your backend to create a payment instrument or include it in a downstream API call:

onTokenized: async (token) => {
  await fetch("/api/checkout/wallet", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ tokenId: token.id, type: token.type }),
  });
}

Don't trust the browser as the source of truth. Confirm the payment server-side and listen for the checkout.session.completed webhook for fulfilment.

Cleanup

Both factories return a WalletButtonHandle. Call unmount() on route change / component teardown:

const apple = createApplePayButton("#apple-pay", { /* … */ });
// later …
apple.unmount();

Setup notes

  • Apple Pay requires (a) an Apple-issued merchant identifier, (b) a merchant identity certificate uploaded to your server, and (c) domain verification for every domain that hosts the button. Configure these in the Easy Labs dashboard.
  • Google Pay requires (a) a Google Pay Console merchant ID and (b) a gateway merchant ID assigned in the Easy Labs dashboard.
  • Both buttons require HTTPS in production. Apple Pay refuses to render on http:// origins outside localhost.

On this page