PayFacto API - V2.0 - Digital Wallets : Google Pay™ - Online Checkout

PayFacto API - V2.0 - Digital Wallets : Google Pay™ - Online Checkout

PayFacto API - V2.0 - Digital Wallets : Google Pay™ - Online Checkout

In-App

Integrate Google Pay into your Android application and process payments through the PayFacto Payment API v2.0. There are two implementation methods depending on who decrypts the Google Pay token — your server or PayFacto.

Choose an Integration Method

A

 Partner Decrypts

Your server decrypts the Google Pay token and extracts the raw card data (PAN, expiry, cryptogram). You then send the decrypted fields to PayFacto for processing.

✅ Full control over decryption

✅ You own the HSM / key management

⚠️ Requires ECv2 decryption implementation

Google Pay type: DIRECT

B

 PayFacto Decrypts

Your server forwards the raw encrypted Google Pay token to PayFacto. PayFacto handles decryption on its end — your integration is simpler.

✅ Simpler — no decryption required

✅ Pass the token as-is

⚠️ Requires payfacto gateway in Google Pay config

Google Pay type: PAYMENT_GATEWAY

A
   Method A — Partner DecryptsGoogle Pay config: type = DIRECT
A1

  Configure Google Pay — type: DIRECT

ℹ️

In your Google Pay API configuration, set the tokenization type to DIRECT. This tells Google Pay to use your own merchant public key for encryption, which your server will decrypt.

JSON — Google Pay tokenization config (DIRECT)
"type": "DIRECT"
A2

  Receive the Encrypted Token from Google Pay

ℹ️

After the customer approves the payment, Google Pay returns an encrypted token from paymentMethodData.tokenizationData.token. The outer envelope uses the ECv2 protocol.

JSON — Raw Google Pay token (ECv2)
{
"protocolVersion": "ECv2",
"signedMessage": "...",
"signature": "...",
"intermediateSigningKey": {
"signedKey": "...",
"signatures": ["..."]
}
}

Inside the verified signedMessage is a payload containing:

FieldDescription
encryptedMessageThe AES-256-GCM encrypted payment data ciphertext.
ephemeralPublicKeyGoogle's one-time EC public key used in the ECDH key agreement.
tagThe authentication tag for the AES-GCM operation. Discard the token if verification fails.
A3

  Decrypt the Token (ECv2)

⚠️

Always verify the Google signature chain before decrypting. This prevents token forgery and replay attacks.

Follow these six steps on your server to produce the plaintext payment data:

1

  Verify token authenticity

Validate Google's signature chain. Verify intermediateSigningKey, then signedMessage. Confirm all signing keys trace to Google's trusted root certificate. Do not proceed if verification fails.

2

  Load your merchant private key

Retrieve the Elliptic Curve (P‑256) private key that corresponds to the public key you uploaded in the Google Pay Business Console. Store it securely in an HSM or KMS.

3

  Perform ECDH key agreement

Use your merchant private key and Google's ephemeralPublicKey from the token to compute a shared secret via Elliptic Curve Diffie-Hellman (ECDH).

4

  Derive symmetric keys with HKDF

Run the shared secret through HKDF (SHA‑256) using Google-specified context strings (protocol version, sender/recipient identifiers) to produce an AES‑256 symmetric key and an HMAC key.

5

  Decrypt the payment data

Decrypt encryptedMessage using AES‑256‑GCM with the derived AES key and tag as the authentication tag. If authentication fails, discard the token immediately.

6

  Parse the decrypted payload

The result is a JSON payload containing PAN, expiry, cryptogram, and ECI indicator. Extract these four fields for the next step.

JSON — Decrypted payload
{
"gatewayMerchantId": "94087155",
"messageExpiration": "1741304144394",
"messageId": "AH2EjtdzTuvrRcGAbH2k9B...",
"paymentMethod": "CARD",
"paymentMethodDetails": {
"expirationYear": 2030,
"expirationMonth": 10,
"pan": "1234567890123456",
"authMethod": "CRYPTOGRAM_3DS",
"eciIndicator": "07",
"cryptogram": "xQBBBBBB12abCDefGh+9Z0AAAA="
}
}

Fields to extract from the decrypted payload

Decrypted fieldMaps toNotes
panCard numberPass as card.number in the charge request.
expirationYearExpiry year (YYYY)Pass as card.expiry.year.
expirationMonthExpiry month (MM)Pass as card.expiry.month. Zero-pad to 2 digits.
cryptogramCryptogramMust be converted from Base64 to HEX before sending to PayFacto. See below.
eciIndicatorECI indicatorPass as card.authentication.wallet.eciIndicator.
A4

  Convert the Cryptogram from Base64 to HEX

⚠️

The cryptogram returned by Google Pay is Base64-encoded. PayFacto requires it in hexadecimal (HEX) format. Convert it before building the charge request.

