satnam-singh / sbi-epay
Seamless and secure SBI ePay payment gateway integration for Laravel applications.
Fund package maintenance!
Requires
- php: ^8.3||^8.4||^8.5
- illuminate/http: ^11.0||^12.0||^13.0
- illuminate/support: ^11.0||^12.0||^13.0
Requires (Dev)
- larastan/larastan: ^3.9
- laravel/agent-detector: ^2.0
- laravel/chisel: ^0.1
- laravel/pao: ^1.0
- laravel/pint: ^1.29
- laravel/prompts: ^0.3
- orchestra/testbench: ^10.0||^11.0
- pestphp/pest: ^4.6||^5.0
- pestphp/pest-plugin-laravel: ^4.1||^5.0
- pestphp/pest-plugin-type-coverage: ^4.0||^5.0
- phpstan/extension-installer: ^1.4
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-30 11:32:26 UTC
README
A modern, fluent, and strongly-typed SBI ePay (State Bank of India Payment Gateway) integration package for Laravel applications.
Note
Disclaimer: This is an independent, community-developed package and is not an official package from State Bank of India (SBI) or SBI ePay. It is neither endorsed by, affiliated with, nor maintained by State Bank of India.
Highlights
- โก Fluent Payment Initiation: One-liner payment generation with auto-submitting redirect form or headless API responses for SPAs.
- ๐ฆ Bank Account Routing: Route payments to specific mapped bank accounts on your SBI ePay dashboard via
accountIdentifier. - ๐ Custom User Details: Attach arbitrary key-value user metadata arrays with automatic SBI character sanitization and round-trip callback extraction.
- ๐ AES-128-CBC Encryption: Compliant with official SBI ePay specifications using PHP's native OpenSSL.
- ๐ก๏ธ Double Verification Support: Built-in server-to-server query verification to prevent client tampering and guarantee authentic bank status.
- ๐ข Multi-Merchant / Multi-Tenant Support: Seamlessly switch merchant credentials dynamically using
SbiEpay::merchant($id, $key). - ๐ Environment Switching: Out-of-the-box configuration for
test(UAT) andlive(Production) gateways. - ๐งช Production-Grade Quality: Strict types declared, PHPStan Level 7 compliant, 100% type coverage, and tested with Pest.
Requirements
- PHP:
^8.3or^8.4 - Laravel:
^11.0or^12.0 - PHP OpenSSL Extension enabled
Installation
Install the package into your Laravel application via Composer:
composer require satnam-singh/sbi-epay
Publish Configuration
Publish the sbi-epay.php configuration file:
php artisan vendor:publish --tag="sbi-epay-config"
Configuration
Add your SBI ePay merchant credentials to your .env file:
# Environment: 'test' for UAT sandbox, 'live' for production SBI_EPAY_MODE=test # SBI ePay Merchant Credentials SBI_EPAY_MERCHANT_ID=1000003 SBI_EPAY_MERCHANT_KEY=your_16_byte_merchant_key # Optional settings (sensible defaults provided) SBI_EPAY_AGGREGATOR_ID=SBIEPAY SBI_EPAY_OPERATING_MODE=2 SBI_EPAY_COUNTRY=IN SBI_EPAY_CURRENCY=INR # Optional URL overrides # SBI_EPAY_PAYMENT_URL=https://test.epay.sbiuat.bank.in/secure/AggregatorHostedListener # SBI_EPAY_VERIFICATION_URL=https://test.epay.sbiuat.bank.in/payagg/statusQuery/getStatusQuery
Important: Exclude Callback Route from CSRF Verification
SBI ePay returns customers back to your application by issuing a cross-site HTTP POST request containing encrypted payload data (encData). In Laravel 11 and 12, make sure to exclude your payment callback route from CSRF verification:
In bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) { $middleware->validateCsrfTokens(except: [ 'payment/sbi/callback', ]); })
Quick Usage
1. Initiating a Payment
In your controller, use the SbiEpay facade to create a payment request:
namespace App\Http\Controllers; use Illuminate\Http\Request; use SbiEpay\SbiEpay\Facades\SbiEpay; use SbiEpay\SbiEpay\DTOs\PaymentRequest; class CheckoutController extends Controller { public function initiatePayment() { $initiation = SbiEpay::initiate(new PaymentRequest( orderId: 'ORDER_' . uniqid(), amount: 1500.00, successUrl: route('payment.sbi.callback'), failUrl: route('payment.sbi.callback'), // Bank account unique identifier mapped in your SBI ePay dashboard accountIdentifier: 'MUNICIPALITY_COLLECTION_ACC', // Send arbitrary key-value user details (auto-sanitized and encoded) userDetails: [ 'consumer_id' => 'CNS98452', 'consumer_name' => 'John Doe', 'ward_no' => '14', 'bill_month' => 'October 2026', ], customerEmail: 'customer@example.com', customerMobile: '9876543210', )); // Returns an auto-submitting POST view that redirects the user to SBI ePay return $initiation->redirect(); } }
For Headless / Inertia / Vue / React SPAs: Instead of
$initiation->redirect(), retrieve the raw form parameters and submit them from your frontend:return response()->json([ 'action' => $initiation->paymentUrl, 'form_data' => $initiation->formData(), ]);
2. Handling the Payment Callback
When the transaction finishes, SBI ePay posts the encrypted status payload to your successUrl or failUrl. Decrypt and parse it with SbiEpay::handleCallback():
namespace App\Http\Controllers; use Illuminate\Http\Request; use SbiEpay\SbiEpay\Facades\SbiEpay; class CheckoutController extends Controller { public function handleCallback(Request $request) { try { // Decrypt and parse the response $response = SbiEpay::handleCallback($request->input('encData')); if ($response->isSuccess()) { // Highly recommended: Perform server-to-server Double Verification $verification = SbiEpay::verify($response->orderId, $response->amount); if ($verification->isSuccess()) { // Mark order as paid in your database // $order = Order::where('order_id', $response->orderId)->first(); // $order->markAsPaid($response->sbiTransactionId); return redirect()->route('order.success', [ 'order_id' => $response->orderId, ])->with('success', 'Payment completed successfully!'); } } return redirect()->route('order.failed')->with('error', 'Payment verification failed.'); } catch (\Exception $e) { return redirect()->route('order.failed')->with('error', $e->getMessage()); } } }
Available Methods on PaymentResponse:
$response->isSuccess(); // bool: true if status is SUCCESS $response->isFailed(); // bool: true if status is FAIL/FAILED $response->isPending(); // bool: true if status is PENDING/AWAITED $response->orderId; // string: your original order ID $response->status; // string: 'SUCCESS', 'FAIL', etc. $response->amount; // float: paid amount $response->currency; // ?string: 'INR' $response->paymode; // ?string: 'NB', 'CC', 'DC', etc. $response->sbiTransactionId; // ?string: SBI reference ID $response->bankReferenceNo; // ?string: Bank reference number $response->bankName; // ?string: Paying bank name (e.g. State Bank of India) $response->transactionDate; // ?string: Transaction timestamp $response->otherDetails; // ?string: Raw other details string $response->userDetails; // array<string, string>: Parsed key-value user details $response->merchantId; // ?string: SBI merchant ID $response->cin; // ?string: Challan Identification Number (if applicable) $response->rawResponse; // string: raw pipe-delimited decrypted string $response->toArray(); // array<string, mixed>
3. Server-to-Server Double Verification
To eliminate any chance of client-side callback tampering, query SBI's Double Verification API directly from your server. You can pass the PaymentResponse instance directly, or supply the orderId and amount, or even pass the raw decrypted decData string:
use SbiEpay\SbiEpay\Facades\SbiEpay; // Option A: Pass PaymentResponse instance directly $verification = SbiEpay::verify($response); // Option B: Pass order ID and amount $verification = SbiEpay::verify( orderId: 'ORDER_12345', amount: 1500.00 ); // Option C: Pass raw decrypted callback string (e.g. decData) $verification = SbiEpay::verify($decData); if ($verification->isSuccess()) { // Verified by SBI server $sbiRef = $verification->sbiTransactionId; $amount = $verification->amount; }
Available Methods on VerificationResponse:
$verification->isSuccess(); // bool: true if status is SUCCESS or SUCCESSFUL $verification->orderId; // string: original merchant order ID $verification->status; // string: 'SUCCESS', 'FAILED', 'NO RECORDS FOUND', etc. $verification->amount; // float: verified transaction amount $verification->sbiTransactionId; // ?string: SBI transaction reference ID (ATRN) $verification->merchantId; // ?string: merchant ID $verification->message; // ?string: status description or message $verification->otherDetails; // ?string: other details $verification->userDetails; // array<string, string>: parsed key-value user details $verification->rawResponse; // string: raw response from SBI ePay $verification->toArray(); // array<string, mixed>
4. Dynamic Multi-Merchant Support
If your application processes payments for multiple branches, municipalities, or tenants with different merchant accounts:
$initiation = SbiEpay::merchant('MERCHANT_BRANCH_02', 'KEY_BRANCH_02') ->initiate($paymentRequest);
5. Direct Encryption & Decryption Helpers
You can also use the encryption engine standalone:
use SbiEpay\SbiEpay\Facades\SbiEpay; // Encrypt string with configured merchant key $cipherText = SbiEpay::encrypt('Hello World'); // Decrypt back to plaintext $plainText = SbiEpay::decrypt($cipherText);
Testing
Run the package test suite:
composer test
Individual checks:
# Pest test suite composer test:unit # Type coverage (100%) composer test:types # PHPStan static analysis composer analyse # Laravel Pint code styling composer lint:check
Changelog
Please see CHANGELOG.md for details on recent changes.
Contributing
Please see CONTRIBUTING.md and CODE_OF_CONDUCT.md for details.
Security
Please review our security policy on how to report security vulnerabilities.
Credits
- Satnam Singh (@satnamgills)
- All Contributors
Disclaimer
This package is an independent, custom-built open-source integration developed to assist Laravel developers integrating with the SBI ePay payment gateway. This project is not an official product of, nor is it endorsed, certified, or maintained by State Bank of India (SBI) or SBI ePay. All trademarks, service marks, and company names are the property of their respective owners.
License
The MIT License (MIT). Please see License File for more information.