ข้ามไปยังเนื้อหาหลัก

Transfer และการจ่ายเงิน

ทำการจ่ายเงินไปยังบัญชีธนาคารอัตโนมัติ จัดการ recipient และกำหนดเวลา transfer แบบวนซ้ำโดยใช้ Transfer API ของ Omise เพื่อการกระจายเงินที่ราบรื่น

ภาพรวม

Transfer ช่วยให้คุณส่งเงินจากยอดคงเหลือในบัญชี Omise ของคุณไปยังบัญชีธนาคาร ซึ่งมีประโยชน์สำหรับการจ่ายเงินในตลาดกลาง (marketplace), ค่าคอมมิชชันพันธมิตร, การคืนเงินสำหรับวิธีการชำระเงินที่ไม่ใช่บัตร, การชำระเงินให้ซัพพลายเออร์ หรือสถานการณ์ใดๆ ที่คุณต้องการกระจายเงินอัตโนมัติ

ฟีเจอร์หลัก:

  • การจ่ายเงินอัตโนมัติ - transfer ที่ขับเคลื่อนด้วย API หรือตามกำหนดเวลา
  • Recipient หลายราย - บันทึกและนำข้อมูล recipient มาใช้ซ้ำ
  • การกำหนดเวลาที่ยืดหยุ่น - transfer รายวัน รายสัปดาห์ หรือรายเดือน
  • หลายสกุลเงิน - รองรับสกุลเงินหลายประเภท
  • Batch transfer - ประมวลผลการจ่ายเงินหลายรายการอย่างมีประสิทธิภาพ
  • การแจ้งเตือน Webhook - อัปเดตสถานะ transfer แบบเรียลไทม์
  • การตรวจสอบธนาคาร - การตรวจสอบธนาคาร recipient อัตโนมัติ

วิธีการทำงาน

วงจรชีวิตของ Transfer:

  1. pending - สร้าง transfer แล้ว รอการประมวลผล
  2. sent - ส่ง transfer ไปยังธนาคารแล้ว
  3. paid - Recipient ได้รับเงินแล้ว
  4. failed - Transfer ล้มเหลว (ยอดคงเหลือไม่เพียงพอ, บัญชีไม่ถูกต้อง)

การใช้งาน

ขั้นตอนที่ 1: สร้าง Recipient

curl https://api.omise.co/recipients \
-u skey_test_YOUR_SECRET_KEY: \
-d "name=John Doe" \
-d "email=john@example.com" \
-d "type=individual" \
-d "bank_account[brand]=bbl" \
-d "bank_account[number]=1234567890" \
-d "bank_account[name]=John Doe"

ธนาคารที่รองรับ (ประเทศไทย):

  • bbl - Bangkok ธนาคาร
  • kbank - Kasikorn ธนาคาร
  • scb - Siam Commercial ธนาคาร
  • ktb - Krung Thai ธนาคาร
  • bay - ธนาคาร of Ayudhya (Krungsri)
  • tmb - TMB ธนาคาร
  • citi - Citibank
  • uob - United Overseas ธนาคาร
  • และอื่นๆ...

ขั้นตอนที่ 2: สร้าง Transfer

const transfer = await omise.transfers.create({
amount: 100000, // THB 1,000.00
recipient: recipient.id,
metadata: {
order_id: '12345',
payout_date: new Date().toISOString()
}
});

console.log('Transfer ID:', transfer.id);
console.log('Status:', transfer.status); // 'pending'

ขั้นตอนที่ 3: ตรวจสอบสถานะ Transfer

// ดึงข้อมูล transfer
const transfer = await omise.transfers.retrieve('trsf_test_...');

console.log('Status:', transfer.status);
// 'pending' → 'sent' → 'paid' or 'failed'

if (transfer.status === 'paid') {
console.log('Transfer สำเร็จแล้ว');
console.log('จ่ายเมื่อ:', transfer.paid_at);
} else if (transfer.status === 'failed') {
console.log('Transfer ล้มเหลว:', transfer.failure_message);
}

ขั้นตอนที่ 4: จัดการ Webhook

app.post('/webhooks/omise', (req, res) => {
const event = req.body;

switch (event.key) {
case 'transfer.create':
handleTransferCreated(event.data);
break;

case 'transfer.send':
handleTransferSent(event.data);
break;

case 'transfer.pay':
handleTransferPaid(event.data);
break;

case 'transfer.fail':
handleTransferFailed(event.data);
break;
}

res.sendStatus(200);
});

