Skip to main content

Google Pay & Apple Pay#

Tuna supports both Google Pay and Apple Pay as first-class payment methods. Buyers get the native wallet experience they expect — biometric authentication, no card entry, and full liability shift to the issuer — while you receive a standard encrypted token that flows into Tuna's Payment/Init just like any other card payment.


VTEX#

Tuna is the only payment connector on VTEX that combines all of the following in a single integration, without redirecting buyers away from the checkout:

FeatureTunaOthers
Real authenticated wallet payments (full liability shift)Some
First-party and third-party devicesPartial
Installments on wallet transactionsRare
Fully embedded — no redirect from checkoutOften redirect

Google Pay is enabled automatically in the Tuna VTEX connector — no additional setup required beyond standard Tuna account configuration.

Apple Pay requires the Tuna VTEX IO app:

vtex install tunabr.tuna-gateway

Follow the standard Tuna VTEX setup to configure your credentials. Tuna handles merchant domain verification and session validation automatically.

Headless & mobile apps on VTEX

Tuna has partnerships with the leading headless and mobile implementors in the VTEX ecosystem. Our wallet features — including authenticated Google Pay and Apple Pay with liability shift and installments — are replicated in frameworks built by Compra Rápida, Trinio, and Kobe. If your storefront is built on one of these platforms, contact your implementor or your Tuna Account Manager to enable wallet payments.


Tuna Checkout#

If you use Tuna Checkout — whether as a hosted payment link or embedded via iframe — both Google Pay and Apple Pay are available out of the box. No additional integration work is needed. Enable them for your account through Tuna Console flow settings.


Direct integration#

For direct integrations the flow is the same for both wallets:

  1. Frontend: Display the wallet button using the native JS API (or tuna.js to simplify).
  2. Frontend: Buyer authenticates with biometrics / Face ID / Touch ID. You receive an encrypted payment token from the wallet.
  3. Backend: Send a NewSession, receive sessionId.
  4. Backend: Call POST /api/Payment/Init with the encrypted token as cardInfo.token and the appropriate tokenProvider.
Postman collection

Full working examples are available in the Wallets → Google Pay and Wallets → Apple Pay folders in the official Postman collection.


Google Pay — direct integration#

Step 1: Set up the Google Pay button#

Follow the Google Pay Web integration guide (or Android guide for apps).

When configuring the tokenization method, use PAYMENT_GATEWAY and set the gateway to tuna:

const tokenizationSpecification = {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'tuna',
gatewayMerchantId: 'YOUR_TUNA_MERCHANT_ID',
},
};
const cardPaymentMethod = {
type: 'CARD',
parameters: {
allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
allowedCardNetworks: ['VISA', 'MASTERCARD', 'AMEX', 'DISCOVER', 'JCB'],
},
tokenizationSpecification,
};

Use ENVIRONMENT_TEST while testing and ENVIRONMENT_PRODUCTION for live payments.

After the buyer approves, extract the token from the Google Pay response:

const paymentDataRequest = { /* your request object */ };
const client = new google.payments.api.PaymentsClient({ environment: 'TEST' });
client.loadPaymentData(paymentDataRequest).then((paymentData) => {
const googlePayToken = paymentData.paymentMethodData.tokenizationData.token;
// googlePayToken is a JSON string — send it to your backend
yourBackend.initPayment({ googlePayToken });
});

Step 2: Call Payment/Init#

Your backend calls POST https://engine.tunagateway.com/api/Payment/Init. Pass the entire token string as received from Google Pay — do not parse it.

{
"TokenSession": "{{sessionid}}",
"partneruniqueid": "ORDER-GPAY-001",
"customer": {
"id": "customer-123",
"name": "Maria Silva",
"email": "maria@example.com",
"document": "744.479.870-23",
"documentType": "CPF"
},
"paymentItems": {
"items": [
{
"amount": 150,
"detailUniqueId": "ITEM-1",
"productDescription": "Product name",
"itemQuantity": 1
}
]
},
"paymentdata": {
"paymentmethods": [
{
"partneruniqueid": "ORDER-GPAY-001",
"paymentmethodtype": "1",
"amount": 150,
"installments": 1,
"cardinfo": {
"TokenProvider": "GooglePay",
"Token": "{\"signature\":\"...\",\"intermediateSigningKey\":{...},\"protocolVersion\":\"ECv2\",\"signedMessage\":\"{...}\"}",
"billinginfo": {
"name": "Maria Silva",
"taxedamount": 150,
"billedamount": 150
},
"savecard": false
}
}
],
"countrycode": "BR",
"amount": 150,
"currency": "BRL"
},
"frontdata": {
"useragent": "Mozilla/5.0 ...",
"IpAddress": "203.0.113.10"
}
}

Key fields:

FieldValue
paymentmethodtype"1" (card)
cardinfo.TokenProvider"GooglePay"
cardinfo.TokenThe full JSON string from paymentData.paymentMethodData.tokenizationData.token

Installments with Google Pay#

To offer installments, increment installments in the payment method. The buyer sees the Google Pay sheet with the total amount; your backend splits it by sending the installment count to Tuna:

"paymentmethodtype": "1",
"amount": 300,
"installments": 3

Apple Pay — direct integration#

Requirements#

  • An Apple Developer account with Apple Pay enabled
  • A merchant identifier (e.g. merchant.com.yourcompany.store)
  • Your domain verified with Apple (a file hosted at /.well-known/apple-developer-merchantid-domain-association)
  • HTTPS on your domain
