TrueMoney QR
タイのTrueMoneyの3000万人以上のユーザーからオフラインQRコード決済を受け付けます。顧客はTrueMoneyアプリでQRコードをスキャンし、複数の支払い元から選択します。
概要
TrueMoney QRは、顧客がTrueMoneyモバイルアプリを使用して決済するためのスキャン可能なQRコードを生成するオフライン決済方法です。リダイレクトフローとは異なり、顧客はWebサイトや販売時点情報管理システムに表示されたQRコードをスキャンして、スマートフォンで決済を完了します。
主な機能:
- ✅ オフライン決済 - リダイレクト不要、顧客がQRコードをスキャン
- ✅ 複数の資金源 - ウォレット、カード、銀行口座、Pay Next
- ✅ 大規模なユーザーベース - タイのTrueMoneyユーザー3000万人以上
- ✅ 柔軟な最小金額 - ほとんどの決済方法で最低0.01バーツから
- ✅ 迅速な決済 - 従来の銀行振込より高速
- ✅ POSに対応 - 店舗内およびオンライン決済に対応
サポート地域
| 地域 | 通貨 | 最小金額 | 最大金額 | 備考 |
|---|---|---|---|---|
| タイ | THB | ฿0.01* | ฿50,000 | *最小金額は資金源により異なる |
資金源別の最小金額
顧客はQRコードをスキャンする際に、希望する決済方法を選択できます。各方法には異なる最小要件があります:
| 資金源 | 最小金額 | 備考 |
|---|---|---|
| ウォレット残高 | ฿0.01 | TrueMoneyウォレットの資金 |
| クレジット/デビットカード | ฿0.01 | TrueMoney経由のカード決済 |
| Pay Next(全額払い) | ฿0.01 | 後払い(全額) |
| Pay Next Extra(全額払い) | ฿0.01 | 拡張後払いオプション(全額) |
| 銀行口座 | 銀行により異なる | 最小金額は発行銀行に依存 |
資金源の選択
顧客がQRコードをスキャンすると、TrueMoneyアプリ内で決済元を選択します。加盟店は顧客が選択する資金源を制御できません。すべての資金源に対応する最小取引金額を設定するか、最小要件を明確に伝えてください。
仕組み
決済フロー

