Developer Guidelines

1. Introduction

This guide provides detailed instructions on integrating Google Pay™ for web and in-app applications. Google Pay is a digital wallet that streamlines card payments, enabling swift and effortless transactions without the need to repeatedly input card information. Google securely stores the card data. This option is compatible with all devices (mobile phones and computers), irrespective of the operating system and web browser.

2. Register with Google

You’ll need to register as a Google Pay merchant using the Google Pay Business Console. You will be given a Google merchant identifier which you will need to provide to us when you are boarded:

1. If your business profile has never registered on Google, you will need to create one:

Bonum Logo
2. After your business profile creation, click "Business Profile":
Bonum Logo
3. Setup your Business Profile:
Bonum Logo
3.1. Setup your Payments Profile:
Bonum Logo
3.2. Edit your Business Information:
Bonum Logo
4. Once you setup Business profile, you will be able to use Google Pay feature:
Bonum Logo
Note: If your business profile has been registered already, you don't need to fill your Business Profile. You will get this screen when you enter "Business Profile".

3. Web App Integration

3.1 Web App Implementation

1. PREREQUISITES
Before proceeding, ensure you have:
  • Merchant ID (You will have it after you create your Business Profile at Google Pay Business Console. See "Your Merchant ID is HERE")
  • Merchant Key (The Merchant Key should have been provided by Bonum PSP)
  • Demo Web App Source google-pay-example-v1.0.0.zip (Source files should have been provided by Bonum PSP)

2. INSTRUCTION

For website integration with the Google Pay method, follow these references:

1. Google Pay Web developer documentation
2. Google Pay Web integration checklist
3. Google Pay Web Brand Guidelines

Note: if you provide Google Pay as a payment method to your customers, you must use the official Google Pay logo and button assets in compliance with Google Pay Google Pay Web Brand Guidelines, without modifications to the Google Pay asset colors, proportions, or appearance.

Our implementation with Google Pay simplifies your ability to provide Google Pay as a payment option to your customers. You must additionally complete the following essential step to enable Google Pay functionality:


The gateway parameter in the script should have the constant value of "bonumpsp", according to the example below:
 tokenizationSpecification: {
      type: 'PAYMENT_GATEWAY',
      parameters: {
          gateway: 'bonumpsp',  // This is Bonum's Gateway ID.
          gatewayMerchantId: 'BCR2DN7TVGEYH4JB' //Replace with your Merchant ID.
        }
      }

Please be aware that Bonum, as the processor of Google Pay payments, facilitates the handling of payment card type issued by MasterCard organization. This necessitates configuring the Google script as follows:

 parameters: {
    allowedAuthMethods: ['CRYPTOGRAM_3DS'], //We support CRYPTOGRAM_3DS auth method
    allowedCardNetworks: ['MASTERCARD'] //Currently we support Mastercard
  },

As a response, Google will provide the PaymentData item, wherein the paymentMethodData.tokenizationData.token field will include encrypted Google Pay Token (a string of characters). Your front-end web app will need to send this token with your order_id, amount and currency_code to your back-end server:

 "token": "{\"signature\":\"MESDDFCr5Hsu+h4jDGdo1pRbmhgHWBuLLvkrBXK+Ahdhh3hhdhhs+HDKKSduueuust388d\\u003d\",\"intermediateSigningKey\":{\"signedKey\":\"{\\\"keyValue\\\":\\\"HSHF5shhdCfaa3995f3ccc+ivsddabQ\\\\u003d\\\\u003d\\\",\\\"keyExpiration\\\":\\\"1762383604000\\\"}\",\"signatures\":[\"MEUCIBBLQ8Gn/+1IXD8BEZ0S30sD0GeCSsfoGsLiyTtH3RWdAiEAvPhPUPjdzXSVVZ72I21Exu9zakHP700NlLdtYKY6So4\\u003d\"]},\"protocolVersion\":\"ECv2\",\"signedMessage\":\"{\\\"encryptedMessage\\\":\\\"DgorZjE21nXjNObra/xxxxxxAAXXAXXXXXXT8X/u/Djqp+AdFM\\\\u003d\\\",\\\"ephemeralPublicKey\\\":\\\"BO/oauy773u3jj3+vDjuauuahyhe772jjca\\\\u003d\\\",\\\"tag\\\":\\\"J4no/tst663hbdhhshs73najja+EHYg\\\\u003d\\\"}\"}"

If a billing address is required for Google Pay, ensure that you include required parameters. For more details, see BillingAddressParameters.
Billing address request example:

 "allowedPaymentMethods": [
            {
              "type": "CARD",
              "parameters": {
                "billingAddressRequired": true,
                "billingAddressParameters": {
                  "phoneNumberRequired": true,
                  "format": "MIN"
                },
                "allowedCardNetworks": [...],
                "allowedAuthMethods": [...]
              },
              "tokenizationSpecification": {...}
            },
        ]"

