• Callback Response
  • Getting Started
    • Mobile Integration (Android/IOS)
      Enterprise Solutions
      Retail Solutions
      Accept Payments
      Process Payments
      Paytm Payouts
      API References
      Refunds
      Guides
      Other links
      Mini Apps Platform
  • Features for Investments PG
  • All-in-One SDK Integration in Flutter App

    For merchants who have built their app on Flutter paltform - Paytm provides a bridge for you to conveniently integrate All-in-One SDK. In this document, we will highlight the steps required to integrate All-in-One SDK with Flutter platform for your app. This platform helps you to build a seamless and responsive checkout experience for your application.

    This integration will support following two flows:

    App Invoke Flow: In case Paytm app is installed, it will be launched to complete the transaction and give the response back to your app.

    Redirection Flow : In case Paytm app is not installed, All-in-One SDK will open a webview to process transaction and give the response back to your app.

    Overview of payment processing in Flutter App

    1. On your mobile app, the user adds goods/services into the shopping/order cart and proceeds to checkout. You call Initiate Transaction API from your backend to generate transaction token.
      Within the Initiate Transaction API you also get an option to include single or multiple payment sources for the users, thus, allowing you to make your own payment page with multiple payment sources.
    2. Launch the Hybrid app bridge to invoke Paytm All-in-One SDK with the transaction token received in step 1.
    3. If Paytm app is installed on user's phone, the payment will be completed on Paytm app using user's saved credentials else transaction will be processed via web view within the All-in-One SDK(Paytm hosted redirection flow).
    4. Paytm processes the transaction with the user’s bank and returns the transaction response to your app.
    5. You call the Transaction Status API to verify the transaction response.
    6. Notify the payment status to the user and proceed with the order/service fulfillment.

    Pre-requisites

    1. Create an account on Paytm as a merchant. Click on how to create an account.
    2. Get the merchant id and merchant key for the integration environment after creating the account.
    3. Go through the checksum logic to understand how to generate and validate the checksum.
    4. Get the staging android or iOS paytm app for integration testing on the merchant staging enviornment.
    5. Go through All-in-One SDK documentation before proceeding with integration.
    6. Call Initiate Transaction API from your backend to generate Transaction Token.

    Please go through the following steps to integrate All-in-One SDK in your flutter app:

    Android Project of Flutter

    1. Add the below line to ‘repositories’ section of your project level build.gradle file
      maven {
         url "https://artifactory.paytm.in/libs-release-local"
      }
    2. Add below line to ‘dependencies’ section of your App build.gradle
      implementation “com.paytm.appinvokesdk:appinvokesdk:1.5
    3. Add AllInOneSDKPlugin class in your project (see Appendix at the end of this document)
    4. In the pre-existing MainApplication class make changes as shared in doc (see Appendix)
    5. Update setResult method in AllInOneSDKPlugin class as per your response requirement in the flutter app.
    6. Call startTransaction method from your Flutter App to invoke Paytm module.
    For further queries visit - https://developer.paytm.com/docs/all-in-one-sdk/
    Note: Please change minSDKversion to ‘18’ in your project level build.gradle file

    Flutter Project

    1. Import services.dart package.
      import 'package:flutter/services.dart';
    2. Using MethodChannel create a link to AllInOneSDKPlugin of Android project.
      var CHANNEL = "samples.flutter.dev/allInOne"; //CHANNEL as set in MainActivity of android project. 
      static const platform = const MethodChannel('CHANNEL');
    3. Start process by calling platform.invokeMethod with the appropriate arguments
      var arguments = <String, dynamic>{
          "mid": mid,
          "orderId": orderId,
          "amount": amount,
          "txnToken": txnToken,
          "callbackUrl": callbackUrl, //send this if custom callback url is required
          "isStaging": isStaging
      };
      try {
          var result = await platform.invokeMethod("startTransaction", arguments);
          print(result.toString());
      } catch (err) {
          print(err.message);
      }
      AttributesDescriptionMandatory
      orderidString(50)Unique reference ID for a transaction which is generated by merchant Special characters allowed in Order ID are: "@" "-" "_" ".".Yes
      midString(20)This is a unique identifier provided to every merchant by Paytm. MID is part of your account credentials and is different on staging and production environment.Yes
      txnTokenStringTransaction token received from calling Initiate Transaction API (Note - pass same order id in sdk which was used for initiateTransaction).Yes
      amountStringAmount in INR payable by customer. Should contain digits up to two decimal points. The amount should not include any separator like (",")Yes
      callbackurlString(255)On completion of transaction, Paytm payment gateway will send the response on this URL. This can be a static response URL as mentioned below:
      Staging Environment: "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=<order_id>"
      Production Environment: "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=<order_id>"
      Yes
      IsStagingBooleanIsStaging is to define staging or production server (True for staging and False for production) Yes
    4. Callback will be received in the above “result” as below string in case of transaction success or failure else “error will be thrown” which will have a string message like onBackedPressed, networkError etc. You can handle this as per your requirement in the AllInOneSDKPlugin.setResult method which is in your flutter android project.
      1. In case of App Invoke flow, response will be received in onActivityResult
      2. In case of Redirection flow (WebView), response will be received in PaytmPaymentTransactionCallback interface.

        Sample Response
        Bundle[
            {
                STATUS=TXN_SUCCESS, 
                ORDERID=”Order Id”, 
                CHARGEAMOUNT=0.00, 
                TXNAMOUNT=1.00, 
                TXNDATE=2020-07-21 19:00:05.0, 
                MID=”Merchant Id”, 
                TXNID=”Transaction Value”, 
                RESPCODE=01, 
                PAYMENTMODE=UPI, 
                BANKTXNID=”Bank transaction Id”, 
                CURRENCY=INR, 
                GATEWAYNAME=ICICI, 
                RESPMSG=Txn Success
            }
        ]
    5. Verifying Payment

      1. You should validate transaction response via a server-side request using the Transaction Status API. This API requires checksumhash in request and response. You must verify the Order ID and Amount with your data. The status should be treated as the final status of the transaction in all cases.
      2. Paytm provides payment response on both Callback URL and Webhook URL. Please refer to the sample response for different payment sources here.

    Appendix

    MainActivity.kt
    package
    import android.content.Intent
    import io.flutter.embedding.android.FlutterActivity
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodChannel
     
    class MainActivity: FlutterActivity() {
       private val CHANNEL = "samples.flutter.dev/allInOne" //Change as per project
       private lateinit var plugin : AllInOneSDKPlugin
     
       override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
           super.configureFlutterEngine(flutterEngine)
           MethodChannel(flutterEngine.dartExecutor.binaryMessenger,CHANNEL).setMethodCallHandler { call, result ->
               plugin = AllInOneSDKPlugin(this,call,result)
           }
        }
     
       override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
           super.onActivityResult(requestCode, resultCode, data)
           plugin.onActivityResult(requestCode,resultCode,data)
        }
    }
    AllInOneSDKPlugin.kt
    package 
    import android.app.Activity
    import android.content.Intent
    import android.os.Bundle
    import android.widget.Toast
    import com.paytm.pgsdk.PaytmOrder
    import com.paytm.pgsdk.PaytmPaymentTransactionCallback
    import com.paytm.pgsdk.TransactionManager
    import io.flutter.plugin.common.MethodCall
    import io.flutter.plugin.common.MethodChannel
     
    class AllInOneSDKPlugin(var activity: Activity, var call: MethodCall, var result: MethodChannel.Result) {
        private val REQ_CODE = 0
        init {
                if (call.method == "startTransaction") {
                    startTransaction()
                }
        }
        private fun startTransaction() {
            val arg = call.arguments as Map<*, *>?
            if (arg != null) {
                val mid = arg["mid"] as String?
                val orderId = arg["orderId"] as String?
                val amount = arg["amount"] as String?
                val txnToken = arg["txnToken"] as String?
                val callbackUrl = arg["callbackUrl"] as String?
                val isStaging = arg["isStaging"] as Boolean
                if (mid == null || orderId == null || amount == null || mid.isEmpty() || orderId.isEmpty() || amount.isEmpty()) {
                    showToast("Please enter all field")
                    return
                }
                if (txnToken == null || txnToken.isEmpty()) {
                    showToast("Token error")
                    return
                }
                initiateTransaction(mid, orderId, amount, txnToken, callbackUrl, isStaging)
            } else {
                showToast("Please send arguments")
            }
        }
        private fun initiateTransaction(mid: String, orderId: String, amount: String, txnToken: String, callbackUrl: String?, isStaging: Boolean) {
            var host = "https://securegw.paytm.in/"
            if (isStaging) {
                host = "https://securegw-stage.paytm.in/"
            }
            val callback = if (callbackUrl == null || callbackUrl.trim().isEmpty()) {
                host + "theia/paytmCallback?ORDER_ID=" + orderId
            } else {
                callbackUrl
            }
            val paytmOrder = PaytmOrder(orderId, mid, txnToken, amount, callback)
            val transactionManager = TransactionManager(paytmOrder, object : PaytmPaymentTransactionCallback {
                override fun onTransactionResponse(bundle: Bundle) {
            //Return in both cases if transaction is success or failure
                    setResult("Payment Transaction response $bundle", true)
                }
                override fun networkNotAvailable() {
                    setResult("networkNotAvailable", false)
                }
                override fun onErrorProceed(s: String) {
                    setResult(s, false)
                }
                override fun clientAuthenticationFailed(s: String) {
                    setResult(s, false)
                }
                override fun someUIErrorOccurred(s: String) {
                    setResult(s, false)
                }
                override fun onErrorLoadingWebPage(iniErrorCode: Int, inErrorMessage: String, inFailingUrl: String) {
                    setResult(inErrorMessage, false)
                }
                override fun onBackPressedCancelTransaction() {
                    setResult("onBackPressedCancelTransaction", false)
                }
                override fun onTransactionCancel(s: String, bundle: Bundle) {
                    setResult("$s $bundle", false)
                }
            })
            transactionManager.setShowPaymentUrl(host + "theia/api/v1/showPaymentPage")
            transactionManager.startTransaction(activity, REQ_CODE)
        }
        fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            if (requestCode == REQ_CODE && data != null) {
                val message = data.getStringExtra("nativeSdkForMerchantMessage")
                val response = data.getStringExtra("response")
        // data.getStringExtra("nativeSdkForMerchantMessage") this return message if transaction was stopped by users
        // data.getStringExtra("response") this returns the shared response if the transaction was successful or failure.
                if(response !=null &&  response.isNotEmpty()){
                    setResult(response,true)
                }else{
                    setResult(message,false)
                }
            }
        }
        private fun setResult(message: String, isSuccess: Boolean) {
            if (isSuccess) {
                result.success(message)
            } else {
                result.error("0", message, null)
            }
        }
        private fun showToast(message: String) {
            Toast.makeText(activity, message, Toast.LENGTH_LONG).show()
        }
    }