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
| Option | Type | Description |
|---|---|---|
merchantId | string | Apple-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. |
countryCode | string | ISO-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" }) => void | Fired with the Easy Labs token reference after successful authorisation. |
onError | (err: Error) => void | Fired 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
| Option | Type | Description |
|---|---|---|
merchantId | string | Google-issued merchant identifier (set up in Google Pay Console). |
gatewayMerchantId | string | Gateway merchant ID — Easy Labs assigns this in the dashboard. |
total | { value: number; currency: string } | Total to charge. value is in the smallest currency unit. |
countryCode | string | ISO-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" }) => void | Fired with the Easy Labs token reference after successful authorisation. |
onError | (err: Error) => void | Fired 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 outsidelocalhost.