顧客体験:
- 顧客がチェックアウトでTrueMoney QRを選択
- 加盟店が画面にQRコードを表示
- 顧客がTrueMoneyアプリを開く
- 顧客がQRコードをスキャン
- 顧客が決済元(ウォレット/カード/銀行/Pay Next)を選択
- 顧客が決済を承認
- 決済完了
実装
ステップ1: TrueMoney QRソースの作成
- cURL
- Node.js
- PHP
- Python
curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=truemoney_qr" \
-d "amount=50000" \
-d "currency=THB"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'truemoney_qr',
amount: 50000, // THB 500.00
currency: 'THB'
});
<?php
$source = OmiseSource::create(array(
'type' => 'truemoney_qr',
'amount' => 50000,
'currency' => 'THB'
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='truemoney_qr',
amount=50000,
currency='THB'
)
レスポンス:
{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "truemoney_qr",
"flow": "offline",
"amount": 50000,
"currency": "THB"
}
ステップ2: チャージの作成
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"
レスポンスにはQRコードが含まれます:
{
"object": "charge",
"id": "chrg_test_5rt6s9vah5lkvi1rh9d",
"amount": 50000,
"currency": "THB",
"status": "pending",
"source": {
"object": "source",
"type": "truemoney_qr",
"flow": "offline",
"scannable_code": {
"object": "barcode",
"type": "qr",
"image": {
"download_uri": "https://api.omise.co/charges/chrg_test_.../documents/docu_test_.../downloads/..."
}
}
}
}
ステップ3: QRコードの表示
app.post('/create-truemoney-qr-payment', async (req, res) => {
try {
const { amount, order_id } = req.body;
// Validate amount
if (amount < 1 || amount > 5000000) {
return res.status(400).json({
error: 'Amount must be between ฿0.01 and ฿50,000'
});
}
// Create source
const source = await omise.sources.create({
type: 'truemoney_qr',
amount: amount,
currency: 'THB'
});
// 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
}
});
// Get QR code image URL
const qrCodeUrl = charge.source.scannable_code.image.download_uri;
// Return to frontend
res.json({
charge_id: charge.id,
qr_code_url: qrCodeUrl,
amount: amount
});
} catch (error) {
console.error('TrueMoney QR payment error:', error);
res.status(500).json({ error: error.message });
}
});
フロントエンドの表示:
<div class="payment-container">
<h2>TrueMoneyでスキャンして支払う</h2>
<div class="qr-code-container">
<img id="qrCode" src="" alt="TrueMoney QR Code" />
</div>
<p class="amount">金額: <strong>฿<span id="amount"></span></strong></p>
<div class="instructions">
<h3>お支払い方法:</h3>
<ol>
<li>スマートフォンでTrueMoneyアプリを開く</li>
<li>「QRスキャン」ボタンをタップ</li>
<li>上記のコードをスキャン</li>
<li>決済方法を選択(ウォレット/カード/銀行/Pay Next)</li>
<li>決済を承認</li>
</ol>
</div>
</div>
<script>
async function createPayment(amount, orderId) {
const response = await fetch('/create-truemoney-qr-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount, order_id: orderId })
});
const data = await response.json();
// Display QR code
document.getElementById('qrCode').src = data.qr_code_url;
document.getElementById('amount').textContent = (data.amount / 100).toFixed(2);
// Start polling for payment status
pollPaymentStatus(data.charge_id);
}
async function pollPaymentStatus(chargeId) {
const interval = setInterval(async () => {
const response = await fetch(`/check-payment-status/${chargeId}`);
const data = await response.json();
if (data.status === 'successful') {
clearInterval(interval);
window.location.href = '/payment-success';
} else if (data.status === 'failed') {
clearInterval(interval);
window.location.href = '/payment-failed';
}
}, 3000); // Check every 3 seconds
}
</script>
ステップ4: Webhookの処理
app.post('/webhooks/omise', (req, res) => {
const event = req.body;
if (event.key === 'charge.complete' && event.data.source.type === 'truemoney_qr') {
const charge = event.data;
if (charge.status === 'successful') {
// Process order
processOrder(charge.metadata.order_id);
console.log(`TrueMoney QR payment successful: ${charge.id}`);
} else if (charge.status === 'failed') {
// Handle failure
handleFailedPayment(charge.metadata.order_id, charge.failure_message);
}
}
res.sendStatus(200);
});
完全な実装例
// Express.js server with TrueMoney QR
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
const app = express();
app.use(express.json());
// Create payment and get QR code
app.post('/checkout/truemoney-qr', async (req, res) => {
try {
const { amount, order_id } = req.body;
// Validate amount
if (amount < 1 || amount > 5000000) {
return res.status(400).json({
error: 'Amount must be between ฿0.01 and ฿50,000'
});
}
// Create source
const source = await omise.sources.create({
type: 'truemoney_qr',
amount: amount,
currency: 'THB'
});
// 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,
created_at: new Date().toISOString()
}
});
// Get QR code URL
const qrCodeUrl = charge.source.scannable_code.image.download_uri;
res.json({
success: true,
charge_id: charge.id,
qr_code_url: qrCodeUrl,
amount: amount
});
} catch (error) {
console.error('TrueMoney QR error:', error);
res.status(500).json({
success: false,
error: error.message
});
}
});
// Check payment status (for polling)
app.get('/check-payment-status/:chargeId', async (req, res) => {
try {
const charge = await omise.charges.retrieve(req.params.chargeId);
res.json({
status: charge.status,
paid: charge.paid,
amount: charge.amount
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Webhook handler (primary method)
app.post('/webhooks/omise', (req, res) => {
const event = req.body;
if (event.key === 'charge.complete') {
const charge = event.data;
if (charge.source.type === 'truemoney_qr') {
if (charge.status === 'successful') {
updateOrderStatus(charge.metadata.order_id, 'paid');
sendConfirmation(charge.metadata.order_id);
} else {
updateOrderStatus(charge.metadata.order_id, 'failed');
}
}
}
res.sendStatus(200);
});
app.listen(3000);
ボイドと返金のサポート
チャージのボイド
TrueMoney QRは当日のみボイドをサポートしています:
// Void same-day (full amount only)
const refund = await omise.charges.refund('chrg_test_...', {
amount: 50000 // Must be full amount
});
if (refund.voided) {
console.log('Charge was voided (same-day)');
}
当日のボイドのみ
ボイドはチャージが作成された当日のみ利用可能です。深夜を過ぎると、代わりに返金を使用する必要があります。
返金
30日以内の返金が可能です。サポートは資金源により異なります:
// Full refund (all payment methods)
const refund = await omise.charges.refund('chrg_test_...', {
amount: 50000 // Full amount
});
// Partial refund (Wallet, Bank Account, Pay Next)
const partialRefund = await omise.charges.refund('chrg_test_...', {
amount: 25000 // Half amount
});
資金源別の返金サポート:
| 決済方法 | 全額返金 | 部分返金 | 期間 |
|---|---|---|---|
| ウォレット残高 | ✅ あり | ✅ あり | 30日以内 |
| 銀行口座 | ✅ あり | ✅ あり | 30日以内 |
| Pay Next | ✅ あり | ✅ あり | 30日以内 |
| Pay Next Extra | ✅ あり | ✅ あり | 30日以内 |
| クレジット/デビットカード | ✅ あり(翌日以降) | ❌ なし | 30日以内 |
クレジット/デビットカードの返金
カード決済は全額返金のみをサポートし、取引日以降(翌日以降)のみ可能です。当日のカード返金はサポートされていません。
よくある問題とトラブルシューティング
問題: QRコードが表示されない
原因:
- 無効な画像URL
- CORS制限
- ネットワークの問題
解決策:
// Add error handling for QR code loading
<img
src={qrCodeUrl}
onError={(e) => {
console.error('QR code load failed');
e.target.src = '/images/qr-placeholder.png';
showRetryButton();
}}
alt="TrueMoney QR Code"
/>