Flutter Mobile SDKs

Integrate Pine Labs payments into your mobile application using our Flutter Native SDK.

Integration Steps

Learn how you can integrate with Pine Labs native SDK across all platforms. The SDK provides a secure hosted checkout experience using backend APIs and client-side SDKs for seamless payment processing.

  1. Prerequisites
  2. Integrate APIs in Your Backend
  3. SDK Installation and Initialization
  4. Handle Payments
  5. Manage Transactions

❗️ Security Best Practices:

  • Ensure you store your client_id and client_secret in your Backend securely.
  • Integrate our APIs on your backend system.
  • We strictly recommend not to call our APIs from the frontend.
  • Failure to adhere to the above guidelines may result in legal implications. In such cases, you will be held responsible for any damage or loss arising from non-compliance.

1. Prerequisites

Before integrating the SDK, ensure your Flutter project meets the following requirements:

RequirementVersion
Flutter3.3.0 or later
Dart SDK3.11.1 or later
AndroidAndroid 8.0+, API level 26 or later
iOSiOS 13.0 or later

Minimum Compatibility Matrix

Platform and Build Environment

CategoryMinimum SupportedNotes
Flutter Version3.3.0Apps must use Flutter 3.3.0 or higher
Dart SDK3.11.1Required for null-safe SDK APIs
Android minSdkAPI 26 (Android 8.0)Required by the Pine Labs Android SDK
Android compileSdkAPI 34+Recommended to use latest stable
iOS Deployment TargetiOS 13.0Required by the Pine Labs iOS SDK
Xcode VersionXcode 15.0+Required to build iOS 13+ apps
Swift Version5.0+Required for the iOS plugin
Kotlin2.x+Used in the Android plugin
Java Compatibility17Required for Android compilation

Supported Platforms

PlatformSupported
Android (phone/tablet)
iOS (iPhone/iPad)
Web❌ Not supported
macOS Desktop❌ Not supported
Windows Desktop❌ Not supported
Linux Desktop❌ Not supported

Native SDK Dependencies

The following packages are included automatically as transitive dependencies. You do not need to add them manually to your app.

PlatformDependencyVersionSource
Androidcom.github.plural-pinelabs:Pinelabs-Android-SDK1.1.6JitPack
iOSPineLabsOnline_IOS_SDK.xcframeworkBundledVendored in plugin

Flutter Dependencies

PackageVersionPurpose
plugin_platform_interface^2.0.2Platform channel abstraction

Unsupported Configurations

The SDK does not support the following configurations:

  • Flutter versions below 3.3.0
  • Dart SDK versions below 3.11.1
  • Android apps with minSdk below 26
  • iOS apps targeting below iOS 13.0
  • Web, Desktop (macOS, Windows, Linux) platforms

2. Integrate APIs in Your Backend

Start a payment by triggering the payment flow. To start a payment follow the below steps:

2.1. Generate Auth Token

Integrate our Generate Token API in your backend servers to generate the auth token. Use the token generated to authenticate Pine Labs Online APIs.

Below are the sample requests and response for the Generate Token API.

cURL
curl --location 'https://pluraluat.v2.pinepg.in/api/auth/v1/token' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --header 'Request-Timestamp: 2024-07-09T07:57:08.022Z' \ --header 'Request-ID: c17ce30f-f88e-4f81-ada1-c3b4909ed235' \ --data ' { "client_id": "a17ce30e-f88e-4f81-ada1-c3b4909ed232", "client_secret": "fgwei7egyhuggwp39w8rh", "grant_type": "client_credentials" } '

Refer to our Generate Token API documentation to learn more.

2.2. Generate Checkout Link

Use this API to Generate a checkout link, for authentication use the generated access token in the headers of the API request.

Below are the sample requests and response for a Generate Checkout Link API.

