DEV Community

Cover image for Hướng Dẫn Tích Hợp Thanh Toán iPay API Năm 2026
Sebastian Petrus
Sebastian Petrus

Posted on • Originally published at apidog.com

Hướng Dẫn Tích Hợp Thanh Toán iPay API Năm 2026

Tóm tắt

API iPay cho phép 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, khóa API, cung cấp các endpoint RESTful cho thanh toán, hoàn tiền, giao dịch và đối chiếu. Để triển khai thực tế, bạn cần tuân thủ PCI DSS và các giới hạn tỷ lệ chuẩn ngành. Bài viết này hướng dẫn từng bước: 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à checklist triển khai production.

Hãy dùng thử Apidog ngay hôm nay

💡 Apidog đơn giản hóa kiểm thử API thanh toán: Kiểm thử endpoint thanh toán ở chế độ sandbox, xác thực chữ ký webhook, kiểm tra phản hồi giao dịch và debug các vấn đề tích hợp trong một workspace duy nhất. Nhập spec API, giả lập response và chia sẻ test case cho cả team.

Lưu ý: Bài viết sử dụng mẫu tích hợp API thanh toán phổ biến, áp dụng với iPay và các dịch vụ tương tự. Luôn kiểm tra lại tài liệu chính thức của iPay cho từng endpoint và xác thực.

API iPay là gì?

API thanh toán như iPay cung cấp RESTful endpoint để xử lý giao dịch tài chính, bao gồm:

  • Ủy quyền & thu tiền thanh toán
  • Hoàn tiền & bồi hoàn (chargebacks)
  • Lịch sử giao dịch, báo cáo
  • Mã hóa thông tin khách hàng (vault)
  • Đăng ký & thanh toán định kỳ
  • Tạo/quản lý hóa đơn
  • Đối chiếu, thanh toán bù trừ
  • Ngăn chặn gian lận

Các tính năng chính

Tính năng Mô tả
API RESTful Endpoint 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 real-time
Mã hóa token 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ợ >100 loại tiền tệ
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 TT     │
│ (Browser)   │    │ (Server)    │    │ Thanh toán  │
└─────────────┘    └─────────────┘    └─────────────┘
     │                │                  │
     │ Nhập thẻ       │                  │
     │───────────────▶│                  │
     │                │                  │
     │ Mã hóa token   │                  │
     │───────────────▶│ Tạo ý định       │
     │                │───────────────▶  │
     │                │                  │
     │                │ Xác nhận TT      │
     │                │───────────────▶  │
     │                │                  │
     │                │ Kết quả          │
     │                │◀───────────────  │
     │                │                  │
     │ Biên nhận      │                  │
     │◀───────────────│                  │
Enter fullscreen mode Exit fullscreen mode

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 thực tế

Bắt đầu: Thiết lập xác thực

Bước 1: Tạo tài khoản iPay

  1. Đăng ký tài khoản người bán iPay.
  2. Hoàn tất xác minh doanh nghiệp (KYB).
  3. Gửi giấy tờ: đăng ký kinh doanh, tài khoản ngân hàng, giấy tờ tùy thân.
  4. 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

  1. Đăng nhập dashboard người bán iPay.
  2. Vào Cài đặt > Khóa API.
  3. Tạo khóa API mới.
  4. Lưu khóa & secret ở nơi an toàn.
# .env (KHÔNG commit lên git)
IPAY_API_KEY="live_xxxxxx"
IPAY_API_SECRET="secret_xxxxxx"
IPAY_WEBHOOK_SECRET="whsec_xxxxxx"
Enter fullscreen mode Exit fullscreen mode

Lưu ý: Dùng khóa riêng cho sandbox & production.

Bước 3: Hiểu các phương pháp xác thực

Phương pháp Tốt nhất cho Mức bảo mật
Basic Auth Server-to-server Cao
OAuth 2.0 Ứng dụng đa tenant Cao hơn
JWT Microservices Cao

Bước 4: Gọi API xác thực

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;

  // Basic Auth (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)}`;
}

// Sử dụng
const account = await ipayRequest('/account');
console.log(`Người bán: ${account.business_name}`);
Enter fullscreen mode Exit fullscreen mode

Xử lý thanh toán

Tạo ý định thanh toán

const createPayment = async (paymentData) => {
  const payment = {
    amount: paymentData.amount, // Đơn vị nhỏ nhất (cent)
    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',
    statement_descriptor: paymentData.statementDescriptor || 'MYCOMPANY'
  };

  const response = await ipayRequest('/payments', {
    method: 'POST',
    body: JSON.stringify(payment),
    idempotencyKey: paymentData.idempotencyKey
  });

  return response;
};

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

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

