振込・出金
OmiseのTransfer APIを使用して、銀行口座への出金を自動化し、受取人を管理し、定期的な振込をスケジュールして、シームレスな資金配分を実現します。
概要
振込を使用すると、Omiseアカウントの残高から銀行口座へ資金を送金できます。これは、マーケットプレイスの出金、アフィリエイト手数料、カード以外の決済方法への返金、サプライヤーへの支払い、または資金を自動的に配分する必要があるあらゆるシナリオに役立ちます。
主な機能:
- ✅ 自動出金 - API駆動またはスケジュールされた振込
- ✅ 複数の受取人 - 受取人情報を保存して再利用
- ✅ 柔軟なスケジューリング - 日次、週次、または月次の振込
- ✅ 複数通貨 - 複数の通貨をサポート
- ✅ バッチ振込 - 複数の出金を効率的に処理
- ✅ Webhook通知 - 振込ステータスのリアルタイム更新
- ✅ 銀行確認 - 自動受取人銀行検証
仕組み
振込のライフサイクル:
- pending - 振込が作成され、処理待ち
- sent - 振込が銀行に送信されました
- paid - 受取人が資金を受け取りました
- failed - 振込が失敗しました(残高不足、無効な口座)
実装
ステップ 1: 受取人を作成
- 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', // バンコク銀行
number: '1234567890',
name: 'John Doe'
},
metadata: {
user_id: '12345',
payout_type: 'commission'
}
});
console.log('受取人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- バンコク銀行kbank- カシコン銀行scb- サイアム商業銀行ktb- クルンタイ銀行bay- アユタヤ銀行 (クルンシー)tmb- TMB銀行citi- シティバンクuob- ユナイテッド・オーバーシーズ銀行- その他...
ステップ 2: 振込を作成
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('振込ID:', transfer.id);
console.log('ステータス:', transfer.status); // 'pending'
ステップ 3: 振込ステータスを確認
// 振込を取得
const transfer = await omise.transfers.retrieve('trsf_test_...');
console.log('ステータス:', transfer.status);
// 'pending' → 'sent' → 'paid' or 'failed'
if (transfer.status === 'paid') {
console.log('振込が正常に完了しました');
console.log('支払日:', transfer.paid_at);
} else if (transfer.status === 'failed') {
console.log('振込が失敗しました:', 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.id}が完了しました`);
// データベースを更新
await db.payouts.update({
transfer_id: transfer.id,
status: 'completed',
paid_at: transfer.paid_at
});
// 受取人に通知
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 });
// 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
}
});
// 受取人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 です'
});
}
// 振込を作成
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 });
}
});
// スケジュールされた日次出金(深夜0時に実行)
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ハンドラー
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);