TrueMoney Jump App
TrueMoneyモバイルアプリへのアプリ間リダイレクトによる決済を受け付け、タイでシームレスなモバイルチェックアウト体験を提供します。
OTPベースのオンライン決済については、TrueMoney Walletをご覧ください。オフラインQRコード決済については、TrueMoney QRをご覧ください。
概要
TrueMoney Jump Appは、お客様のモバイルアプリやウェブサイトからTrueMoneyモバイルアプリへ直接ディープリンクするアプリ間リダイレクト決済方式です。OTP認証やQRコードスキャンと比較して、より高速でネイティブなモバイル体験を提供します。
主な特徴:
- アプリ間リダイレクト - TrueMoneyアプリへの直接ディープリンク
- 複数の決済オプション - ウォレット、カード、銀行口座、Pay Next(BNPL)
- タイ市場 - 3,000万人以上のTrueMoneyユーザー
- 高速チェックアウト - 生体認証によるネイティブアプリ体験
- 3分間の有効期限 - 短い決済ウィンドウで離脱を削減
- 30日間の返金期間 - 全額および部分返金に対応
お客様のマーチャントアカウントでTrueMoney Jump Appを有効にするには、support@omise.coまでお問い合わせください。
対応地域
| 地域 | 通貨 | 最小金額 | 最大金額 | APIバージョン |
|---|---|---|---|---|
| タイ | THB | 20.00(2,000サタン) | 50,000.00(5,000,000サタン) | 2017-11-02 |
決済オプション
顧客はTrueMoneyアプリ内で複数の決済方法から選択できます:
| 決済オプション | 対応 | 備考 |
|---|---|---|
| TrueMoneyウォレット残高 | 対応 | ウォレットからの直接決済 |
| 銀行口座 | 対応 | 連携された銀行口座 |
| クレジット/デビットカード | 対応 | TrueMoneyに保存されたカード |
| Pay Next(BNPL) | 対応 | 後払いオプション |
顧客がTrueMoneyアプリにリダイレクトされると、希望の決済方法を選択します。加盟店は顧客が選択する資金源を制御できません。
仕組み
決済フロー:
- 顧客がモバイルデバイスでTrueMoneyを選択
- 加盟店が
truemoney_jumpappタイプでソースを作成 - 顧客がディープリンク経由でリダイレクト
- TrueMoneyアプリが自動的に起動
- 顧客が決済方法を選択(ウォレット、カード、銀行、Pay Next)
- 顧客がPINまたは生体認証で認証
- 顧客が決済を確認
- 顧客が加盟店のアプリ/サイトに戻る
- Webhookで決済ステータスを確認
通常の完了時間: 30秒〜2分
顧客は3分以内に決済を完了する必要があります。それ以外の場合、チャージは期限切れになります。UIでこの緊急性を明確に伝えてください。
実装
ステップ1: ソースを作成
- cURL
- Node.js
- PHP
- Omise.js
curl https://api.omise.co/sources \
-u $OMISE_PUBLIC_KEY: \
-d "amount=100000" \
-d "currency=THB" \
-d "type=truemoney_jumpapp" \
-d "platform_type=ANDROID"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'truemoney_jumpapp',
amount: 100000, // THB 1,000.00
currency: 'THB',
platform_type: 'ANDROID' // or 'IOS'
});
<?php
$source = OmiseSource::create([
'type' => 'truemoney_jumpapp',
'amount' => 100000,
'currency' => 'THB',
'platform_type' => 'ANDROID'
]);
?>
Omise.setPublicKey(omise_public_key);
Omise.createSource('truemoney_jumpapp', {
amount: 100000,
currency: 'THB',
platform_type: detectPlatform() // 'IOS' or 'ANDROID'
}, function(statusCode, response) {
console.log(response);
});
function detectPlatform() {
const ua = navigator.userAgent;
if (/iPhone|iPad|iPod/.test(ua)) return 'IOS';
if (/Android/.test(ua)) return 'ANDROID';
return 'ANDROID'; // Default
}
ステップ2: チャージを作成
curl https://api.omise.co/charges \
-u $OMISE_SECRET_KEY: \
-d "amount=100000" \
-d "currency=THB" \
-d "return_uri=https://example.com/payment/complete" \
-d "source=src_test_xxx"
統合リクエスト
ソースとチャージを1回のリクエストで作成:
curl https://api.omise.co/charges \
-u $OMISE_SECRET_KEY: \
-d "amount=100000" \
-d "currency=THB" \
-d "return_uri=https://example.com/payment/complete" \
-d "source[type]=truemoney_jumpapp" \
-d "source[platform_type]=ANDROID"
ステップ3: 顧客をリダイレクト
// Detect platform and redirect
function redirectToTrueMoney(authorizeUri) {
// The authorize_uri contains the deep link
window.location.href = authorizeUri;
}
// After creating charge
redirectToTrueMoney(charge.authorize_uri);
ステップ4: 戻りを処理
app.get('/payment/complete', async (req, res) => {
try {
// Get charge status
const chargeId = req.query.charge;
const charge = await omise.charges.retrieve(chargeId);
if (charge.status === 'successful') {
await fulfillOrder(charge.metadata.order_id);
res.redirect('/order-success');
} else if (charge.status === 'failed') {
res.redirect('/payment-failed?error=' + charge.failure_code);
} else {
// Still pending - wait for webhook
res.redirect('/payment-pending');
}
} catch (error) {
res.redirect('/payment-error');
}
});
ステップ5: Webhookを処理
app.post('/webhooks/omise', (req, res) => {
const event = req.body;
if (event.key === 'charge.complete') {
const charge = event.data;
if (charge.source.type === 'truemoney_jumpapp') {
if (charge.status === 'successful') {
fulfillOrder(charge.metadata.order_id);
} else if (charge.status === 'failed') {
handleFailedPayment(charge);
}
}
}
res.status(200).send('OK');
});
完全な実装例
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
const app = express();
app.use(express.json());
// Checkout endpoint
app.post('/checkout/truemoney-jumpapp', async (req, res) => {
try {
const { amount, order_id, platform_type } = req.body;
// Validate amount (min 2000, max 5000000 satang)
if (amount < 2000 || amount > 5000000) {
return res.status(400).json({
error: 'Amount must be between THB 20.00 and THB 50,000.00'
});
}
// Validate platform
const platform = ['IOS', 'ANDROID'].includes(platform_type)
? platform_type
: 'ANDROID';
// Create source
const source = await omise.sources.create({
type: 'truemoney_jumpapp',
amount: amount,
currency: 'THB',
platform_type: platform
});
// Create charge
const charge = await omise.charges.create({
amount: amount,
currency: 'THB',
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/complete`,
metadata: {
order_id: order_id
}
});
// Return deep link URL
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id,
expires_at: charge.expires_at
});
} catch (error) {
console.error('TrueMoney Jump App error:', error);
res.status(500).json({ error: error.message });
}
});
// Return handler
app.get('/payment/complete', async (req, res) => {
const chargeId = req.query.charge;
try {
const charge = await omise.charges.retrieve(chargeId);
if (charge.status === 'successful') {
res.redirect(`/order-confirmation?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_jumpapp') {
if (charge.status === 'successful') {
processOrder(charge.metadata.order_id);
sendConfirmationEmail(charge);
} else {
notifyPaymentFailure(charge);
}
}
}
res.sendStatus(200);
});
app.listen(3000);
モバイルアプリ統合
iOS (Swift)
import UIKit
class PaymentViewController: UIViewController {
func openTrueMoneyJumpApp(authorizeUri: String) {
guard let url = URL(string: authorizeUri) else {
showError("Invalid payment URL")
return
}
UIApplication.shared.open(url, options: [:]) { success in
if !success {
// TrueMoney app not installed - show fallback
self.showAppStorePrompt()
}
}
}
func showAppStorePrompt() {
let alert = UIAlertController(
title: "TrueMoney App Required",
message: "Please install the TrueMoney app to continue with this payment method.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Download", style: .default) { _ in
if let appStoreURL = URL(string: "https://apps.apple.com/th/app/truemoney-wallet/id1128152283") {
UIApplication.shared.open(appStoreURL)
}
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert, animated: true)
}
}
Android (Kotlin)
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
class PaymentActivity : AppCompatActivity() {
fun openTrueMoneyJumpApp(authorizeUri: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(authorizeUri))
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// TrueMoney app not installed - show fallback
showPlayStorePrompt()
}
}
private fun showPlayStorePrompt() {
AlertDialog.Builder(this)
.setTitle("TrueMoney App Required")
.setMessage("Please install the TrueMoney app to continue with this payment method.")
.setPositiveButton("Download") { _, _ ->
val playStoreIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=th.co.truemoney.wallet")
)
startActivity(playStoreIntent)
}
.setNegativeButton("Cancel", null)
.show()
}
}
React Native
import { Linking, Alert, Platform } from 'react-native';
const openTrueMoneyJumpApp = async (authorizeUri) => {
try {
const supported = await Linking.canOpenURL(authorizeUri);
if (supported) {
await Linking.openURL(authorizeUri);
} else {
showAppStorePrompt();
}
} catch (error) {
console.error('Failed to open TrueMoney:', error);
showAppStorePrompt();
}
};
const showAppStorePrompt = () => {
const storeUrl = Platform.select({
ios: 'https://apps.apple.com/th/app/truemoney-wallet/id1128152283',
android: 'https://play.google.com/store/apps/details?id=th.co.truemoney.wallet'
});
Alert.alert(
'TrueMoney App Required',
'Please install the TrueMoney app to continue with this payment method.',
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Download',
onPress: () => Linking.openURL(storeUrl)
}
]
);
};
export { openTrueMoneyJumpApp };
チャージステータス値
| ステータス | 説明 |
|---|---|
pending | TrueMoneyアプリでの顧客の承認を待機中 |
successful | 決済完了 |
failed | 決済が拒否されたかエラー |
expired | 顧客が3分間のウィンドウ内に完了しなかった |
失敗コード
| コード | 説明 | 推奨アクション |
|---|---|---|
payment_expired | 承認ウィンドウが期限切れ(3分) | 顧客に再試行を促す |
payment_rejected | TrueMoneyが取引を拒否 | 顧客の決済方法ステータスを確認 |
insufficient_balance | ウォレット残高不足 | 代替の決済方法を提案 |
failed_processing | 一般的な処理エラー | 再試行またはサポートに連絡 |
invalid_account | 顧客アカウントの問題 | 顧客がTrueMoneyアカウントを確認する必要あり |
返金
TrueMoney Jump Appは、元の取引から30日以内の全額および部分返金をサポートしています。
返金を作成
// Full refund
const fullRefund = await omise.charges.refund('chrg_test_xxx');
// Partial refund
const partialRefund = await omise.charges.refund('chrg_test_xxx', {
amount: 50000 // Partial refund of THB 500.00
});
返金に関する考慮事項
| 項目 | 詳細 |
|---|---|
| 期間 | 元のチャージから30日 |
| 部分返金 | ほとんどの決済方法でサポート |
| 処理時間 | 通常1〜3営業日 |
| 元の決済方法 | 返金は元の資金源に戻る |
Pay Next(BNPL)取引の返金は、処理時間や要件が異なる場合があります。特定のケースについてはサポートにお問い合わせください。
取消
TrueMoney Jump App取引では当日の取消がサポートされています。取消は決済前に取引をキャンセルします。
// Void a charge (same day only)
const voidResult = await omise.charges.reverse('chrg_test_xxx');
取消は元の取引と同じ暦日に処理する必要があります。決済締め切り後は、代わりに返金を使用してください。
ベストプラクティス
- プラットフォームを正確に検出 - 最適なディープリンクのために、常に正しい
platform_type(IOS/ANDROID)を検出して渡す - アプリ未インストール時の処理 - TrueMoneyアプリがインストールされていない場合、明確なフォールバックメッセージを提供
- モバ イル専用方式 - この方式はTrueMoneyアプリを搭載したモバイルデバイスが必要;デスクトップユーザーには代替手段を提供
- 緊急性を伝達 - 3分間の決済ウィンドウを示すカウントダウンタイマーを表示
- Webhookを優先 - 注文の履行には常にリターンURLステータスではなくWebhookを使用
- 金額の検証 - API呼び出し前にTHB 20.00〜THB 50,000.00の範囲内であることを検証
- エラー処理 - すべての失敗シナリオに対する包括的なエラー処理を実装
- テスト - 本番稼働前にiOSとAndroidの両方のデバイスで完全なフローをテスト
FAQ
TrueMoney Jump App、TrueMoney Wallet、TrueMoney QRの違いは何ですか?
TrueMoney Jump App(truemoney_jumpapp): TrueMoneyモバイルアプリに直接ディープリンクするアプリ間リダイレクト。最速のチェックアウト体験を持つモバイルアプリ統合に最適です。
TrueMoney Wallet(truemoney): 顧客が電話番号を入力しOTPで認証するオンラインリダイレクトフロー。ブラウザを持つあらゆるデバイスで動作します。
TrueMoney QR(truemoney): 顧客がTrueMoneyアプリでスキャンするQRコードを表示。POSおよびデスクトップウェブチェックアウトに最適です。
顧客はTrueMoneyアプリでどの決済方法を使用できますか?
顧客は以下を使用して支払いできます:
- TrueMoneyウォレット残高 - TrueMoneyアカウントの資金
- 銀行口座 - 連携された銀行口座
- クレジット/デビットカード - TrueMoneyに保存されたカード
- Pay Next(BNPL) - 後払いオプション
利用可能なオプションは、顧客のTrueMoneyアカウント設定と認証レベルによって異なります。
なぜ決済の有効期限が3分だけなのですか?
3分間の有効期限ウィンドウは以下のために設計されています:
- 放棄された取引を削減
- リアルタイムの決済確認を確保
- 在庫保持時間を最小化
- シームレスなモバイルチェックアウト体験を提供
顧客がより多くの時間を必要とする場合、チェックアウトから決済プロセスを再開できます。
プラットフォームタイプを指定する必要がありますか?
platform_typeパラメータ(IOSまたはANDROID)は、最適なディープリンク動作のために推奨されます。TrueMoneyアプリが顧客のデバイスに最適な体験を提供するのに役立ちます。指定されていない場合、システムは自動的に検出を試みますが、明示的な指定の方が信頼性が高くなります。
顧客がTrueMoneyアプリをインストールしていない場合はどうなりますか?
TrueMoneyアプリがインストールされていない場合、ディープリンクは機能しません。以下のフォールバックを実装してください:
- アプリが正常に開くかどうかを検出
- App StoreまたはGoogle Playからダウンロードするプロンプトを表示
- TrueMoney Wallet(OTP)やその他のオプションなどの代替決済方法を提供
デスクトップでこの決済方法を使用できますか?
TrueMoney Jump Appはモバイルデバイス専用に設計されています。デスクトップユーザーには以下を使用してください:
- TrueMoney Wallet - OTPベースのリダイレクトフロー
- TrueMoney QR - 電話でスキャンできるQRコード
返金の制限事項は何ですか?
返金は元の取引から30日以内に処理する必要があります。ほとんどの決済方法で全額および部分返金がサポートされています。主な考慮事項:
- 返金は顧客が使用した元の資金源に戻る
- 処理には通常1〜3営業日かかる
- Pay Next(BNPL)の返金には追加要件がある場合がある
- 当日のキャンセルは返金の代わりに取消を使用できる
関連リソース
- TrueMoney Wallet - OTPベースのオンライン決済
- TrueMoney QR - QRコード決済
- デジタルウォレット概要 - すべてのウォレットオプション
- Webhooks - Webhook処理
- 返金 - 返金ポリシー