async function handleTransferPaid(transfer) {
console.log(`Transfer ${transfer.id} เสร็จสมบูรณ์`);

// อัปเดตฐานข้อมูล
await db.payouts.update({
transfer_id: transfer.id,
status: 'completed',
paid_at: transfer.paid_at
});

// แจ้ง recipient
await sendPayoutConfirmation(transfer.recipient, transfer);
}

ตัวอย่างการจ่ายเงินในตลาดกลางแบบสมบูรณ์

// แพลตฟอร์มตลาดกลางที่มีการจ่ายเงินให้ผู้ขาย
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});

const app = express();
app.use(express.json());

// ลงทะเบียนผู้ขายสำหรับการจ่ายเงิน
app.post('/sellers/:sellerId/register-payout', async (req, res) => {
try {
const { sellerId } = req.params;
const { bank_brand, account_number, account_name } = req.body;

const seller = await db.sellers.findOne({ id: sellerId });

// สร้าง recipient ใน Omise
const recipient = await omise.recipients.create({
name: account_name,
email: seller.email,
type: 'individual',
bank_account: {
brand: bank_brand,
number: account_number,
name: account_name
},
metadata: {
seller_id: sellerId
}
});

// บันทึก recipient ID
await db.sellers.update({
id: sellerId,
omise_recipient_id: recipient.id,
payout_enabled: true
});

res.json({
success: true,
message: 'ลงทะเบียนวิธีการจ่ายเงินแล้ว'
});

} catch (error) {
res.status(500).json({ error: error.message });
}
});

// ประมวลผลการจ่ายเงินให้ผู้ขาย
app.post('/sellers/:sellerId/payout', async (req, res) => {
try {
const { sellerId } = req.params;
const { amount, order_ids } = req.body;

const seller = await db.sellers.findOne({ id: sellerId });

if (!seller.omise_recipient_id) {
return res.status(400).json({
error: 'ผู้ขายยังไม่ได้ลงทะเบียนวิธีการจ่ายเงิน'
});
}

// ตรวจสอบจำนวนเงินขั้นต่ำ
if (amount < 10000) { // ฿100 ขั้นต่ำ
return res.status(400).json({
error: 'จำนวนเงินขั้นต่ำคือ ฿100'
});
}

// สร้าง transfer
const transfer = await omise.transfers.create({
amount: amount,
recipient: seller.omise_recipient_id,
metadata: {
seller_id: sellerId,
order_ids: order_ids.join(','),
payout_date: new Date().toISOString()
}
});

// บันทึกการจ่ายเงิน
await db.payouts.create({
seller_id: sellerId,
transfer_id: transfer.id,
amount: amount,
order_ids: order_ids,
status: 'pending',
created_at: new Date()
});

res.json({
success: true,
transfer_id: transfer.id,
status: transfer.status
});

} catch (error) {
res.status(500).json({ error: error.message });
}
});

// การจ่ายเงินรายวันตามกำหนดเวลา (ทำงานเวลาเที่ยงคืน)
cron.schedule('0 0 * * *', async () => {
console.log('กำลังประมวลผลการจ่ายเงินให้ผู้ขายรายวัน...');

// ค้นหาผู้ขายที่มีรายได้ค้างจ่าย
const sellers = await db.sellers.find({
pending_earnings: { $gte: 10000 }, // ฿100+ ขั้นต่ำ
payout_enabled: true
});

for (const seller of sellers) {
try {
const transfer = await omise.transfers.create({
amount: seller.pending_earnings,
recipient: seller.omise_recipient_id,
metadata: {
seller_id: seller.id,
payout_type: 'daily_automatic'
}
});

// รีเซ็ตรายได้ค้างจ่าย
await db.sellers.update({
id: seller.id,
pending_earnings: 0,
last_payout_at: new Date()
});

console.log(`✓ จ่ายเงินให้ ${seller.name}: ฿${seller.pending_earnings / 100}`);

} catch (error) {
console.error(`✗ การจ่ายเงินให้ ${seller.name} ล้มเหลว:`, error.message);
await notifyAdminPayoutFailed(seller, error);
}
}
});