EncodingExample value
Base64 (from Google Pay)xQBBBBBB12abCDefGh+9Z0AAAA=
HEX (send to PayFacto)C50041041041075D9A6C305E9C1FBD6740000000
Java — Base64 → HEX conversion
import java.util.HexFormat;

public String getCryptogramHexString(final GooglePayPaymentPlainData plainData) {
final String base64String = plainData.getCryptogram3ds();
final byte[] bytes = decodeBase64(base64String);
return HexFormat.of().formatHex(bytes);
}
A5

  Build and Submit the Charge

ℹ️

Use paymentMethod.type: "CARD" with a card.authentication.wallet block. Set wallet.type to GOOGLE_PAY and pass the HEX-encoded cryptogram.

Charge request body — Method A

FieldConstraintDescription
amountinteger · requiredAmount in cents. Example: 5000 = $50.00
invoiceNumberstring · requiredMerchant invoice reference. Max 25 chars.
captureboolean · optionalDefault: true. Set false for pre-authorization.
paymentMethod.typestring · requiredCARD
paymentMethod.card.numberstring · requiredPAN extracted from the decrypted Google Pay payload.
paymentMethod.card.expiry.monthstring · requiredExpiry month (MM) from the decrypted payload.
paymentMethod.card.expiry.yearstring · requiredExpiry year (YYYY) from the decrypted payload.
paymentMethod.card.authentication.wallet.typestring · requiredGOOGLE_PAY
paymentMethod.card.authentication.wallet.eciIndicatorstring · requiredECI indicator from the decrypted payload.
paymentMethod.card.authentication.wallet.cryptogramstring · requiredCryptogram converted to HEX. Do not send the raw Base64 value.
JSON — POST /charges body (Method A — Partner Decrypts)
{
"amount": "5000",
"invoiceNumber": "123456789012",
"capture": true,
"paymentMethod": {
"type": "CARD",
"card": {
"number": "1234567890123456",
"expiry": {
"month": "08",
"year": "2030"
},
"authentication": {
"wallet": {
"eciIndicator": "05",
"type": "GOOGLE_PAY",
"cryptogram": "C50041041041075D9A6C305E9C1FBD6740000000"
}
}
}
}
}
B
Method B — PayFacto DecryptsGoogle Pay config: type = PAYMENT_GATEWAY
B1

  Configure Google Pay — gateway: payfacto

ℹ️

In your Google Pay API configuration, set the tokenization type to PAYMENT_GATEWAY and specify payfacto as the gateway. The gatewayMerchantId is your PayFacto merchant account UUID, found in the merchant back office.

JSON — Google Pay tokenization config (PAYMENT_GATEWAY)
{
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "payfacto",
"gatewayMerchantId": "merchant_123"
}
}
}
ParameterDescription
gatewayMust be exactly payfacto (lowercase). This tells Google Pay which gateway will decrypt the token.
gatewayMerchantIdYour PayFacto merchant account UUID. Found in the PayFacto merchant back office.
B2

  Receive and Forward the Token

ℹ️

With PAYMENT_GATEWAY mode, Google returns a complete encrypted token payload. Your server does not need to decrypt it. Extract the full value of paymentMethodData.tokenizationData.token as a JSON string and pass it directly to PayFacto as paymentData.

⚠️

Pass the token value exactly as received — as a JSON string. Do not parse, modify, or re-serialize it. PayFacto will handle all decryption internally.

B3

  Build and Submit the Charge

ℹ️

Use paymentMethod.type: "CARD" with a card.authentication.wallet block. Set wallet.type to GOOGLE_PAY and pass the raw token JSON string as wallet.paymentData. No card number, expiry, or cryptogram are required.

Charge request body — Method B

FieldConstraintDescription
amountinteger · requiredAmount in cents.
invoiceNumberstring · requiredMerchant invoice reference. Max 25 chars.
captureboolean · optionalDefault: true. Set false for pre-authorization.
paymentMethod.typestring · requiredCARD
paymentMethod.card.authentication.wallet.typestring · requiredGOOGLE_PAY
paymentMethod.card.authentication.wallet.paymentDatastring · requiredThe complete Google Pay token JSON string from paymentMethodData.tokenizationData.token. Pass as-is — do not parse.
JSON — POST /charges body (Method B — PayFacto Decrypts)
{
"amount": "10000",
"invoiceNumber": "581113481611",
"capture": true,
"metadata": {
"device_type": "android"
},
"paymentMethod": {
"type": "CARD",
"card": {
"authentication": {
"wallet": {
"type": "GOOGLE_PAY",
"paymentData": "{\"signature\":\"MEUCIHcdC0B4TKe...\",\"protocolVersion\":\"ECv2\",\"signedMessage\":\"{\\\"encryptedMessage\\\":\\\"kQl0kOsKNhE3FQ...\\\"}\"}"
}
}
}
}
}