swichpay_flutter 2.1.3
swichpay_flutter: ^2.1.3 copied to clipboard
Flutter SDK for integrating Swich payment services.
swichpay_flutter #
SwichPay SDK for Flutter — card, e-wallet, bank account, biller, QR, and RTP payments through a built-in payment sheet UI, plus a hosted checkout option and standalone single-method checkouts.
Runs on every platform Flutter supports: Android, iOS, Web, Windows,
macOS, Linux. The OTP / 3-D Secure and hosted-checkout WebView steps need
a native plugin (webview_flutter), which only has official support on
Android, iOS, and macOS — see Platform notes.
Features #
- Built-in payment sheet (
SwichPay.presentPaymentSheet) — a single bottom sheet listing every payment method enabled for your merchant:- Card payments (Visa/Mastercard), with saved cards and 3-D Secure (device-data-collection + OTP step-up) handled automatically.
- E-Wallet payments (EasyPaisa/JazzCash), with saved wallets.
- Bank Account payments, including the OTP confirmation step.
- Biller (1Bill) payments.
- QR (RAAST dynamic) payments.
- RTP Now payments (Raast mobile/IBAN, or bank account).
- RTP E-Wallet payments.
- Automatic discount lookup for E-Wallet and Card payments — if your merchant has an eligible discount campaign, the sheet shows the discounted total and pays that amount without any extra integration work.
- Standalone "direct" checkouts — skip the payment-method picker and go
straight to one method:
presentEwalletCheckout,presentBankTransferCheckout,presentOneBillCheckout,presentQrCheckout,presentRtpNowCheckout,presentRtpEwalletCheckout,presentCardCheckout(requiressecretHashKeyoninitialize()— see its doc comment). Its card form includes a "Scan card" shortcut (camera-based, Android/iOS only) that fills in the card number and expiry for you. - Hosted checkout (
presentHostedCheckout/presentHostedCheckoutSheet) — SwichPay's own hosted payment page in a WebView, full-screen or as a bottom sheet. - Custom UI (
SwichPay.pay) — submit a card payment directly against your own form. - Typed errors — every SDK call throws a
SwichPayExceptionsubtype instead of a raw HTTP exception.
Install #
dependencies:
swichpay_flutter: ^2.1.0
flutter pub get
import 'package:swichpay_flutter/swichpay.dart';
1. Initialize #
Call once, as early as possible (e.g. in main()):
void main() {
SwichPay.initialize(
clientId: 'your-client-id', // from your SwichPay dashboard
clientSecret: 'your-client-secret', // from your SwichPay dashboard
referrer: 'https://your-app.example.com/', // must match what's registered
merchantId: 1,
appId: 'com.yourapp', // your app's bundle/package id
environment: Environment.sandbox, // or Environment.production
);
runApp(const MyApp());
}
That's the whole integration - no backend proxy to stand up. The SDK
exchanges clientId/clientSecret for an OAuth2 bearer token itself
(refreshed automatically) and uses it to create/fetch payment sessions,
submit payments, and map errors - no separate token-fetching code needed on
your side.
baseUrlOverrideis available for pointing testing at a local backend.clientSecretis technically optional - omitting it makes every request fall back to sendingclientIdas a plainx-public-keyheader instead of a bearer token, which only a subset of endpoints accept. Pass it whenever you have it.secretHashKeyis a separate, different secret - only needed forSwichPay.presentCardCheckout(the direct/session-less card flow), which uses it to HMAC-sign that flow's checksum. Don't pass the same value for bothclientSecretandsecretHashKey- the server rejects the token exchange (invalid_client) if you do.
2. Describe the order #
final details = PaymentDetails(
orderNumber: 'ORD123456',
customerTransactionId: 'HelloWorld-1245',
billReferenceNo: 'HelloWorld-123',
merchantName: 'Demo Merchant',
consumerName: 'John Doe',
amount: 1000,
currency: 'PKR',
email: 'john.doe@example.com',
msisdn: '03001234567',
cnic: '42101-1234567-1',
item: 'Test Item',
successRedirectUrl: 'https://example.com/success',
failedRedirectUrl: 'https://example.com/failure',
);
3. Take a payment #
Option A — built-in payment sheet (recommended) #
Shows a bottom sheet listing every payment method enabled for your merchant
(card, e-wallet, bank account, biller, QR, RTP). Resolves to null if the
user dismisses it without paying.
final result = await SwichPay.presentPaymentSheet(
context: context,
details: details,
// Optional - restrict to a subset of your merchant's enabled categories.
// categories: [PaymentCategory.visaMasterCardPayment, PaymentCategory.ewallet],
);
if (result != null && result.isSuccess) {
// payment succeeded
} else if (result != null) {
// result.status, result.code, result.message
}
Option B — a single payment method, no session #
For a simpler integration that skips the payment-method picker entirely:
final result = await SwichPay.presentEwalletCheckout(
context: context,
details: details,
);
Also available: presentBankTransferCheckout, presentOneBillCheckout,
presentQrCheckout, presentRtpNowCheckout, presentRtpEwalletCheckout —
same signature, one per payment method.
Option C — hosted checkout #
Opens SwichPay's own hosted payment page in a WebView:
final result = await SwichPay.presentHostedCheckout(
context: context,
details: details,
);
// or, as a bottom sheet:
final result = await SwichPay.presentHostedCheckoutSheet(
context: context,
details: details,
);
Option D — fully custom card UI #
Build your own card form and confirm directly:
final result = await SwichPay.pay(
details: details,
card: CardDetails(
number: '4242424242424242',
expMonth: 12,
expYear: 2030,
cvv: '123',
),
);
With custom UI, you're responsible for handling any redirection yourself — only the built-in payment sheet and hosted checkout automate that.
4. Handling payment results #
Every entry point above returns a PaymentResult? (null means the sheet
was dismissed without paying). Key fields:
| Field | Meaning |
|---|---|
isSuccess |
true once the payment is confirmed complete |
status |
raw status string, e.g. "success", "failed", "otp_required", "cancelled" |
message |
human-readable detail, when the API provided one |
code |
vendor/error code, when present |
orderId |
SwichPay's order id, on success |
Some flows resolve in more than one step (e.g. Bank Account/1Bill/QR OTP or status-check steps) — the built-in sheet and direct checkouts already handle these internally and only resolve once the flow reaches a final state.
You can also listen for every result app-wide (in addition to whatever a specific call returns):
final subscription = SwichPay.onResult((result) {
print('Payment ${result.status}: ${result.message}');
});
// later
subscription.cancel();
Error handling #
Every SDK call throws a subtype of SwichPayException instead of a raw
HTTP/parsing error:
| Exception | When |
|---|---|
SwichPayNotInitializedException |
a method was called before SwichPay.initialize() |
SwichPayValidationException |
bad input (invalid card number, missing fields) caught before any network call |
SwichPayNetworkException |
the SwichPay API couldn't be reached (timeout, no connection) |
SwichPayApiException |
the API returned an error (has statusCode and optional code) |
try {
await SwichPay.pay(details: details, card: card);
} on SwichPayApiException catch (e) {
// e.statusCode, e.code, e.message
} on SwichPayException catch (e) {
// any other SDK error
}
Sandbox vs Production #
Pass Environment.sandbox or Environment.production to
SwichPay.initialize(). This selects the checkout/gateway hosts the SDK
talks to; your clientId/referrer/merchantId must be registered for
the matching environment. Use baseUrlOverride only for pointing local
testing at a custom backend.
Platform notes #
- Android / iOS / macOS: works out of the box, including the OTP / 3-D Secure and hosted-checkout WebView steps.
- Web: requests go directly from the browser to the SwichPay API, so
your SwichPay account must allow CORS for your app's origin. Run with
flutter run -d chrome. The OTP/3-D Secure WebView step isn't wired up for web yet — a card payment that requires it will returnisRedirectionRequired: true/an OTP-required status without showing a challenge. - Windows / Linux: card, e-wallet, bank account, biller, QR, and RTP
payments work, but the OTP / 3-D Secure and hosted-checkout WebView steps
aren't supported (
webview_flutterhas no official plugin for these platforms). UseSwichPay.pay()/ a direct checkout and handle any redirect URL yourself (e.g. viaurl_launcher) on these platforms.
Saving/sharing a QR code (via presentQrCheckout or the payment sheet's QR
method) uses the gal and share_plus plugins, which request
photo-library/share permissions at the OS level only when the user actually
taps "Download"/"Share". On iOS, add an NSPhotoLibraryAddUsageDescription
to your Info.plist — without it, iOS terminates the app when the user taps
"Download". See gal's setup notes for the
Android ≤ 9 storage permission as well.
The "Scan card" button (presentCardCheckout's card form) uses
package:card_scanner, which needs a camera permission and only ships an
Android/iOS implementation - it renders nothing on every other platform, so
no conditional code is needed on your side. Camera access:
- Android: the plugin declares
android.permission.CAMERAin its own manifest, merged into your app automatically - nothing to add. - iOS: requires iOS ≥ 12.0, and
use_frameworks!must be commented out of yourios/Podfile'starget 'Runner' doblock (see the example app's Podfile for a working reference). Add anNSCameraUsageDescriptionto yourInfo.plist(required by iOS for any camera access).
Example app #
See example/ for a runnable app demonstrating initialization,
the payment sheet, direct checkouts, and result handling. It targets all
six platforms:
cd example
flutter run -d chrome # web
flutter run -d macos # or windows / linux / a connected device