This is a simple example of integrating Paytm SDK into your android app for accepting payments. It is optimised and tested with the latest Paytm SDK as of February 2019.

PREREQUISITES

Obtain Paytm test credentials

Login to Paytm developer account and on the left-hand side of dashboard click on API key. Copy your test credentials: Test Merchant ID and Test Account Secret Key. These are testing keys; and once you activate your account(Top right Corner), Paytm support team will send you an email with Production key and Merchant ID.

Server-side work: Checksum Kit

Download the Paytm App Checksum Kit PHP folder and upload it to your server root directory. Rename the folder to something simple to your liking.

Go to config_paytm.php (in the lib folder paytm/lib/config_paytm.php), and add your “Test Account Secret Key” credential and save the file.

We just need to route to the generateChecksum.php file. So your checksum URL will look like http://www.your-domain/foldername/generateChecksum.php. Save this URL.

INTEGRATING PAYTM TO ANDROID APP

App dependency

In your app level build.gradle file, add the PayTm dependency

implementation('com.paytm:pgplussdk:1.2.9') {
    transitive = true;
}

We will also need Retrofit

implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'

Add permissions in Manifest

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>

Also in your manifest, inside Application tag

<activity android:name="com.paytm.pgsdk.PaytmPGActivity"
    android:screenOrientation="portrait" android:configChanges="keyboardHidden|orientation|keyboard"/>

Proguard rules

-keepclassmembers class com.paytm.pgsdk.PaytmWebView$PaytmJavaScriptInterface {
   public *;
}

Retrofit

Let’s create our Retrofit client & interface for handling the network call we are going to make for generating checksum through your server.

ApiClient.java

public class ApiClient {
    private static Retrofit retrofit = null;
    public static Retrofit getRetrofit() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(Config.url_base)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

ApiInterface.java

import java.util.List;

import io.gruppe.gruppe.models.item.ItemGroupObj;
import io.gruppe.gruppe.models.item.ItemObj;
import io.gruppe.gruppe.models.paytm.Checksum;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;

public interface ApiInterface {
    @FormUrlEncoded
    @POST("generateChecksum.php")
    Call<Checksum> getChecksum(
            @Field("MID") String mId,
            @Field("ORDER_ID") String orderId,
            @Field("CUST_ID") String custId,
            @Field("CHANNEL_ID") String channelId,
            @Field("TXN_AMOUNT") String txnAmount,
            @Field("WEBSITE") String website,
            @Field("CALLBACK_URL") String callbackUrl,
            @Field("INDUSTRY_TYPE_ID") String industryTypeId
    );
}

Checksum.java

import com.google.gson.annotations.SerializedName;
public class Checksum {

    @SerializedName("CHECKSUMHASH")
    private String checksumHash;

    @SerializedName("ORDER_ID")
    private String orderId;

    @SerializedName("payt_STATUS")
    private String paytStatus;

    public Checksum(String checksumHash, String orderId, String paytStatus) {
        this.checksumHash = checksumHash;
        this.orderId = orderId;
        this.paytStatus = paytStatus;
    }

    public String getChecksumHash() {
        return checksumHash;
    }

    public String getOrderId() {
        return orderId;
    }

    public String getPaytStatus() {
        return paytStatus;
    }
}

Add this helper method anywhere, either in your activity or in your helper/utility class.

/*
* The following method we are using to generate a random string everytime
* As we need a unique customer id and order id everytime
* For real scenario you can implement it with your own application logic
* */
private String generateRandomString() {
String uuid = UUID.randomUUID().toString();
return uuid.replaceAll("-", "");
}

Config.java

Define your credentials here. Replace PAYTM_MERCHANT_ID with your test ID and url_base with your server URL.

public class Config {
    public static final String PAYTM_MERCHANT_ID = "xxxxxxxx"; //YOUR TEST MERCHANT ID
    public static final String url_paytm_callback = "https://pguat.paytm.com/paytmchecksum/paytmCallback.jsp"; 
    public static final String url_base = "http://www.your-domain/foldername/";
}

Payment screen

Now let’s come to the main activity java class where we want to show the Paytm instance.

Order ID always has to be unique. Here we are generating a random string for OrderId.

public class ActCart extends AppCompatActivity implements PaytmPaymentTransactionCallback {

    private ApiInterface apiServicePaytm;
    String custid="", orderId="";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cart);

        //creating random orderId and custId just for demonstration.
        orderId = Helper.generateRandomString();
        custid = Helper.generateRandomString();

        apiServicePaytm = ApiClient.getRetrofit().create(ApiInterface.class);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_SMS}, 101);
        }

        //call this function on click event for BUY or CHECKOUT button
        generateCheckSum();
    }

    private void generateCheckSum() {
        Call<Checksum> call = apiServicePaytm.getChecksum(
                Config.PAYTM_MERCHANT_ID,
                orderId,
                custid,
                "WAP",
                "100",
                "WEBSTAGING",
                Config.url_paytm_callback,
                "Retail"
        );

        call.enqueue(new Callback<Checksum>() {
            @Override
            public void onResponse(Call<Checksum> call, Response<Checksum> response) {
                Checksum checksum = response.body();

                PaytmPGService Service = PaytmPGService.getStagingService();
                // when app is ready to publish use production service
                // PaytmPGService  Service = PaytmPGService.getProductionService();
                
                //below parameter map is required to construct PaytmOrder object, Merchant should replace below map values with his own values
                HashMap<String, String> paramMap = new HashMap<String, String>();
                //these are mandatory parameters
                paramMap.put("MID", Config.PAYTM_MERCHANT_ID); //MID provided by paytm
                paramMap.put("ORDER_ID", orderId);
                paramMap.put("CUST_ID", custid);
                paramMap.put("CHANNEL_ID", "WAP");
                paramMap.put("TXN_AMOUNT", "100");
                paramMap.put("WEBSITE", "WEBSTAGING");
                paramMap.put("CALLBACK_URL" ,Config.url_paytm_callback);
                //paramMap.put( "EMAIL" , "abc@gmail.com");   // no need
                //paramMap.put( "MOBILE_NO" , "999999999");  // no need
                paramMap.put("CHECKSUMHASH" ,checksum.getChecksumHash());
                //paramMap.put("PAYMENT_TYPE_ID" ,"CC");    // no need
                paramMap.put("INDUSTRY_TYPE_ID", "Retail");
                PaytmOrder Order = new PaytmOrder(paramMap);

                Service.initialize(Order,null);

                // start payment service call here
                Service.startPaymentTransaction(ActCart.this, true, true,
                        ActCart.this  );

            }

            @Override
            public void onFailure(Call<Checksum> call, Throwable t) {

            }
        });
    }

    @Override
    public void onTransactionResponse(Bundle bundle) {
        //handle 
    }

    @Override
    public void networkNotAvailable() {
    }

    @Override
    public void clientAuthenticationFailed(String s) {
    }

    @Override
    public void someUIErrorOccurred(String s) {
    }

    @Override
    public void onErrorLoadingWebPage(int i, String s, String s1) {
    }

    @Override
    public void onBackPressedCancelTransaction() {
    }

    @Override
    public void onTransactionCancel(String s, Bundle bundle) {
    }

}