#Cross platform integration with your own payment gateway
This quickstart explains how to integrate when you opt for your own payment gateway. Use this guide for Setu’s default UPI payment option.
In case you are using a cross platform solution—like Flutter, React Native, Ionic—for your Android and iOS apps, you can refer to the code snippets provided below for a custom payment integration. The integration process remains the same, but changes as per the language you use.
The code snippets provided below deal specifically with how the web view is loaded and dismissed within your Android/iOS app. Usage of the Create Link API will remain unaffected.
#Flutter
#Step 1 - Implement webview in your app
The following steps need to be taken for webview integration—
- Get link from the backend
- Open the link in
InAppWebView
and attach aWebViewController
- Execute payment flow and redirect back to the
InWebView
post payment
Switch control from your app to Setu
The link returned by the Create link API should be loaded within the Webview. Our sample below uses the flutter_inappwebview plugin for webviews. Feel free to use a plugin as per your requirements.
The controller
will need to implement two JavaScript handlers -
initiatePayment
- Used to initiate payment & transfer control from Setu webview to the flutter application.unload
- Used by the parent app to dismiss the webview
Special use case: This unload
function can also be used for dismissing the webview and redirecting a user back to your native app once a bill payment journey is completed (i.e. payment is successful) via a CTA from the Setu webview. Please let our team know if you would like to enable this use case for your app.
Note: For downloading and saving transaction receipts from the webview, the webview will need to handle a onDownloadStartRequest
(or a similar function as per your webview plugin). Our sample below uses the flutter_downloader and path_provider plugins for downloading and saving transaction receipts. Please follow the plugin specific documentation for implementation. Make sure you have added necessary permissions in your AndroidManifest.xml
and Info.plist
files for downloading and saving files.
import 'dart:io';import 'dart:isolate';import 'dart:ui';import 'package:flutter/material.dart';import 'package:url_launcher/url_launcher.dart';import 'package:flutter_inappwebview/flutter_inappwebview.dart';import 'package:flutter_downloader/flutter_downloader.dart';import 'package:path_provider/path_provider.dart';Future main() async {WidgetsFlutterBinding.ensureInitialized();await FlutterDownloader.initialize(debug: true, // optional: set false to disable printing logs to console);runApp(new MyApp());}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(home: RpWebPage(link: 'https://billpay.setu.co/1234',), // Replace with the actual URL);}}class RpWebPage extends StatefulWidget {const RpWebPage({super.key, required this.link});final String link;@overrideState<RpWebPage> createState() => _RpWebPageState();}class _RpWebPageState extends State<RpWebPage> {late InAppWebViewController webView;bool isButtonClicked = false;@overridevoid initState() {super.initState();}void _loadUrl() {setState(() {isButtonClicked = true;});}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Bill Payments'),),body: Column(children: [if (!isButtonClicked)ElevatedButton(onPressed: _loadUrl,child: Text('Load webview'),),Expanded(child: isButtonClicked? InAppWebView(initialSettings: InAppWebViewSettings(allowFileAccess: true,allowFileAccessFromFileURLs: true),initialUrlRequest: URLRequest(url: WebUri.uri(Uri.parse(widget.link))),onWebViewCreated: (InAppWebViewController controller) {webView = controller;},onLoadStop: (controller, url) async {controller.addJavaScriptHandler(handlerName: 'initiatePayment',callback: (args) async {print('Received from WebView: $args');var paymentData = args[0];print('Payment data: $paymentData');// add your custom payment logic here},);controller.addJavaScriptHandler(handlerName: 'unload',callback: (args) async {// logic to close webview and return to app},);},// Handle downloading the receiptonDownloadStartRequest: (controller, request) async {print("onDownloadStart $request");final dir = Platform.isAndroid? (await getExternalStorageDirectory())?.path: (await getApplicationDocumentsDirectory()).uri.path;print("saving in $dir");final taskId = await FlutterDownloader.enqueue(url: request.url.toString(),savedDir: dir!,showNotification: true, // show download progress in status bar (for Android)openFileFromNotification: true, // click on notification to open downloaded file (for Android)saveInPublicStorage: true,allowCellular: true);// Open the downloaded fileawait FlutterDownloader.open(taskId: taskId!);},): Container(),),],),);}}
Handle payment flow
The initiatePayment
method in the controller
takes an object param with the following fields
orderId
on the Setu COU System. It always starts withCOUWL
. Example—COUWLZ7pFtTgr9LtO
amount
to be paid by the customer. Example —3522.20
callback
URL which needs to be loaded in the webview once the payment is completed. Example —https://billpay.setu.co/payment-callback/68c7217b-8fa7-4c1f-8e5f-317ff3027668
beneVpa
to which amount is to be transferred—this is relevant only if you can transfer in real time using UPI rails.remarks
used to communicate information between mobile app and webviewmobileNumber
mobile number used for the session. Example -9876543210
refId
BBPS reference ID linked to a particular bill (only available for fetch billers). Example -CMA0I65RCU2I32C3L0H0KNYQYAG40021831
customerId
linked to a particular session. Example -cust@1234
allowedPaymentModes
comma separated list of modes allowed for this payment. One of these should be sent in thepaymentMode
in the payment confirmation webhook.
When initiate_payment case is called by the webview, your app needs to do the following—
- Remove the webview
- Initiate the payment flow
- Send Setu the webhook event for payment—this need not be done for UPI transfers in real time
- Once payment is executed, load the webview again with the callback URL
#Step 2 — Optionally configure webhook
You may optionally want to listen to user events—like successful or failed bill fetch, bill payment status and more—through webhooks. Refer to this guide for more information.
#Step 3 — Get Production credentials and go live
Once you are done testing your integration, ensure that all KYC and legal agreements are submitted. Contact Setu for getting enabled on production.
We are updating the docs for custom payment based integration for other cross platform frameworks like React native
Please bear with us for a while.
Was this page helpful?