cURL
curl --location 'https://pluraluat.v2.pinepg.in/api/checkout/v1/orders' \ --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \ --header 'Content-Type: application/json' \ --header 'Request-ID: c17ce30f-f88e-4f81-ada1-c3b4909ed235' \ --header 'Request-Timestamp: 2024-07-09T07:57:08.022Z' \ --header 'accept: application/json' \ --data ' { "merchant_order_reference": "f4c45dbd-6eba-453d-b317-158c6ba12825", "order_amount": { "value": 500, "currency": "INR" }, "purchase_details": { "customer": { "email_id": "joe.sam@gmail.com", "first_name": "joe", "last_name": "kumar", "customer_id": "192212", "mobile_number": "192192883", "country_code": "91", "billing_address": { "address1": "H.No 15, Sector 17", "address2": "", "address3": "", "pincode": "61232112", "city": "CHANDIGARH", "state": "PUNJAB", "country": "INDIA" }, "shipping_address": { "address1": "H.No 15, Sector 17", "address2": "", "address3": "", "pincode": "144001123", "city": "CHANDIGARH", "state": "PUNJAB", "country": "INDIA" } }, "merchant_metadata": { "key1": "value1", "key2": "value2" }, "integration_mode": "SDK" } } '

Refer to our Generate Checkout Link documentation to learn more.

3. SDK Installation & Initialization

Installation

Add the SDK Dependency

Open your Flutter project’s pubspec.yaml file and add pinelabs_native under dependencies.

YAML
dependencies: flutter: sdk: flutter pinelabs_native: ^1.0.0

Then run:

Bash
flutter pub get

This downloads the SDK and all required dependencies automatically.

Android Configuration

The SDK requires Android 8.0 or later, which corresponds to API level 26.

Set Minimum SDK Version

Open your app’s android/app/build.gradle.kts or android/app/build.gradle file and ensure minSdk is set to 26 or higher:

