Tóm tắt
API 2Checkout (nay là Verifone) cho phép bạn tự động xử lý thanh toán, quản lý đăng ký và giao dịch thương mại điện tử qua các endpoint RESTful với xác thực JSON bằng API Key. Bài viết này hướng dẫn bạn từng bước tích hợp, từ thiết lập xác thực đến xử lý webhook nâng cao, giúp bạn sẵn sàng triển khai thanh toán ở môi trường sản xuất.
💡 Apidog giúp kiểm thử tích hợp API 2Checkout/Verifone dễ dàng hơn: nhập OpenAPI spec, kiểm thử endpoint, xác thực payload webhook, mô phỏng response và chia sẻ test case cho nhóm.
API 2Checkout là gì?
2Checkout (Verifone Digital Commerce) là nền tảng API RESTful để xử lý thanh toán, quản lý đăng ký và đơn hàng, hỗ trợ:
- Thanh toán một lần & định kỳ
- Quản lý khách hàng, sản phẩm
- Theo dõi vòng đời đơn hàng, hoàn tiền, tranh chấp
- Tự động hóa thuế, tuân thủ
- Hỗ trợ hơn 100 loại tiền tệ
Các tính năng chính
| Tính năng | Mô tả |
|---|---|
| Thiết kế RESTful | Chuẩn HTTP (GET, POST, PUT, DELETE), payload JSON |
| Môi trường Sandbox | Test thanh toán không phát sinh giao dịch thực |
| Hỗ trợ Webhook | Thông báo realtime cho sự kiện đơn hàng |
| Mã hóa Token | Thanh toán an toàn, không lưu trữ thông tin thẻ |
| Tuân thủ Toàn cầu | PCI DSS L1, GDPR, PSD2, 3D Secure 2.0 |
Tổng quan kiến trúc API
API có version rõ ràng:
https://api.2checkout.com/1/
https://api.2checkout.com/2/
Nên dùng version 2 để quản lý đăng ký và xử lý webhook tốt hơn.
Bắt đầu: Thiết lập xác thực
Bước 1: Tạo tài khoản 2Checkout
- Đăng ký tài khoản người bán trên 2Checkout (Verifone)
- Hoàn thành xác minh doanh nghiệp (nộp giấy tờ)
- Chờ duyệt tài khoản (24-48h)
- Đăng nhập Dashboard để lấy thông tin xác thực API
Bước 2: Lấy Khóa API
Truy cập Tích hợp > Khóa API trên Dashboard:
- Private API Key: xác thực phía server (luôn bảo mật)
- Public API Key: xác thực phía client (dùng cho tokenization)
- Webhook Secret: xác minh chữ ký webhook
Cách bảo mật: Lưu key vào biến môi trường, không commit vào codebase:
# .env
TWOCHECKOUT_PRIVATE_KEY="your_private_key"
TWOCHECKOUT_PUBLIC_KEY="your_public_key"
TWOCHECKOUT_WEBHOOK_SECRET="your_webhook_secret"
Bước 3: Môi trường Sandbox vs. Sản xuất
| Môi trường | URL cơ sở | Dùng cho |
|---|---|---|
| Sandbox | https://sandbox.2checkout.com/api/ |
Phát triển, test |
| Sản xuất | https://api.2checkout.com/ |
Giao dịch thực |
Làm việc trên sandbox trước, chỉ chuyển sang production khi sẵn sàng live.
Bước 4: Các phương pháp xác thực
Phương pháp 1: Xác thực bằng API Key (Khuyên dùng)
const response = await fetch('https://api.2checkout.com/1/orders', {
method: 'GET',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
Phương pháp 2: Xác thực bằng chữ ký HMAC
const crypto = require('crypto');
function generateSignature(payload, privateKey) {
return crypto.createHmac('sha256', privateKey)
.update(JSON.stringify(payload))
.digest('hex');
}
const payload = { order_id: '12345', amount: 99.99 };
const signature = generateSignature(payload, privateKey);
const response = await fetch('https://api.2checkout.com/1/orders', {
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'X-Signature': signature,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
Xử lý thanh toán: Các endpoint cốt lõi
Tạo một đơn hàng một lần
const createOrder = async (customerData, productData) => {
const payload = {
currency: 'USD',
customer: {
email: customerData.email,
first_name: customerData.firstName,
last_name: customerData.lastName,
phone: customerData.phone,
billing_address: {
address1: customerData.address,
city: customerData.city,
state: customerData.state,
zip: customerData.zip,
country: customerData.country
}
},
items: [
{
name: productData.name,
quantity: productData.quantity,
price: productData.price,
product_code: productData.sku
}
],
payment_method: {
type: 'card',
card_token: customerData.cardToken
}
};
const response = await fetch('https://api.2checkout.com/1/orders', {
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
return await response.json();
};
Phản hồi dự kiến
{
"order_id": "ORD-2026-001234",
"status": "approved",
"amount": 99.99,
"currency": "USD",
"customer_id": "CUST-789456",
"transaction_id": "TXN-9876543210",
"created_at": "2026-03-20T10:30:00Z"
}
Xử lý lỗi thanh toán
try {
const result = await createOrder(customer, product);
if (result.error) {
switch (result.error.code) {
case 'CARD_DECLINED':
// Yêu cầu khách nhập thẻ khác
break;
case 'INSUFFICIENT_FUNDS':
// Báo không đủ tiền
break;
case 'INVALID_CVV':
// Yêu cầu nhập lại CVV
break;
default:
console.error('Payment failed:', result.error);
}
}
} catch (error) {
// Lỗi mạng hoặc server
console.error('API request failed:', error);
}
Các mã lỗi phổ biến
| Mã lỗi | HTTP | Mô tả | Giải pháp |
|---|---|---|---|
CARD_DECLINED |
402 | Thẻ bị từ chối | Yêu cầu phương thức khác |
INVALID_CARD |
400 | Số thẻ không hợp lệ | Kiểm tra đầu vào thẻ |
EXPIRED_CARD |
400 | Thẻ hết hạn | Cập nhật ngày hết hạn |
INVALID_CVV |
400 | CVV sai | Nhập lại CVV |
INSUFFICIENT_FUNDS |
402 | Không đủ tiền | Đề xuất thanh toán thay thế |
DUPLICATE_ORDER |
409 | Đơn hàng trùng lặp | Kiểm tra trùng lặp |
INVALID_CURRENCY |
400 | Tiền tệ không hỗ trợ | Kiểm tra mã tiền tệ |
API_KEY_INVALID |
401 | Xác thực thất bại | Kiểm tra khóa API |
Quản lý khách hàng
Tạo khách hàng
const createCustomer = async (customerData) => {
const payload = {
email: customerData.email,
first_name: customerData.firstName,
last_name: customerData.lastName,
phone: customerData.phone,
company: customerData.company,
billing_address: {
address1: customerData.address,
address2: customerData.address2 || '',
city: customerData.city,
state: customerData.state,
zip: customerData.zip,
country: customerData.country
},
shipping_address: customerData.shippingAddress || null,
tax_exempt: false,
language: 'en'
};
const response = await fetch('https://api.2checkout.com/1/customers', {
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
return await response.json();
};
Lấy chi tiết khách hàng
const getCustomer = async (customerId) => {
const response = await fetch(
`https://api.2checkout.com/1/customers/${customerId}`,
{
method: 'GET',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
}
}
);
return await response.json();
};
Cập nhật thông tin khách hàng
const updateCustomer = async (customerId, updates) => {
const response = await fetch(
`https://api.2checkout.com/1/customers/${customerId}`,
{
method: 'PUT',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
}
);
return await response.json();
};
Xóa khách hàng
const deleteCustomer = async (customerId) => {
const response = await fetch(
`https://api.2checkout.com/1/customers/${customerId}`,
{
method: 'DELETE',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY
}
}
);
return response.status === 204;
};
Lưu ý: Không thể xóa khách hàng còn đăng ký hoạt động hoặc còn nợ.
Các mẫu tích hợp nâng cao
Giao dịch bất biến (Idempotent)
const createIdempotentOrder = async (payload, idempotencyKey) => {
const response = await fetch('https://api.2checkout.com/1/orders', {
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json',
'X-Idempotency-Key': idempotencyKey
},
body: JSON.stringify(payload)
});
return await response.json();
};
Sử dụng idempotency key duy nhất cho mỗi đơn hàng để tránh bị tính phí trùng lặp khi retry.
Xử lý 3D Secure 2.0
const createOrderWith3DS = async (payload) => {
const response = await fetch('https://api.2checkout.com/1/orders', {
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
...payload,
three_ds: {
enabled: true,
challenge_required: 'preferred',
notification_url: 'https://your-site.com/3ds-callback'
}
})
});
const result = await response.json();
if (result.three_ds_redirect_url) {
// Redirect khách đến trang xác thực ngân hàng
res.redirect(result.three_ds_redirect_url);
}
return result;
};
Định giá đa tiền tệ
const getLocalizedPrice = async (basePrice, targetCurrency) => {
const response = await fetch(
`https://api.2checkout.com/1/rates?from=USD&to=${targetCurrency}`,
{
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY
}
}
);
const rates = await response.json();
return basePrice * rates.rate;
};
const eurPrice = await getLocalizedPrice(99.99, 'EUR');
console.log(`Price: EUR ${eurPrice.toFixed(2)}`);
Tính phí prorate khi nâng cấp đăng ký
const upgradeSubscription = async (subscriptionId, newPlanId) => {
const response = await fetch(
`https://api.2checkout.com/1/subscriptions/${subscriptionId}/upgrade`,
{
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
plan_id: newPlanId,
proration: 'immediate',
invoice_proration: true
})
}
);
return await response.json();
};
Khắc phục sự cố phổ biến
Webhook không đến
- Kiểm tra log delivery webhook trên dashboard
- Đảm bảo endpoint trả về 200 OK <5s, dùng HTTPS, allow IP 2Checkout
- Kiểm tra logic xác minh chữ ký webhook
- Test webhook bằng tool giả lập trước khi live
Thanh toán thử thất bại trong Sandbox
- Kiểm tra dùng đúng API key & URL sandbox
- Sử dụng đúng thẻ test
- Check trạng thái tài khoản sandbox
Gia hạn đăng ký thất bại âm thầm
- Kiểm tra payment method hết hạn
- Xem lại cấu hình dunning
- Xác minh webhook
subscription.payment_failed - Đảm bảo bật auto_renew
Sai lệch chuyển đổi tiền tệ
- Hiển thị tỷ giá xấp xỉ, kèm disclaimer
- Khóa tỷ giá khi tạo cart (timeout 15 phút)
- Lưu log giao dịch theo nội tệ
Lỗi AVS (địa chỉ)
- Sử dụng autocomplete địa chỉ (Google Places, Lob)
- Yêu cầu nhập zip-code
- AVS mềm (cảnh báo, không từ chối)
- Cho phép khách cập nhật địa chỉ billing
Quản lý đăng ký
Tạo đăng ký
const createSubscription = async (customerId, planId) => {
const payload = {
customer_id: customerId,
plan_id: planId,
start_date: new Date().toISOString(),
billing_cycle: 'monthly',
payment_method: {
type: 'card',
card_token: 'tok_card_tokenized'
},
options: {
trial_days: 14,
auto_renew: true
}
};
const response = await fetch('https://api.2checkout.com/1/subscriptions', {
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
return await response.json();
};
Cập nhật đăng ký
const updateSubscription = async (subscriptionId, updates) => {
const payload = { ...updates };
const response = await fetch(
`https://api.2checkout.com/1/subscriptions/${subscriptionId}`,
{
method: 'PUT',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
}
);
return await response.json();
};
Hủy đăng ký
const cancelSubscription = async (subscriptionId, reason = '') => {
const payload = {
cancel_at_period_end: false,
reason: reason
};
const response = await fetch(
`https://api.2checkout.com/1/subscriptions/${subscriptionId}/cancel`,
{
method: 'POST',
headers: {
'X-Api-Key': process.env.TWOCHECKOUT_PRIVATE_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
}
);
return await response.json();
};
Tích hợp Webhook: Xử lý realtime
Bước 1: Cấu hình endpoint webhook
- Vào Dashboard > Tích hợp > Webhook
- Thêm URL endpoint (HTTPS)
- Chọn event muốn nhận
- Lưu, lưu lại webhook secret
Bước 2: Tạo handler nhận webhook
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/2checkout', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = req.body;
// Xác minh signature webhook
const isValid = verifyWebhookSignature(payload, signature, process.env.TWOCHECKOUT_WEBHOOK_SECRET);
if (!isValid) {
console.error('Invalid webhook signature');
return res.status(401).send('Unauthorized');
}
const event = JSON.parse(payload.toString());
switch (event.type) {
case 'order.created':
await handleOrderCreated(event.data);
break;
case 'order.approved':
await handleOrderApproved(event.data);
break;
case 'order.declined':
await handleOrderDeclined(event.data);
break;
case 'subscription.created':
await handleSubscriptionCreated(event.data);
break;
case 'subscription.renewed':
await handleSubscriptionRenewed(event.data);
break;
case 'subscription.cancelled':
await handleSubscriptionCancelled(event.data);
break;
case 'refund.processed':
await handleRefundProcessed(event.data);
break;
default:
console.log('Unhandled event type:', event.type);
}
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')
);
}
Các sự kiện Webhook quan trọng
| Sự kiện | Trigger | Hành động gợi ý |
|---|---|---|
order.created |
Đơn hàng mới | Gửi email xác nhận |
order.approved |
Thanh toán thành công | Thực hiện đơn hàng, cấp quyền |
order.declined |
Thanh toán thất bại | Thông báo khách, retry |
subscription.renewed |
Gia hạn định kỳ | Gia hạn quyền truy cập |
subscription.payment_failed |
Gia hạn thất bại | Nhắc nhở khách thanh toán |
subscription.cancelled |
Hủy đăng ký | Thu hồi quyền truy cập cuối kỳ |
refund.processed |
Hoàn tiền | Cập nhật số dư tài khoản |
chargeback.received |
Tranh chấp (chargeback) | Thu thập bằng chứng |
Best practice webhook
- Luôn xác minh chữ ký - chống webhook giả
- Trả về 200 OK sớm - 2Checkout sẽ retry nếu không phải 200
- Xử lý async - xếp queue, không block webhook
- Triển khai idempotency - xử lý gửi lại nhiều lần
- Ghi log - theo dõi & audit sự kiện
Kiểm thử tích hợp
Môi trường Sandbox
const BASE_URL = 'https://sandbox.2checkout.com/api/1';
const TEST_CARDS = {
APPROVED: '4111111111111111',
DECLINED: '4000000000000002',
INSUFFICIENT_FUNDS: '4000000000009995',
EXPIRED_CARD: '4000000000000069'
};
const TEST_ADDRESS = {
country: 'US',
zip: '90210'
};
Kiểm thử webhook cục bộ với ngrok
npm install -g ngrok
node server.js
ngrok http 3000
# Dán URL ngrok vào cấu hình webhook 2Checkout
Kiểm thử API với Apidog
- Nhập OpenAPI spec của 2Checkout
- Tạo test case cho từng endpoint
- Mô phỏng response, kiểm thử webhook payload
- Chia sẻ workspace kiểm thử cho nhóm
- Dùng biến môi trường để chuyển đổi sandbox/production dễ dàng
Checklist triển khai production
- [ ] Đổi API key từ sandbox sang production
- [ ] Update base URL thành
https://api.2checkout.com/ - [ ] Kích hoạt xác minh chữ ký webhook
- [ ] Thiết lập monitoring các payment thất bại
- [ ] Logic retry cho lỗi tạm thời
- [ ] Test kỹ hoàn tiền, tranh chấp
- [ ] Đảm bảo tuân thủ PCI DSS (dùng tokenization)
- [ ] Bật 3D Secure 2.0 cho khách EU
- [ ] Ghi log đầy đủ cho audit
- [ ] Viết runbook cho xử lý sự cố thanh toán
Theo dõi & cảnh báo
const successRate = approvedOrders / totalOrders * 100;
if (successRate < 95) {
sendAlert('Tỷ lệ thanh toán thành công <95%');
}
const errorBreakdown = errors.reduce((acc, err) => {
acc[err.code] = (acc[err.code] || 0) + 1;
return acc;
}, {});
if (errorBreakdown['CARD_DECLINED'] > threshold) {
sendAlert('Tăng đột biến lỗi từ chối thẻ');
}
Case study thực tế
Tích hợp cửa hàng thương mại điện tử
- Tự động hỗ trợ 100+ loại tiền tệ
- Giảm 23% tỷ lệ bỏ giỏ hàng
- Tự động xử lý VAT EU
- Giao dịch >2 triệu USD năm đầu
- Lộ trình: ban đầu dùng hosted checkout, sau chuyển sang tích hợp API custom
Doanh nghiệp SaaS
- Quản lý >5000 đăng ký hoạt động
- Xử lý prorate nâng cấp gói
- Nhắc nhở tự động khi gia hạn thất bại
- Giảm 15% churn nhờ retry thông minh
- Quyền truy cập user điều khiển qua webhook:
subscription.renewed(cấp quyền),subscription.cancelled(thu hồi)
Kết luận
API 2Checkout cung cấp giải pháp đầy đủ cho thanh toán và đăng ký:
- Phát triển, kiểm thử trên sandbox trước khi production
- Luôn xác minh chữ ký HMAC cho webhook
- Xử lý lỗi linh hoạt theo từng mã lỗi
- Test kỹ các luồng đăng ký (dùng thử, gia hạn, hủy)
- Theo dõi các chỉ số thanh toán production
- Tận dụng Apidog để kiểm thử API và cộng tác nhóm
Phần Câu hỏi thường gặp
API 2Checkout là gì?
API 2Checkout (Verifone) là RESTful API để xử lý thanh toán, quản lý đăng ký, hoàn tiền, hỗ trợ JSON payload, xác thực HMAC, và webhook realtime.
2Checkout có giống Verifone không?
Có. 2Checkout được Verifone mua lại và đổi tên. Endpoint và chức năng vẫn giữ nguyên.
Lấy API Key 2Checkout ở đâu?
Đăng nhập Dashboard, vào Tích hợp > Khóa API để tạo key mới (private key cho server, public key cho client).
2Checkout có môi trường sandbox không?
Có. Sử dụng https://sandbox.2checkout.com/api/ để test, tạo tài khoản sandbox để lấy key test và xử lý giao dịch thử.
2Checkout hỗ trợ phương thức thanh toán nào?
Thẻ tín dụng (Visa, Mastercard, Amex, Discover), PayPal, Apple Pay, Google Pay, bank transfer và local payment cho hơn 100 quốc gia.
Làm sao xử lý webhook an toàn?
Luôn xác thực header X-Webhook-Signature bằng HMAC-SHA256 với webhook secret. Xử lý event async, trả về 200 OK ngay để tránh retry.
Điều gì xảy ra khi thanh toán đăng ký thất bại?
2Checkout gửi webhook subscription.payment_failed. Nên triển khai retry (3 lần trong 7 ngày), hết retry sẽ gửi subscription.cancelled.
2Checkout có tuân thủ PCI DSS không?
Có, đạt PCI DSS Cấp 1. Luôn dùng token hóa phía client để giảm phạm vi PCI.
Có thể kiểm thử đăng ký trong sandbox không?
Có. Sandbox hỗ trợ test toàn bộ vòng đời đăng ký (dùng thử, gia hạn, upgrade, downgrade, hủy). Thẻ test: 4111111111111111.
Làm sao hoàn tiền qua API?
Gửi POST /refunds với order ID và số tiền hoàn. 2Checkout xử lý toàn bộ/quá trình, gửi webhook refund.processed khi xong.

Top comments (0)