From zero to accepting payments in 30 minutes.
| Field | Value |
|---|---|
| API Key | sk_test_... |
| Secret Key | your_secret_key |
| Merchant ID | TEST_MID |
| Base URL | https://staging-sb-merchant-api.sabpaisa.in |
| Method | Test Value | Result |
|---|---|---|
| UPI (success) | success@upi | Completes after ~5 seconds |
| UPI (failure) | failure@upi | Payment fails |
| UPI (timeout) | timeout@upi | Times out after 15 min |
| Card (success) | 4111 1111 1111 1111, expiry: any future, CVV: 123 | Success, OTP: 123456 |
| Card (declined) | 4000 0000 0000 0002 | Card declined |
~2 minutes
Add your SabPaisa credentials to a .env file in your backend project. You can find these values in your SabPaisa Dashboard.
1SABPAISA_API_KEY=sk_test_...
2SABPAISA_SECRET_KEY=your_secret_key
3SABPAISA_MERCHANT_ID=TEST_MID
4SABPAISA_BASE_URL=https://staging-sb-merchant-api.sabpaisa.in~10 minutes
Generate an HMAC-SHA256 checksum and call POST /api/v2/payments with your payment details. The checksum input format is: merchantId|merchantTxnId|amount|currency|timestamp
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,
9));
10
11Future<void> createPayment(String orderId, int amount,
12 String customerName, String customerEmail, String customerPhone) async {
13 final payment = await sabpaisa.payments.createSession(
14 CreatePaymentRequest(
15 merchantTxnId: 'ORD_${orderId}_${DateTime.now().millisecondsSinceEpoch}',
16 amount: amount, // Amount in paise (50000 = ₹500)
17 customerName: customerName,
18 customerEmail: customerEmail,
19 customerMobile: customerPhone,
20 ),
21 );
22
23 // payment.paymentId — store in your database
24 // payment.checkoutUrl — ready-to-use URL with clientSecret
25 // payment.status — "PENDING" on creation
26 // payment.expiresAt — session expiry (30 min)
27
28 // Open checkout in in-app browser
29 await sabpaisa.payments.redirectToCheckout(payment);
30}1<?php
2function createPayment($orderId, $amount, $customerName, $customerEmail, $customerPhone) {
3 $merchantId = getenv('SABPAISA_MERCHANT_ID');
4 $merchantTxnId = "ORD_{$orderId}_" . round(microtime(true) * 1000);
5 $currency = 'INR';
6 $timestamp = time();
7
8 // Generate checksum: merchantId|merchantTxnId|amount|currency|timestamp
9 $checksumInput = "{$merchantId}|{$merchantTxnId}|{$amount}|{$currency}|{$timestamp}";
10 $checksum = hash_hmac('sha256', $checksumInput, getenv('SABPAISA_SECRET_KEY'));
11
12 $ch = curl_init(getenv('SABPAISA_BASE_URL') . '/api/v2/payments');
13 curl_setopt_array($ch, [
14 CURLOPT_POST => true,
15 CURLOPT_RETURNTRANSFER => true,
16 CURLOPT_HTTPHEADER => [
17 'X-Api-Key: ' . getenv('SABPAISA_API_KEY'),
18 'Content-Type: application/json'
19 ],
20 CURLOPT_POSTFIELDS => json_encode([
21 'merchantId' => $merchantId,
22 'merchantTxnId' => $merchantTxnId,
23 'amount' => $amount,
24 'currency' => $currency,
25 'timestamp' => $timestamp,
26 'checksum' => $checksum,
27 'returnUrl' => 'https://yoursite.com/payment/result',
28 'customerName' => $customerName,
29 'customerEmail' => $customerEmail,
30 'customerPhone' => $customerPhone,
31 ]),
32 ]);
33
34 $session = json_decode(curl_exec($ch), true);
35 curl_close($ch);
36 // $session["paymentId"] — store in your database
37 // $session["checkoutUrl"] — redirect customer here
38 // $session["clientSecret"] — store securely (returned only once)
39 // $session["status"] — "PENDING" on creation
40 // $session["expiresAt"] — session expiry (30 min)
41 return $session;
42}The response includes paymentId, checkoutUrl, clientSecret, status, and expiresAt (30 min).
~1 minute
Send the checkoutUrl from the payment session response to your frontend and redirect the customer.
1// After creating the payment session on your server,
2// send the checkoutUrl to the frontend and redirect:
3window.location.href = checkoutUrl;checkoutUrl returned by the Create Payment Session API.~10 minutes
When the customer returns to your returnUrl, verify the payment server-side using one (or both) of these methods:
Call POST /api/v2/payments/enquiry from your return URL handler to confirm the payment status.
Receive real-time payment.success / payment.failed events at your webhook URL.
1// Option A: Transaction Enquiry API
2Future<void> verifyPayment(String merchantTxnId) async {
3 final txn = await sabpaisa.transactions.enquiry(
4 merchantTxnId: merchantTxnId,
5 );
6
7 if (txn.data.status == 'SUCCESS') {
8 // Fulfil the order
9 // txn.data.amount — amount in paise
10 // txn.data.paymentMode — UPI, CARD, NB, etc.
11 // txn.data.bankRrn — bank reference number
12 } else {
13 // Show failure page with retry option
14 }
15}1<?php
2// Option A: Transaction Enquiry API
3function verifyPayment($merchantTxnId) {
4 $ch = curl_init(getenv('SABPAISA_BASE_URL') . '/api/v2/payments/enquiry');
5 curl_setopt_array($ch, [
6 CURLOPT_POST => true,
7 CURLOPT_RETURNTRANSFER => true,
8 CURLOPT_HTTPHEADER => [
9 'X-Api-Key: ' . getenv('SABPAISA_API_KEY'),
10 'Content-Type: application/json',
11 ],
12 CURLOPT_POSTFIELDS => json_encode([
13 'clientCode' => getenv('SABPAISA_MERCHANT_ID'),
14 'merchantTxnId' => $merchantTxnId,
15 ]),
16 ]);
17
18 $result = json_decode(curl_exec($ch), true);
19 curl_close($ch);
20
21 if ($result['status'] === 'SUCCESS') {
22 // Fulfil the order
23 // $result['amountPaise'] — amount in paise
24 // $result['paymentMode'] — UPI, CARD, NB, etc.
25 // $result['bankRrn'] — bank reference number
26 } else {
27 // Show failure page with retry option
28 }
29
30 return $result;
31}1// Option B: Verify return URL callback signature
2// After checkout, SabPaisa redirects to returnUrl with signed params
3
4final isValid = sabpaisa.payments.verifyReturnUrl(
5 ReturnUrlParams.fromJson(callbackQueryParams),
6);
7
8if (isValid) {
9 // Signature is authentic — safe to show success
10 // Always confirm via Transaction Enquiry API on your backend
11}1<?php
2// Option B: Webhook handler
3$rawBody = file_get_contents('php://input');
4$sigHeader = $_SERVER['HTTP_X_SABPAISA_SIGNATURE'] ?? '';
5
6// Split signature: timestamp.base64_signature
7$parts = explode('.', $sigHeader, 2);
8if (count($parts) !== 2) {
9 http_response_code(401);
10 echo json_encode(['error' => 'Invalid signature']);
11 exit;
12}
13
14[$timestamp, $receivedSig] = $parts;
15
16// Check timestamp freshness (5 min)
17$now = round(microtime(true) * 1000);
18if (abs($now - intval($timestamp)) > 300000) {
19 http_response_code(401);
20 echo json_encode(['error' => 'Signature expired']);
21 exit;
22}
23
24// Compute expected signature (base64, NOT hex)
25$toSign = $timestamp . '.' . $rawBody;
26$expectedSig = base64_encode(hash_hmac('sha256', $toSign, getenv('SABPAISA_WEBHOOK_SECRET'), true));
27
28if (!hash_equals($expectedSig, $receivedSig)) {
29 http_response_code(401);
30 echo json_encode(['error' => 'Invalid signature']);
31 exit;
32}
33
34$payload = json_decode($rawBody, true);
35
36if ($payload['event'] === 'payment.success') {
37 // Update order: $payload['txn_id'], $payload['merchant_txn_id'], $payload['paid_amount']
38}
39
40echo json_encode(['status' => 'received']);~10 minutes
When you are ready for production, complete the following checklist:
staging-sb-merchant-api.sabpaisa.in to merchant-api.sabpaisa.in