Phương thức thanh toán

Phương thức Loại Trường hợp sử dụng
card Thẻ tín dụng/ghi nợ Thanh toán chuẩn
bank_transfer ACH, SEPA Chuyển khoản phí thấp
digital_wallet Apple Pay, Google Pay Thanh toán di động
buy_now_pay_later Klarna, Afterpay Thanh toán trả góp

Mã hóa Token thông tin thẻ

const tokenizeCard = async (cardData) => {
  // KHÔNG gửi thẻ thô lên server - mã hóa phía client
  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 về server
};

// Server: tạo payment method từ token
const createPaymentMethod = async (tokenId, customerId) => {
  const response = await ipayRequest('/payment_methods', {
    method: 'POST',
    body: JSON.stringify({
      type: 'card',
      token: tokenId,
      customer: customerId
    })
  });

  return response;
};
Enter fullscreen mode Exit fullscreen mode

Xác thực 3D Secure

const createPaymentWith3DS = async (paymentData) => {
  const payment = await createPayment({
    ...paymentData,
    confirmation_token: true // Trả về client secret cho 3DS
  });

  if (payment.status === 'requires_action') {
    // Client xử lý thử thách 3DS
    return {
      requiresAction: true,
      clientSecret: payment.client_secret,
      nextAction: payment.next_action
    };
  }

  return { success: true, payment };
};

// Client: dùng iPay.js hoặc SDK để hiển thị thử thách 3DS
Enter fullscreen mode Exit fullscreen mode

Quản lý hoàn tiền

Hoàn tiền toàn bộ

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;
};

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

Hoàn tiền một phần

const partialRefund = async (paymentId, amount, reason = null) => {
  const refund = {
    payment: paymentId,
    amount: amount, // Đơn vị 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;
};

// Sử dụng - Hoàn 15,00 USD từ khoả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}`);
Enter fullscreen mode Exit fullscreen mode

Lý do hoàn tiền

Mã lý do Mô tả
duplicate Giao dịch trùng lặp
fraudulent Giao dịch gian lận
requested_by_customer Yêu cầu khách hàng
order_canceled Hủy đơn hàng
product_not_received Chưa nhận sản phẩm
product_not_as_described Không như mô tả

Quản lý khách hàng

Tạo khách hàng

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;
};

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

Gắn phương thức thanh toán

const attachPaymentMethod = async (paymentMethodId, customerId) => {
  const response = await ipayRequest(`/payment_methods/${paymentMethodId}/attach`, {
    method: 'POST',
    body: JSON.stringify({
      customer: customerId
    })
  });

  return response;
};

// Sử dụng
await attachPaymentMethod('pm_67890', 'cus_12345');
Enter fullscreen mode Exit fullscreen mode

Liệt kê phương thức thanh toán của khách

const getCustomerPaymentMethods = async (customerId) => {
  const response = await ipayRequest(`/customers/${customerId}/payment_methods`);
  return response;
};

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

Webhooks

Cấu hình Webhooks

  1. Đăng nhập dashboard iPay.
  2. Vào Nhà phát triển > Webhooks.
  3. Thêm endpoint HTTPS của bạn.
  4. Chọn sự kiện cần đăng ký.

Sự kiện Webhook

Sự kiện Kích hoạt
payment.succeeded Thanh toán hoàn tất
payment.failed Thanh toán bị từ chối
payment.refunded Hoàn tiền thành công
payment.disputed Đã có tranh chấp
customer.created Khách hàng mới
customer.subscription.updated Đă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 sự kiện
  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('Sự kiện chưa xử lý:', 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')
  );
}

async function handlePaymentSucceeded(data) {
  console.log(`Thanh toán thành công: ${data.id}`);

  // Cập nhật đơ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
  await sendPaymentFailedEmail(data.customer, data.failure_message);

  // Đánh dấu đơn hàng lỗi
  await db.orders.update(data.metadata.orderId, {
    status: 'payment_failed',
    failureReason: data.failure_message
  });
}
Enter fullscreen mode Exit fullscreen mode

Bảo mật và Tuân thủ

Yêu cầu PCI DSS

