Tóm tắt
API iPay cho phép các nhà phát triển tích hợp xử lý thanh toán, lập hóa đơn và giao dịch tài chính theo chương trình. Nó sử dụng xác thực OAuth 2.0 và khóa API, các điểm cuối RESTful cho thanh toán, hoàn tiền, giao dịch và đối chiếu, với các yêu cầu tuân thủ PCI DSS và giới hạn tỷ lệ tiêu chuẩn ngành. Hướng dẫn này bao gồm thiết lập xác thực, xử lý thanh toán, tích hợp webhook, tuân thủ bảo mật và các chiến lược triển khai sản xuất.
Giới thiệu
Xử lý thanh toán kỹ thuật số xử lý hơn 8 nghìn tỷ đô la hàng năm trên toàn thế giới. Đối với các nhà phát triển xây dựng nền tảng thương mại điện tử, ứng dụng SaaS hoặc giải pháp thị trường, tích hợp API thanh toán không phải là tùy chọn—nó rất cần thiết để chấp nhận thanh toán của khách hàng một cách an toàn và tuân thủ.
Đây là thực tế: các doanh nghiệp mất 5-10% doanh thu do thanh toán thất bại, đối chiếu thủ công và gian lận thanh toán. Một tích hợp API thanh toán vững chắc sẽ tự động hóa quá trình xử lý thanh toán, giảm thiểu lỗi với logic thử lại thông minh, cho phép đối chiếu tự động và triển khai phát hiện gian lận.
Hướng dẫn này sẽ đi sâu vào quy trình tích hợp API thanh toán hoàn chỉnh. Bạn sẽ tìm hiểu thiết lập xác thực, xử lý thanh toán, quản lý hoàn tiền, xử lý webhook, tuân thủ PCI DSS, các phương pháp bảo mật tốt nhất và chiến lược triển khai sản xuất. Cuối cùng, bạn sẽ có một tích hợp thanh toán sẵn sàng sản xuất.
Lưu ý: Hướng dẫn này bao gồm các mẫu tích hợp API thanh toán chung áp dụng cho iPay và các bộ xử lý thanh toán tương tự. Các URL điểm cuối và chi tiết xác thực cụ thể có thể khác nhau—hãy luôn tham khảo tài liệu chính thức của iPay để biết chi tiết triển khai.
API iPay là gì?
Các API thanh toán như iPay cung cấp giao diện RESTful để xử lý các giao dịch tài chính. API xử lý:
- Ủy quyền và thu tiền thanh toán
- Hoàn tiền và bồi hoàn (chargebacks)
- Lịch sử giao dịch và báo cáo
- Mã hóa thông tin khách hàng (vault)
- Đăng ký và thanh toán định kỳ
- Tạo và quản lý hóa đơn
- Đối chiếu và thanh toán bù trừ
- Phát hiện và ngăn chặn gian lận
Các tính năng chính
| Tính năng | Mô tả |
|---|---|
| API RESTful | Điểm cuối dựa trên JSON |
| OAuth 2.0 + Khóa API | Xác thực an toàn |
| Webhooks | Thông báo thanh toán theo thời gian thực |
| Mã hóa token (Tokenization) | Lưu trữ thẻ an toàn |
| 3D Secure | Tuân thủ SCA |
| PCI DSS | Yêu cầu tuân thủ Cấp độ 1 |
| Đa tiền tệ | Hỗ trợ hơn 100 loại tiền tệ |
| Công cụ chống gian lận | Chấm điểm rủi ro, kiểm tra tốc độ |
Tổng quan về luồng thanh toán
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Khách hàng │───▶│ Người bán │───▶│ Cổng │
│ (Trình duyệt)│ │ (Máy chủ) │ │ Thanh toán │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
│ 1. Nhập thẻ │ │
│───────────────────▶│ │
│ │ │
│ 2. Mã hóa token │ │
│───────────────────▶│ 3. Tạo Ý định │
│ │───────────────────▶│
│ │ │
│ │ 4. Xác nhận thanh toán│
│ │───────────────────▶│
│ │ │
│ │ 5. Kết quả │
│ │◀───────────────────│
│ │ │
│ 6. Biên nhận │ │
│◀───────────────────│ │
Môi trường API
| Môi trường | URL | Trường hợp sử dụng |
|---|---|---|
| Sandbox | https://sandbox.ipay.com/api |
Phát triển, kiểm thử |
| Production | https://api.ipay.com/api |
Giao dịch trực tiếp |
Bắt đầu: Thiết lập xác thực
Bước 1: Tạo tài khoản iPay
Trước khi truy cập API:
- Truy cập đăng ký tài khoản người bán iPay
- Hoàn thành xác minh doanh nghiệp (KYB)
- Gửi các tài liệu cần thiết:
- Đăng ký kinh doanh
- Chi tiết tài khoản ngân hàng
- Giấy tờ tùy thân do chính phủ cấp
- Chờ phê duyệt (1-3 ngày làm việc)
Bước 2: Lấy thông tin xác thực API
Tạo thông tin xác thực API:
- Đăng nhập vào Bảng điều khiển người bán iPay
- Điều hướng đến Cài đặt > Khóa API
- Tạo khóa API mới
- Sao chép thông tin xác thực một cách an toàn
# Tệp .env (KHÔNG BAO GIỜ cam kết lên git)
IPAY_API_KEY="live_xxxxxxxxxxxxxxxxxxxx"
IPAY_API_SECRET="secret_xxxxxxxxxxxxxxxxxxxx"
IPAY_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxx"
Lưu ý bảo mật: Sử dụng các khóa riêng biệt cho môi trường thử nghiệm (sandbox) và môi trường sản xuất (production).
Bước 3: Hiểu các phương pháp xác thực
iPay hỗ trợ nhiều phương pháp xác thực:
| Phương pháp | Tốt nhất cho | Mức độ bảo mật |
|---|---|---|
| Xác thực cơ bản (Basic Auth) | Server-to-server | Cao |
| OAuth 2.0 | Ứng dụng đa đối tượng thuê | Cao hơn |
| JWT | Microservices | Cao |
Bước 4: Thực hiện các cuộc gọi API đã được xác thực
Tạo client API có thể tái sử dụng:
const IPAY_BASE_URL = process.env.IPAY_SANDBOX
? 'https://sandbox.ipay.com/api'
: 'https://api.ipay.com/api';
const ipayRequest = async (endpoint, options = {}) => {
const apiKey = process.env.IPAY_API_KEY;
const apiSecret = process.env.IPAY_API_SECRET;
// Xác thực cơ bản (Mã hóa Base64)
const authHeader = Buffer.from(`${apiKey}:${apiSecret}`).toString('base64');
const response = await fetch(`${IPAY_BASE_URL}${endpoint}`, {
...options,
headers: {
'Authorization': `Basic ${authHeader}`,
'Content-Type': 'application/json',
'Idempotency-Key': options.idempotencyKey || generateIdempotencyKey(),
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Lỗi API iPay: ${error.message}`);
}
return response.json();
};
function generateIdempotencyKey() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// Cách sử dụng
const account = await ipayRequest('/account');
console.log(`Người bán: ${account.business_name}`);
Xử lý thanh toán
Tạo ý định thanh toán
Khởi tạo thanh toán:
const createPayment = async (paymentData) => {
const payment = {
amount: paymentData.amount, // Đơn vị tiền tệ nhỏ nhất (cents)
currency: paymentData.currency || 'USD',
customer: paymentData.customerId,
payment_method: paymentData.paymentMethodId,
confirm: true,
description: paymentData.description,
metadata: {
orderId: paymentData.orderId,
customerId: paymentData.customerId
},
capture_method: paymentData.captureMethod || 'automatic', // 'automatic' hoặc 'manual'
statement_descriptor: paymentData.statementDescriptor || 'MYCOMPANY'
};
const response = await ipayRequest('/payments', {
method: 'POST',
body: JSON.stringify(payment),
idempotencyKey: paymentData.idempotencyKey
});
return response;
};
// Cách sử dụng
const payment = await createPayment({
amount: 2999, // 29,99 USD
currency: 'USD',
customerId: 'cus_12345',
paymentMethodId: 'pm_67890',
description: 'Đơn hàng #ORD-001',
orderId: 'ORD-001',
statementDescriptor: 'MYCOMPANY INC'
});
console.log(`Trạng thái thanh toán: ${payment.status}`);
console.log(`ID thanh toán: ${payment.id}`);
Luồng trạng thái thanh toán
yêu_cầu_phương_thức_thanh_toán → yêu_cầu_xác_nhận → yêu_cầu_hành_động
→ đang_xử_lý → yêu_cầu_thu_tiền → thành_công
→ thất_bại
→ đã_hủy
Phương thức thanh toán
| Phương thức | Loại | Trường hợp sử dụng |
|---|---|---|
card (thẻ) |
Thẻ tín dụng/ghi nợ | Thanh toán tiêu chuẩn |
bank_transfer (chuyển khoản ngân hàng) |
ACH, SEPA | Chuyển khoản phí thấp |
digital_wallet (ví điện tử) |
Apple Pay, Google Pay | Thanh toán trên di động |
buy_now_pay_later (mua trước trả sau) |
Klarna, Afterpay | Thanh toán trả góp |
Mã hóa Token thông tin thẻ
Lưu trữ thẻ an toàn để sử dụng trong tương lai:
const tokenizeCard = async (cardData) => {
// KHÔNG BAO GIỜ gửi dữ liệu thẻ thô đến máy chủ của bạn
// Thay vào đó, hãy sử dụng mã hóa token phía client
// Phía client (trình duyệt/di động)
const response = await fetch(`${IPAY_BASE_URL}/tokens`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CLIENT_PUBLISHABLE_KEY}`
},
body: JSON.stringify({
card: {
number: cardData.number,
exp_month: cardData.expMonth,
exp_year: cardData.expYear,
cvc: cardData.cvc
}
})
});
const token = await response.json();
return token; // Gửi token.id đến máy chủ của bạn
};
// Phía máy chủ: Sử dụng token để tạo phương thức thanh toán
const createPaymentMethod = async (tokenId, customerId) => {
const response = await ipayRequest('/payment_methods', {
method: 'POST',
body: JSON.stringify({
type: 'card',
token: tokenId,
customer: customerId
})
});
return response;
};
Xác thực 3D Secure
Thực hiện tuân thủ SCA:
const createPaymentWith3DS = async (paymentData) => {
const payment = await createPayment({
...paymentData,
confirmation_token: true // Trả về client secret cho 3DS
});
if (payment.status === 'requires_action') {
// Client phải hoàn thành thử thách 3DS
return {
requiresAction: true,
clientSecret: payment.client_secret,
nextAction: payment.next_action
};
}
return { success: true, payment };
};
// Phía client: Xử lý thử thách 3DS
// Sử dụng iPay.js hoặc SDK di động để hiển thị thử thách xác thực
Quản lý hoàn tiền
Xử lý hoàn tiền toàn bộ
Hoàn lại toàn bộ khoản thanh toán:
const refundPayment = async (paymentId, reason = null) => {
const refund = {
payment: paymentId,
reason: reason || 'khách hàng yêu cầu'
};
const response = await ipayRequest('/refunds', {
method: 'POST',
body: JSON.stringify(refund),
idempotencyKey: `refund_${paymentId}_${Date.now()}`
});
return response;
};
// Cách sử dụng
const refund = await refundPayment('pay_12345', 'trùng lặp');
console.log(`Trạng thái hoàn tiền: ${refund.status}`);
console.log(`ID hoàn tiền: ${refund.id}`);
Xử lý hoàn tiền một phần
Hoàn lại một phần khoản thanh toán:
const partialRefund = async (paymentId, amount, reason = null) => {
const refund = {
payment: paymentId,
amount: amount, // Đơn vị tiền tệ nhỏ nhất
reason: reason || 'khách hàng yêu cầu'
};
const response = await ipayRequest('/refunds', {
method: 'POST',
body: JSON.stringify(refund),
idempotencyKey: `refund_${paymentId}_${amount}_${Date.now()}`
});
return response;
};
// Cách sử dụng - Hoàn lại 15,00 USD từ khoản thanh toán 29,99 USD
const refund = await partialRefund('pay_12345', 1500, 'giao hàng một phần');
console.log(`Đã hoàn tiền: $${refund.amount / 100}`);
Lý do hoàn tiền
| Mã lý do | Mô tả |
|---|---|
duplicate (trùng lặp) |
Giao dịch trùng lặp |
fraudulent (gian lận) |
Giao dịch gian lận |
requested_by_customer (khách hàng yêu cầu) |
Yêu cầu của khách hàng |
order_canceled (đơn hàng bị hủy) |
Hủy đơn hàng |
product_not_received (chưa nhận được sản phẩm) |
Mặt hàng chưa được giao |
product_not_as_described (sản phẩm không như mô tả) |
Mặt hàng khác với mô tả |
Quản lý khách hàng
Tạo khách hàng
Lưu trữ khách hàng để thanh toán định kỳ:
const createCustomer = async (customerData) => {
const customer = {
email: customerData.email,
name: customerData.name,
phone: customerData.phone,
metadata: {
internalId: customerData.internalId,
tier: customerData.tier
}
};
const response = await ipayRequest('/customers', {
method: 'POST',
body: JSON.stringify(customer)
});
return response;
};
// Cách sử dụng
const customer = await createCustomer({
email: 'customer@example.com',
name: 'John Doe',
phone: '+1-555-0123',
internalId: 'USR-12345',
tier: 'premium'
});
console.log(`Đã tạo khách hàng: ${customer.id}`);
Gắn phương thức thanh toán vào khách hàng
Lưu thẻ để sử dụng trong tương lai:
const attachPaymentMethod = async (paymentMethodId, customerId) => {
const response = await ipayRequest(`/payment_methods/${paymentMethodId}/attach`, {
method: 'POST',
body: JSON.stringify({
customer: customerId
})
});
return response;
};
// Cách sử dụng
await attachPaymentMethod('pm_67890', 'cus_12345');
Liệt kê các phương thức thanh toán của khách hàng
Lấy các thẻ đã lưu:
const getCustomerPaymentMethods = async (customerId) => {
const response = await ipayRequest(`/customers/${customerId}/payment_methods`);
return response;
};
// Cách sử dụng
const methods = await getCustomerPaymentMethods('cus_12345');
methods.data.forEach(method => {
console.log(`${method.card.brand} kết thúc bằng ${method.card.last4}`);
console.log(`Hết hạn: ${method.card.exp_month}/${method.card.exp_year}`);
});
Webhooks
Cấu hình Webhooks
Thiết lập các điểm cuối webhook:
- Đăng nhập vào Bảng điều khiển iPay
- Điều hướng đến Nhà phát triển > Webhooks
- Nhấp vào Thêm điểm cuối
- Nhập URL HTTPS của bạn
- Chọn các sự kiện để đăng ký
Sự kiện Webhook
| Sự kiện | Kích hoạt |
|---|---|
payment.succeeded (thanh toán thành công) |
Thanh toán hoàn tất |
payment.failed (thanh toán thất bại) |
Thanh toán bị từ chối |
payment.refunded (đã hoàn tiền) |
Đã xử lý hoàn tiền |
payment.disputed (thanh toán bị tranh chấp) |
Đã yêu cầu bồi hoàn (chargeback) |
customer.created (đã tạo khách hàng) |
Khách hàng mới |
customer.subscription.updated (đã cập nhật đăng ký của khách hàng) |
Đăng ký đã thay đổi |
Xử lý Webhooks
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/ipay', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['ipay-signature'];
const payload = req.body;
// Xác minh chữ ký webhook
const isValid = verifyWebhookSignature(payload, signature, process.env.IPAY_WEBHOOK_SECRET);
if (!isValid) {
console.error('Chữ ký webhook không hợp lệ');
return res.status(401).send('Không được ủy quyền');
}
const event = JSON.parse(payload.toString());
// Định tuyến đến trình xử lý phù hợp
switch (event.type) {
case 'payment.succeeded':
await handlePaymentSucceeded(event.data);
break;
case 'payment.failed':
await handlePaymentFailed(event.data);
break;
case 'payment.refunded':
await handlePaymentRefunded(event.data);
break;
case 'payment.disputed':
await handlePaymentDisputed(event.data);
break;
default:
console.log('Loại sự kiện chưa được xử lý:', event.type);
}
// Xác nhận đã nhận
res.status(200).send('OK');
});
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
async function handlePaymentSucceeded(data) {
console.log(`Thanh toán thành công: ${data.id}`);
// Cập nhật trạng thái đơn hàng
await db.orders.update(data.metadata.orderId, {
status: 'paid',
paymentId: data.id,
paidAt: new Date()
});
// Gửi email xác nhận
await sendOrderConfirmation(data.metadata.orderId);
}
async function handlePaymentFailed(data) {
console.log(`Thanh toán thất bại: ${data.id} - ${data.failure_code}`);
// Thông báo cho khách hàng
await sendPaymentFailedEmail(data.customer, data.failure_message);
// Logic thử lại hoặc đánh dấu đơn hàng là thất bại
await db.orders.update(data.metadata.orderId, {
status: 'payment_failed',
failureReason: data.failure_message
});
}
Bảo mật và Tuân thủ
Yêu cầu PCI DSS
Tích hợp thanh toán phải tuân thủ PCI DSS:
| Yêu cầu | Triển khai |
|---|---|
| Mạng an toàn | Sử dụng HTTPS, tường lửa, cấu hình an toàn |
| Bảo vệ dữ liệu chủ thẻ | Không bao giờ lưu trữ CVV, mã hóa PAN |
| Quản lý lỗ hổng | Cập nhật bảo mật thường xuyên, phần mềm diệt virus |
| Kiểm soát truy cập | Quyền hạn tối thiểu, MFA, ID duy nhất |
| Giám sát | Ghi nhật ký, phát hiện xâm nhập |
| Chính sách bảo mật | Chính sách được lập thành văn bản, đào tạo thường xuyên |
Các phương pháp bảo mật tốt nhất
// 1. Sử dụng mã hóa token - KHÔNG BAO GIỜ xử lý dữ liệu thẻ thô
const token = await tokenizeCard(cardData); // Phía client
// 2. Thực hiện tính bất biến (idempotency) cho tất cả các hoạt động thanh toán
const idempotencyKey = `pay_${orderId}_${Date.now()}`;
// 3. Xác thực số tiền phía máy chủ
if (req.body.amount !== calculatedAmount) {
throw new Error('Không khớp số tiền - có thể bị giả mạo');
}
// 4. Ghi nhật ký tất cả các hoạt động thanh toán (không có dữ liệu nhạy cảm)
logger.info('Đã thử thanh toán', {
orderId,
amount,
currency,
customerId,
timestamp: new Date().toISOString()
// KHÔNG BAO GIỜ ghi nhật ký: số thẻ, CVV, chi tiết đầy đủ phương thức thanh toán
});
// 5. Sử dụng biến môi trường cho các bí mật
const apiKey = process.env.IPAY_API_KEY; // Không mã hóa cứng
// 6. Thực hiện giới hạn tốc độ trên các điểm cuối thanh toán
const paymentLimiter = rateLimit({
windowMs: 60000,
max: 10 // 10 lần thử thanh toán mỗi phút
});
Danh sách kiểm tra triển khai sản xuất
Trước khi xử lý các khoản thanh toán trực tiếp:
- [ ] Hoàn thành Bảng câu hỏi tự đánh giá PCI DSS
- [ ] Sử dụng HTTPS cho tất cả các điểm cuối
- [ ] Lưu trữ khóa API trong quản lý bí mật an toàn
- [ ] Triển khai xác minh chữ ký webhook
- [ ] Thêm tính bất biến (idempotency) cho tất cả các hoạt động thanh toán
- [ ] Thiết lập ghi nhật ký toàn diện (không có dữ liệu nhạy cảm)
- [ ] Cấu hình các quy tắc phát hiện gian lận
- [ ] Kiểm thử các luồng hoàn tiền và tranh chấp
- [ ] Tạo sổ tay vận hành (runbook) cho các lỗi thanh toán
- [ ] Thiết lập giám sát và cảnh báo
- [ ] Triển khai bộ xử lý thanh toán dự phòng
Các trường hợp sử dụng thực tế
Thanh toán thương mại điện tử
Một nhà bán lẻ trực tuyến tích hợp thanh toán:
- Thách thức: Xử lý thanh toán thủ công, tỷ lệ bỏ giỏ hàng cao
- Giải pháp: Thanh toán một trang với thẻ đã được mã hóa token
- Kết quả: Tăng 35% tỷ lệ chuyển đổi, thanh toán tức thì
Thanh toán đăng ký SaaS
Một công ty phần mềm tự động hóa việc lập hóa đơn:
- Thách thức: Tạo và thu thập hóa đơn thủ công
- Giải pháp: Thanh toán định kỳ với tính năng thử lại tự động
- Kết quả: 95% thanh toán đúng hạn, tiết kiệm 80% thời gian quản trị
Ký quỹ thị trường
Một nền tảng xử lý các khoản thanh toán đa bên:
- Thách thức: Thanh toán chia nhỏ phức tạp giữa các nhà cung cấp
- Giải pháp: Ý định thanh toán với lập lịch chuyển tiền
- Kết quả: Tự động thanh toán cho nhà cung cấp, giảm gian lận
Kết luận
Tích hợp API thanh toán đòi hỏi sự chú ý cẩn thận đến bảo mật, tuân thủ và xử lý lỗi. Những điểm chính cần ghi nhớ:
- Không bao giờ xử lý dữ liệu thẻ thô—hãy sử dụng mã hóa token
- Thực hiện tính bất biến (idempotency) cho tất cả các hoạt động thanh toán
- Xác minh chữ ký webhook để ngăn chặn gian lận
- Tuân thủ các yêu cầu PCI DSS
- Kiểm thử kỹ lưỡng trong môi trường sandbox trước khi triển khai sản xuất
- Apidog đơn giản hóa việc kiểm thử API và hợp tác nhóm
Phần Câu hỏi thường gặp (FAQ)
Làm cách nào để xác thực với API iPay?
Sử dụng xác thực cơ bản với khóa và bí mật API, hoặc OAuth 2.0 cho các ứng dụng đa đối tượng thuê.
Tôi có thể lưu trữ chi tiết thẻ của khách hàng không?
Có, nhưng bạn phải tuân thủ PCI DSS. Sử dụng mã hóa token để lưu trữ thẻ một cách an toàn trong kho lưu trữ (vault) của iPay.
Làm cách nào để xử lý các khoản thanh toán thất bại?
Thực hiện logic thử lại với chiến lược trì hoãn lũy thừa (exponential backoff), thông báo cho khách hàng và cung cấp các phương thức thanh toán thay thế.
Tính bất biến (Idempotency) là gì và tại sao nó quan trọng?
Tính bất biến (Idempotency) đảm bảo rằng các yêu cầu trùng lặp với cùng một khóa sẽ tạo ra cùng một kết quả, ngăn chặn việc tính phí trùng lặp.
Làm cách nào để kiểm thử thanh toán mà không tính phí thẻ?
Sử dụng chế độ sandbox với các số thẻ kiểm thử được cung cấp trong tài liệu của iPay.
Chữ ký webhook là gì?
Các chữ ký mật mã dùng để xác minh rằng webhook đến từ iPay, chứ không phải từ một tác nhân độc hại.
