Tóm tắt
API của Braintree xử lý thanh toán qua thẻ tín dụng, PayPal, Venmo và ví điện tử. Bạn tích hợp thông qua SDK phía máy chủ (Node, Python, Ruby, v.v.), tạo client token để bảo mật frontend, và xử lý giao dịch, hoàn tiền cũng như đăng ký. Để kiểm thử, sử dụng Apidog để xác thực payload webhook và kiểm tra tích hợp với dữ liệu sandbox trước khi triển khai thực tế.
Giới thiệu
Braintree xử lý hàng tỷ giao dịch mỗi năm, là nền tảng thanh toán đứng sau Uber, Airbnb, GitHub. Hỗ trợ thẻ tín dụng, PayPal, Venmo, Apple Pay, Google Pay, ACH...
API thanh toán yêu cầu độ chính xác cao: lỗi tích hợp có thể gây mất tiền thật và phá vỡ niềm tin khách hàng. Có hai dạng tích hợp: giao diện Drop-in (mẫu dựng sẵn) và giao diện tùy chỉnh (kiểm soát hoàn toàn). Cả hai dùng chung API phía máy chủ để xử lý thanh toán. Hướng dẫn này tập trung vào công việc phía server sau khi khách hàng nhấn “Thanh toán”.
💡 Nếu bạn xây dựng tích hợp thanh toán, Apidog giúp kiểm thử webhook handler và xác thực phản hồi thanh toán. Bạn có thể mô phỏng webhook Braintree tại môi trường local, kiểm tra các trường hợp thành công, thất bại, biên… trước khi giao dịch thật.
Kiểm thử webhook Braintree với Apidog - miễn phí
Thiết lập Braintree
Tạo tài khoản Braintree
- Truy cập braintreepayments.com
- Đăng ký tài khoản sandbox.
- Lưu lại:
- Merchant ID:
abc123xyz - Public Key:
def456... - Private Key:
ghi789...
- Merchant ID:
Bảo mật: Không lưu private key trong Git hoặc repo công khai.
Cài đặt SDK
Cài đặt SDK phía server phù hợp với ngôn ngữ bạn dùng:
Node.js:
npm install braintree
Python:
pip install braintree
Ruby:
gem install braintree
Khởi tạo gateway:
const braintree = require('braintree')
const gateway = new braintree.BraintreeGateway({
environment: braintree.Environment.Sandbox,
merchantId: process.env.BRAINTREE_MERCHANT_ID,
publicKey: process.env.BRAINTREE_PUBLIC_KEY,
privateKey: process.env.BRAINTREE_PRIVATE_KEY
})
Tạo client token
Trước khi render form thanh toán, tạo client token để frontend giao tiếp với Braintree:
app.get('/checkout/token', async (req, res) => {
const clientToken = await gateway.clientToken.generate()
res.json({ clientToken: clientToken.clientToken })
})
Frontend sẽ dùng token này để khởi tạo Drop-in UI hoặc tích hợp tùy chỉnh.
Xử lý thanh toán
Luồng thanh toán
- Frontend gửi payment method nonce đến backend
- Backend tạo giao dịch với nonce này
- Braintree xử lý thanh toán
- Backend nhận kết quả thành công/thất bại
- Xử lý đơn hàng hoặc báo lỗi cho user
Tính phí thẻ tín dụng
app.post('/checkout', async (req, res) => {
const { paymentMethodNonce, amount, orderId } = req.body
const result = await gateway.transaction.sale({
amount: amount,
paymentMethodNonce: paymentMethodNonce,
orderId: orderId,
options: {
submitForSettlement: true
}
})
if (result.success) {
res.json({
success: true,
transactionId: result.transaction.id
})
} else {
res.status(400).json({
success: false,
message: result.message
})
}
})
Tính phí bằng phương thức thanh toán đã lưu
Lưu phương thức thanh toán sau giao dịch đầu tiên để dùng về sau:
// Tạo customer với payment method
const result = await gateway.customer.create({
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
paymentMethodNonce: nonce
})
// Lấy token phương thức thanh toán đã lưu
const paymentMethodToken = result.customer.paymentMethods[0].token
// Dùng token để thu tiền sau này
await gateway.transaction.sale({
amount: '49.99',
paymentMethodToken: paymentMethodToken,
options: {
submitForSettlement: true
}
})
Giao dịch PayPal
Xử lý PayPal như thẻ tín dụng, chỉ cần payment nonce:
const result = await gateway.transaction.sale({
amount: '99.00',
paymentMethodNonce: paypalNonce,
orderId: 'ORDER-123',
options: {
submitForSettlement: true
}
})
Hoàn tiền và hủy
Hoàn tiền đầy đủ
const result = await gateway.transaction.refund('transaction_id')
if (result.success) {
console.log('Đã hoàn tiền:', result.transaction.id)
}
Hoàn tiền một phần
const result = await gateway.transaction.refund('transaction_id', '50.00')
if (result.success) {
console.log('Đã xử lý hoàn tiền một phần')
}
Hủy giao dịch
Hủy giao dịch chưa settle (chỉ mới ủy quyền):
const result = await gateway.transaction.void('transaction_id')
if (result.success) {
console.log('Giao dịch đã bị hủy')
}
Luồng trạng thái giao dịch
được ủy quyền → được gửi để thanh toán → đã thanh toán
↓
đã hủy
đã thanh toán → đã hoàn tiền
Đăng ký và thanh toán định kỳ
Tạo một gói
Tạo plan mới trong dashboard hoặc qua API:
const result = await gateway.plan.create({
id: 'monthly-premium',
name: 'Monthly Premium',
billingFrequency: 1,
currencyIsoCode: 'USD',
price: '29.99'
})
Tạo một đăng ký
const result = await gateway.subscription.create({
paymentMethodToken: paymentMethodToken,
planId: 'monthly-premium',
firstBillingDate: new Date()
})
if (result.success) {
console.log('Đã tạo đăng ký:', result.subscription.id)
}
Hủy đăng ký
const result = await gateway.subscription.cancel('subscription_id')
if (result.success) {
console.log('Đăng ký đã bị hủy')
}
Cập nhật đăng ký
const result = await gateway.subscription.update('subscription_id', {
planId: 'annual-premium',
price: '299.99'
})
Webhooks cho các sự kiện thanh toán
Webhooks rất quan trọng để cập nhật trạng thái giao dịch, quản lý đăng ký, tranh chấp...
Tạo endpoint webhook
app.post('/webhooks/braintree', (req, res) => {
const signature = req.body.bt_signature
const payload = req.body.bt_payload
gateway.webhookNotification.parse(
signature,
payload,
(err, webhookNotification) => {
if (err) {
return res.status(400).send('Webhook không hợp lệ')
}
switch (webhookNotification.kind) {
case 'subscription_charged_successfully':
handleSuccessfulCharge(webhookNotification.subscription)
break
case 'subscription_charged_unsuccessfully':
handleFailedCharge(webhookNotification.subscription)
break
case 'dispute_opened':
handleDispute(webhookNotification.dispute)
break
case 'transaction_settled':
handleSettledTransaction(webhookNotification.transaction)
break
}
res.status(200).send('OK')
}
)
})
Đăng ký webhook trong Braintree
Truy cập dashboard Braintree → Cài đặt → Webhooks → Thêm endpoint. Trong môi trường dev, dùng ngrok để nhận webhook từ internet về local.
Kiểm thử với Apidog
API thanh toán phải kiểm thử kỹ, không phụ thuộc dữ liệu thật. Apidog giúp mô phỏng và xác thực các luồng webhook an toàn, hiệu quả.
1. Mô phỏng payload webhook
Tạo payload mô phỏng và gửi về endpoint webhook để xác thực handler:
{
"bt_signature": "test_signature",
"bt_payload": "eyJraW5kIjoidHJhbnNhY3Rpb25fc2V0dGxlZCIsInRyYW5zYWN0aW9uIjp7ImlkIjoiYWJjMTIzIiwiYW1vdW50IjoiNDkuOTkiLCJzdGF0dXMiOiJzZXR0bGVkIn19"
}
2. Phân tách môi trường
Quản lý biến môi trường rõ ràng giữa sandbox và production:
# Sandbox
BRAINTREE_MERCHANT_ID: sandbox_merchant
BRAINTREE_PUBLIC_KEY: sandbox_public
BRAINTREE_PRIVATE_KEY: sandbox_private
BRAINTREE_ENVIRONMENT: sandbox
# Production
BRAINTREE_MERCHANT_ID: live_merchant
BRAINTREE_PUBLIC_KEY: live_public
BRAINTREE_PRIVATE_KEY: live_private
BRAINTREE_ENVIRONMENT: production
3. Xác thực phản hồi webhook
Kiểm tra phản hồi API và ghi nhận transaction ID:
pm.test('Webhook đã xử lý thành công', () => {
pm.response.to.have.status(200)
pm.response.to.have.body('OK')
})
pm.test('ID giao dịch đã được ghi lại', () => {
const transactionId = pm.environment.get('last_transaction_id')
pm.expect(transactionId).to.not.be.empty
})
Kiểm thử webhook Braintree với Apidog - miễn phí
Các lỗi và cách khắc phục thường gặp
Bộ xử lý từ chối
Nguyên nhân: Ngân hàng từ chối giao dịch (thường do không đủ tiền, nghi ngờ gian lận).
Khắc phục: Hiển thị thông báo chung, đề xuất thử thẻ khác, ghi lại processorResponseCode để debug.
if (!result.success) {
if (result.transaction.processorResponseCode === '2000') {
return res.status(400).json({
error: 'Ngân hàng của bạn đã từ chối giao dịch này. Vui lòng thử một thẻ khác.'
})
}
}
Gateway từ chối
Nguyên nhân: Bị chặn bởi anti-fraud của Braintree.
Khắc phục: Kiểm tra lý do qua gatewayRejectionReason:
if (result.transaction.gatewayRejectionReason === 'cvv') {
// CVV không khớp
}
if (result.transaction.gatewayRejectionReason === 'avs') {
// Xác minh địa chỉ thất bại
}
if (result.transaction.gatewayRejectionReason === 'fraud') {
// Anti-fraud nâng cao chặn
}
Lỗi thanh toán
Nguyên nhân: Giao dịch bị từ chối khi settle (sau ủy quyền).
Khắc phục: Theo dõi webhook transaction_settlement_declined. Các nguyên nhân thường gặp:
- Thẻ hết hạn giữa lúc ủy quyền và settle
- Nhà phát hành chặn giao dịch
- Không đủ tiền
Giao dịch trùng lặp
Nguyên nhân: Người dùng bấm “Thanh toán” nhiều lần, hoặc backend retry.
Khắc phục: Dùng orderId để tránh duplicate:
const result = await gateway.transaction.sale({
amount: '49.99',
paymentMethodNonce: nonce,
orderId: 'UNIQUE-ORDER-123',
options: {
submitForSettlement: true
}
})
Các lựa chọn thay thế và so sánh
| Tính năng | Braintree | Stripe | PayPal |
|---|---|---|---|
| Giá | 2.9% + 30¢ | 2.9% + 30¢ | 2.9% + 30¢ |
| Hỗ trợ PayPal | Bản địa | Add-on | Bản địa |
| Đăng ký | Có | Có | Hạn chế |
| Quốc tế | 46 quốc gia | 46 quốc gia | 200+ quốc gia |
| Công cụ chống gian lận | Tích hợp sẵn | Tích hợp sẵn | Cơ bản |
| Chất lượng SDK | Tuyệt vời | Tuyệt vời | Tốt |
| Thanh toán | Có | Có | Có |
Lợi thế của Braintree là hỗ trợ PayPal/Venmo gốc. Nếu bạn cần cả thẻ và PayPal, một API Braintree đơn giản hơn Stripe + PayPal riêng biệt.
Các trường hợp sử dụng thực tế
- Nền tảng SaaS: Quản lý đăng ký hàng tháng, xử lý thẻ hết hạn qua webhook, gửi email tự động.
- Marketplace: Chia tiền giữa phí nền tảng và freelancer qua merchant/sub-merchant account của Braintree.
- E-commerce hỗ trợ PayPal: Một tích hợp, xử lý đồng thời thẻ và PayPal.
Kết luận
Tóm lại, bạn cần thực hiện:
- Tích hợp SDK server-side của Braintree
- Tạo client token cho frontend
- Xử lý giao dịch thẻ/PayPal qua API
- Đăng ký thanh toán định kỳ với subscription
- Lắng nghe webhook để cập nhật trạng thái
- Kiểm thử kỹ lưỡng với Apidog trước khi triển khai
Câu hỏi thường gặp
Nonce phương thức thanh toán là gì?
Nonce là token dùng một lần đại diện cho phương thức thanh toán, do frontend tạo sau khi người dùng nhập thông tin thẻ. Backend dùng nonce này để thu tiền. Nonce hết hạn sau 3 giờ.
Sự khác biệt giữa ủy quyền và thanh toán là gì?
- Ủy quyền: Đặt giữ tiền trên thẻ, chưa thu về.
- Thanh toán: Thực sự thu tiền.
- Mặc định Braintree sẽ thanh toán luôn. Nếu cần pre-order, chỉ ủy quyền rồi submit for settlement sau:
// Chỉ ủy quyền
await gateway.transaction.sale({
amount: '99.00',
paymentMethodNonce: nonce,
options: {
submitForSettlement: false // Chỉ ủy quyền
}
})
// Thanh toán sau
await gateway.transaction.submitForSettlement('transaction_id')
Làm sao xử lý đa tiền tệ?
Mỗi merchant account có một loại tiền tệ. Nếu cần đa tiền tệ, liên hệ Braintree để tạo nhiều merchant account.
Thẻ kiểm thử nào nên dùng?
-
4111111111111111– Visa (thành công) -
4000111111111115– Visa (từ chối) -
5555555555554444– Mastercard (thành công) -
378282246310005– Amex (thành công)
Làm sao xử lý tranh chấp/hoàn trả?
Lắng nghe webhook dispute_opened, dispute_won, dispute_lost. Cung cấp bằng chứng qua dashboard Braintree. Lưu mọi thông tin: giao tiếp khách hàng, xác nhận giao hàng, điều khoản.
Tôi có được lưu số thẻ tín dụng không?
Không. Theo PCI, không được lưu số thẻ thô. Lưu token phương thức thanh toán (do Braintree cung cấp) thay vì số thẻ.
3D Secure là gì?
3D Secure thêm một lớp xác thực cho thanh toán online. Braintree hỗ trợ. Bật trong dashboard, xử lý response authentication_required:
const result = await gateway.transaction.sale({
amount: '100.00',
paymentMethodNonce: nonce,
threeDSecure: {
required: true
}
})
Hoàn tiền mất bao lâu?
Thường từ 3-5 ngày làm việc, tùy ngân hàng. Nhận webhook transaction_refunded khi hoàn tất.


Top comments (0)