Yêu cầu Triển khai
Mạng an toàn Sử dụng HTTPS, firewall, cấu hình an toàn
Bảo vệ chủ thẻ Không lưu CVV, mã hóa PAN
Quản lý lỗ hổng Update bảo mật, antivirus
Kiểm soát truy cập Quyền tối thiểu, MFA, user ID duy nhất
Giám sát Ghi log, phát hiện xâm nhập
Chính sách bảo mật Văn bản hóa, đào tạo định kỳ

Các phương pháp bảo mật tốt nhất

// 1. Token hóa phía client - KHÔNG xử lý thẻ thô
const token = await tokenizeCard(cardData);

// 2. Dùng idempotency cho mọi giao dịch
const idempotencyKey = `pay_${orderId}_${Date.now()}`;

// 3. Xác thực số tiền phía server
if (req.body.amount !== calculatedAmount) {
  throw new Error('Không khớp số tiền - có thể bị giả mạo');
}

// 4. Ghi log không chứa dữ liệu nhạy cảm
logger.info('Đã thử thanh toán', {
  orderId,
  amount,
  currency,
  customerId,
  timestamp: new Date().toISOString()
  // KHÔNG bao gồm số thẻ, CVV, v.v.
});

// 5. Dùng biến môi trường cho bí mật
const apiKey = process.env.IPAY_API_KEY;

// 6. Giới hạn tốc độ endpoint thanh toán
const paymentLimiter = rateLimit({
  windowMs: 60000,
  max: 10 // 10 lần/phút
});
Enter fullscreen mode Exit fullscreen mode

Checklist triển khai production

Trước khi xử lý thanh toán thật, kiểm tra:

  • [ ] Hoàn thành PCI DSS Self Assessment Questionnaire
  • [ ] Tất cả endpoint dùng HTTPS
  • [ ] Lưu khóa API trong secret manager an toàn
  • [ ] Đã xác minh chữ ký webhook
  • [ ] Thực hiện idempotency cho mọi thao tác thanh toán
  • [ ] Ghi log toàn diện (không dữ liệu nhạy cảm)
  • [ ] Kích hoạt anti-fraud rules
  • [ ] Kiểm thử hoàn tiền & tranh chấp
  • [ ] Có runbook xử lý lỗi thanh toán
  • [ ] Giám sát & cảnh báo
  • [ ] Có payment processor 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ử

  • Thách thức: Xử lý thanh toán thủ công, tỷ lệ bỏ giỏ hàng cao
  • Giải pháp: One-page checkout với mã hóa token thẻ
  • Kết quả: Tăng 35% conversion, thanh toán tức thì

Thanh toán đăng ký SaaS

  • Thách thức: Lập hóa đơn, thu thập thủ công
  • Giải pháp: Thanh toán định kỳ, tự động retry
  • Kết quả: 95% thanh toán đúng hạn, giảm 80% thời gian quản trị

Ký quỹ thị trường

  • Thách thức: Chia nhỏ thanh toán giữa nhiều nhà cung cấp
  • Giải pháp: Ý định thanh toán + lập lịch chuyển khoản
  • Kết quả: Thanh toán tự động cho vendor, giảm gian lận

Kết luận

Tích hợp API thanh toán đòi hỏi chú trọng bảo mật, tuân thủ và xử lý lỗi kỹ lưỡng. Tóm lại:

  • Không bao giờ xử lý thẻ thô – luôn token hóa phía client
  • Tất cả payment operation phải idempotent
  • Xác minh chữ ký webhook để chống gian lận
  • Phải tuân thủ PCI DSS
  • Kiểm thử kỹ trên sandbox trước khi production
  • Apidog giúp kiểm thử API và cộng tác nhóm hiệu quả

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 Basic Auth với API key/secret, hoặc OAuth 2.0 cho ứng dụng đa tenant.

Tôi có thể lưu trữ chi tiết thẻ của khách hàng không?

Có, nhưng phải tuân thủ PCI DSS. Sử dụng token hóa để lưu thẻ an toàn trong vault của iPay.

Làm cách nào để xử lý thanh toán thất bại?

Xây dựng logic retry với exponential backoff, gửi thông báo cho khách và cho phép đổi phương thức thanh toán.

Tính bất biến (Idempotency) là gì và tại sao nó quan trọng?

Idempotency đảm bảo các request trùng key luôn ra cùng kết quả, tránh bị 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ẻ?

Dùng môi trường sandbox với số thẻ test, lấy trong tài liệu iPay.

Chữ ký webhook là gì?

Chữ ký HMAC dùng để xác minh webhook thực sự gửi từ iPay, không phải kẻ gian.

Top comments (0)