// Webhook handler
app.post('/webhooks/omise', (req, res) => {
const event = req.body;

if (event.key === 'transfer.pay') {
const transfer = event.data;

// อัปเดตสถานะการจ่ายเงิน
db.payouts.update({
transfer_id: transfer.id,
status: 'completed',
completed_at: new Date()
});

// แจ้งผู้ขาย
const sellerId = transfer.metadata.seller_id;
sendPayoutConfirmationEmail(sellerId, transfer);
}

if (event.key === 'transfer.fail') {
const transfer = event.data;

// จัดการความล้มเหลว
db.payouts.update({
transfer_id: transfer.id,
status: 'failed',
failure_reason: transfer.failure_message
});

// แจ้งผู้ขายและผู้ดูแลระบบ
const sellerId = transfer.metadata.seller_id;
sendPayoutFailedEmail(sellerId, transfer);
notifyAdminPayoutFailed(transfer);
}

res.sendStatus(200);
});

app.listen(3000);

Transfer ตามกำหนดเวลา

สร้าง transfer อัตโนมัติแบบวนซ้ำ:

// สร้างกำหนดเวลา transfer รายวัน
const schedule = await omise.schedules.create({
every: 1,
period: 'day',
start_date: '2025-02-15',
transfer: {
recipient: recipient.id,
amount: 50000, // ฿500 รายวัน
currency: 'THB'
}
});

// สร้างกำหนดเวลา transfer รายเดือน
const monthlySchedule = await omise.schedules.create({
every: 1,
period: 'month',
on: {
days_of_month: [1] // วันที่ 1 ของทุกเดือน
},
start_date: '2025-03-01',
transfer: {
recipient: recipient.id,
amount: 1000000, // ฿10,000 รายเดือน
currency: 'THB'
}
});

แนวทางปฏิบัติที่ดีที่สุด

1. ตรวจสอบข้อมูล Recipient

async function validateRecipient(bankAccount) {
// ตรวจสอบรูปแบบหมายเลขบัญชี
if (!/^\d{10}$/.test(bankAccount.number)) {
throw new Error('หมายเลขบัญชีธนาคารต้องเป็นตัวเลข 10 หลัก');
}

// ตรวจสอบชื่อบัญชี
if (bankAccount.name.length < 3) {
throw new Error('ชื่อบัญชีสั้นเกินไป');
}

// ตรวจสอบข้อมูลซ้ำ
const existing = await db.recipients.findOne({
bank_account_number: bankAccount.number
});

if (existing) {
throw new Error('Recipient นี้ลงทะเบียนไว้แล้ว');
}

return true;
}

2. กำหนดจำนวนเงินขั้นต่ำ

const MIN_PAYOUT = {
THB: 10000, // ฿100
SGD: 1000, // $10
MYR: 5000 // RM50
};

function validatePayoutAmount(amount, currency) {
if (amount < MIN_PAYOUT[currency]) {
return {
valid: false,
error: `จำนวนเงินขั้นต่ำคือ ${MIN_PAYOUT[currency] / 100} ${currency}`
};
}

return { valid: true };
}

3. จัดการยอดคงเหลือไม่เพียงพอ

async function createTransferSafely(transferData) {
// ตรวจสอบยอดคงเหลือก่อน
const account = await omise.account.retrieve();
const availableBalance = account.balance;

if (availableBalance < transferData.amount) {
throw new Error(`ยอดคงเหลือไม่เพียงพอ มี: ฿${availableBalance / 100}, ต้องการ: ฿${transferData.amount / 100}`);
}

// สร้าง transfer
return await omise.transfers.create(transferData);
}

4. การประมวลผลแบบ Batch

async function processBatchPayouts(payouts) {
const results = [];

for (const payout of payouts) {
try {
const transfer = await omise.transfers.create({
amount: payout.amount,
recipient: payout.recipient_id
});

results.push({
payout_id: payout.id,
transfer_id: transfer.id,
status: 'success'
});

// หน่วงเวลาระหว่าง transfer เพื่อหลีกเลี่ยงการจำกัดอัตรา
await sleep(1000);

} catch (error) {
results.push({
payout_id: payout.id,
status: 'failed',
error: error.message
});
}
}

return results;
}

5. ลองใหม่สำหรับ Transfer ที่ล้มเหลว

