TrueMoney Wallet
3000万人以上のアクティブユーザーを持つタイで最も人気のあるe-walletの1つからオンライン決済を受け付けます。顧客は電話番号を入力し、OTPで認証するためにリダイレクトされます。
- アプリ間リダイレクト: TrueMoneyへのディープリンクを使用したモバイルアプリについては、TrueMoney Jump Appをご覧ください。
- QRコード決済: オフラインQRコードベースの決済については、TrueMoney QRをご覧ください。
このページではオンラインOTPベースのリダイレクトフローについて説明しています。
支払いフロー

上記の画像は、ワンタイムパスワード(OTP)検証を使用した完全なredirect支払いフローを示しています。
概要
ユーザー数は概算であり、公開されている情報に基づいています。実際のアクティブユーザー数は異なる場合があります。
TrueMoney Walletは、3000万人以上のユーザーを持つタイの主要なモバイル決済ソリューションです。ウォレットにより、顧客はセキュリティ強化のためのOTP検証付きで携帯電話番号を使用して支払いを行うことができます。
主な機能:
- ✅ 大規模なユーザーベース - タイで3000万人以上のアクティブユーザー
- ✅ シンプルなフロー - 電話番号 + OTP認証
- ✅ 迅速な決済 - 従来の銀行よりも高速
- ✅ モバイルファースト - スマートフォンユーザーに最適化
- ✅ 信頼できるブランド - Ascend Group(CPグループ)の一部
サポートされている地域
| Region | Currency | Min Amount | Max Amount | API Version |
|---|---|---|---|---|
| Thailand | THB | ฿20.00 | ฿100,000.00 | 2017-11-02 |
検証レベル別の取引制限
| 検証レベル | 取引ごと | 1日の上限 | 月間上限 |
|---|---|---|---|
| Basic(電話のみ) | ฿100,000 | ฿40,000 | ฿200,000 |
| Plus(IDカード) | ฿100,000 | ฿100,000 | ฿500,000 |
| Premium(銀行口座) | ฿100,000 | ฿200,000 | 無制限 |
仕組み
顧客体験:
- 顧客がチェックアウト時にTrueMoneyを選択
- 携帯電話番号を入力
- SMSでOTPを受信
- OTPを入力して承認
- 支払い金額を確認
- 加盟店サイトに戻る
実装
ステップ1: TrueMoney Sourceの作成
- cURL
- Node.js
- PHP
- Python
curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=truemoney" \
-d "amount=50000" \
-d "currency=THB" \
-d "phone_number=+66876543210"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'truemoney',
amount: 50000, // THB 500.00
currency: 'THB',
phone_number: '+66876543210'
});
<?php
$source = OmiseSource::create(array(
'type' => 'truemoney',
'amount' => 50000,
'currency' => 'THB',
'phone_number' => '+66876543210'
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='truemoney',
amount=50000,
currency='THB',
phone_number='+66876543210'
)
レスポンス:
{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "truemoney",
"flow": "redirect",
"amount": 50000,
"currency": "THB",
"phone_number": "+66876543210"
}
ステップ2: Chargeの作成
curl https://api.omise.co/charges \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=50000" \
-d "currency=THB" \
-d "source=src_test_5rt6s9vah5lkvi1rh9c" \
-d "return_uri=https://yourdomain.com/payment/callback"
ステップ3: 顧客のredirect
app.post('/create-truemoney-payment', async (req, res) => {
// Create source
const source = await omise.sources.create({
type: 'truemoney',
amount: req.body.amount,
currency: 'THB',
phone_number: req.body.phone_number
});
// Create charge
const charge = await omise.charges.create({
amount: req.body.amount,
currency: 'THB',
source: source.id,
return_uri: 'https://yourdomain.com/payment/callback',
metadata: {
order_id: req.body.order_id
}
});
// Redirect customer
res.redirect(charge.authorize_uri);
});
ステップ4: returnの処理
app.get('/payment/callback', async (req, res) => {
const chargeId = req.query.charge_id;
// Retrieve charge status
const charge = await omise.charges.retrieve(chargeId);
if (charge.status === 'successful') {
// Payment successful
await processOrder(charge.metadata.order_id);
res.redirect('/payment-success');
} else if (charge.status === 'failed') {
// Payment failed
res.redirect('/payment-failed?reason=' + charge.failure_message);
} else {
// Still pending
res.redirect('/payment-pending');
}
});
ステップ5: webhookの処理
app.post('/webhooks/omise', (req, res) => {
const event = req.body;
if (event.key === 'charge.complete' && event.data.source.type === 'truemoney') {
const charge = event.data;
if (charge.status === 'successful') {
processOrder(charge.metadata.order_id);
}
}
res.sendStatus(200);
});
完全な実装例
// Express.js server
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
const app = express();
app.use(express.json());
// Checkout page
app.post('/checkout/truemoney', async (req, res) => {
try {
const { amount, phone_number, order_id } = req.body;
// Validate phone number format
if (!/^\+66\d{9}$/.test(phone_number)) {
return res.status(400).json({
error: 'Invalid phone number. Use format: +66876543210'
});
}
// Check amount limits
if (amount < 2000 || amount > 10000000) {
return res.status(400).json({
error: 'Amount must be between ฿20 and ฿100,000'
});
}
// Create source
const source = await omise.sources.create({
type: 'truemoney',
amount: amount,
currency: 'THB',
phone_number: phone_number
});
// Create charge
const charge = await omise.charges.create({
amount: amount,
currency: 'THB',
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/callback`,
metadata: {
order_id: order_id,
customer_phone: phone_number
}
});
// Return authorization URL
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id
});
} catch (error) {
console.error('TrueMoney payment error:', error);
res.status(500).json({ error: error.message });
}
});
// Callback handler
app.get('/payment/callback', async (req, res) => {
try {
const chargeId = req.query.charge_id;
const charge = await omise.charges.retrieve(chargeId);
if (charge.status === 'successful') {
res.redirect(`/order-success?order=${charge.metadata.order_id}`);
} else {
res.redirect(`/payment-failed?charge=${chargeId}`);
}
} catch (error) {
res.redirect('/payment-error');
}
});
// Webhook handler
app.post('/webhooks/omise', (req, res) => {
const event = req.body;
if (event.key === 'charge.complete') {
const charge = event.data;
if (charge.source.type === 'truemoney') {
if (charge.status === 'successful') {
// Process order
updateOrderStatus(charge.metadata.order_id, 'paid');
sendConfirmation(charge.metadata.customer_phone);
} else {
// Handle failure
updateOrderStatus(charge.metadata.order_id, 'failed');
}
}
}
res.sendStatus(200);
});
app.listen(3000);
voidと返金のサポート
課金のvoid
TrueMoneyは課金作成から24時間以内のvoidをサポート:
// Void immediately (full or partial)
const refund = await omise.charges.refund('chrg_test_...', {
amount: 50000 // Full amount
});
if (refund.voided) {
console.log('Charge was voided (within 24 hours)');
}
返金
30日以内の全額返金のみ:
// Full refund only
const refund = await omise.charges.refund('chrg_test_...', {
amount: 50000 // Must be full amount
});
TrueMoney Walletは部分返金をサポートしていません。30日以内の全額返金のみが許可されています。
よくある問題とトラブルシューティング
問題: "無効な電話番号"
原因:
- 間違った形式
- 国コードが欠落
- タイ以外の番号
解決策:
function validateThaiPhone(phone) {
// Accept formats: +66876543210, 0876543210
let normalized = phone.replace(/\s/g, '');
if (normalized.startsWith('0')) {
normalized = '+66' + normalized.substring(1);
}
if (!/^\+66\d{9}$/.test(normalized)) {
throw new Error('Invalid Thai phone number');
}
return normalized;
}
問題: 顧客が1日の上限を超過
エラー: 取引が拒否されました
解決策:
- 顧客がTrueMoneyアカウントの検証をアップグレードする必要があります
- 複数日にわたって支払いを分割
- 代替決済方法を使用
問題: 支払いが長時間保留中
原因: 顧客がOTP検証を完了しませんでした
解決策:
- 15〜20分のタイムアウトを設定
- 顧客が新しい課金で再試行できるようにする
- 明確な指示を表示
問題: return URIが呼び出されない
原因: 顧客がブラウザを閉じました
解決策:
- webhook処理を実装(より信頼性が高い)
- 注文ステータス確認ページを提供
- 顧客にSMS確認を送信
ベストプ ラクティス
1. 電話番号の検証
const phoneRegex = /^\+66[0-9]{9}$/;
if (!phoneRegex.test(phoneNumber)) {
return res.status(400).json({
error: 'Please enter a valid Thai phone number (e.g., +66876543210)'
});
}
2. 明確な指示を表示
<div class="truemoney-instructions">
<h3>TrueMoney Walletで支払う</h3>
<ol>
<li>TrueMoneyに登録されている電話番号を入力してください</li>
<li>SMSでOTPが送信されます</li>
<li>OTPを入力して支払いを承認してください</li>
<li>金額を確認してください</li>
</ol>
<p>TrueMoney Walletに十分な残高があることを確認してください。</p>
</div>
3. タイムアウトの処理
// Set reasonable timeout
setTimeout(() => {
if (!paymentConfirmed) {
showTimeoutMessage();
allowRetry();
}
}, 15 * 60 * 1000); // 15 minutes
4. webhookを使用
redirectコールバックのみに依存しないでください:
// Webhook is more reliable
app.post('/webhooks/omise', handleWebhook);
// Callback is backup
app.get('/payment/callback', handleCallback);
5. 顧客サポートを提 供
metadata: {
order_id: orderId,
customer_phone: phoneNumber,
customer_email: email,
support_ticket: ticketId
}
FAQ
TrueMoney Walletとは何ですか?
TrueMoney Walletは、3000万人以上のユーザーを持つタイのモバイル決済アプリです。顧客はウォレットにお金をロードし、OTP認証付きの電話番号を使用して支払うことができます。
顧客は最初に登録する必要がありますか?
はい、顧客は既存のTrueMoney Walletアカウントを持っている必要があります。アプリをダウンロードして、タイの電話番号で登録できます。
取引手数料はいくらですか?
現在の料金については、Omiseダッシュボードを確認してください。e-wallet手数料は通常、クレジットカードよりも低くなっています。
決済にはどのくらいかかりますか?
決済は通常、クレジットカードよりも高速です。具体的なタイムラインについては、Omiseサポートに確認してください。
海外の顧客はTrueMoneyを使用できますか?
TrueMoneyは、タイの電話番号とタイの銀行口座を持つタイの顧客のみが利用できます。
顧客の残高が不足している場合はどうなりますか?
支払いは失敗します。顧客は以下の方法でTrueMoney Walletに入金できます:
- セブンイレブン店舗
- 銀行振込
- クレジット/デビットカード
- TrueMoneyキオスク
その後、支払いを再試行してください。
テスト
テストモード
TrueMoney Walletは、テストAPIキーを使用してテストモードでテストできます。テストモードでは:
テスト認証情報:
- 有効なタイの電話番号形式(+66XXXXXXXXX)を使用
- テスト課金は実際に顧客アカウントから引き落とされません
- すべてのテストデータはテストAPIキー(skey_test_xxx)を使用
テストフロー:
- テストAPIキーを使用してsourceとchargeを作成
- redirectの
authorize_uriを 受け取ります - テストモードでは、ダッシュボードで課金を成功/失敗として手動でマーク
- ステータスの変更に基づいてwebhookがトリガーされます
ステータス変更のテスト:
// Create test charge
const charge = await omise.charges.create({
amount: 50000,
currency: 'THB',
source: testSourceId,
return_uri: 'https://example.com/callback'
});
// In test mode, use Omise Dashboard to:
// 1. Navigate to the charge
// 2. Use "Actions" menu to mark as successful or failed
// 3. Verify webhook handling
テストシナリオ:
- 成功した支払い: 注文処理ワークフローを検証
- 失敗した支払い: エラー処理と再試行ロジックをテスト
- タイムアウト: 放棄された支払いシナリオをテスト
- webhook配信: すべてのwebhookが適切に受信されることを確認
重要な注意事項:
- テストモードのQR codeはredirectしますが、実際のTrueMoneyサーバーには接続しません
- ダッシュボードを使用して支払い完了をシミュレート
- 本番環境に移行する前に常にwebhook処理をテスト
- 金額制限と検証ロジックを検証
包括的なテストガイドラインについては、テストドキュメントを参照してください。
関連リソース
- デジタルウォレットの概要 - すべてのウォレットオプション
- TrueMoney QR - オフラインQR決済
- GrabPay - 代替ウォレット
- Rabbit LINE Pay - 別のタイのウォレット
- 返金 - 返金ポリシー
- テスト - TrueMoney統合のテスト