laravel-epay maintained by nawrasbukhari
Laravel ePay Package
A comprehensive, production-ready Laravel package for integrating ePayment.kz payment gateway into your Laravel applications. Built with strict typing, enums, and 100% test coverage.
Features
- ✅ OAuth2 Token Management - Automatic token retrieval, caching, and refresh
- ✅ Invoice Link API - Create payment links via API with full type safety
- ✅ Payment Widget - JavaScript widget integration with event handling
- ✅ Transaction Status - Real-time payment status checking
- ✅ Callback Handling - Secure webhook processing with signature validation
- ✅ Laravel Events - Event-driven architecture for payment callbacks
- ✅ Blade Components - Ready-to-use payment buttons
- ✅ Type Safety - Strict types and PHP 8.1+ enums throughout
- ✅ Test & Prod Environments - Easy environment switching
- ✅ Comprehensive Tests - 100% test coverage with 56+ tests
- ✅ PSR-12 Compliant - Clean, maintainable, production-ready code
Requirements
- PHP ^8.1
- Laravel ^10.0 | ^11.0 | ^12.0
- Composer
Installation
Step 1: Install via Composer
composer require nawrasbukhari/laravel-epay
Step 2: Publish Configuration
php artisan vendor:publish --tag=epay-config
Step 3: Configure Environment Variables
Add to your .env file:
# Environment (test or prod)
EPAY_ENV=test
# OAuth2 Credentials
EPAY_CLIENT_ID=your_client_id
EPAY_CLIENT_SECRET=your_client_secret
EPAY_TERMINAL_ID=your_terminal_id
# For Invoice Link API
EPAY_SHOP_ID=your_shop_id
EPAY_USERNAME=your_username
EPAY_PASSWORD=your_password
# Callback URLs (optional, defaults provided)
EPAY_CALLBACK_URL=/epay/callback
EPAY_SUCCESS_URL=/epay/success
EPAY_FAILURE_URL=/epay/failure
Step 4: Publish Migrations (Optional)
If you want to store invoices in the database:
php artisan vendor:publish --tag=epay-migrations
php artisan migrate
Quick Start
Create Invoice Link
use NawrasBukhari\Epay\DTOs\InvoiceRequest;
use NawrasBukhari\Epay\Enums\Currency;
use NawrasBukhari\Epay\Enums\Language;
use NawrasBukhari\Epay\Services\PaymentService;
$paymentService = app(PaymentService::class);
$request = new InvoiceRequest(
invoiceId: '123456789012',
amount: 1000.00,
accountId: 'user-123',
description: 'Order payment',
recipientContact: 'customer@example.com',
recipientContactSms: '+77771234567',
currency: Currency::KZT,
language: Language::RUSSIAN,
);
$invoice = $paymentService->createInvoiceLink($request);
// Redirect user to payment URL
return redirect($invoice['invoice_url']);
Use Blade Component
<x-epay-button
:amount="1000"
:orderId="'123456789012'"
description="Order payment"
currency="KZT"
language="rus"
/>
Handle Payment Callbacks
use NawrasBukhari\Epay\Events\EpayPaymentSucceeded;
use NawrasBukhari\Epay\Events\EpayPaymentFailed;
// In your EventServiceProvider or dedicated listener
Event::listen(EpayPaymentSucceeded::class, function ($event) {
$paymentData = $event->paymentData;
// Update order status
Order::where('invoice_id', $paymentData['invoiceId'])
->update(['status' => 'paid']);
// Send confirmation email
Mail::to($paymentData['email'] ?? null)
->send(new PaymentConfirmation($paymentData));
});
Event::listen(EpayPaymentFailed::class, function ($event) {
$paymentData = $event->paymentData;
// Log failure
Log::warning('Payment failed', $paymentData);
// Notify user
// ...
});
API Reference
Services
PaymentService
use NawrasBukhari\Epay\Services\PaymentService;
$paymentService = app(PaymentService::class);
// Create invoice link
$invoice = $paymentService->createInvoiceLink($invoiceRequest);
// Check invoice status
$status = $paymentService->checkInvoiceLinkStatus('invoice-id');
// Check transaction status
$transaction = $paymentService->checkTransactionStatus('invoice-id');
$normalizedStatus = $paymentService->normalizeStatus($transaction['transaction'] ?? []);
// Deactivate invoice link
$paymentService->deactivateInvoiceLink('invoice-link-id');
// Get widget token
$token = $paymentService->getWidgetToken($widgetRequest);
TokenService
use NawrasBukhari\Epay\Services\TokenService;
$tokenService = app(TokenService::class);
// Get OAuth2 token (cached automatically)
$token = $tokenService->getToken();
// Get password token (for invoice status checks)
$passwordToken = $tokenService->getPasswordToken();
// Clear cached tokens
$tokenService->clearToken();
$tokenService->clearPasswordToken();
Enums
The package uses PHP 8.1+ enums for type safety:
use NawrasBukhari\Epay\Enums\PaymentStatus;
use NawrasBukhari\Epay\Enums\Currency;
use NawrasBukhari\Epay\Enums\Language;
use NawrasBukhari\Epay\Enums\Environment;
use NawrasBukhari\Epay\Enums\ResultCode;
// Payment Status
$status = PaymentStatus::PAID;
$status->isSuccessful(); // true
$status->isFailed(); // false
// Currency
$currency = Currency::KZT;
// Language
$language = Language::RUSSIAN;
$language->toWidgetFormat(); // 'RUS'
$language->getDisplayName(); // 'Russian'
// Environment
$env = Environment::fromString('prod');
$env->isProduction(); // true
// Result Code
$code = ResultCode::fromString('100');
$code->isSuccess(); // true
$code->getMessage(); // 'Success'
DTOs
InvoiceRequest
use NawrasBukhari\Epay\DTOs\InvoiceRequest;
use NawrasBukhari\Epay\Enums\Currency;
use NawrasBukhari\Epay\Enums\Language;
$request = new InvoiceRequest(
invoiceId: '123456789012', // Required: 6-15 digits
amount: 1000.00, // Required: float
accountId: 'user-123', // Required: string
description: 'Order payment', // Required: max 125 chars
recipientContact: 'user@example.com', // Required: email
recipientContactSms: '+77771234567', // Required: +7XXXXXXXXXX format
notifierContactSms: '+77771234568', // Optional
currency: Currency::KZT, // Optional: defaults to KZT
language: Language::RUSSIAN, // Optional: defaults to RUSSIAN
expirePeriod: '2d', // Optional: defaults to '2d'
postLink: 'https://...', // Optional: callback URL
failurePostLink: 'https://...', // Optional: failure callback
backLink: 'https://...', // Optional: success redirect
failureBackLink: 'https://...', // Optional: failure redirect
);
WidgetRequest
use NawrasBukhari\Epay\DTOs\WidgetRequest;
use NawrasBukhari\Epay\Enums\Currency;
use NawrasBukhari\Epay\Enums\Language;
$request = new WidgetRequest(
invoiceId: '123456789012', // Required: 6-15 digits
amount: 1000.00, // Required: float
terminal: 'terminal-id', // Required: string
invoiceIdAlt: 'alt-123', // Optional
backLink: 'https://...', // Optional
failureBackLink: 'https://...', // Optional
postLink: 'https://...', // Optional
failurePostLink: 'https://...', // Optional
language: Language::RUSSIAN, // Optional: defaults to RUSSIAN
description: 'Order payment', // Optional
accountId: 'user-123', // Optional
currency: Currency::KZT, // Optional: defaults to KZT
name: 'John Doe', // Optional
data: '{"custom": "data"}', // Optional: JSON string
);
Routes
The package automatically registers the following routes:
POST /epay/callback- Webhook endpoint (CSRF disabled)GET /epay/success- Success redirect pageGET /epay/failure- Failure redirect pagePOST /epay/api/invoice- Create invoice linkGET /epay/api/invoice/status- Check invoice statusGET /epay/api/transaction/status- Check transaction statusPOST /epay/api/widget/config- Get widget configuration
Events
The package dispatches the following Laravel events:
EpayPaymentSucceeded- Payment completed successfullyEpayPaymentFailed- Payment failedEpayPaymentPending- Payment is pendingEpayPaymentRefunded- Payment was refunded
Test Credentials
For testing, use these credentials from ePayment.kz:
Payments:
- ClientID:
test - ClientSecret:
yF587AV9Ms94qN2QShFzVR3vFnWkhjbAK3sG - TerminalID:
67e34d63-102f-4bd1-898e-370781d0074d
Payment Link by API:
- ClientID:
halykfinanceUSD - ClientSecret:
U01gQZVL##lJ$NhJ - TerminalID:
d9d7978c-d6ee-4ec0-8cda-165251a4bf16 - Shop ID:
04f25a4b-d2bd-4dd8-b3a7-9390be4774c4 - Username:
halykfinanceUSD@halykbank.nb - Password:
XVp36qar
Test Cards:
- PAN:
4405639704015096, Expire:01/27, CVC:321(unlock) - PAN:
5522042705066736, Expire:01/27, CVC:775(unlock) - PAN:
377514500004820, Expire:01/28, CVC:0198(unlock)
Testing
Run the test suite:
vendor/bin/phpunit
The package includes 56+ tests with 100% coverage of critical paths.
Security
- ✅ All sensitive data is masked in logs
- ✅ Token caching with automatic expiration
- ✅ Signature validation for callbacks (configurable)
- ✅ CSRF protection (disabled only for callback route)
- ✅ Input validation on all endpoints
- ✅ Type-safe enums prevent invalid values
- ✅ No sensitive data stored unencrypted
Documentation
- Full Documentation: See DEVELOPMENT.md
- ePay Official Docs: https://epayment.kz/en-US/docs
- Test Results: See tests/TEST_RESULTS.md
License
MIT License - see LICENSE file for details.
Support
- GitHub Issues: Create an issue
- Documentation: DEVELOPMENT.md
- ePay Support: https://epayment.kz
Contributing
Contributions are welcome! Please ensure:
- All tests pass (
vendor/bin/phpunit) - Code follows PSR-12 standards
- Strict types are used (
declare(strict_types=1)) - Enums are used for constants
- All new features include tests
Changelog
Version 1.0.0
Initial Release
- ✅ Complete ePayment.kz integration
- ✅ OAuth2 token management with caching
- ✅ Invoice Link API support
- ✅ Payment Widget integration
- ✅ Transaction status checking
- ✅ Callback handling with events
- ✅ Type-safe enums (PaymentStatus, Currency, Language, Environment, ResultCode)
- ✅ Strict typing throughout
- ✅ 100% test coverage (56+ tests)
- ✅ Comprehensive documentation
Made with ❤️ for the Laravel community
Package: nawrasbukhari/laravel-epay
Version: 1.0.0
Laravel: 10.x, 11.x, 12.x
PHP: 8.1+