Laravel
QPay V2 payment integration for Laravel 10+. Built on top of qpay-php , this package provides a service provider, Facade, Blade components, webhook controller, and Laravel events.
- GitHub: qpay-sdk/qpay-laravel
- Packagist: qpay-sdk/laravel
- Requirements: PHP 8.1+, Laravel 10 or 11
Installation
composer require qpay-sdk/laravelRun the install command to publish the config file:
php artisan qpay:installThis publishes config/qpay.php and displays the required environment variables.
Manual Setup (Optional)
If you prefer not to use the install command, publish the config manually:
php artisan vendor:publish --tag=qpay-configTo publish the Blade view templates for customization:
php artisan vendor:publish --tag=qpay-viewsThe service provider and Facade alias are auto-discovered via
composer.json— no manual registration needed.
Configuration
Environment Variables
Add the following to your .env file:
QPAY_BASE_URL=https://merchant.qpay.mn
QPAY_USERNAME=your_username
QPAY_PASSWORD=your_password
QPAY_INVOICE_CODE=your_invoice_code
QPAY_CALLBACK_URL=https://yoursite.com/qpay/webhookConfig File
The published config/qpay.php file:
return [
'base_url' => env('QPAY_BASE_URL', 'https://merchant.qpay.mn'),
'username' => env('QPAY_USERNAME'),
'password' => env('QPAY_PASSWORD'),
'invoice_code' => env('QPAY_INVOICE_CODE'),
'callback_url' => env('QPAY_CALLBACK_URL'),
'webhook_path' => env('QPAY_WEBHOOK_PATH', '/qpay/webhook'),
];| Key | Env Variable | Default | Description |
|---|---|---|---|
base_url | QPAY_BASE_URL | https://merchant.qpay.mn | QPay API base URL |
username | QPAY_USERNAME | — | Merchant username |
password | QPAY_PASSWORD | — | Merchant password |
invoice_code | QPAY_INVOICE_CODE | — | Default invoice code |
callback_url | QPAY_CALLBACK_URL | — | Payment callback URL |
webhook_path | QPAY_WEBHOOK_PATH | /qpay/webhook | Webhook endpoint path |
Quick Start
use QPay\Laravel\Facades\QPay;
use QPay\Models\CreateSimpleInvoiceRequest;
// Create an invoice
$invoice = QPay::createSimpleInvoice(new CreateSimpleInvoiceRequest(
invoiceCode: config('qpay.invoice_code'),
senderInvoiceNo: 'ORDER-001',
amount: 10000,
callbackUrl: config('qpay.callback_url'),
));
// $invoice->invoiceId -- QPay invoice ID
// $invoice->qrImage -- Base64-encoded QR code image
// $invoice->qrText -- QR code text for rendering
// $invoice->qPayShortUrl -- Short URL for payment
// $invoice->urls -- Array of bank deep linksCreate Invoice
Simple Invoice
use QPay\Laravel\Facades\QPay;
use QPay\Models\CreateSimpleInvoiceRequest;
$invoice = QPay::createSimpleInvoice(new CreateSimpleInvoiceRequest(
invoiceCode: config('qpay.invoice_code'),
senderInvoiceNo: 'ORDER-' . $order->id,
amount: $order->total,
callbackUrl: config('qpay.callback_url'),
));Full Invoice (Advanced)
use QPay\Laravel\Facades\QPay;
use QPay\Models\CreateInvoiceRequest;
$invoice = QPay::createInvoice(new CreateInvoiceRequest(
invoiceCode: config('qpay.invoice_code'),
senderInvoiceNo: 'ORDER-' . $order->id,
invoiceReceiverCode: 'receiver_001',
invoiceDescription: 'Payment for Order #' . $order->id,
amount: $order->total,
callbackUrl: config('qpay.callback_url'),
));Cancel Invoice
QPay::cancelInvoice($invoiceId);Check Payment Status
use QPay\Models\PaymentCheckRequest;
$result = QPay::checkPayment(new PaymentCheckRequest(
objectType: 'INVOICE',
objectId: $invoiceId,
));
if (count($result->rows) > 0) {
// Payment confirmed
}List Payments
use QPay\Models\PaymentListRequest;
$payments = QPay::listPayments(new PaymentListRequest(
objectType: 'INVOICE',
objectId: $invoiceId,
));Get Payment Detail
$payment = QPay::getPayment($paymentId);Webhook Handling
The package automatically registers a webhook route at the configured path (default: /qpay/webhook). The route is excluded from CSRF verification.
When QPay sends a callback, the webhook controller:
- Extracts the
invoice_idfrom the request body - Calls
checkPaymentto verify the payment - Dispatches a
PaymentReceivedevent if payment rows are found - Dispatches a
PaymentFailedevent if no payment is found or an error occurs - Returns a JSON response with the status
Webhook Route
The route is registered automatically in routes/qpay.php:
Route::post(config('qpay.webhook_path', '/qpay/webhook'), WebhookController::class)
->name('qpay.webhook')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);You can customize the webhook path via the QPAY_WEBHOOK_PATH environment variable.
Events
The package dispatches two Laravel events:
PaymentReceived
Fired when a payment is confirmed (at least one payment row found).
use QPay\Laravel\Events\PaymentReceived;
// In EventServiceProvider or using Event::listen
Event::listen(PaymentReceived::class, function (PaymentReceived $event) {
$event->invoiceId; // string -- QPay invoice ID
$event->result; // PaymentCheckResponse -- Full check result
// Example: Update your order status
$order = Order::where('qpay_invoice_id', $event->invoiceId)->first();
$order->update(['status' => 'paid']);
});PaymentFailed
Fired when no payment is found or when an error occurs during verification.
use QPay\Laravel\Events\PaymentFailed;
Event::listen(PaymentFailed::class, function (PaymentFailed $event) {
$event->invoiceId; // string -- QPay invoice ID
$event->reason; // string -- Failure reason
Log::warning("QPay payment failed for {$event->invoiceId}: {$event->reason}");
});Blade Components
QR Code
Renders the QPay QR code image.
<x-qpay-qr-code :qr-image="$invoice->qrImage" />
{{-- With custom size --}}
<x-qpay-qr-code :qr-image="$invoice->qrImage" :size="200" />
{{-- Using QR text instead of image --}}
<x-qpay-qr-code :qr-text="$invoice->qrText" />Props:
| Prop | Type | Default | Description |
|---|---|---|---|
qr-image | string | '' | Base64-encoded QR code image |
qr-text | string | '' | QR code text to render |
size | int | 256 | QR code width/height in pixels |
Payment Button
Renders bank deep link buttons.
<x-qpay-payment-button :urls="$invoice->urls" :short-url="$invoice->qPayShortUrl" />Props:
| Prop | Type | Default | Description |
|---|---|---|---|
urls | array | [] | Bank deep link URLs from invoice response |
short-url | string | '' | QPay short URL for payment |
Customizing Views
Publish the views and edit them:
php artisan vendor:publish --tag=qpay-viewsPublished to resources/views/vendor/qpay/.
Testing
Use Laravel’s built-in mocking to test QPay integration.
Mocking the Client
use QPay\QPayClient;
use QPay\Models\PaymentCheckResponse;
// In your test
$mockResult = new PaymentCheckResponse(
count: 1,
paidAmount: 10000.0,
rows: [(object)['paymentId' => 'pay_123']],
);
$mock = $this->createMock(QPayClient::class);
$mock->method('checkPayment')->willReturn($mockResult);
$this->app->instance(QPayClient::class, $mock);Testing Webhook Events
use Illuminate\Support\Facades\Event;
use QPay\Laravel\Events\PaymentReceived;
Event::fake();
$this->postJson('/qpay/webhook', ['invoice_id' => 'inv_123']);
Event::assertDispatched(PaymentReceived::class, function ($event) {
return $event->invoiceId === 'inv_123';
});Testing with Testbench
The package uses Orchestra Testbench for testing:
use Orchestra\Testbench\TestCase;
use QPay\Laravel\QPayServiceProvider;
class MyTest extends TestCase
{
protected function getPackageProviders($app): array
{
return [QPayServiceProvider::class];
}
}API Reference
Facade Methods (QPay::)
| Method | Return Type | Description |
|---|---|---|
createInvoice(CreateInvoiceRequest $req) | InvoiceResponse | Create a full invoice |
createSimpleInvoice(CreateSimpleInvoiceRequest $req) | InvoiceResponse | Create a simple invoice |
cancelInvoice(string $invoiceId) | void | Cancel an invoice |
getPayment(string $paymentId) | PaymentDetail | Get payment details |
checkPayment(PaymentCheckRequest $req) | PaymentCheckResponse | Check payment status |
listPayments(PaymentListRequest $req) | PaymentListResponse | List payments |
Classes
| Class | Namespace | Description |
|---|---|---|
QPayServiceProvider | QPay\Laravel | Auto-discovered service provider |
QPay (Facade) | QPay\Laravel\Facades | Facade for QPayClient |
WebhookController | QPay\Laravel\Http\Controllers | Webhook endpoint handler |
PaymentReceived | QPay\Laravel\Events | Event dispatched on payment success |
PaymentFailed | QPay\Laravel\Events | Event dispatched on payment failure |
QrCode | QPay\Laravel\Components | Blade component for QR codes |
PaymentButton | QPay\Laravel\Components | Blade component for bank links |
InstallCommand | QPay\Laravel\Console | qpay:install artisan command |
Links
- GitHub: github.com/qpay-sdk/qpay-laravel
- Packagist: packagist.org/packages/qpay-sdk/laravel
- Base SDK: qpay-php