Khalti Flutter SDK (with Payment Interface)

Khalti Payment Gateway SDK for Flutter with default payment interface, works out of the box without having to add any additional user interface.


Khalti Payment Gateway

Khalti Payment Gateway for Flutter

Pub Khalti Docs BSD-3 License GitHub issues Website Follow Khalti in Facebook Follow Khalti in Instagram Follow Khalti in Twitter Subscribe Youtube Channel


Introduction

Read the introduction here.

Getting Started

Integrating Khalti Payment Gateway requires merchant account. You can always create one easily from here.

Read the steps to integrate Khalti Payment Gateway in details here.

Supported Platforms

Payment Method Android iOS Web Desktop (macOS, Linux, Windows)
Khalti Wallet ✔️ ✔️ ✔️ ✔️
E-Banking ✔️ ✔️ ✔️
Mobile Banking ✔️ ✔️ ✔️
Connect IPS ✔️ ✔️ ✔️
SCT ✔️ ✔️ ✔️

Setup

Detailed setup for each platform.

Android

In your app's AndroidManifest.xml, add these lines inside <activity>...</activity> tag:

<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="khalti" android:host="pay" />
</intent-filter>

iOS

In your app's Info.plist, add these properties:

<key>FlutterDeepLinkingEnabled</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>khalti</string>
        </array>
        <key>CFBundleURLName</key>
        <string>pay</string>
    </dict>
</array>

Web

No configuration is required for web.

Desktop

No configuration is required for desktop.

Initialization

Wrap the topmost widget of your app with KhaltiScope widget. And add supported locales and KhaltiLocalizations.delegate as shown below.

When using MaterialApp or siblings.

KhaltiScope(
  publicKey: <public-key>,
  child: (context, navigatorKey) {
    return MaterialApp(
      navigatorKey: navigatorKey,
      supportedLocales: const [
        Locale('en', 'US'),
        Locale('ne', 'NP'),
      ],
      localizationsDelegates: const [
        KhaltiLocalizations.delegate,
        ...
      ],
      ...
    );  
  } 
);

Router Approach

When using MaterialApp.router or siblings.

final routerDelegate = YourRouterDelegate();
KhaltiScope(
  publicKey: <public-key>,
  navigatorKey: routerDelegate.navigatorKey, 
  child: (context, _) {
    return MaterialApp.router(
      routerDelegate: routerDelegate,
      supportedLocales: const [
        Locale('en', 'US'),
        Locale('ne', 'NP'),
      ],
      localizationsDelegates: const [
        KhaltiLocalizations.delegate,
        ...
      ],
      ...
    );  
  } 
);

Launching Payment Interface

Khalti Payment interface can be launched in two ways:

Using KhaltiButton

The plugin includes easy to use button to launch the payment interface. It can be used as shown below:

final config = PaymentConfig(
  amount: 10000, // Amount should be in paisa
  productIdentity: 'dell-g5-g5510-2021',
  productName: 'Dell G5 G5510 2021',
  productUrl: 'https://www.khalti.com/#/bazaar',
  additionalData: { // Not mandatory; can be used for reporting purpose
    'vendor': 'Khalti Bazaar',
  },
)
KhaltiButton(
  config: config,
  preferences: [ // Not providing this will enable all the payment methods.
    PaymentPreference.khalti,
    PaymentPreference.eBanking,
  ],
  onSuccess: (successModel) {
    // Perform Server Verification 
  },
  onFailure: (failureModel) {
    // What to do on failure?
  },
  onCancel: () {
    // User manually cancelled the transaction
  },
),

If you want to use only specific payment method then the following dedicated buttons can be used instead: - KhaltiButton.wallet(...) - KhaltiButton.eBanking(...) - KhaltiButton.mBanking(...) - KhaltiButton.connectIPS(...) - KhaltiButton.sct(...)

Manual Method

Another method to launch the payment interface is using KhaltiScope.pay() method:

Inkwell(
  onTap: () {
    KhaltiScope.of(context).pay(
      config: config,
      preferences: [
        PaymentPreference.connectIPS,
        PaymentPreference.eBanking,
        PaymentPreference.sct,
      ],
      onSuccess: onSuccess,
      onFailure: onFailure,
      onCancel: onCancel,
    );
  },
  child: Text('Launch Payment Interface'),
);

Customizing Return URL

Their might be a need to use custom returnUrl, specially in Web platform.

Passing a custom return url will result in data url, in following format after successful payment.

<returnUrl>/?<data>

e.g. Let's say you set a returnUrl = 'https://example.com/test';. Then the data url will be https://example.com/test/?key=value.

A custom return url can be set in PaymentConfig:

final config = PaymentConfig(
  returnUrl: 'https://example.com/test',
  ...
);

Customizing UI

This package doesn't support high level of customization as this is more of a plug & play package.

If a custom interface is required then khalti package can be used.

Example

Find more detailed example here.

Server Verification

After success from the client side payment, the next step is to perform server verification.

A server verification is required since the client side makes the payment directly to Khalti without going through your server first, you need to be sure that the customer actually paid the money they were supposed to before completing their order. This type of verification can only be done securely from the server.

Know how to perform server verification here.

Contributing

Contributions are always welcome. Also, if you have any confusion, please feel free to create an issue.

Internationalization

Steps to add support for new language 1. Create a new file for the language khalti_localizations_<language-code>.dart inside localization directory. Let's say you want to add support for Nepali language, then the file should be khalti_localizations_ne.dart.

  1. Copy contents of khalti_localizations_en.dart to the newly created file and rename the class accordingly.

  2. Replace all the strings with the localized strings inside the file.

  3. Add entry to _localizations map inside khalti_localizations.dart. dart const Map<String, KhaltiLocalizations> _localizations = { 'en': _KhaltiLocalizationsEn(), 'ne': _KhaltiLocalizationsNe(), // Newly added entry };

  4. Submit a Pull Request with the changes. But ensure that the code changes are well formatted. Format the generated code if needed: flutter format .

Support

For Queries, feel free to call us at:

Contact Our Merchant Team * Mobile (Viber / Whatsapp): 9801165567, 9801165538 * Email: merchant@khalti.com

(To integrate Khalti to your business and other online platforms.)

Contact Our Merchant Support * Mobile (Viber / Whatsapp): 9801165565, 9801856383, 9801856451 * Email: merchantcare@khalti.com

Contact Our Technical Team * Mobile (Viber / Whatsapp): 9843007232 * Email / Skype: sashant@khalti.com

(For payment gateway integration support.)

License

Copyright (c) 2021 The Khalti Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.
    * Neither the name of Sparrow Pay Pvt. Ltd. nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.