# Go-live checklist

> Verify your Google Pay integration before accepting live payments on VINR.

Work through this checklist before switching your integration to the `PRODUCTION` environment. Each section covers a distinct failure mode — missing any item is a common reason for Google to reject a merchant registration or for live payments to silently fail.

## 1. Account and registration

#### Google Pay enabled in Dashboard

In **Settings → Payment methods**, confirm Google Pay is toggled on for your VINR account. This must be done before Google Pay tokens will be accepted in production.

#### Google merchant registration complete

Register your integration in the [Google Pay & Wallet Console](https://pay.google.com/business/console):

- Integration type: **Gateway**
- Gateway: `vinr`
- Gateway merchant ID: your VINR merchant ID (from **Settings → Account**)

Wait for Google's approval email — typically 1–2 business days. You cannot accept live payments until this is approved.

#### Merchant IDs populated in your integration

Confirm both IDs are set correctly in your `paymentDataRequest`:

- `merchantInfo.merchantId` — your **Google merchant ID** from the Google Pay & Wallet Console
- `tokenizationSpecification.parameters.gatewayMerchantId` — your **VINR merchant ID**

Mixing these up is the most common cause of `invalid_token` errors in production.

## 2. Authentication methods and card networks

#### allowedAuthMethods confirmed with VINR

Check with your VINR account manager which authentication methods are enabled for your account — `CRYPTOGRAM_3DS`, `PAN_ONLY`, or both. Your integration's `allowedAuthMethods` array must match exactly. A mismatch causes a runtime error when the payment sheet loads.

See [Authentication methods](/docs/payments/payment-methods/add-payment-methods/wallets/google-pay/authentication-methods) for what each method means and the implications of each configuration.

#### allowedCardNetworks confirmed with VINR

Verify that `allowedCardNetworks` in your `paymentDataRequest` lists only the networks enabled on your VINR account. Remove any network your account does not support — specifying an unsupported network can cause token decryption failures.

## 3. Environment switch

#### PaymentsClient set to PRODUCTION

For direct API integrations, update the `PaymentsClient` constructor:

```javascript
const googlePayClient = new google.payments.api.PaymentsClient({
  environment: 'PRODUCTION',
});
```

For Elements and hosted checkout, no code change is needed — switch to your production publishable key and VINR handles the environment automatically.

## 4. Button and brand compliance

#### Button rendered via approved API or element

The Google Pay button must be rendered using `googlePayClient.createButton()` or the VINR `GooglePayElement`. Do not create a custom button, image, or HTML substitute — this will fail Google's integration review.

#### Button only shown when isReadyToPay returns true

The button must be hidden (not disabled) when `isReadyToPay()` returns false. Displaying the button unconditionally and letting it fail silently is a brand guideline violation.

#### Button receives visual parity with other payment methods

Google's guidelines require the Google Pay button to receive equal or greater visual prominence compared to other third-party payment methods. It must not be smaller, positioned below the fold, or styled to appear secondary. See [Button guidelines](/docs/payments/payment-methods/add-payment-methods/wallets/google-pay/button-guidelines).

#### Button color matches the background

Use the black button on light backgrounds and the white button on dark backgrounds. The white button requires a visible border — do not render it without a border on a white background.

## 5. Checkout experience

#### loadPaymentData called synchronously in the click handler

Call `loadPaymentData()` directly inside the button's click handler — not after an `await` or inside a `.then()`. Deferring the call breaks user-activation and causes pop-up blockers to intercept the payment sheet in most browsers.

```javascript
// Correct — synchronous call in click handler
onClick: () => googlePayClient.loadPaymentData(paymentDataRequest)
  .then(handlePayment)
  .catch(handleError)

// Wrong — deferred call after an await breaks user-activation
onClick: async () => {
  const price = await fetchLatestPrice();
  googlePayClient.loadPaymentData(...); // blocked by pop-up blocker
}
```

#### Final price confirmed before processing

The customer must see the final order total before the payment is submitted. If the amount changes based on data returned from the Google Pay sheet (for example, shipping cost derived from the shipping address), show a confirmation step with the final price before calling your server-side payment creation endpoint.

#### PAN\_ONLY requires\_action handled

PAN\_ONLY transactions will enter `requires_action` when VINR's 3DS step-up triggers. Confirm your integration handles this state:

- **Elements and hosted checkout** — handled automatically; no code needed.
- **Direct API integration** — handle `requires_action` exactly as you would for any 3DS-challenged card payment. See [Strong Customer Authentication](/docs/payments/strong-customer-authentication).

## 6. Error handling

#### Customer cancellation handled silently

When the customer dismisses the sheet, the Promise rejects with `statusCode: 'CANCELED'`. Catch this and handle it silently — do not show an error message for a cancellation.

```javascript
googlePayClient.loadPaymentData(paymentDataRequest)
  .then(handlePayment)
  .catch(err => {
    if (err.statusCode !== 'CANCELED') {
      showError(err.message || 'Payment failed');
    }
    // CANCELED: do nothing — let the customer retry or choose another method
  });
```

#### Declines surface a clear message with retry option

When a payment is declined, display the decline reason clearly and offer the customer a way to retry or choose a different payment method. Do not leave the checkout in a broken or unresponsive state after a decline.

## 7. Webhook confirmation

#### Fulfillment triggered by webhook, not client-side redirect

Order fulfillment — sending a confirmation email, provisioning access, shipping goods — must be triggered by the `payment.completed` webhook received on your server, not by the client-side redirect. The customer's browser may close before the redirect fires.

Confirm your webhook endpoint is live, reachable from the internet, and correctly verifying the VINR signature before going live.

## 8. Dynamic checkout updates (if applicable)

If your integration uses `paymentDataCallbacks` to update the order total or shipping options in real time:

#### callbackIntents matches your callback implementations

Every intent listed in `callbackIntents` must have a corresponding handler in `paymentDataCallbacks`. Declaring an intent without a handler causes the payment sheet to stall indefinitely.

#### All callbacks resolve promptly

Google Pay waits for each callback to resolve before updating the sheet. A callback that never returns — due to an unhandled rejection or a hanging network request — will freeze the payment sheet for the customer. Add timeouts to any network calls made inside callbacks.

## See also

[Authentication methods](/docs/payments/payment-methods/add-payment-methods/wallets/google-pay/authentication-methods) — Confirm which auth methods are enabled for your account and what each means.

[Button guidelines](/docs/payments/payment-methods/add-payment-methods/wallets/google-pay/button-guidelines) — Google-compliant button styles, types, sizing, and what not to do.

[Test & go live](/docs/payments/payment-methods/add-payment-methods/wallets/google-pay/test-and-go-live) — Test both credential types in the sandbox before switching to production.