Google Pay   >   PSP   >   Demo Web App Source

A.) DEMO SOURCE FILES

Extract google-pay-example-v1.0.0.zip file in a folder:

  • index.html - The frontend with the Google Pay button and JavaScript integration.
  • server.js - The backend server (Node.js with Express) that handles Google Pay merchant payment processing.
  • package.json - Lists dependencies needed for your backend (e.g., express, node-fetch).
  • package-lock.json - Automatically generated to lock dependency versions.

Web App   >   Frontend Integration

B.) INDEX.HTML
// Google Pay integration
    const paymentsClient = new google.payments.api.PaymentsClient({ environment: 'TEST' });
    // TEST is for Sandbox environment
    // PRODUCTION is for prod environment

    const baseRequest = {
        apiVersion: 2,
        apiVersionMinor: 0
    };

    function getPaymentDataRequest() {
        const total = cart.reduce((sum, item) => sum + item.price * item.quantity, 0).toFixed(2);
        return Object.assign({}, baseRequest, {
            allowedPaymentMethods: [{
                type: 'CARD',
                parameters: {
                    allowedAuthMethods: ['CRYPTOGRAM_3DS'],
                    allowedCardNetworks: ['MASTERCARD']
                },
                tokenizationSpecification: {
                    type: 'PAYMENT_GATEWAY',
                    parameters: {
                        gateway: 'bonumpsp',  // Set Bonum's gateway ID: bonumpsp
                        gatewayMerchantId: 'BCR2DN7TVGEYH4JB' //Replace with your Merchant ID.
                    }
                }
            }],
            merchantInfo: {
                merchantName: 'Set Your Business Name here', //Replace with Your Business Name.
                merchantId: 'BCR2DN7TVGEYH4JB' //Replace with your Merchant ID.
            },
            transactionInfo: {
                totalPriceStatus: 'FINAL',
                totalPrice: total,
                currencyCode: 'MNT' //Currency code
            }
        });
    }

    function onGooglePayButtonClicked() {
        const request = getPaymentDataRequest();
        paymentsClient.loadPaymentData(request).then(function(paymentData) {
            console.log('Payment token:', paymentData.paymentMethodData.tokenizationData.token);
            alert('Payment token received! Send it to your Back here.');
            sendPaymentData(paymentData.paymentMethodData.tokenizationData.token, request.transactionInfo.totalPrice, request.transactionInfo.currencyCode);

        }).catch(function(err) {
            console.error(err);
        });
    }

    function sendPaymentData(token, totalPrice, currencyCode) {
        
        try {
            //frontend will send token to its backend. merchant can customize to their needs.
            const response = await fetch('http://localhost:3000/api/send/payment', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ token, orderId: 'REPLACE_ORDER_ID_HERE', amount: totalPrice, currencyCode: currencyCode}),
            });
            const result = await response.json();

        // Return transaction state to Google Pay
        return {
            transactionState: result.transactionState,
            error: result.transactionState === 'ERROR' ? {
              reason: 'PAYMENT_AUTHORIZATION',
              message: result.details.message,
              intent: 'PAYMENT_AUTHORIZATION'
            } : undefined
          };

        } catch (error) {
            console.error('Error processing payment:', error);
            alert('Unexpected error occurred while processing payment.');
            // Return transaction state to Google Pay
            return {
                transactionState: 'ERROR',
                error: result.transactionState === 'ERROR' ? {
                  reason: 'PAYMENT_AUTHORIZATION',
                  message: result.details.message,
                  intent: 'PAYMENT_AUTHORIZATION'
                } : undefined
            };
        }
        
    }

Web App   >   The backend Integration

C.) SERVER.JS

Note: Handle payment authorization and process the payment.
Replace “REPLACE_YOUR_MERCHANT_KEY"with your merchant key.

const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const cors = require('cors');
const app = express();
const PORT = 3000;

// Allow specific origins (replace `http://example.com` with your frontend's URL)
app.use(cors({
  origin: 'https://testpsp.bonum.mn', // Allow this specific origin for TEST
  //origin: 'https://psp.bonum.mn', // Allow this specific origin for PROD
}));

// Middleware: Parses incoming JSON request bodies
app.use(bodyParser.json());

/**
 * Endpoint to process payment authorization.
 * The client sends a token and an orderId, which are forwarded to the PSP (Payment Service Provider).
 */
