บัตรที่บันทึกไว้และการชำระเงินซ้ำ
จัดเก็บบัตรลูกค้าอย่างปลอดภัยสำหรับการเรียกเก็บเงินในอนาคตโดยใช้ Customers API เหมาะสำหรับการสมัครสมาชิก การเรียกเก็บเงินซ้ำๆ และลูกค้าที่กลับมาใช้บริการอีก
ภาพรวม
Omise Customers API ช่วยให้คุณสามารถบันทึกวิธีการชำระเงินเพื่อใช้ในอนาคต แทนที่จะขอให้ลูกค้ากรอกรายละเอียดบัตรใหม่ทุกครั้งที่ซื้อ คุณสามารถบันทึกบัตรของพวกเขาอย่างปลอดภัยและเรียกเก็บเงินด้วยการเรียก API เพียงครั้งเดียว
กรณีการใช้งาน:
- การสมัครสมาชิกรายเดือน (โมเดล Netflix, Spotify)
- การเรียกเก็บเงินซ้ำๆ (สาธารณูปโภค, ค่าเช่า)
- การเช็คเอาต์คลิกเดียวสำหรับลูก ค้าที่กลับมาใช้บริการอีก
- การต่ออายุอัตโนมัติ
- การชำระเงินแบบผ่อนชำระ
วิธีการทำงาน
คู่มือการใช้งาน
ขั้นตอนที่ 1: สร้าง Customer ด้วยบัตร
เมื่อลูกค้าทำการซื้อครั้งแรก ให้สร้างวัตถุ Customer:
- cURL
- Node.js
- PHP
- Python
curl https://api.omise.co/customers \
-u skey_test_YOUR_SECRET_KEY: \
-d "email=john@example.com" \
-d "description=John Doe - สมาชิกพรีเมียม" \
-d "card=tokn_test_5rt6s9vah5lkvi1rh9c"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const customer = await omise.customers.create({
email: 'john@example.com',
description: 'John Doe - สมาชิกพรีเมียม',
card: tokenId // Token จาก Omise.js
});
// บันทึก customer ID ในฐานข้อมูลของคุณ
console.log(customer.id); // cust_test_...
<?php
$customer = OmiseCustomer::create(array(
'email' => 'john@example.com',
'description' => 'John Doe - สมาชิกพรีเมียม',
'card' => $_POST['omiseToken']
));
// จัดเก็บ customer ID ในฐานข้อมูลของคุณ
$customerId = $customer['id'];
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
customer = omise.Customer.create(
email='john@example.com',
description='John Doe - สมาชิกพรีเมียม',
card='tokn_test_5rt6s9vah5lkvi1rh9c'
)
# บันทึก customer ID ในฐานข้อมูลของคุณ
customer_id = customer.id
ขั้นตอนที่ 2: จัดเก็บ Customer ID
บันทึก customer ID ในฐานข้อมูลของคุณพร้อมกับข้อมูลผู้ใช้:
-- ตัวอย่างสคีมาฐานข้อมูล
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255),
omise_customer_id VARCHAR(50), -- จัดเก็บสิ่งนี้!
subscription_status VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- แทรกผู้ใช้พร้อม customer ID
INSERT INTO users (email, name, omise_customer_id, subscription_status)
VALUES ('john@example.com', 'John Doe', 'cust_test_...', 'active');
ขั้นตอนที่ 3: เรียกเก็บเงินจากบัตรที่บันทึกไว้
สำหรับการชำระเงินในอนาคต ให้เรียกเก็บเงินโดยใช้ customer ID แทน token:
- cURL
- Node.js
- PHP
curl https://api.omise.co/charges \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=29900" \
-d "currency=thb" \
-d "customer=cust_test_5rt6s9vah5lkvi1rh9c" \
-d "description=การสมัครสมาชิกรายเดือน - กุมภาพันธ์ 2024"
// ดึง customer ID จากฐานข้อมูลของคุณ
const customerId = await getUserOmiseCustomerId(userId);
// สร้างการเรียกเก็บเงิน
const charge = await omise.charges.create({
amount: 29900, // THB 299.00
currency: 'thb',
customer: customerId,
description: 'การสมัครสมาชิกรายเดือน - กุมภาพันธ์ 2024'
});
<?php
// ดึง customer ID จากฐานข้อมูล
$customerId = getUserOmiseCustomerId($userId);
$charge = OmiseCharge::create(array(
'amount' => 29900,
'currency' => 'thb',
'customer' => $customerId,
'description' => 'การสมัครสมาชิกรายเดือน - กุมภาพันธ์ 2024'
));
?>
เมื่อเรียกเก็บเงิน customer ID คุณไม่จำเป็นต้องสร้าง token Omise จะใช้บัตรเริ่มต้นของลูกค้าโดยอัตโนมัติ
การจัดการบัตรหลายใบ
เพิ่มบัตรเพิ่มเติม
// สร้าง token สำหรับบัตรใหม่ผ่าน Omise.js ก่อน
const token = 'tokn_test_...';
// เพิ่มบัตรให้กับ customer ที่มีอยู่
const card = await omise.customers.addCard(customerId, {
card: token
});
แสดงรายการบัตรของลูกค้า
curl https://api.omise.co/customers/cust_test_.../cards \
-u skey_test_YOUR_SECRET_KEY:
ตั้งบัตรเริ่มต ้น
await omise.customers.update(customerId, {
default_card: 'card_test_...'
});
ลบบัตร
curl https://api.omise.co/customers/cust_test_.../cards/card_test_... \
-X DELETE \
-u skey_test_YOUR_SECRET_KEY:
การใช้งานการชำระเงินซ้ำ
ตัวอย่าง: การสมัครสมาชิกรายเดือน
// ฟังก์ชันการเรียกเก็บเงินการสมัครสมาชิก (รันทุกวันผ่าน cron)
async function processSubscriptionBilling() {
// ค้นหาการสมัครสมาชิกที่ครบกำหนดต่ออายุวันนี้
const dueSubscriptions = await db.query(`
SELECT user_id, omise_customer_id, subscription_plan, amount
FROM users
WHERE subscription_status = 'active'
AND next_billing_date = CURRENT_DATE
`);
for (const sub of dueSubscriptions) {
try {
// เรียกเก็บเงินจากลูกค้า
const charge = await omise.charges.create({
amount: sub.amount,
currency: 'thb',
customer: sub.omise_customer_id,
description: `${sub.subscription_plan} - ${new Date().toISOString().slice(0, 7)}`,
metadata: {
user_id: sub.user_id,
subscription_type: sub.subscription_plan
}
});
if (charge.status === 'successful') {
// อัปเดตวันที่เรียกเก็บเงินครั้งถัดไป
await db.query(`
UPDATE users
SET next_billing_date = DATE_ADD(CURRENT_DATE, INTERVAL 1 MONTH),
last_charge_id = ?
WHERE user_id = ?
`, [charge.id, sub.user_id]);
// ส่งอีเมลใบเสร็จ
await sendReceiptEmail(sub.user_id, charge);
} else {
// จัดการการชำระเงินที่ล้มเหลว
await handleFailedPayment(sub.user_id, charge.failure_message);
}
} catch (error) {
console.error(`ไม่สามารถเรียกเก็บเงินผู้ใช้ ${sub.user_id}:`, error);
await handleBillingError(sub.user_id, error);
}
}
}
ตรรกะการลองใหม่สำหรับการชำระเงินที่ล้มเ หลว
async function handleFailedPayment(userId, failureMessage) {
const user = await db.getUserById(userId);
const retryCount = user.payment_retry_count || 0;
if (retryCount < 3) {
// กำหนดการล องใหม่
await db.query(`
UPDATE users
SET payment_retry_count = ?,
next_retry_date = DATE_ADD(CURRENT_DATE, INTERVAL ? DAY)
WHERE user_id = ?
`, [retryCount + 1, retryCount + 1, userId]);
// แจ้งเตือนลูกค้า
await sendPaymentFailedEmail(userId, {
reason: failureMessage,
retryDate: new Date(Date.now() + (retryCount + 1) * 24 * 60 * 60 * 1000)
});
} else {
// ถึงจำนวนการลองใหม่สูงสุดแล้ว - ระงับการสมัครสมาชิก
await db.query(`
UPDATE users
SET subscription_status = 'suspended',
suspension_reason = 'payment_failure'
WHERE user_id = ?
`, [userId]);
await sendSubscriptionSuspendedEmail(userId);
}
}
อัปเดตข้อมูลบัตร
อัปเดตวันหมดอายุ
ลูกค้าสามารถอัปเดตวันหมดอายุของบัตรโดยไม่ต้องกรอกหมายเลขบัตรใหม่:
await omise.customers.updateCard(customerId, cardId, {
expiration_month: 12,
expiration_year: 2028,
name: 'John Doe',
postal_code: '10110'
});
เปลี่ยนบัตรทั้งหมด
ด้วยเหตุผลด้านความปลอดภัย หมายเลขบัตรไม่สามารถอัปเดตได้ ในการเปลี่ยนบัตร:
- สร้าง token ใหม่ด้วย Omise.js
- เพิ่มบัตรใหม่ให้กับ customer
- ตั้งเป็นบัตรเริ่มต้น
- ลบบัตรเก่า
// 1. สร้าง token ผ่าน Omise.js (ฝั่งไคลเอนต์)
const newToken = 'tokn_test_...';
// 2. เพิ่มบัตรใหม่
const newCard = await omise.customers.addCard(customerId, {
card: newToken
});
// 3. ตั้งเป็นค่าเริ่มต้น
await omise.customers.update(customerId, {
default_card: newCard.id
});
// 4. ลบบัตรเก่า
await omise.customers.destroyCard(customerId, oldCardId);
ความปลอดภัยและการปฏิบัติตาม
การปฏิบัติตาม PCI
Omise จัดการการจัดเก็บบัตรใน vault ที่ปฏิบัติตาม PCI คุณจัดเก็บเฉพาะ:
- Customer ID (ปลอดภัยในการจัดเก็บ)
- Metadata ของบัตร (4 หลักสุดท้าย, แบรนด์, วันหมดอายุ - ปลอดภัยในการแสดง)
อย่าจัดเก็บ:
- หมายเลขบัตรเต็ม
- CVV/รหัสความปลอดภัย
- ข้อมูลบัตรดิบ
การป้องกันข้อมูลลูกค้า
// ✅ ดี: จัดเก็บเฉพาะ ID และ metadata
const user = {
id: 12345,
email: 'john@example.com',
omise_customer_id: 'cust_test_...',
card_last_digits: '4242', // ปลอ ดภัยในการแสดง
card_brand: 'Visa', // ปลอดภัยในการแสดง
card_expiry: '12/2027' // ปลอดภัยในการแสดง
};
// ❌ แย่: อย่าจัดเก็บสิ่งเหล่านี้
const badExample = {
card_number: '4242424242424242', // อย่าจัดเก็บสิ่งนี้!
cvv: '123' // อย่าจัดเก็บสิ่งนี้!
};
ความยินยอมของลูกค้า
ขอความยินยอมอ ย่างชัดเจนเสมอก่อนบันทึกบัตร:
<form id="payment-form">
<!-- ฟิลด์ป้อนข้อมูลบัตร -->
<label>
<input type="checkbox" id="save-card" name="save_card" />
บันทึกบัตรนี้สำหร ับการซื้อในอนาคต
</label>
<button type="submit">ทำการชำระเงินให้เสร็จสิ้น</button>
</form>
<script>
document.getElementById('payment-form').addEventListener('submit', function(e) {
e.preventDefault();
const saveCard = document.getElementById('save-card').checked;
// ถ้าบันทึกบัตร สร้าง customer
// ถ้าไม่ เพียงสร้างการเรียกเก็บเงินด้วย token
});
</script>
ปัญหาทั่วไปและการแก้ไขปัญหา
ปัญหา: Customer มีอยู่แล้ว
ข้อผิดพลาด: customer_already_exists
วิธีแก้: ดึง customer ที่มีอยู่หรืออัปเดต:
try {
const customer = await omise.customers.create({
email: email,
card: token
});
} catch (error) {
if (error.code === 'customer_already_exists') {
// ดึงและอัปเดตแทน
const existingCustomer = await omise.customers.list({
limit: 1,
// ใช้ฐานข้อมูลของคุณเพื่อค้นหา customer ID
});
}
}