async function retryFailedTransfer(originalTransferId) {
const originalTransfer = await omise.transfers.retrieve(originalTransferId);

if (originalTransfer.status !== 'failed') {
throw new Error('สามารถลองใหม่ได้เฉพาะ transfer ที่ล้มเหลว');
}

// สร้าง transfer ใหม่ด้วยรายละเอียดเดิม
const retryTransfer = await omise.transfers.create({
amount: originalTransfer.amount,
recipient: originalTransfer.recipient,
metadata: {
...originalTransfer.metadata,
retry_of: originalTransferId,
retry_count: (originalTransfer.metadata.retry_count || 0) + 1
}
});

return retryTransfer;
}

คำถามที่พบบ่อย

Transfer ใช้เวลานานเท่าไหร่?

เวลาของ Transfer แตกต่างกันไป:

  • สร้างไปจนถึงส่ง: ภายใน 24 ชั่วโมง
  • ส่งไปจนถึงจ่าย: 1-3 วันทำการ
  • รวม: โดยทั่วไป 2-4 วันทำการ

ตรวจสอบเวลาประมวลผลของธนาคารเฉพาะในภูมิภาคของคุณ

ค่าธรรมเนียม Transfer คือเท่าไหร่?

ค่าธรรมเนียม Transfer แตกต่างกันตามภูมิภาคและธนาคาร ตรวจสอบแดชบอร์ด Omise ของคุณหรือติดต่อ support@omise.co สำหรับราคาปัจจุบัน

ฉันสามารถยกเลิก Transfer ได้หรือไม่?

สามารถยกเลิก Transfer ได้เฉพาะในขณะที่อยู่ในสถานะ pending (ก่อนที่จะส่งไปยังธนาคาร) ใช้:

await omise.transfers.destroy('trsf_test_...');
จะเกิดอะไรขึ้นถ้า Transfer ล้มเหลว?

สาเหตุความล้มเหลวทั่วไป:

  • ยอดคงเหลือในบัญชีไม่เพียงพอ
  • หมายเลขบัญชีธนาคารไม่ถูกต้อง
  • บัญชี Recipient ปิดแล้ว
  • ธนาคารปฏิเสธ (การตรวจสอบการฉ้อโกง)

Transfer ที่ล้มเหลวจะไม่ถูกลองใหม่โดยอัตโนมัติ ตรวจสอบข้อความที่ล้มเหลวและสร้าง transfer ใหม่หลังจากแก้ไขปัญหา

ฉันสามารถ transfer ไปยังธนาคารต่างประเทศได้หรือไม่?

ความพร้อมของ Transfer และธนาคารที่รองรับแตกต่างกันตามภูมิภาค ปัจจุบัน transfer ส่วนใหญ่เป็นการโอนภายในประเทศในไทย สิงคโปร์ และมาเลเซีย ติดต่อฝ่ายสนับสนุนเพื่อขอความสามารถในการ transfer ระหว่างประเทศ

ฉันจัดการหลายสกุลเงินอย่างไร?

สร้าง recipient แยกต่างหากสำหรับแต่ละสกุลเงิน และตรวจสอบให้แน่ใจว่ายอดคงเหลือในบัญชีของคุณมีเงินเพียงพอในสกุลเงินนั้น Omise ไม่แปลงสกุลเงินโดยอัตโนมัติสำหรับ transfer

Recipient สามารถรับ Transfer หลายครั้งได้หรือไม่?

ได้ เมื่อสร้าง recipient แล้ว คุณสามารถสร้าง transfer ไปยัง recipient นั้นได้ไม่จำกัด

แหล่งข้อมูลที่เกี่ยวข้อง

  • Recipients API - การจัดการ Recipient
  • Transfers API - การดำเนินการ Transfer
  • Schedules - Transfer อัตโนมัติ
  • Balance - การจัดการยอดคงเหลือในบัญชี
  • Webhooks - การแจ้งเตือน Transfer
  • Testing - ทดสอบ Transfer

ขั้นตอนถัดไป

  1. สร้าง Recipient
  2. สร้าง Transfer
  3. ตั้งค่า Webhook
  4. ใช้งานตรรกะการจ่ายเงิน
  5. ทดสอบ Transfer
  6. เริ่มใช้งานจริง