app.post('/api/send/payment', async (req, res) => {
  const { token, orderId, amount, currencyCode } = req.body;

  // Step 1: Validate incoming request data
  if (!token || !orderId || !amount || !currencyCode) {
    return res.status(400).json({
      success: false,
      message: 'Missing token, orderId, amount or currencyCode',
    });
  }

  try {
    // Step 2: Forward the payment data to the PSP
    const response = await axios.post(
      'https://testpsp.bonum.mn/api/payment/process/google', // Bonum PSP Test endpoint
      //'https://psp.bonum.mn/api/payment/process/google', // Bonum PSP Production endpoint
      {
        token,          // Payment token received from Google Pay
        order_id: orderId, // Merchant invoice/order id
        amount: amount, // Amount
        currency_code: currencyCode, // MNT, USD ...etc Currency code
      },
      {
        headers: {
          'Content-Type': 'application/json',
          'x-merchant-key': 'REPLACE_YOUR_MERCHANT_KEY', // Replace with your actual merchant key
        },
      }
    );
        console.log('resp', response.data);


          // Map PSP response to Google Pay transactionState
    let transactionState = 'ERROR';
    if (response.data.success) {
      transactionState = 'SUCCESS';
    } 

    res.json({
    transactionState,
    details: {
      orderId: response.data.orderId,
      message: response.data.desc,
      code: response.data.status_code
    }
  });


  } catch (error) {
    console.error('Error processing payment:', error.message);

    // Step 4: Handle errors from the PSP or network issues
    if (error.response) {
      // Errors returned directly by the PSP

     res.json({
        transactionState,
        details: {
          orderId: error.response.data.orderId,
          message: error.response.data.desc,
          code: error.response.data.status_code
        }
      });
    }

  // Step 5: Handle unexpected or generic errors (network, server, etc.)
   res.json({
      transactionState,
      details: {
        orderId,
        code: 500
        message: 'Unexpected error occurred while processing payment.',
      }
    });
  }
});

// Start the Express server
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Web App   >   The backend integration

D.) CHECK PAYMENT

Note: You can use the /api/payment-log/read API for handling any payment failure cases.
Replace “REPLACE_YOUR_MERCHANT_KEY" with your merchant key.
This API call should be executed on your backend.

func checkPaymentByOrderId(orderId: String) {
  
  let manager = AFHTTPSessionManager()
  manager.requestSerializer = AFJSONRequestSerializer()
  manager.responseSerializer = AFJSONResponseSerializer()
  manager.responseSerializer.acceptableContentTypes = manager.responseSerializer.acceptableContentTypes?.union(["application/json"])
  //TODO: set Merchant Key here. Bonum will provide Merchant Key.
  manager.requestSerializer.setValue("SET-YOUR-MERCHANT-KEY-HERE", forHTTPHeaderField: "x-merchant-key")
  
  
  //Demo URL. Note: This URL charges the bank transaction. Please use small amount when you test
  var urlString = "https://testpsp.bonum.mn/api/payment-log/read"
  //Production URL. When you push your Build to the production
  //var urlString = "https://psp.bonum.mn/api/payment-log/read"
  
  urlString = urlString + "?order_id=" + orderId
  // Convert the JSON object to a JSON string
  print("API Url: \(urlString)")
  
  manager.get(urlString,
              parameters: nil,
              headers: nil, progress: { progress in
      print("Download progress: \(progress.totalUnitCount)")
  }, success: { task, responseObject in
      print("Transactions for Order ID: \(orderId)")
      print("GET response: \(responseObject ?? "No response")")
  }, failure: { task, error in
      print("Error on GET request: \(error.localizedDescription)")
  })
}

Web App   >   The backend integration

E.) CHECK PAYMENT RESPONSE

Note: "success": false indicates that the transaction failed for some reason.

Note: "success": true indicates that the transaction was processed successfully.

[
    {
      "merchant_order_id": "9876543",
      "amount": 5000,
      "success": false,
      "createdAt": "2025-01-24T03:22:03.135Z"
    },
    {
      "merchant_order_id": "9876543",
      "amount": 5000,
      "success": true,
      "createdAt": "2025-01-24T03:22:03.135Z"
    }
]

3.2 Submit Your Web App for Google Review

1. PREREQUISITES
Before proceeding, ensure that you have completed:

Your integration must be completed within your Sandbox/Test environment. And you need to prepare below screenshots of your web app for Google Review:

1. Item selection
2. Pre-purchase screen
3. Payment method screen
4. Google Pay API payment screen
5. Post-purchase screen

2. INSTRUCTION

Go to Google Pay Business Console and login with your credentials.

1. Select "Google Pay API", scroll down and click "Add a website" in "Add an integration" section:

Bonum Logo

2. Enter your domain, choose "Gateway" from "Integration Type" and upload your screenshots:

Bonum Logo

3. After uploading your screenshots, click "Save" and you will be able to submit for the review:

Bonum Logo

4. Submit for review:

Bonum Logo

After submition, the reviewing process will take 2-3 business days. If your submition gets approved by Google, you will be able to integrate your app in the production environment.

4. Android App Integration

4.1 Android App Implementation

