Tích hợp Laravel
Tích hợp
Cập nhật: 22/03/2026
Tích hợp ThueAPI.VN vào Laravel
Hướng dẫn đầy đủ tích hợp webhook ThueAPI vào ứng dụng Laravel với queue processing và lưu database.
1. Cấu hình
# Thêm vào .env
THUEAPI_KEY=your_api_key_here
THUEAPI_WEBHOOK_SECRET=your_webhook_secret_here
THUEAPI_BASE_URL=https://thueapi.vn/api/v1
// config/services.php
'thueapi' => [
'key' => env('THUEAPI_KEY'),
'webhook_secret' => env('THUEAPI_WEBHOOK_SECRET'),
'base_url' => env('THUEAPI_BASE_URL', 'https://thueapi.vn/api/v1'),
],
2. Migration
// database/migrations/xxxx_create_bank_transactions_table.php
Schema::create('bank_transactions', function (Blueprint $table) {
$table->id();
$table->string('transaction_number')->unique();
$table->string('gateway', 20);
$table->string('account_number', 50);
$table->enum('transfer_type', ['IN', 'OUT']);
$table->unsignedBigInteger('transfer_amount');
$table->text('content');
$table->timestamp('transaction_date');
$table->timestamps();
$table->index(['account_number', 'transfer_type']);
$table->index('transaction_date');
});
3. Model
// app/Models/BankTransaction.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class BankTransaction extends Model
{
protected $fillable = [
'transaction_number', 'gateway', 'account_number',
'transfer_type', 'transfer_amount', 'content', 'transaction_date',
];
protected $casts = [
'transaction_date' => 'datetime',
'transfer_amount' => 'integer',
];
}
4. Route
// routes/api.php
// Bỏ qua CSRF cho webhook endpoint
Route::post('/webhook/thueapi', [ThueApiWebhookController::class, 'handle'])
->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);
5. Controller
// app/Http/Controllers/ThueApiWebhookController.php
namespace App\Http\Controllers;
use App\Jobs\ProcessBankTransaction;
use App\Models\BankTransaction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class ThueApiWebhookController extends Controller
{
public function handle(Request $request)
{
// Xác thực chữ ký HMAC
$secret = config('services.thueapi.webhook_secret');
$payload = $request->getContent();
$signature = $request->header('X-Webhook-Signature', '');
$expected = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $signature)) {
Log::warning('ThueAPI webhook: chữ ký không hợp lệ', [
'ip' => $request->ip(),
]);
return response()->json(['error' => 'Invalid signature'], 401);
}
// Đưa vào queue để xử lý bất đồng bộ
foreach ($request->input('transactions', []) as $tx) {
// Kiểm tra trùng trước khi dispatch
if (!BankTransaction::where('transaction_number', $tx['transactionNumber'])->exists()) {
ProcessBankTransaction::dispatch($tx);
}
}
return response()->json(['success' => true]);
}
}
6. Job xử lý bất đồng bộ
// app/Jobs/ProcessBankTransaction.php
namespace App\Jobs;
use App\Models\BankTransaction;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class ProcessBankTransaction implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
public int $timeout = 60;
public function __construct(private array $transaction) {}
public function handle(): void
{
$tx = $this->transaction;
// Lưu vào database (INSERT IGNORE để tránh duplicate)
BankTransaction::firstOrCreate(
['transaction_number' => $tx['transactionNumber']],
[
'gateway' => $tx['gateway'],
'account_number' => $tx['accountNumber'],
'transfer_type' => $tx['transferType'],
'transfer_amount' => $tx['transferAmount'],
'content' => $tx['content'],
'transaction_date' => $tx['transactionDate'],
]
);
Log::info('ThueAPI: giao dịch đã lưu', [
'number' => $tx['transactionNumber'],
'type' => $tx['transferType'],
'amount' => $tx['transferAmount'],
]);
// TODO: Thêm business logic tại đây
// - Cập nhật trạng thái đơn hàng
// - Gửi email xác nhận
// - Tích điểm khách hàng
}
}