ftech/laravel-azopay

Laravel package for the AzoPay payment gateway (VietQR bank transfer with automatic reconciliation).

Maintainers

Package info

github.com/banam8910/laravel-azopay

Homepage

pkg:composer/ftech/laravel-azopay

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-05 08:37 UTC

This package is auto-updated.

Last update: 2026-06-05 08:42:53 UTC


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ẽ:

  1. Xác thực header X-AzoPay-Signature (t=<ts>,v1=<hmac>), HMAC-SHA256 trên "{timestamp}.{body}".
  2. Chống trùng theo X-AzoPay-Event-Id.
  3. 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.