Transfer และการจ่ายเงิน
ทำการจ่ายเงินไปยังบัญชีธนาคารอัตโนมัติ จัดการ recipient และกำหนดเวลา transfer แบบวนซ้ำโดยใช้ Transfer API ของ Omise เพื่อการกระจายเงินที่ราบรื่น
ภาพรวม
Transfer ช่วยให้คุณส่งเงินจากยอดคงเหลือในบัญชี Omise ของคุณไปยังบัญชีธนาคาร ซึ่งมีประโยชน์สำหรับการจ่ายเงินในตลาดกลาง (marketplace), ค่าคอมมิชชันพันธมิตร, การคืนเงินสำหรับวิธีการชำระเงินที่ไม่ใช่บัตร, การชำระเงินให้ซัพพลายเออร์ หรือสถานการณ์ใดๆ ที่คุณต้องการกระจายเงินอัตโนมัติ
ฟีเจอร์หลัก:
- ✅ การจ่ายเงินอัตโนมัติ - transfer ที่ขับเคลื่อนด้วย API หรือตามกำหนดเวลา
- ✅ Recipient หลายราย - บันทึกและนำข้อมูล recipient มาใช้ซ้ำ
- ✅ การกำหนดเวลาที่ยืดหยุ่น - transfer รายวัน รายสัปดาห์ หรือรายเดือน
- ✅ หลายสกุลเงิน - รองรับสกุลเงินหลายประเภท
- ✅ Batch transfer - ประมวลผลการจ่ายเงินหลายรายการอย่างมีประสิทธิภาพ
- ✅ การแจ้งเตือน Webhook - อัปเดตสถานะ transfer แบบเรียลไทม์
- ✅ การตรวจสอบธนาคาร - การตรวจสอบธนาคาร recipient อัตโนมัติ
วิธีการทำงาน
วงจรชีวิตของ Transfer:
- pending - สร้าง transfer แล้ว รอการประมวลผล
- sent - ส่ง transfer ไปยังธนาคารแล้ว
- paid - Recipient ได้รับเงินแล้ว
- failed - Transfer ล้มเหลว (ยอดคงเหลือไม่เพียงพอ, บัญชีไม่ถูกต้อง)
การใช้งาน
ขั้นตอนที่ 1: สร้าง Recipient
- cURL
- Node.js
- PHP
- Python
- Ruby
- Go
- Java
- C#
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"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const recipient = await omise.recipients.create({
name: 'John Doe',
email: 'john@example.com',
type: 'individual',
bank_account: {
brand: 'bbl', // Bangkok ธนาคาร
number: '1234567890',
name: 'John Doe'
},
metadata: {
user_id: '12345',
payout_type: 'commission'
}
});
console.log('Recipient ID:', recipient.id);
<?php
$recipient = OmiseRecipient::create(array(
'name' => 'John Doe',
'email' => 'john@example.com',
'type' => 'individual',
'bank_account' => array(
'brand' => 'bbl',
'number' => '1234567890',
'name' => 'John Doe'
)
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
recipient = omise.Recipient.create(
name='John Doe',
email='john@example.com',
type='individual',
bank_account={
'brand': 'bbl',
'number': '1234567890',
'name': 'John Doe'
}
)
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
recipient = Omise::Recipient.create({
name: 'John Doe',
email: 'john@example.com',
type: 'individual',
bank_account: {
brand: 'bbl',
number: '1234567890',
name: 'John Doe'
}
})
recipient, err := client.Recipients().Create(&operations.CreateRecipient{
Name: "John Doe",
Email: "john@example.com",
Type: "individual",
BankAccount: &BankAccount{
Brand: "bbl",
Number: "1234567890",
Name: "John Doe",
},
})
Recipient recipient = client.recipients().create(new Recipient.CreateParams()
.name("John Doe")
.email("john@example.com")
.type("individual")
.bankAccount(new BankAccount()
.brand("bbl")
.number("1234567890")
.name("John Doe")));
var recipient = await client.Recipients.Create(new CreateRecipientRequest
{
Name = "John Doe",
Email = "john@example.com",
Type = "individual",
BankAccount = new BankAccount
{
Brand = "bbl",
Number = "1234567890",
Name = "John Doe"
}
});
ธนาคารที่รองรับ (ประเทศไทย):
bbl- Bangkok ธนาคารkbank- Kasikorn ธนาคารscb- Siam Commercial ธนาคารktb- Krung Thai ธนาคารbay- ธนาคาร of Ayudhya (Krungsri)tmb- TMB ธนาคารciti- Citibankuob- 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