Apple Pay domain verification

Tuna handles merchant session validation on its end. You only need to register your domain and merchant identifier in Apple Pay console. Contact your Account Manager for Tuna's payment processing certificate configuration.

Step 1: Start the Apple Pay session#

Follow the Apple Pay on the Web documentation. Check for Apple Pay availability and create a session:

if (!window.ApplePaySession || !ApplePaySession.canMakePayments()) {
// Hide Apple Pay button
return;
}
const request = {
countryCode: 'BR',
currencyCode: 'BRL',
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
merchantCapabilities: ['supports3DS'],
total: {
label: 'Your Store',
amount: '150.00',
},
};
const session = new ApplePaySession(6, request);
session.onvalidatemerchant = async (event) => {
// Your backend calls Apple's merchant validation URL and returns the session object
const merchantSession = await yourBackend.validateApplePayMerchant(
event.validationURL
);
session.completeMerchantValidation(merchantSession);
};
session.onpaymentauthorized = (event) => {
const applePayToken = JSON.stringify(event.payment.token.paymentData);
// Send to your backend
yourBackend.initPayment({ applePayToken })
.then((result) => {
const statusCode = result.success
? ApplePaySession.STATUS_SUCCESS
: ApplePaySession.STATUS_FAILURE;
session.completePayment(statusCode);
});
};
session.begin();

Step 2: Call Payment/Init#

Pass the serialized payment.token.paymentData as Token with TokenProvider: "ApplePay":

{
"TokenSession": "{{sessionid}}",
"partneruniqueid": "ORDER-APAY-001",
"customer": {
"id": "customer-123",
"name": "Maria Silva",
"email": "maria@example.com",
"document": "744.479.870-23",
"documentType": "CPF"
},
"paymentItems": {
"items": [
{
"amount": 150,
"detailUniqueId": "ITEM-1",
"productDescription": "Product name",
"itemQuantity": 1
}
]
},
"paymentdata": {
"paymentmethods": [
{
"partneruniqueid": "ORDER-APAY-001",
"paymentmethodtype": "1",
"amount": 150,
"installments": 1,
"cardinfo": {
"TokenProvider": "ApplePay",
"Token": "{\"data\":\"...\",\"signature\":\"...\",\"header\":{\"publicKeyHash\":\"...\",\"ephemeralPublicKey\":\"...\",\"transactionId\":\"...\"},\"version\":\"EC_v1\"}",
"billinginfo": {
"name": "Maria Silva",
"taxedamount": 150,
"billedamount": 150
},
"savecard": false
}
}
],
"countrycode": "BR",
"amount": 150,
"currency": "BRL"
},
"frontdata": {
"useragent": "Mozilla/5.0 ...",
"IpAddress": "203.0.113.10"
}
}

Key fields:

FieldValue
paymentmethodtype"1" (card)
cardinfo.TokenProvider"ApplePay"
cardinfo.TokenJSON.stringify(event.payment.token.paymentData) from the Apple Pay session

Installments with Apple Pay#

Same as Google Pay — set installments in the payment method. Display the installment choice in your checkout UI before the buyer hits the Apple Pay button, then pass the selected value to Payment/Init.


Using tuna.js#

tuna.js provides ready-made methods that handle the wallet JS lifecycle for you, including button rendering, session management, and the callback with the token data. This is the fastest path to an opinionated but working integration.

Google Pay via tuna.js#

Include the full tuna.js build (not just essentials):

<script src="https://storage.googleapis.com/tuna-statics/tuna-v2.js"></script>

Then call useGooglePay:

tuna.useGooglePay({
googlePayButtonContainerSelector: '#google-pay-button',
merchantInfo: {
merchantName: 'Your Store Name',
merchantId: 'YOUR_GOOGLE_MERCHANT_ID', // required for PRODUCTION
},
transactionInfo: {
totalPriceStatus: 'FINAL',
totalPrice: '150.00',
currencyCode: 'BRL',
},
checkoutCallbackFunction: async (checkoutData) => {
// checkoutData contains the tokenized card data ready for Payment/Init
const result = await yourBackend.initPayment(checkoutData);
return result;
},
});

See the full useGooglePay parameter reference in the tuna.js docs.

Apple Pay via tuna.js#

const applePayReady = await tuna.useApplePay({
buttom: {
selector: '#apple-pay-button',
style: { width: '200px', height: '44px', borderRadius: '8px' },
},
merchantId: 'merchant.com.yourcompany.store',
cart: {
lineItems: [{ label: 'Product', amount: '150.00' }],
total: { label: 'Your Store', amount: '150.00' },
},
applePayCallback: async (paymentData) => {
// paymentData is the token data ready for Payment/Init
const result = await yourBackend.initPayment(paymentData);
return result.success; // must return bool
},
});
if (!applePayReady) {
document.getElementById('apple-pay-button').style.display = 'none';
}

See the full useApplePay parameter reference in the tuna.js docs.


Quick comparison#

Google PayApple Pay
PlatformsWeb, AndroidSafari (macOS/iOS), iOS apps
Device requirementAny Android or ChromeApple device or Safari with Secure Enclave
VTEX setupAutomatictunabr.tuna-gateway app
TokenProvider value"GooglePay""ApplePay"
Token sourcepaymentData.paymentMethodData.tokenizationData.tokenJSON.stringify(payment.token.paymentData)
Installments
Liability shift

Related references#