DEV Community

Cover image for API 2Checkout: Hướng Dẫn Tích Hợp Toàn Diện Xử Lý Thanh Toán (2026)
Sebastian Petrus
Sebastian Petrus

Posted on • Originally published at apidog.com

API 2Checkout: Hướng Dẫn Tích Hợp Toàn Diện Xử Lý Thanh Toán (2026)

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.

Dùng thử Apidog ngay hôm nay

💡 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/
Enter fullscreen mode Exit fullscreen mode

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

  1. Đăng ký tài khoản người bán trên 2Checkout (Verifone)
  2. Hoàn thành xác minh doanh nghiệp (nộp giấy tờ)
  3. Chờ duyệt tài khoản (24-48h)
  4. Đă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"
Enter fullscreen mode Exit fullscreen mode

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'
  }
});
Enter fullscreen mode Exit fullscreen mode

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)
});
Enter fullscreen mode Exit fullscreen mode

2Checkout API Key example


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();
};
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

Đị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)}`);
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

Tích hợp Webhook: Xử lý realtime

Bước 1: Cấu hình endpoint webhook

  1. Vào Dashboard > Tích hợp > Webhook
  2. Thêm URL endpoint (HTTPS)
  3. Chọn event muốn nhận
  4. 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')
  );
}
Enter fullscreen mode Exit fullscreen mode

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

  1. Luôn xác minh chữ ký - chống webhook giả
  2. Trả về 200 OK sớm - 2Checkout sẽ retry nếu không phải 200
  3. Xử lý async - xếp queue, không block webhook
  4. Triển khai idempotency - xử lý gửi lại nhiều lần
  5. 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'
};
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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ẻ');
}
Enter fullscreen mode Exit fullscreen mode

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)