Tích hợp Node.js
Tích hợp
Cập nhật: 23/03/2026
Tích hợp ThueAPI.VN với Node.js
Xây dựng webhook server với Express, lưu vào database, và push thông báo realtime qua Socket.io.
Cài đặt dependencies
npm install express axios crypto mongoose socket.io dotenv
Cấu hình .env
THUEAPI_KEY=your_api_key_here
THUEAPI_WEBHOOK_SECRET=your_webhook_secret_here
MONGODB_URI=mongodb://localhost:27017/thueapi_app
PORT=3000
Model (Mongoose)
// models/Transaction.js
const mongoose = require('mongoose');
const transactionSchema = new mongoose.Schema({
transactionNumber: { type: String, unique: true, required: true },
gateway: { type: String, required: true },
accountNumber: { type: String, required: true },
transferType: { type: String, enum: ['IN', 'OUT'], required: true },
transferAmount: { type: Number, required: true },
content: { type: String },
transactionDate: { type: Date, required: true },
}, { timestamps: true });
transactionSchema.index({ accountNumber: 1, transferType: 1 });
module.exports = mongoose.model('Transaction', transactionSchema);
Webhook Server với Socket.io
// server.js — Express + Socket.io webhook handler
require('dotenv').config();
const express = require('express');
const http = require('http');
const crypto = require('crypto');
const { Server } = require('socket.io');
const mongoose = require('mongoose');
const Transaction = require('./models/Transaction');
const app = express();
const server = http.createServer(app);
const io = new Server(server);
// Kết nối MongoDB
mongoose.connect(process.env.MONGODB_URI)
.then(() => console.log('MongoDB connected'))
.catch(err => console.error('MongoDB error:', err));
// Raw body cho webhook (để tính HMAC chính xác)
app.use('/webhook', express.raw({ type: 'application/json' }));
app.use(express.json());
// Webhook endpoint
app.post('/webhook/thueapi', async (req, res) => {
const rawBody = req.body; // Buffer
const signature = req.headers['x-webhook-signature'];
const secret = process.env.THUEAPI_WEBHOOK_SECRET;
// Xác thực chữ ký HMAC-SHA256
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature || ''))) {
return res.status(401).json({ error: 'Invalid signature' });
}
const data = JSON.parse(rawBody.toString());
for (const tx of data.transactions) {
try {
// Lưu vào MongoDB (bỏ qua nếu đã tồn tại)
const saved = await Transaction.findOneAndUpdate(
{ transactionNumber: tx.transactionNumber },
{ $setOnInsert: {
gateway: tx.gateway,
accountNumber: tx.accountNumber,
transferType: tx.transferType,
transferAmount: tx.transferAmount,
content: tx.content,
transactionDate: new Date(tx.transactionDate),
}},
{ upsert: true, new: true, rawResult: true }
);
// Chỉ emit nếu là giao dịch mới
if (saved.lastErrorObject?.updatedExisting === false) {
// Realtime notification qua Socket.io
io.emit('new_transaction', {
type: tx.transferType,
amount: tx.transferAmount,
bank: tx.gateway,
content: tx.content,
time: tx.transactionDate,
});
console.log(`Giao dịch mới: ${tx.transferType} ${tx.transferAmount} VND`);
}
} catch (err) {
console.error('Lỗi lưu giao dịch:', err.message);
}
}
res.json({ success: true });
});
// Client kết nối Socket.io để nhận realtime
io.on('connection', (socket) => {
console.log('Client kết nối:', socket.id);
socket.on('disconnect', () => console.log('Client ngắt kết nối:', socket.id));
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => console.log(`Server chạy trên port ${PORT}`));
Client HTML nhận realtime
<!-- public/index.html -->
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
socket.on('new_transaction', (tx) => {
const msg = `[${tx.time}] ${tx.type} ${tx.amount.toLocaleString()} VND từ ${tx.bank}`;
document.getElementById('transactions').insertAdjacentHTML(
'afterbegin', `<div class="alert">${msg}</div>`
);
});
</script>
API Client (lấy lịch sử giao dịch)
// thueapi-client.js — Wrapper gọi ThueAPI
const axios = require('axios');
const thueApi = axios.create({
baseURL: 'https://thueapi.vn/api/v1',
headers: { 'Authorization': `Bearer ${process.env.THUEAPI_KEY}` },
});
async function getTransactions(params = {}) {
const { data } = await thueApi.get('/transactions', { params });
return data;
}
async function getBankAccounts() {
const { data } = await thueApi.get('/bank-accounts');
return data;
}
module.exports = { getTransactions, getBankAccounts };