1. PREREQUISITES
Before proceeding, ensure you have:
  • Merchant ID (You will have it after you create your Business Profile at Google Pay Business Console. See "Your Merchant ID is HERE")
  • Merchant Key (The Merchant Key should have been provided by Bonum PSP)
  • Demo Flutter App Source google-pay-example-v1.0.0.zip (Source files should have been provided by Bonum PSP)

2. INSTRUCTION

For Android app integration with the Google Pay method, follow these references:

1. Google Pay Android developer documentation
2. Google Pay Android integration checklist
3. Google Pay Android brand guidelines

Note: if you provide Google Pay as a payment method to your customers, you must use the official Google Pay logo and button assets in compliance with Google Pay Google Pay Android brand guidelines, without modifications to the Google Pay asset colors, proportions, or appearance.

Our implementation with Google Pay simplifies your ability to provide Google Pay as a payment option to your customers. You must additionally complete the following essential step to enable Google Pay functionality:


The gateway parameter in the script should have the constant value of "bonumpsp", according to the example below:
 tokenizationSpecification: {
      type: 'PAYMENT_GATEWAY',
      parameters: {
          gateway: 'bonumpsp',  // This is Bonum's Gateway ID.
          gatewayMerchantId: 'BCR2DN7TVGEYH4JB' //Replace with your Merchant ID.
        }
      }

Please be aware that Bonum, as the processor of Google Pay payments, facilitates the handling of payment card type issued by MasterCard organization. This necessitates configuring the Google script as follows:

 parameters: {
    allowedAuthMethods: ['CRYPTOGRAM_3DS'], //We support CRYPTOGRAM_3DS auth method
    allowedCardNetworks: ['MASTERCARD'] //Currently we support Mastercard
  },

As a response, Google will provide the PaymentData item, wherein the paymentMethodData.tokenizationData.token field will include encrypted Google Pay Token (a string of characters). Your Android app will need to send this token with your order_id, amount and currency_code to your back-end server. And your back-end server should send the payload to our end-point "/api/payment/process/google" as described above:

 "token": "{\"signature\":\"MESDDFCr5Hsu+h4jDGdo1pRbmhgHWBuLLvkrBXK+Ahdhh3hhdhhs+HDKKSduueuust388d\\u003d\",\"intermediateSigningKey\":{\"signedKey\":\"{\\\"keyValue\\\":\\\"HSHF5shhdCfaa3995f3ccc+ivsddabQ\\\\u003d\\\\u003d\\\",\\\"keyExpiration\\\":\\\"1762383604000\\\"}\",\"signatures\":[\"MEUCIBBLQ8Gn/+1IXD8BEZ0S30sD0GeCSsfoGsLiyTtH3RWdAiEAvPhPUPjdzXSVVZ72I21Exu9zakHP700NlLdtYKY6So4\\u003d\"]},\"protocolVersion\":\"ECv2\",\"signedMessage\":\"{\\\"encryptedMessage\\\":\\\"DgorZjE21nXjNObra/xxxxxxAAXXAXXXXXXT8X/u/Djqp+AdFM\\\\u003d\\\",\\\"ephemeralPublicKey\\\":\\\"BO/oauy773u3jj3+vDjuauuahyhe772jjca\\\\u003d\\\",\\\"tag\\\":\\\"J4no/tst663hbdhhshs73najja+EHYg\\\\u003d\\\"}\"}"

If a billing address is required for Google Pay, ensure that you include required parameters. For more details, see BillingAddressParameters.
Billing address request example:

 "allowedPaymentMethods": [
            {
              "type": "CARD",
              "parameters": {
                "billingAddressRequired": true,
                "billingAddressParameters": {
                  "phoneNumberRequired": true,
                  "format": "MIN"
                },
                "allowedCardNetworks": [...],
                "allowedAuthMethods": [...]
              },
              "tokenizationSpecification": {...}
            },
        ]"

4.2 Submit Your Android App for Google Review

1. PREREQUISITES
Before proceeding, ensure that you have completed:

Your integration must be completed within your Sandbox/Test environment. And you need to prepare below screenshots of your Android app for Google Review:

1. Item selection
2. Pre-purchase screen
3. Payment method screen
4. Google Pay API payment screen
5. Post-purchase screen

2. INSTRUCTION

Go to Google Pay Business Console and login with your credentials.

1. Select "Google Pay API", choose your app to integrate and click "Add" of integration screenshots:

Bonum Logo

2. Choose "Gateway" from "Integration Type" and upload your screenshots:

Bonum Logo

3. After uploading your screenshots, click "Save" and "Submit":

Bonum Logo

After submition, the reviewing process will take 2-3 business days. If your submition gets approved by Google, you will be able to integrate your app in the production environment.

5. SUPPORT & CONTACT



If you need further assistance, please contact our team:
- Email: [email protected]
- Phone: +976 7200-5000