In today's digital era, businesses are constantly seeking secure and reliable payment gateways to facilitate seamless transactions. CCAvenue is a popular payment gateway in India, offering a wide range of payment options for online businesses. In this blog, we will explore how to integrate CCAvenue into a Flutter application using PHP server.
Note: There is no official SDK available for flutter, so we are going to integrate through Flutter Webview.
Prerequisites:
Before we begin, make sure you have the following requirements in place:
- Flutter SDK installed on your machine
- Basic knowledge of Flutter and PHP
- CCAvenue merchant account credentials
Note: CCAvenue does not allow payment transaction in live or test mode until you whitelist your Domain/IP. For Whitelisting your domain, you can email them.
Lets understand how does transaction Handle through CCAvenue?
CCAvenue has two phase for completing transaction
-
Initiate Payment : In this step,client send
amount
andcurrency
and other required details to server and than server encrypt these values to a single encrypted(lets saysenc_val
) string and sendenc_val
andaccess_code
to client.
Note: When your CCAvenue approved and whitelisted for transaction then you can get following
access_code
,working_key
andmerchant_id
from CCAvenue.
- Generate enc_val: Merchant need to encrypt following set of parameters using encryption tool provided by CCAvenue(We will use PHP)
We will encrypt following String:
merchant_id=123&order_id=123456redirect_url=www.amazonaws.com/payment
/ccav_resp.phpcancel_url=www.amazonaws.com/payment/ccav_resp.phpamount=1.00¤cy=INR
after encryption we will get string like
a5eed2d2a51358773bb1de741b0b2f1261308043c2a8f78bf59d9d3d5081f785792599d64876
220964ebdd1578ce633aae959b804f2b2d53cda3821baf5480b3a082ea89a0e6784af4fef98e0
54f3a5c78f0ec9e611a01dd7666e9903e6b5d62c7a11d8db869d665c0077a292cfa6aba80a1ab
a94882168ede009b2c3806a4b08c781e2e5a7d54411b5a288ff28d499bc9de
Parameter Name | Description | Type (length) |
---|---|---|
Merchant Id | Merchant Id is a unique identifier generated by CCAvenue for each activated merchant. | Numeric |
Order Id | This ID is used by merchants to identify the order. Ensure that you send a unique id with each request. CCAvenue will not check the uniqueness of this order id. As it generates a unique payment reference number for each order which is sent by the merchant. | Alphanumeric (30) |
Redirect Url | CCAvenue will post the status of the order along with the parameters to this URL. | Alphanumeric (100) |
Cancel Url | CCAvenue will redirect the customer to this URL if the customer cancels the transaction on the billing page. | Alphanumeric (100) |
Amount | Order amount | Numeric (12, 2) |
Currency | Currency in which you want to process the transaction. AED - Arab Emirates dirham USD - United States Dollar SAR - Saudi Arabia Riyal INR – Indian Rupee SGD – Singapore Dollar GBP – Pound Sterling EUR – Euro, official currency of Eurozone |
Alphabets (3) |
Note: we will talk about
cancel_url
andredirect_url
in the next steps.
- Start payment in WebView: you can start payment in webview through following url
https://secure.ccavenue.com/transaction.do?command=initiateTransaction&encRequest=enc_val&access_code=access_code
Note for testing replace
secure.ccavenue.com
totest.ccavenue.com
.
-
Response Handler: When a user completes a payment, either in case of failure or success, CCAvenue will send an encrypted string to either the redirect_url or cancel_url using a POST request.
-
redirect_url
: It refers to a webpage hosted on your server's domain/IP, which must be whitelisted by CCAVenue. This webpage will handle the necessary steps after the payment request is completed, including handling both failure and success scenarios. -
cancel_url
: Similar to theredirect_url
, thecancel_url
is also hosted on your server's domain/IP. However, it specifically handles requests where the user cancels the payment.
-
Now we will use decryption tool to decrypt string given by CCAvenue
after payment complete.
Lets Start Integration (Server Side)
- We need encryption and decryption function to encrypt and decrypted request.
create crypto.php
and with following content:
<?php | |
function encrypt($plainText, $key) | |
{ | |
$secretKey = hex2bin(md5($key)); | |
$initVector = hex2bin('000102030405060708090a0b0c0d0e0f'); | |
$encryptedText = openssl_encrypt($plainText, 'AES-128-CBC', $secretKey, OPENSSL_RAW_DATA, $initVector); | |
return bin2hex($encryptedText); | |
} | |
function decrypt($encryptedText, $key) | |
{ | |
$secretKey = hex2bin(md5($key)); | |
$initVector = hex2bin('000102030405060708090a0b0c0d0e0f'); | |
$encryptedText = hex2bin($encryptedText); | |
$decryptedText = openssl_decrypt($encryptedText, 'AES-128-CBC', $secretKey, OPENSSL_RAW_DATA, $initVector); | |
return $decryptedText; | |
} |
Install required Library:
sudo apt-get install php7.4-openssl
- Now we need to create a page that accept
POST
request and returnenc_val
andaccess_code
.
ccAvenueRequestHandler.php
<?php | |
include 'Crypto.php'; | |
$merchant_data = ''; | |
$working_key = 'WORKING_KEY'; //replace with your WORKING_KEY | |
$access_code = 'ACCESS_CODE'; //REPLACE WITH YOUR ACCESS CODE | |
$merchant_id = 'MERCHANT_ID'; //REPLACE WITH YOUR MERCHANT_ID | |
$response_url = '<YOUR-DOMAIN>//ccavResponseHandler.php'; //Redirect URL or CANCEL URL | |
$order_id = "ORD" . rand(10000, 99999999) . time(); //GENERATE RANDOM ORDER ID | |
foreach ($_POST as $key => $value) { | |
$merchant_data .= $key . '=' . $value . '&'; | |
} | |
// // randon and unique order id with time | |
// $merchant_data .= "order_id=" . $order_id; | |
$merchant_data .= 'merchant_id=' . $merchant_id . '&'; | |
$merchant_data .= 'order_id=' . $order_id . '&'; | |
$merchant_data .= 'redirect_url=' . $response_url . '&'; | |
$encrypted_data = encrypt($merchant_data, $working_key); | |
// create json of encrypted data and access code | |
$access_code = urlencode($access_code); | |
$encrypted_data = urlencode($encrypted_data); | |
$data = [ | |
'enc_val' => $encrypted_data, | |
'access_code' => $access_code, | |
]; | |
echo json_encode($data); |
Note: you can edit page as per your requirement,but later on flutter side you need JavaScript function to get desired result.
- We also need to create a page like above which accept
POST
request and return decrypted data.
ccavResponseHandler.php
<?php include 'Crypto.php';?> | |
<?php | |
$working_key = 'WORKING_KEY; //Replace with your working keys | |
$encResponse = $_POST["encResp"]; // This is the response sent by the CCAvenue Server | |
$rcvdString = decrypt($encResponse, $working_key); // Crypto Decryption used as per the specified working key. | |
$order_status = ""; | |
$decryptValues = explode('&', $rcvdString); | |
$dataSize = sizeof($decryptValues); | |
for ($i = 0; $i < $dataSize; $i++) { | |
$information = explode('=', $decryptValues[$i]); | |
$responseMap[$information[0]] = $information[1]; | |
} | |
$order_status = $responseMap['order_status']; | |
echo json_encode($responseMap); |
Note: Following url should be accessible through whitelisted domain
https://your-domain/ccavResponseHandler.php
.
Integration in Flutter(Client):
- Adding following to
pubspec.yaml
```
dependencies:
http: ^0.13.6
webview_flutter: ^2.0.6
html:
- Android Configuration: Change in `build.gradle`(android/app)
android {
defaultConfig {
minSdkVersion 19
}
}
- Create Payment handler Screen with following content:
lets say `payment_screen.dart`:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:html/parser.dart' show parse;
import 'package:http/http.dart' as http;
import 'package:webview_flutter/webview_flutter.dart';
//change to it false when your application is in production.
bool isTesting = true;
final Set<JavascriptChannel> jsChannels = {
JavascriptChannel(
name: 'Print',
onMessageReceived: (JavascriptMessage message) {
log(message.message.toString());
}),
};
class PaymentScreen extends StatefulWidget {
final int amount;
const PaymentScreen({Key? key, required this.amount}) : super(key: key);
@override
PaymentScreenState createState() => PaymentScreenState();
}
class PaymentScreenState extends State<PaymentScreen> {
String url = "";
bool initializedPayment = false;
String errorMessage = "";
String loadingMessage = "";
late WebViewController controller;
String cancelUrl = "CANCEL_URL";
String redirectUrl = "REDIRECT_URL";
String requestInitiateUrl = "REQUEST_INITIATE_URL";
@override
void initState() {
initAsync();
super.initState();
}
initAsync() async {
//Generating payment order and fetching URLs for the payment
try {
errorMessage = "";
loadingMessage =
"Please Do not close window,\nprocessing your request....";
setState(() {});
final res = await initPayment((widget.amount ~/ 100).toString());
url =
"https://${isTesting ? "test" : "secure"}.ccavenue.com/transaction.do?command=initiateTransaction&encRequest=${res['enc_val']}&access_code=${res['access_code']}";
initializedPayment = true;
setState(() {});
} catch (e) {
errorMessage = "Something went wrong";
} finally {
loadingMessage = "";
setState(() {});
}
}
initPayment(String amount) async {
var url = requestInitiateUrl;
Uri uri = Uri.parse(url);
var res = await http.post(uri, body: {
'currency': 'INR',
'amount': amount,
});
if (res.statusCode == 200) {
var jsonData = jsonDecode(res.body);
return jsonData;
} else {
throw Exception();
}
}
@override
Widget build(context) {
return Scaffold(
appBar: AppBar(
title: const Text("Payment Screen"),
),
body: initializedPayment
? WebView(
initialUrl: url,
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: jsChannels,
onWebViewCreated: (c) async {
controller = c;
setState(() {});
},
onPageFinished: (url) async {
if (url == redirectUrl) {
//following javascript function,could be different as per data you sent from the server
final String htmlContent = await controller
.runJavascriptReturningResult(```your javascript function to fetch data```);
final parsedJson = parse(htmlContent);
final jsonData = parsedJson.body?.text;
controller.clearCache();
final result = jsonDecode(jsonDecode(jsonData!));
log(result.toString());
//TODO: ON RESULT
}
if (url == cancelUrl) {
//TODO: ON RESULT
}
},
navigationDelegate: (NavigationRequest nav) async {
if (nav.url == redirectUrl) {
return NavigationDecision.navigate;
}
if (nav.url == cancelUrl) {
return NavigationDecision.navigate;
}
return NavigationDecision.prevent;
},
)
: (loadingMessage.isNotEmpty
? const Center(
child: CircularProgressIndicator(),
)
: (errorMessage.isNotEmpty
? Center(
child: Text(
errorMessage,
style: const TextStyle(
color: Colors.red,
),
),
)
: const SizedBox.shrink())),
);
}
}
-
isTesting
(Variable):
- Description: A boolean variable used to indicate whether the application is in testing mode or production mode.
- Type:
bool
-
jsChannels
(Variable):
- Description: A set of
JavascriptChannel
objects that define the JavaScript channels available for communication between the Flutter app and the WebView.
- Type:
Set<JavascriptChannel>
-
initPayment
(Method):
- Description: This method is responsible for initializing the payment by making an HTTP POST request to the
requestInitiateUrl
with the specified amount.
- Parameters:
-
amount
(Type: String
): The amount for the payment.
- Returns: A Future object that resolves to the payment data in JSON format.
- Type:
Future<dynamic>
-
onPageFinished
(Method):
- Description: This method is called when the WebView finishes loading a page.
- Parameters:
-
url
(Type: String
): The URL of the loaded page.
- Returns:
void
- Type:
void
-
navigationDelegate
(Method):
- Description: This method is used to control the navigation behavior of the WebView based on the requested URL.
- Parameters:
-
nav
(Type: NavigationRequest
): The navigation request object containing information about the requested URL.
- Returns: A
NavigationDecision
that determines whether to allow or prevent the navigation.
- Type:
NavigationDecision
Source code :
Follow me on
Top comments (2)
what if backend was written in nodejs?
Process going to same, you just need Library to encrypt request using encoders.
You can use this module as reference
npm.io/package/node-ccavenue