Kotlin
android { defaultConfig { minSdk = 26 // ... } }

📘 Note:

  • If your app already targets minSdk 26 or higher, no changes are needed. If your current minSdk is lower than 26, you must update it to 26.

Add JitPack Repository

The Android component of the SDK depends on the Pine Labs Android SDK hosted on JitPack.

Open your project-level:

Code
settings.gradle.kts

and ensure JitPack is added under repositories.

Kotlin
dependencyResolutionManagement { repositories { google() mavenCentral() maven("https://jitpack.io") } }

For older Gradle projects that use allprojects in the root build.gradle, add JitPack there instead.

Gradle
allprojects { repositories { google() mavenCentral() maven { url 'https://jitpack.io' } } }

Add Internet Permission

The SDK requires internet access. Most Flutter apps already include this permission, but verify that your android/app/src/main/AndroidManifest.xml file contains:

XML
<uses-permission android:name="android.permission.INTERNET" />

📘 Note:

  • The native Android SDK handles UPI intent schemes and payment app queries internally.

iOS Configuration

The SDK requires iOS 13.0 or later.

Set iOS Deployment Target

Open your ios/Podfile and ensure the platform version is set to 13.0 or higher:

Ruby
platform :ios, '13.0'

Add UPI Query Schemes in Info.plist

To allow the SDK to detect and launch UPI payment apps installed on the user’s device, declare the required URL schemes in your app’s Info.plist.

Open ios/Runner/Info.plist and add:

XML
<key>LSApplicationQueriesSchemes</key> <array> <string>bhim</string> <string>cred</string> <string>credpay</string> <string>tez</string> <string>paytmmp</string> <string>phonepe</string> <string>kiwi</string> <string>mobikwik</string> </array>

Starting from iOS 9, apps must declare the URL schemes they intend to query using LSApplicationQueriesSchemes.

Without these entries, the SDK will not be able to detect installed UPI apps, and payment app redirection may fail silently.

Initialize the SDK

Import the SDK in your Dart file:

Dart
import 'package:pinelabs_native/pinelabs_native.dart';

Create an SDK instance:

Dart
final sdk = const PinelabsFlutterSdk();

The SDK instance is lightweight and can be created as const. You can create it once and reuse it across multiple payment calls.

Start a Payment

Use the startPayment method to initiate a payment.

Your backend creates an order using the Generate Checkout Link API and receives a token in the response. Pass this token directly to the SDK.

Dart
Future<void> startPayment(String orderToken) async { final sdk = const PinelabsFlutterSdk(); final result = await sdk.startPayment( PinelabsPaymentRequest( orderToken: orderToken, environment: PinelabsEnvironment.uat, // Use .prod for production ), ); if (result.isSuccess) { // Payment was successful print('Order ID: ${result.orderId}'); } else { // Payment failed, was cancelled, or user pressed back print('Status: ${result.status.name}'); print('Message: ${result.message}'); } }

Parameters

ParameterTypeRequiredDescription
TokenStringYesThe token returned in the response of our Generate Checkout Link API. This token authenticates and identifies the payment session.
environmentPinelabsEnvironmentYesThe SDK environment. Use PinelabsEnvironment.uat for testing and PinelabsEnvironment.prod for production.

Extract the Token

You will get Token in the response of the Generate Checkout Link api, use this token to initiate the SDK.

Example token:

Code
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "order_id": "v1-5757575757-aa-hU1rUd", "redirect_url": "https://api.pluralonline.com/api/v3/checkout-bff/redirect/checkout?token=REDIRECT_TOKEN", "response_code": 200, "response_message": "Order Creation Successful." }

In this case, the Token is:

Code
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Complete Flutter Integration Example

Below is an example showing how to integrate the SDK in a Flutter app:

Dart
import 'package:flutter/material.dart'; import 'package:pinelabs_native/pinelabs_native.dart'; class CheckoutScreen extends StatefulWidget { const CheckoutScreen({super.key}); @override State<CheckoutScreen> createState() => _CheckoutScreenState(); } class _CheckoutScreenState extends State<CheckoutScreen> { final _sdk = const PinelabsFlutterSdk(); final _tokenController = TextEditingController(); bool _isProcessing = false; PinelabsPaymentResult? _lastResult; @override void dispose() { _tokenController.dispose(); super.dispose(); } Future<void> _startPayment() async { final token = _tokenController.text.trim(); if (token.isEmpty) return; setState(() => _isProcessing = true); try { final result = await _sdk.startPayment( PinelabsPaymentRequest( orderToken: token, environment: PinelabsEnvironment.uat, // Use .prod for production ), ); if (!mounted) return; setState(() => _lastResult = result); switch (result.status) { case PinelabsPaymentStatus.success: _showMessage('Payment Successful! Order: ${result.orderId}'); // Important: // Verify the payment on your backend using the Order Inquiry API // before fulfilling the order. break; case PinelabsPaymentStatus.failure: _showMessage('Payment Failed: ${result.message}'); break; case PinelabsPaymentStatus.cancelled: _showMessage('Payment Cancelled: ${result.message}'); break; case PinelabsPaymentStatus.backPressed: _showMessage('User pressed back'); break; } } catch (e) { if (!mounted) return; _showMessage('Error: $e'); } finally { if (mounted) { setState(() => _isProcessing = false); } } } void _showMessage(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message)), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Checkout'), ), body: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextField( controller: _tokenController, decoration: const InputDecoration( labelText: 'Order Token', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), FilledButton( onPressed: _isProcessing ? null : _startPayment, child: Text(_isProcessing ? 'Processing...' : 'Pay Now'), ), ], ), ), ); } }

📘 Important:

  • Always confirm the final payment status from your backend by calling the Get Order by Order ID API with the order ID. Do not use the client-side SDK response alone to fulfil or complete an order.

4. Handle Payments

You need to implement call-back methods to handle your payment responses. This will provide the payment status and reason for transaction failures. Based on the reasons for failures, handling can be built at your end. Transaction callbacks can be listened to via overriding methods of EdgeResponseCallback.

PaymentResult

Both SDK payment methods return a PaymentResult object when the payment flow ends.

Code
class PinelabsPaymentResult { final PinelabsPaymentStatus status; // Payment outcome status final String? orderId; // Order ID from the payment gateway final String? code; // Response code from the gateway final String? message; // Descriptive message from the gateway bool get isSuccess; // Convenience getter: true if status == success }

PaymentStatus

The SDK returns one of the following standard status values:

StatusValueDescription
PinelabsPaymentStatus.successsuccessPayment completed successfully. The order ID is available in result.orderId.
PinelabsPaymentStatus.failurefailurePayment failed due to bank decline, timeout, or other error. Check result.message for details.
PinelabsPaymentStatus.cancelledcancelledUser cancelled the payment from within the native payment UI.
PinelabsPaymentStatus.backPressedbackPressedUser pressed the system back button (Android) or swipe-to-dismiss (iOS) to exit the payment screen.

Handling Payment Outcomes

Use the status field in PaymentResult to handle each payment outcome.

Dart
final result = await sdk.startPayment( PinelabsPaymentRequest( orderToken: orderToken, environment: PinelabsEnvironment.uat, ), ); switch (result.status) { case PinelabsPaymentStatus.success: // Payment succeeded. // result.orderId contains the gateway order ID. // ALWAYS call your backend Order Inquiry API to confirm. break; case PinelabsPaymentStatus.failure: // Payment failed. // result.code contains the error code from the gateway. // result.message contains a human-readable error description. // Show an appropriate message and offer retry. break; case PinelabsPaymentStatus.cancelled: // User cancelled the payment within the payment UI. // result.message describes the cancellation reason. // Offer the user an option to retry. break; case PinelabsPaymentStatus.backPressed: // User pressed the back button to exit the payment screen. // result.message contains a description of the action. // Offer the user an option to retry or go back. break; }

UPI and External App Handling

The native SDKs handle all UPI intent routing internally. When the payment flow requires opening an external UPI app (GPay, PhonePe, Paytm, CRED, etc.):

  • The native SDK detects and launches the appropriate UPI app.
  • When the user completes or cancels the payment in the external app, the native SDK receives the callback.
  • The result is returned to Flutter automatically.

No additional code is required in your Flutter app. UPI app handling is fully managed by the native SDK.

Error Handling

PlatformException

If the native SDK encounters an internal error before it can return a structured result, the startPayment call will throw a PlatformException. Always wrap your SDK call in a try-catch:

Dart
try { final result = await sdk.startPayment(request); // Handle result... } on PlatformException catch (e) { // Native SDK error print('Error code: ${e.code}'); print('Error message: ${e.message}'); } catch (e) { // Unexpected error print('Unexpected error: $e'); }

Common Error Codes

CodeDescriptionResolution
INVALID_ARGSArguments are missing or malformed.Ensure you are passing a valid PinelabsPaymentRequest.
INVALID_TOKENThe orderToken is empty or null.Ensure the order token is not empty. Check your Create Hosted Checkout API response.
INVALID_ENVIRONMENTThe environment value is not recognized.Use only PinelabsEnvironment.uat or PinelabsEnvironment.prod.
NO_ACTIVITY (Android)No Android activity is available to launch the SDK.Ensure you are calling startPayment from a widget that is attached to a running activity.
NO_VIEW_CONTROLLER (iOS)No root view controller is available.Ensure you are calling startPayment after the app UI is fully loaded.
PAYMENT_IN_PROGRESS (Android)Another payment is already in progress.Wait for the current startPayment call to complete before starting a new one.
NULL_RESPONSENative SDK returned no response.This is unexpected. Retry the payment or contact support.

5. Manage Transactions

Track and verify transaction status using Pine Labs APIs. To retrieve the latest status, use the Fetch APIs or subscribe to webhooks for real-time transaction updates.

Get Order by Order ID

Fetch real-time transaction status by order ID.

Learn More →

Webhooks

Configure webhook events for automatic transaction updates.

Learn More →