Last updated: October 13, 2026
Use this guide to integrate the Google Pay payment handler for Google's Universal Commerce Protocol (UCP) with PayPal as your payment provider. This supports AI-powered checkout experiences through Google AI Mode (Gemini), where Google Pay returns a tokenized credential that PayPal processes through the Orders v2 API. This guide applies to PayPal merchants on the direct, connected, and embedded integration paths.
In a standard Google Pay integration, tokenization happens client-side. With UCP, Google moves it to the server side. Google sends the encrypted payment credential in the checkout session in ECv2 format. You don't decrypt or parse the credential on your server. Instead, you forward it to PayPal, which decrypts it server-side.
payment_source.google_pay object.Complete these three steps to integrate the Google Pay payment handler for UCP with PayPal: configure the handler, handle the checkout payload from Google, and create an order with the Orders v2 API.
When you register your UCP profile with Google, define the Google Pay payment handler. Set tokenization_specification to the PAYMENT_GATEWAY type, which uses the same structure as the configuration that paypal.Googlepay().config() already returns:
{
"payment_handlers": {
"com.google.pay": [
{
"id": "YOUR_HANDLER_UUID",
"version": "2026-01-23",
"spec": "https://pay.google.com/gp/p/ucp/2026-01-23/",
"schema": "https://pay.google.com/gp/p/ucp/2026-01-23/schemas/config.json",
"config": {
"api_version": 2,
"api_version_minor": 0,
"environment": "PRODUCTION",
"merchant_info": {
"merchant_name": "YOUR_BUSINESS_NAME",
"merchant_id": "BCR2DN4TXSDMVTKM", // PayPal’s Google Merchant Id
"merchant_origin": "checkout.yourdomain.com"
},
"allowed_payment_methods": [
{
"type": "CARD",
"parameters": {
"allowed_auth_methods": ["PAN_ONLY"],
"allowed_card_networks": ["AMEX", "DISCOVER", "MASTERCARD", "VISA"],
"assurance_details_required": true,
"billing_address_required": true,
"billing_address_parameters": { "format": "FULL", "phone_number_required": false }
},
"tokenization_specification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "paypalppcp",
"gatewayMerchantId": "YOUR_PAYPAL_MERCHANT_ID"
}
}
}
]
}
}
]
}
}The following table describes the parameters in the sample that identify PayPal as the payment gateway.
| Parameter | Description |
|---|---|
gateway | Set to paypalppcp. This is PayPal's registered Google Pay gateway, and the value is the same for all PayPal merchants. |
gatewayMerchantId | The PayPal encrypted merchant account ID for the individual merchant. This value is different for each merchant. |
merchant_info.merchant_id | Set to BCR2DN4TXSDMVTKM. This is Google's registered gateway ID for PayPal. The value is the same for all merchants and identifies PayPal as the gateway to Google. |
The allowed_auth_methods value must be PAN_ONLY. This is the only value that Google's UCP config schema supports. The credential that Google returns is an FPAN that contains the card number and expiration date. CRYPTOGRAM_3DS is not part of the UCP config.
The PayPal tokenization_specification requires only gateway and gatewayMerchantId. You don't need a tokenization key, an SDK version, or other namespaced parameters. PayPal relies on the paypalppcp gateway registration and its own recipient private keys to decrypt the credential.
When Google calls your /checkout-session/{id}/complete endpoint, the payment method's credential.token is the ECv2 gateway payload, a JSON-serialized string:
{
"payment": {
"instruments": [
{
"id": "pm_1234567890abc",
"handler_id": "YOUR_HANDLER_UUID",
"type": "card",
"display": { "brand": "VISA", "last_digits": "4242" },
"billing_address": {
"street_address": "123 Main Street",
"address_locality": "Charleston",
"address_region": "SC",
"postal_code": "29401",
"address_country": "US",
"first_name": "Jane",
"last_name": "Smith"
},
"credential": {
"type": "PAYMENT_GATEWAY",
"token": "{\"signature\":\"...\",\"protocolVersion\":\"ECv2\",\"signedMessage\":\"...\"}"
}
}
]
},
"risk_signals": { }
}Don't parse or decrypt credential.token on your server. Forward it to PayPal exactly as you receive it, as described in Step 3.
Create a PayPal order with the Google Pay credential set inline on payment_source.google_pay. Because the credential is an inline Google Pay token, PayPal can process it during the create call. You don't need a separate confirm-payment-source call.
PayPal decrypts the token server-side, builds the funding instrument, and authorizes or captures the payment in a single request. Set intent to one of these values:
CAPTURE: Creates the order and captures the payment.AUTHORIZE: Creates the order and authorizes the payment. You capture it later.The payment_source.google_pay object supports these fields: token, decrypted_token, name, email_address, phone_number, card, assurance_details, and experience_context. In the request, card carries only brand and billing_address.
You provide the credential in one of two fields:
token: The encrypted ECv2 payload from Google. PayPal decrypts it.decrypted_token: Use this field only if you have already decrypted the credential yourself. It doesn't apply to this integration, because PayPal decrypts the credential.Send a POST request to /v2/checkout/orders with the Google Pay credential in the payment_source.google_pay object. This single call creates the order and captures the payment.
{
"intent": "CAPTURE", // AUTHORIZE for create + auth (capture later)
"purchase_units": [
{
"amount": { "currency_code": "USD", "value": "120.00" }
}
],
"payment_source": {
"google_pay": {
"token": "<base64-encoded credential.token from Google>"
}
}
}Base64-encode the credential.token value before you send it. Google delivers credential.token as a JSON string, so encode that string directly and put the result in payment_source.google_pay.token. PayPal decodes and decrypts it server-side.
Don't run JSON.stringify on the token first. Doing so double-encodes the value, and PayPal can't parse it. In JavaScript, use Buffer.from(credentialToken).toString('base64').
In the request, google_pay.card carries only brand and billing_address. Don't send number, expiry, or last_digits. PayPal derives them from the decrypted token and returns last_digits, type, and fingerprint in the response.
Billing address fields use PayPal's portable address names:
address_line_1address_line_2admin_area_2: Cityadmin_area_1: State or provincepostal_codecountry_codeInclude these headers:
Prefer: return=representation: Includes the captures array in the response.PayPal-Request-Id: A unique value that you generate for each request. If you retry a request with the same value, PayPal doesn't create a duplicate order.A successful request returns 201 Created with the completed order. The capture is nested under the purchase unit:
{
"id": "8MW02486UJ231741T", // ORDER id
"intent": "CAPTURE",
"status": "COMPLETED",
"payment_source": {
"google_pay": {
"card": { "last_digits": "8960", "type": "CREDIT", "brand": "VISA" }
}
},
"purchase_units": [
{
"payments": {
"captures": [
{
"id": "7FD40336T0573644K", // CAPTURE id
"status": "COMPLETED",
"amount": { "currency_code": "USD", "value": "120.00" },
"final_capture": true
}
]
}
}
]
}