ftech / laravel-azopay
Laravel package for the AzoPay payment gateway (VietQR bank transfer with automatic reconciliation).
Requires
- php: ^8.1
- illuminate/contracts: ^10.0 || ^11.0 || ^12.0
- illuminate/http: ^10.0 || ^11.0 || ^12.0
- illuminate/support: ^10.0 || ^11.0 || ^12.0
Requires (Dev)
- orchestra/testbench: ^8.0 || ^9.0 || ^10.0
- phpunit/phpunit: ^10.0 || ^11.0
README
Tích hợp cổng thanh toán AzoPay (chuyển khoản VietQR, tự động đối soát) cho Laravel.
Package cung cấp client gọi API, tạo đơn thanh toán + QR VietQR, và một webhook endpoint đã xác thực chữ ký để nhận sự kiện biến động giao dịch và bắn ra Laravel events.
- Laravel 10 / 11 / 12 · PHP 8.1+
- Tạo order, lấy QR + thông tin chuyển khoản
- Truy vấn trạng thái order
- Liệt kê tài khoản ngân hàng
- Webhook ký HMAC-SHA256 (
X-AzoPay-Signature) + chống xử lý trùng (idempotency)
Cài đặt
composer require ftech/laravel-azopay php artisan vendor:publish --tag=azopay-config
Cấu hình .env:
AZOPAY_ENV=sandbox # sandbox | live AZOPAY_API_KEY=your-api-key AZOPAY_BANK_ACCOUNT_ID=42 # ID tài khoản nhận tiền trên dashboard AZOPAY_PAY_CODE_PREFIX=DH AZOPAY_EXPIRES_IN=3600 AZOPAY_WEBHOOK_SECRET=whsec_xxx # có thể nhiều secret, cách nhau bằng dấu phẩy
Base URL mặc định: https://staging-api.azopay.vn (sandbox) và https://my.azopay.vn (live).
Tạo đơn thanh toán
use Ftech\AzoPay\Facades\AzoPay; use Ftech\AzoPay\Data\CreateOrderData; $order = AzoPay::orders()->create( CreateOrderData::make() ->amount(100_000) // VND ->merchantOrderId('DH' . $order->id) // mã đối soát, khớp prefix trên dashboard ->description('Đơn hàng #' . $order->id) ->metadata(['order_id' => $order->id]) // ->bankAccount('42') // bỏ qua => dùng config mặc định // ->expiresIn(1800) ); $order->id; // id đơn trên AzoPay $order->transferCode; // nội dung chuyển khoản $order->qrCodeUrl(); // ảnh QR VietQR $order->checkoutUrl(); // trang thanh toán hosted $order->paymentInfo->accountNumber;
Có thể truyền thẳng mảng thay cho CreateOrderData:
AzoPay::orders()->create([ 'amount' => 100_000, 'merchant_order_id' => 'DH123', 'description' => 'Đơn hàng #123', ]);
Truy vấn order & tài khoản ngân hàng
$order = AzoPay::orders()->find('ord_123'); $order->isPaid(); $accounts = AzoPay::bankAccounts()->all(); // Collection<BankAccount> $account = AzoPay::bankAccounts()->find('42');
Webhook
Route POST /azopay/webhook được đăng ký tự động (đổi đường dẫn qua AZOPAY_WEBHOOK_PATH, hoặc tắt bằng AZOPAY_WEBHOOK_ROUTE=false). Endpoint sẽ:
- Xác thực header
X-AzoPay-Signature(t=<ts>,v1=<hmac>), HMAC-SHA256 trên"{timestamp}.{body}". - Chống trùng theo
X-AzoPay-Event-Id. - Bắn Laravel events.
Lắng nghe sự kiện:
use Ftech\AzoPay\Events\OrderPaid; class MarkOrderPaid { public function handle(OrderPaid $event): void { $order = $event->order(); // Ftech\AzoPay\Data\Order $moid = $order->merchantOrderId; // 'DH123' $paid = $order->paidAmount; // ... cập nhật đơn hàng của bạn } }
Các event có sẵn (đều extend AzoPayWebhookReceived — listen class này để nhận tất cả):
| Event | AzoPay type |
|---|---|
OrderPaid |
order.paid |
OrderUnderpaid |
order.underpaid |
OrderOverpaid |
order.overpaid |
OrderCancelled |
order.cancelled |
OrderExpired |
order.expired |
Đăng ký trong EventServiceProvider:
protected $listen = [ \Ftech\AzoPay\Events\OrderPaid::class => [ \App\Listeners\MarkOrderPaid::class, ], ];
Tự xử lý webhook
Muốn tự làm route riêng, tắt route mặc định và dùng middleware xác thực chữ ký:
use Ftech\AzoPay\Http\Middleware\VerifyAzoPaySignature; Route::post('/payments/azopay', PaymentWebhookController::class) ->middleware(VerifyAzoPaySignature::class);
Hoặc xác thực thủ công:
AzoPay::signature()->verify($request->getContent(), $request->header('X-AzoPay-Signature'));
Nội dung chuyển khoản (remark)
VietinBank và ABBANK yêu cầu thêm tiền tố SEVQR. Helper tự xử lý:
AzoPay::remark('DH123', $bankBin); // "DH123" hoặc "SEVQR DH123"
Testing
composer install vendor/bin/phpunit
Trong app của bạn, fake HTTP của Laravel để test:
Http::fake(['*/api/v1/orders' => Http::response(['status' => 'success', 'data' => [...]])]);
License
MIT.