Flutter · Dart · Android, iOS, Web
Features
The Flutter SDK wraps the full SabPaisa PG 3.0 API into a single, type-safe Dart package.
Create Payments
Generate checkout sessions with a single method call
Checkout Redirect
In-app browser or custom WebView integration
URL Verification
HMAC-SHA256 return URL signature verification
Transaction Enquiry
Look up payment status and details by ID
Refunds
Full or partial refunds with status tracking
Type-Safe API
Dart classes for every request and response
Error Handling
Typed exceptions for every error category
Dual Environment
One config flag to switch staging / production
Auto Checksum
SDK generates HMAC-SHA256 checksums automatically
Installation
Prerequisites
Add to pubspec.yaml
1dependencies:
2 sabpaisa: ^1.0.1Install dependencies
1flutter pub getQuick Start
Initialize the SabPaisaClient with your credentials.
1import 'package:sabpaisa/sabpaisa.dart';
2
3final sabpaisa = SabPaisaClient(SabPaisaConfig(
4 apiKey: 'sp_your_api_key',
5 merchantId: 'YOUR_MERCHANT_ID',
6 secretKey: 'sec_your_secret_key',
7 clientCode: 'YOUR_CLIENT_CODE',
8 env: Environment.staging, // or Environment.production
9));Payment Flow
A typical payment integration follows these steps.
Create a payment session via the SDK
sabpaisa.payments.createSession(...)Generates checksum, calls SabPaisa API, returns checkoutUrl
Redirect customer to checkout
sabpaisa.payments.redirectToCheckout(request)Completes payment on SabPaisa checkout page
Verify the return URL signature
sabpaisa.payments.verifyReturnUrl(params)Receive webhook for server-side confirmation
Create Payment
Create a payment session to get a checkoutUrl. The SDK handles checksum generation, API calls, and response parsing.
1final payment = await sabpaisa.payments.createSession(
2 const CreatePaymentRequest(
3 merchantTxnId: 'ORDER_123',
4 amount: 50000, // Rs 500.00 in paise
5 customerName: 'John Doe',
6 customerEmail: '[email protected]',
7 customerMobile: '9876543210',
8 // returnUrl is optional for in-app checkout — SDK provides a default.
9 // Provide one if you handle the redirect yourself:
10 // returnUrl: 'https://yoursite.com/callback',
11 udfFields: { // optional user-defined fields (udf1–udf20)
12 'udf1': 'plan-premium',
13 'udf2': 'campaign-summer',
14 },
15 ),
16);
17
18print(payment.checkoutUrl); // Ready-to-use URL with clientSecret
19print(payment.paymentId);With Idempotency Key
Recommended for production — prevents duplicate payments if the client retries.
1final payment = await sabpaisa.payments.createSession(
2 request,
3 options: const RequestOptions(idempotencyKey: 'unique-order-key-123'),
4);Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| merchantTxnId | String | Required | Your unique order / transaction ID |
| amount | int | Required | Amount in paise (50000 = Rs 500.00) |
| customerName | String | Required | Customer's full name |
| customerEmail | String | Required | Customer's email address |
| customerMobile | String | Required | 10-digit mobile number |
| returnUrl | String | Optional | Optional for in-app checkout (SDK default); set it if you handle the redirect yourself |
| udfFields | Map | Optional | User-defined fields udf1–udf20 |
50000 paise. See Amounts for the full conversion table.Redirect to Checkout
Open the SabPaisa checkout in an in-app browser, or get the raw URL for a custom WebView. The SDK provides two approaches.
AIn-App Browser (Recommended)
Opens SabPaisa checkout in an in-app browser. The customer stays within your app.
1// Opens checkout in an in-app browser (Chrome Custom Tabs on
2// Android, SFSafariViewController on iOS). No returnUrl needed.
3await sabpaisa.payments.redirectToCheckout(
4 const CreatePaymentRequest(
5 merchantTxnId: 'ORDER_123',
6 amount: 50000,
7 customerName: 'John Doe',
8 customerEmail: '[email protected]',
9 customerMobile: '9876543210',
10 ),
11);BCustom WebView
Get the raw checkout URL for full control over navigation, headers, and callbacks.
1// Get checkout URL for custom handling (e.g. WebView)
2final url = sabpaisa.payments.getCheckoutUrl(payment);
3
4// Load in your own WebView widget
5WebView(initialUrl: url);redirectToCheckout is recommended for most apps. Use getCheckoutUrl only for custom WebView behaviour.Verify Return URL
Verify the return URL signature to confirm the payment status is authentic.
1// After checkout, SabPaisa redirects to your returnUrl with
2// signed query parameters. Verify the signature is authentic:
3final isValid = sabpaisa.payments.verifyReturnUrl(
4 ReturnUrlParams.fromJson(callbackQueryParams),
5);
6
7if (isValid) {
8 // Signature is authentic — safe to process the payment
9}ReturnUrlParams Fields
transactionIdSabPaisa transaction IDmerchantTxnIdYour original transaction IDstatusPayment status (SUCCESS, FAILED, etc.)amountOriginal amountpaidAmountAmount actually paidpaymentModeUPI, CARD, etc.timestampServer timestampsignatureHMAC signature to verifyTransaction Enquiry
Look up the authoritative status of a transaction using your merchantTxnId.
1final txn = await sabpaisa.transactions.enquiry(
2 merchantTxnId: 'ORDER_123',
3);
4
5print(txn.data.status); // SUCCESS, FAILED, PENDING
6print(txn.data.amountPaise); // Amount in paise
7print(txn.data.paymentMode); // UPI, CARD, etc.
8print(txn.data.bankTxnId); // Bank transaction reference
9print(txn.data.bankRrn); // Bank RRN
10print(txn.data.udfData); // User-defined fields (Map<String, String>)Payment Statuses
| Status | Meaning | Terminal? | Action |
|---|---|---|---|
| SUCCESS | Payment completed | Yes | Fulfil the order |
| FAILED | Payment failed | Yes | Prompt customer to retry |
| PENDING | Awaiting customer action | No | Wait or show loading |
| PROCESSING | Being processed by bank | No | Poll for status updates |
| EXPIRED | Session timed out | Yes | Create a new session |
| CANCELLED | Cancelled by customer | Yes | Allow retry |
Refunds
Issue full or partial refunds, check refund status, and list all refunds for a payment.
1Create Refund
Pass the SabPaisa txnId, amount in paise, an optional reason, and an idempotency key.
1final refund = await sabpaisa.refunds.create(
2 const CreateRefundRequest(
3 txnId: 'SP_TXN_456', // SabPaisa transaction ID
4 amount: 25000, // Rs 250.00 in paise (partial refund)
5 reason: 'Customer request',
6 ),
7 options: const RequestOptions(idempotencyKey: 'refund_ORDER_123_1'),
8);
9
10print(refund.data.refundId);2Check Refund Status
Query the current state of a refund using its refundId.
1final status = await sabpaisa.refunds.getStatus('REFUND_ID');
2
3print(status.data.status); // PENDING, COMPLETED, FAILED3List Refunds
List refunds with optional filters and pagination.
1final list = await sabpaisa.refunds.list(
2 const RefundListParams(page: 0, size: 20),
3);
4
5for (final r in list.data) {
6 print('${r.refundId}: ${r.status}');
7}
8
9// Pagination
10if (list.pagination != null) {
11 print('Page ${list.pagination!.page + 1} of ${list.pagination!.totalPages}');
12 print('Total: ${list.pagination!.total}');
13}Refund Statuses
| Status | Meaning | Settlement |
|---|---|---|
| PENDING | Refund initiated, awaiting processing | Processing |
| COMPLETED | Refund completed — funds returned | 5–7 business days |
| FAILED | Refund could not be processed | N/A |
Configuration
All configuration is passed to SabPaisaConfig when creating the client.
| Parameter | Type | Required | Description |
|---|---|---|---|
| apiKey | String | Required | API key from SabPaisa dashboard |
| merchantId | String | Required | Merchant ID for authentication |
| secretKey | String | Required | HMAC secret for checksums |
| clientCode | String | Required | Client code for API requests |
| env | Environment | Required | Environment.staging or Environment.production |
| baseUrl | String | Optional | Custom URL override (takes precedence over env) |
Environment URLs
| Environment | Base URL | Use For |
|---|---|---|
| Staging | staging-sb-merchant-api.sabpaisa.in | Development & testing |
| Production | merchant-api.sabpaisa.in | Live transactions |
Error Handling
The SDK throws typed exceptions. Use Dart’s on keyword to catch specific errors.
1try {
2 await sabpaisa.payments.createSession(params);
3} on ValidationError catch (e) {
4 // Client-side validation failed
5 print('${e.field}: ${e.message}');
6} on ApiError catch (e) {
7 // API returned an error
8 print('${e.message} (HTTP ${e.statusCode})');
9 print('Retryable: ${e.retryable}'); // true for 5xx, 429
10 print('Trace ID: ${e.traceId}'); // share with SabPaisa support
11} on SabPaisaError catch (e) {
12 // Network error, timeout, etc.
13 print('${e.code}: ${e.message}');
14}Exception Types
| Exception | When | Key Properties |
|---|---|---|
| ValidationError | Invalid input — caught before the API call | field, message |
| ApiError | API returned an error (4xx, 5xx) | statusCode, code, message, retryable, traceId |
| ChecksumError | Checksum verification failed | message |
| SabPaisaError | Base exception — network errors, timeouts, etc. | code, message |
ApiError.retryable before retrying a request yourself.Request Options
Customize the timeout or attach an idempotency key per request.
1// Idempotency key (prevents duplicate operations on retry)
2const options = RequestOptions(idempotencyKey: 'unique-key');
3
4// Custom timeout (milliseconds)
5const options = RequestOptions(timeoutMs: 60000);
6
7// Both
8const options = RequestOptions(idempotencyKey: 'unique-key', timeoutMs: 60000);
9
10// Use with any method
11await sabpaisa.payments.createSession(request, options: options);
12await sabpaisa.refunds.create(refundRequest, options: options);
13await sabpaisa.refunds.getStatus('RFD_123', options: options);Important Notes
| Topic | Detail |
|---|---|
| Amounts | Always in paise. Rs 500.00 = 50000. The SDK does not convert. |
| Customer Mobile | Use customerMobile in the SDK. It is automatically mapped to the API's customerPhone field. |
| Idempotency Keys | Always use for createSession() and refunds.create() in production to prevent duplicates. |
| Timeout | Default 30 seconds per request. Override with RequestOptions(timeoutMs: ...). |
| Config Immutability | Config cannot be changed after creation. Create a new SabPaisaClient for different credentials. |
Amounts
All monetary values are in paise (1 rupee = 100 paise).
amount_in_paise = rupees × 100| Display | Paise | Dart Code |
|---|---|---|
| Rs 1.00 | 100 | amount: 100 |
| Rs 10.00 | 1000 | amount: 1000 |
| Rs 100.00 | 10000 | amount: 10000 |
| Rs 500.00 | 50000 | amount: 50000 |
| Rs 1,000.00 | 100000 | amount: 100000 |
| Rs 9,999.99 | 999999 | amount: 999999 |
500.00 instead of 50000 charges Rs 5.00, not Rs 500.00.Quick Reference
sabpaisa.payments.createSession(...)sabpaisa.payments.redirectToCheckout(request)sabpaisa.payments.getCheckoutUrl(payment)sabpaisa.payments.verifyReturnUrl(ReturnUrlParams.fromJson(...))sabpaisa.transactions.enquiry(merchantTxnId: ...)sabpaisa.refunds.create(CreateRefundRequest(...))sabpaisa.refunds.getStatus('ID')sabpaisa.refunds.list(RefundListParams(...))Need Help?
For SDK issues or integration help, reach out with your Merchant ID, SDK version, and error details.
Was this page helpful?
Related Pages
SDKs & Libraries
Choose your platform — Flutter, Java, Python, Node.js
Java SDK
Official Java SDK — Spring Boot, Jakarta EE, Quarkus
Quick Start
Get up and running in 30 minutes
API Reference
Complete endpoint documentation
Webhooks
Real-time payment notifications
iFrame Integration
Embed checkout on your site — no redirect
S2S UPI — QR & Intent
Server-to-server UPI QR and Intent payments