Google Pay iFrame
Note
Google Pay is currently a closed Beta feature and does not support CAD at this time.
Pre-Requisites
- Access to our permissioned Google Pay feature
- Legal Entity ID (other than your app's) -- required to create an Account
- Account ID (other than your app's) -- required to create a Payment in the last step of this article
We support the use of Google Pay on your platform. Using Google Pay allows your merchants to simplify the checkout flow, making checkouts faster and improving the conversion performance of your platform. Google Pay payment method tokens are encrypted by Google and decrypted by us, protecting payment information even in the event of a compromised application. Follow this guide to learn how to integrate Google Pay for your merchants.
The sequence diagram below describes the happy path flow of our Google Pay iFrame.
Embed The Google Pay iFrame
Step 1: Generate a Google Pay token via our iFrame
Note that this sample is intended to:
- Showcase the configurable options available on our Google Pay iFrame
- Make the fields in a Google Pay response easily available for testing
Feel free to copy and paste this code into your own project once your app is enabled for Google Pay, or just take the following components:
<div id="google_pay_iframe"></div>
in your payer-facing HTML<script src="https://cdn.wepay.com/wepay.min.js"></script>
in your payer-facing HTML head- The entire JS
#shipping-address {
display: none;
}
#complete-screen {
display: none;
}
<body>
<div class="container">
<ul class="collapsible popout">
<li>
<div class="collapsible-header"><i class="material-icons">shopping_cart</i>Order</div>
<div class="collapsible-body" id="order-body">
<div class="container">
<div class="row">
<img class="responsive-img col m6 materialboxed"
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1671/mop.png" alt="Primo Mop" />
<div class="col m5">
<div class="card-panel blue-grey">
<div class="card-content white-text">
<span class="card-title">Primo Mop</span>
<p>Quantity: 20<br>Price: $15.00 USD</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="card-panel blue-grey">
<div class="card-content white-text center">
<p>Subtotal: 300.00 USD<br>Shipping: $7.50 USD<br>Fees: $2.50 USD</p>
<span class="card-title">Total: $310.00 USD</span>
</div>
</div>
</div>
</div>
</div>
</li>
<li class="active">
<div class="collapsible-header"><i class="material-icons">place</i>Address</div>
<div class="collapsible-body row" id="address-body">
<div class="row">
<div class="col s12">
<div class="card blue-grey">
<div class="card-content white-text">
<span class="card-title">Billing Address</span>
<p>Enter the address associated with your card.</p>
</div>
</div>
</div>
</div>
<div class="container">
<form class="col s12">
<div class="row">
<div class="input-field col s6">
<input placeholder="first name" id="first_name" type="text" class="validate">
<label for="first_name">first name</label>
</div>
<div class="input-field col s6">
<input placeholder="last name" id="last_name" type="text" class="validate">
<label for="last_name">last name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="email" id="email" type="text" class="validate">
<label for="email">email</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input placeholder="street address" id="street_address" type="text" class="validate">
<label for="street_address">street address</label>
</div>
<div class="input-field col s6">
<input placeholder="suite / apt." id="suite" type="text" class="validate">
<label for="suite">suite / apt.</label>
</div>
</div>
<div class="row">
<div class="input-field col s4">
<input placeholder="city" id="city" type="text" class="validate">
<label for="city">city</label>
</div>
<div class="input-field col s4">
<input placeholder="state" id="state" type="text" class="validate">
<label for="state">state</label>
</div>
<div class="input-field col s4">
<input placeholder="zip" id="zip" type="text" class="validate">
<label for="zip">zip</label>
</div>
</div>
</form>
<form action="#">
<p>
<label>
<input type="checkbox" id="same" onclick="showMe('shipping-input')" />
<span>Different from shipping address?</span>
</label>
</p>
</form>
</div>
<form class="col s12" id="shipping-address">
<div class="row">
<div class="col s12">
<div class="card blue-grey">
<div class="card-content white-text">
<span class="card-title">Shipping Address</span>
<p>Enter the address where your order will be shipped.</p>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="input-field col s6">
<input placeholder="first name" id="first_name" type="text" class="validate">
<label for="first_name">first name</label>
</div>
<div class="input-field col s6">
<input placeholder="last name" id="last_name" type="text" class="validate">
<label for="last_name">last name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="email" id="email" type="text" class="validate">
<label for="email">email</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input placeholder="street address" id="street_address" type="text" class="validate">
<label for="street_address">street address</label>
</div>
<div class="input-field col s6">
<input placeholder="suite / apt." id="suite" type="text" class="validate">
<label for="suite">suite / apt.</label>
</div>
</div>
<div class="row">
<div class="input-field col s4">
<input placeholder="city" id="city" type="text" class="validate">
<label for="city">city</label>
</div>
<div class="input-field col s4">
<input placeholder="state" id="state" type="text" class="validate">
<label for="state">state</label>
</div>
<div class="input-field col s4">
<input placeholder="zip" id="zip" type="text" class="validate">
<label for="zip">zip</label>
</div>
</div>
</form>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action"
onclick="closeAddress(); openSubmit();">Next
<i class="material-icons right">send</i>
</button>
</div>
</li>
<li id="checkout">
<div class="collapsible-header"><i class="material-icons">credit_card</i>Submit</div>
<div class="collapsible-body" id="submit">
<span>
<div class="container">
<div class="row">
<img class="responsive-img" id="accepted-cards"
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1671/card-brands.png" border="0"
alt="Accepted Cards" />
</div>
<div class="row">
<div id="google_pay_iframe"></div>
</div>
<div class="row">
<div class="card blue-grey lighten-2">
<div class="card-content white-text">
<p>By clicking submit, you agree to Mop Emporium's <a href="#">refund, cancellation, and return</a>
policy.<br>Orders will be shipped in 2-3 business days, at which time tracking information will be
provided in a confirmation email.</p>
</div>
</div>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action" id="submit-credit-card-button">Submit
<i class="material-icons right">send</i>
</button>
<div id="token"></div>
</div>
</span>
</div>
</li>
</ul>
<div class="row">
<div id="tokenBank"></div>
</div>
<div class="row">
<div id="complete-screen" class="row">
<div class="col s12 m12">
<div class="card blue-grey darken-1">
<div class="card-content white-text">
<span class="card-title">Your order is complete!</span>
<p>We're working on getting your order ready to ship. Once it does, you can log in and track it
here.<br><br><br><br><br></p>
</div>
<div class="card-action">
<a href="#">Track your order</a>
<a href="#">Help</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.wepay.com/wepay.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</body>
//The test app ID for GooglePay has been added here
var appId = "690619";
var myAppId = appId;
var apiVersion = "3.0";
var error = WePay.configure("stage", myAppId, apiVersion);
if (error) {
console.log(error);
}
const google_pay_configs = {
button_configs: {
// "default" | "black" | "white"
buttonColor: 'black',
// "book" | "buy" | "checkout" | "donate" | "order" | "pay" | "plain" | "subscribe" | "long" | "short"
buttonType: 'checkout',
// "en" | "ar" | "bg" | "ca" | "cs" | "da" | "de" | "el" | "es" | "et" | "fi" |
// "fr" | "hr" | "id" | "it" | "ja" | "ko" | "ms" | "nl" | "no" | "pl" |
// "pt" | "ru" | "sk" | "sl" | "sr" | "sv" | "th" | "tr" | "uk" | "zh"
buttonLocale: 'en',
// "static" | "fill"
buttonSizeMode: 'fill',
// any string
className: undefined,
// jsx style css
style: {
width: "100%",
height: "100%",
},
paymentRequest: {
merchantInfo: {
merchantName: 'Mop City'
},
// boolean
emailRequired: true,
/**
* if required, shipping address must be specified
* shippingAddressParameters:
* {
* allowedCountryCodes: string[]
* phoneNumberRequired?: boolean
* }
*/
shippingAddressRequired: true,
shippingAddressParameters: {
allowedCountryCodes: ['US', 'CA', 'AU'],
phoneNumberRequired: true,
},
allowedPaymentMethods: {
// 'MASTERCARD' | 'VISA' | 'AMEX' | 'DISCOVER' | 'JCB'
allowedCardNetworks: ['VISA', 'MASTERCARD', 'AMEX', 'DISCOVER', 'JCB'],
// boolean
billingAddressRequired: true,
},
transactionInfo: {
// "NOT_CURRENTLY_KNOWN" | "ESTIMATED" | "FINAL"
totalPriceStatus: 'FINAL',
// any string
totalPriceLabel: 'Total',
// '4.0'
totalPrice: '310.0',
// USD / CAD etc.
currencyCode: 'USD',
// US / CA etc.
countryCode: 'US',
// "DEFAULT" | "COMPLETE_IMMEDIATE_PURCHASE"
checkoutOption: 'DEFAULT',
/**
* DisplayItemType: "LINE_ITEM" | "SUBTOTAL" | "TAX" | "DISCOUNT" | "SHIPPING_OPTION"
* DisplayItemStatus: "FINAL" | "PENDING"
*
* displayItems: [{ label: string, type: DisplayItemType, price: string, status?; DisplayItemStatus }]
*/
displayItems: [
{ label: '20x Primo Mop', type: 'LINE_ITEM', price: '15.00' },
{ label: "Subtotal", type: 'SUBTOTAL', price: '300.00' },
{ label: "Shipping", type: 'LINE_ITEM', price: '0' },
{ label: "Fees", type: 'TAX', price: '2.50' },
]
},
offerInfo: {
// [{ redemptionCode: string, description: string }]
offers: [{ redemptionCode: 'BIGSPENDER', description: "10% Off Orders of $100 or more" }]
},
/**
* if required, shipping options must be specified
* shippingOptionParameters:
* {
* shippingOptions: [{ id: string, label: string, description?: string}]
* defaultSelectedOptionId: string
* }
*/
shippingOptionRequired: true,
shippingOptionParameters: {
shippingOptions: [
{ id: 'ground', label: 'Ground', description: '7 - 250 Business Days - FREE' },
{ id: 'priority', label: 'Priority', description: '7 - 25 Business Days - $15.99' },
{ id: 'nextday', label: 'Next Day', description: '1 Business Day - $399.99' },
],
defaultSelectedOptionId: 'ground',
},
},
},
on_success: function (data) {
document.getElementById('token').innerHTML = JSON.stringify(data);
},
on_error: function (error) {
document.getElementById('token').innerHTML = JSON.stringify(error);
},
/**
* input:
* intermediatePaymentData {
* // INITIALIZE is sent when the payment window is opened, the rest are
* // when the cardholder selects one of the relevant options
* callbackTrigger: "INITIALIZE" | "SHIPPING_ADDRESS" | "SHIPPING_OPTION" | "OFFER"
* offerData?: {
* redemptionCodes: string[],
* },
* shippingAddress?: {
* administrativeArea: string // "CA"
* countryCode: string // "US"
* locality: string // "Mountain View"
* postalCode: string // "94043"
* },
* shippingOptionData?: {
* id: string // the id of the selected shipping option
* }
*
* returns
* newPaymentData {
* newTransactionInfo?: {
* currencyCode: string
* countryCode?: string
* totalPrice: string
* totalPriceLabel?: string
* totalPriceStatus: "NOT_CURRENTLY_KNOWN" | "ESTIMATED" | "FINAL"
* transactionNote?: string
* checkoutOption?: "DEFAULT" | "COMPLETE_IMMEDIATE_PURCHASE"
* displayItems?: {
* label: string
* type: "LINE_ITEM" | "SUBTOTAL" | "TAX" | "DISCOUNT" | "SHIPPING_OPTION"
* price: string
* status?: "FINAL" | "PENDING"
* }
* },
* newShippingOptionParameters?: {
* shippingOptions: [{ id: string, label: string, description?: string}]
* defaultSelectedOptionId?: string
* },
* newOfferInfo?: {
* offers: [{ redemptionCode: string, description: string }]
* },
* error?: {
* reason: "SHIPPING_ADDRESS_INVALID" | "SHIPPING_ADDRESS_UNSERVICEABLE" | "SHIPPING_OPTION_INVALID" | "OFFER_INVALID" | "PAYMENT_DATA_INVALID" | "OTHER_ERROR"
* intent: // same as callbackIntent - "OFFER" | "SHIPPING_ADDRESS" | "SHIPPING_OPTION" | "PAYMENT_AUTHORIZATION" | "PAYMENT_METHOD"
* message: string
* }
* }
* }
*/
on_update_payment_data: function (intermediatePaymentData) {
return getNewPaymentMethodData(intermediatePaymentData);
}
};
const OFFERS = {
SPRING25: {
label: "25% Off Order",
value: .25,
},
BIGSPENDER: {
label: "10% Off Orders of $100 or more",
value: .1,
}
};
const SHIPPING_COSTS = {
CA: {
ground: 12.99,
priority: 29.99,
nextday: 1199.99,
},
US: {
ground: 0,
priority: 15.99,
nextday: 399.99,
}
};
const TAX_RATES = {
CA: .12,
US: .0925,
};
const CURRENCY_CODES = {
CA: 'CAD',
US: 'USD',
};
const getNewPaymentMethodData = (intermediatePaymentData) => {
const country = intermediatePaymentData?.shippingAddress?.countryCode;
const shippingOption = intermediatePaymentData?.shippingOptionData?.id;
const offers = intermediatePaymentData?.offerData?.redemptionCodes;
const error = getErrors(country, offers);
if (error) {
return error;
}
return {
...getNewTransactionInfo(offers, shippingOption, country),
...getNewShippingOptionParameters(country, shippingOption),
...getNewOfferInfo(offers),
};
};
const getErrors = (country, offers = []) => {
// verifying shipping address without actually verifying
if (country && !(country in CURRENCY_CODES)) {
return {
error: {
reason: "SHIPPING_ADDRESS_INVALID",
intent: "SHIPPING_ADDRESS",
message: "We're sorry, we cannot ship to that address. Please select another one."
}
};
}
const withoutInvalidOffers = offers.filter((offer) => offer in OFFERS);
const hasInvalidOffer = withoutInvalidOffers.length !== offers.length;
if (hasInvalidOffer) {
return {
newOfferInfo: {
offers: getOfferDetails(withoutInvalidOffers)
},
error: {
reason: "OFFER_INVALID",
intent: "OFFER",
message: "Invalid offer entered. Please try again.",
}
};
}
const selectedOffers = new Set();
const withoutDuplicates = offers.filter((offer) => {
if (selectedOffers.has(offer)) {
return false;
}
selectedOffers.add(offer);
return true;
});
const hasDuplicates = withoutDuplicates.length !== offers.length;
if (hasDuplicates) {
return {
newOfferInfo: {
offers: getOfferDetails(withoutDuplicates)
},
error: {
reason: "OFFER_INVALID",
intent: "OFFER",
message: "Invalid offer entered. Maximum one use per offer.",
}
};
}
};
const getNewTransactionInfo = (offers, shippingOption, country) => {
const priceDetails = getPriceDetails(offers, shippingOption, country);
return {
newTransactionInfo: {
currencyCode: 'USD',
countryCode: 'US',
totalPrice: priceDetails.total,
displayItems: getDisplayItems(priceDetails),
totalPriceStatus: 'FINAL',
totalPriceLabel: 'Total',
}
};
};
const getPriceDetails = (offers, shippingOption, country = 'US') => {
const base = 300;
const shipping = SHIPPING_COSTS[country]?.[shippingOption];
const offerAmount = offers && offers.reduce((total, offer) => offer in OFFERS ? total + OFFERS[offer].value : total, 0);
const discount = offerAmount && base * offerAmount;
const subTotal = base - (discount || 0);
const tax = subTotal * TAX_RATES[country];
const total = subTotal + tax + (shipping || 0);
return {
base: base.toFixed(2),
shipping: shipping && shipping.toFixed(2),
discount: discount && discount.toFixed(2),
tax: tax.toFixed(2),
total: total.toFixed(2),
};
};
const getDisplayItems = ({ base, shipping, discount, tax }) => {
return [
{ label: '20x Primo Mop', type: 'LINE_ITEM', price: '15.00' },
{ label: "Subtotal", type: 'SUBTOTAL', price: base },
discount && { label: 'Discount', type: 'LINE_ITEM', price: `-${discount}` },
shipping && { label: "Shipping", type: 'LINE_ITEM', price: shipping },
{ label: "Tax", type: 'TAX', price: tax },
].filter(Boolean);
};
const getNewShippingOptionParameters = (country, shippingOption) => {
if (!shippingOption) {
return {};
}
return {
newShippingOptionParameters: {
shippingOptions: getShippingOptions(country),
defaultSelectedOptionId: shippingOption,
}
};
};
const getShippingOptions = (country = 'US') => {
const { ground, priority, nextday } = SHIPPING_COSTS[country];
return [
{
id: 'ground',
label: 'Ground',
description: `7 - 250 Business Days - ${freeOrMoney(ground)}`,
},
{
id: 'priority',
label: 'Priority',
description: `7 - 25 Business Days - ${freeOrMoney(priority)}`,
},
{
id: 'nextday',
label: 'Next Day',
description: `1 Business Day - ${freeOrMoney(nextday)}`,
},
];
};
const freeOrMoney = (amount) => amount === 0 ? 'FREE' : `$${amount}`;
const getNewOfferInfo = (offers) => {
if (!offers) {
return {};
}
return {
newOfferInfo: {
offers: getOfferDetails(offers),
}
};
};
const getOfferDetails = (offers) => {
return offers.map((offer) => ({
redemptionCode: offer,
description: OFFERS[offer].label,
}));
};
const google_pay_container_id = "google_pay_iframe";
WePay.createGooglePayIframe(google_pay_container_id, google_pay_configs);
// ok
document.addEventListener('DOMContentLoaded', function() {
// initialize materialize collapsible
var collapsibleElement = document.querySelector('.collapsible');
var collapsibleInstance = M.Collapsible.init(collapsibleElement);
// initialize materialize material box
var materialBox = document.querySelectorAll('.materialboxed');
var instances = M.Materialbox.init(materialBox);
// load with address open
collapsibleInstance.open(2);
});
// show shipping address if different
function showMe() {
var box = document.getElementById('same');
var vis = (box.checked) ? "block" : "none";
document.getElementById('shipping-address').style.display = vis;
}
// close address section on "next" click
function closeAddress() {
var elems = document.querySelector('.collapsible');
var instances = M.Collapsible.init(elems);
instances.close(1);
}
// open submit section on "next" click
function openSubmit() {
var elems = document.querySelector('.collapsible');
var instances = M.Collapsible.init(elems);
instances.open(2);
}
Configure The Google Pay Button
You can configure the following properties of the Google Pay button, as seen starting on line 10 of the CodePen:
- Button color
- Button language
- Button text (e.g. checkout, buy, pay, etc.)
- Button size behavior
You can also add custom styling.
Configure The Google Pay Request
You can configure the following properties of the Google Pay request, as seen starting on line 29 of the CodePen:
- Accepted card brands -- Note that this must match the card brands that we accept
- Merchant name
- Whether the payment sheet will require the payer's email address
- Whether the payment sheet will require the payer's shipping address
- Further define requirements of the shipping address, if required
- Details about the transaction (e.g. amount, currency, display items, etc)
- Discount details
- Whether the payer will be required to select a shipping method
- Details about shipping method selections to show the payer
Again, your configuration must include setting the accepted card brands to the card brands that we accept:
const allowedCardNetworks = ["AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"];
Send the returned Google Pay token to your server in preparation for using it with the WePay APIs.
Use The Google Pay Token
Step 2: Convert the Google Pay token into a WePay Payment Method
After you've generated a Google Pay token with your own app ID, you will need to send aPOST /payment_methods
request to us, using the Google Pay token returned by our iFrame. See the sample request below, where the Google Pay token, payment method
type
, and cardholder information need to be provided. All the required card holder information can be retreived from the iFrame response. See our Process Payments article for further information on processing payments.Note
3.0.rc.2.1
or 3.2
in the Version header parameter for your requests to this endpoint.Example request to POST /payment_methods
:
curl -X POST \
--url 'https://stage-api.wepay.com/payment_methods' \
-H 'Accept: application/json'\
-H 'App-Id: {YOUR-APP-ID}'\
-H 'App-Token: {YOUR-APP-TOKEN}'\
-H 'Api-Version: '3.2'\
-H 'Content-Type: application/json'\
-H 'Unique-Key: {UNIQUE-KEY}
--data-raw {
"type": "google_pay",
"google_pay": {
"payment_method_data": "{googlePayToken_value}",
"card_holder": {
"holder_name": "John Snow",
"email": "example@wepay.com",
"address": {
"country": "US",
"postal_code": "94025"
}
}
}
}
Below is a sample response payload where a WePay payment method ID will be returned (be sure to keep this handy - you'll need to use this to create and capture a payment later), as well as fill in other information.
Example response fromPOST /payment_methods
:{
"id": "00000000-6363-0000-0000-00521ec2df84",
"resource": "payment_methods",
"path": "/payment_methods/00000000-6363-0000-0000-00521ec2df84",
"owner": {
"id": "27415",
"resource": "applications",
"path": null
},
"create_time": 1629930873,
"type": "google_pay",
"google_pay": {
"card_holder": {
"holder_name": "Tony Stark",
"email": "example@wepay.com",
"address": {
"line1": null,
"line2": null,
"city": null,
"region": null,
"postal_code": "94025",
"country": "US"
},
"phone": {
"country_code": null,
"phone_number": null,
"type": null
}
},
"expiration_month": 4,
"expiration_year": 2030,
"display_name": "MasterCard xxxxxx4769"
},
"custom_data": null,
"api_version": "3.0"
}
Create A Wepay Payment
Step 3: Use the WePay Payment Method ID to create a Payment
Use the WePay payment method ID returned above to make aPOST /payment_methods
request. You'll use the id
value from the POST /payment_methods
response as the value for payment_method.payment_method_id
in the POST /payments
request. See our Capture Authorized Payments guide to learn about how to execute manual, deferred, and partial captures of payments.
Example request to POST /payments
:
curl -X POST \
--url 'https://stage-api.wepay.com/payments' \
-H 'Accept: application/json'\
-H 'App-Id: {YOUR-APP-ID}'\
-H 'App-Token: {YOUR-APP-TOKEN}'\
-H 'Api-Version: 3.0'\
-H 'Content-Type: application/json'\
-H 'Unique-Key: {UNIQUE-KEY}
--data-raw '{
"amount": AMOUNT_AS_INTEGER,
"currency": "USD",
"account_id": "{merchant's-account-id}",
"payment_method": {
"payment_method_id": "{INSERT_PAYMENT_METHOD-ID}",
"type": "payment_method_id"
}
}
Example response from
POST /payments
:{
"amount" : 1000,
"amount_refunded" : 0,
"amount_disputed" : 0,
"auto_capture" : true,
"capture_at" : null,
"create_time" : 1510080179,
"currency" : "USD",
"custom_data" : null,
"failure_reason" : null,
"fee_amount" : 0,
"id" : "00000000-0000-0000-0000-0000767bf5cd",
"order" : null,
"owner" : {
"id" : "{merchant's-account-id}",
"path" : "/accounts/{merchant's-account-id}",
"resource" : "accounts"
},
"path" : "/payments/00000000-0000-0000-0000-0000767bf5cd",
"payment_method" : {
"id" : "00000000-6363-0000-0000-000008b93a6e",
"path" : "/payment_methods/00000000-6363-0000-0000-000008b93a6e",
"resource" : "payment_methods"
},
"pending_reasons" : [
{
"details" : [],
"reason_code" : "PROCESSING",
"reason_message" : "Payment is being processed."
}
],
"resource" : "payments",
"status" : "pending",
"authorization_code" : "0224241",
"txnr_app_fee" : null,
"txnr_merchant" : null,
"initiated_by" : "none",
"api_version": "3.0"
}
Create a Test Payment
Follow these steps to create test payments with Google Pay:
- Initialize the Google Pay iFrame provided in this guide.
- For testing only, subscribe to the Google Test Card Suite in order to utilize test cards.
- Generate a Google Pay token from the iFrame.
- Call
POST/ payment_methods
with API version3.0.rc.2.1
or3.2
and convert the Google Pay token into a payment method. (Note: a Google Pay token needs to be converted into a payment method and cannot be directly ingested in aPOST/ payments
call) - Utilize the generated
payment_methods_id
in thePOST/ payments
call to make a successful authorization call (setauto_capture
totrue
to capture the auth immediately or callPOST/ payments/{id}/capture
to capture the payment later).
Note
POST/ payment_methods
endpoint with API version 3.0.rc.2.1
or 3.2
can also be used to generate payment_method_token
and payment_methods_id
for CC/DB/ACH respectively.