TrueMoney Jump App
Accept payments with app-to-app redirection to the TrueMoney mobile app for a seamless mobile checkout experience in Thailand.
For OTP-based online payments, see TrueMoney Wallet. For offline QR code payments, see TrueMoney QR.
Overviewโ
TrueMoney Jump App is an app-to-app redirection payment method that deep links customers directly from your mobile app or website to the TrueMoney mobile app for payment authorization. This provides a faster, more native mobile experience compared to OTP verification or QR code scanning.
Key Features:
- App-to-app redirection - Direct deep link to TrueMoney app
- Multiple payment options - Wallet, cards, bank accounts, Pay Next (BNPL)
- Thailand market - 30M+ TrueMoney users
- Fast checkout - Native app experience with biometric authentication
- 3-minute expiry - Quick payment window reduces abandonment
- 30-day refund window - Full and partial refunds supported
Contact support@omise.co to enable TrueMoney Jump App for your merchant account.
Supported Regionsโ
| Region | Currency | Min Amount | Max Amount | API Version |
|---|---|---|---|---|
| Thailand | THB | 20.00 (2,000 satang) | 50,000.00 (5,000,000 satang) | 2017-11-02 |
Payment Optionsโ
Customers can choose from multiple payment methods within the TrueMoney app:
| Payment Option | Supported | Notes |
|---|---|---|
| TrueMoney Wallet Balance | Yes | Direct wallet payment |
| Bank Account | Yes | Linked bank accounts |
| Credit/Debit Card | Yes | Cards saved in TrueMoney |
| Pay Next (BNPL) | Yes | Buy now, pay later option |
When customers are redirected to the TrueMoney app, they select their preferred payment method. The merchant does not control which funding source the customer chooses.
How It Worksโ
Payment Flow:
- Customer selects TrueMoney on mobile device
- Merchant creates source with
truemoney_jumpapptype - Customer is redirected via deep link
- TrueMoney app opens automatically
- Customer selects payment method (wallet, card, bank, Pay Next)
- Customer authenticates with PIN or biometrics
- Customer confirms the payment
- Customer returns to merchant app/site
- Webhook confirms payment status
Typical completion time: 30 seconds - 2 minutes
Customers must complete payment within 3 minutes or the charge will expire. Ensure your UI communicates this urgency clearly.
Implementationโ
Step 1: Create Sourceโ
- 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
}
Step 2: Create Chargeโ
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"
Combined Requestโ
Create source and charge in one request:
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"
Step 3: Redirect Customerโ
// 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);
Step 4: Handle Returnโ
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');
}
});
Step 5: Handle 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');
});
Complete Implementation Exampleโ
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);
Mobile App Integrationโ
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 };
Charge Status Valuesโ
| Status | Description |
|---|---|
pending | Awaiting customer authorization in TrueMoney app |
successful | Payment completed |
failed | Payment declined or error |
expired | Customer didn't complete within 3-minute window |
Failure Codesโ
| Code | Description | Recommended Action |
|---|---|---|
payment_expired | Authorization window expired (3 minutes) | Prompt customer to try again |
payment_rejected | TrueMoney declined transaction | Check customer's payment method status |
insufficient_balance | Insufficient wallet balance | Suggest alternative payment method |
failed_processing | General processing error | Retry or contact support |
invalid_account | Customer account issue | Customer should verify TrueMoney account |
Refundsโ
TrueMoney Jump App supports full and partial refunds within 30 days of the original transaction.
Create a Refundโ
// 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
});
Refund Considerationsโ
| Aspect | Details |
|---|---|
| Window | 30 days from original charge |
| Partial refunds | Supported for most payment methods |
| Processing time | Typically 1-3 business days |
| Original payment method | Refund returns to original funding source |
Refunds for Pay Next (BNPL) transactions may have different processing times and requirements. Contact support for specific cases.
Voidsโ
Same-day voids are supported for TrueMoney Jump App transactions. A void cancels the transaction before settlement.
// Void a charge (same day only)
const voidResult = await omise.charges.reverse('chrg_test_xxx');
Voids must be processed on the same calendar day as the original transaction. After the settlement cutoff, use a refund instead.
Best Practicesโ
- Detect platform accurately - Always detect and pass the correct
platform_type(IOS/ANDROID) for optimal deep linking - Handle app not installed - Provide clear fallback messaging if TrueMoney app isn't installed
- Mobile-only method - This method requires a mobile device with TrueMoney app; offer alternatives for desktop users
- Communicate urgency - Display a countdown timer showing the 3-minute payment window
- Webhook priority - Always use webhooks for order fulfillment, not return URL status
- Amount validation - Validate amounts are within THB 20.00 - THB 50,000.00 range before API calls
- Error handling - Implement comprehensive error handling for all failure scenarios
- Testing - Test the complete flow on both iOS and Android devices before going live
FAQโ
What is the difference between TrueMoney Jump App, TrueMoney Wallet, and TrueMoney QR?
TrueMoney Jump App (truemoney_jumpapp): App-to-app redirection that deep links directly to the TrueMoney mobile app. Best for mobile app integrations with the fastest checkout experience.
TrueMoney Wallet (truemoney): Online redirect flow where customers enter their phone number and verify with OTP. Works on any device with a browser.
TrueMoney QR (truemoney): Displays a QR code that customers scan with their TrueMoney app. Ideal for point-of-sale and desktop web checkout.
What payment methods can customers use in the TrueMoney app?
Customers can pay using:
- TrueMoney Wallet Balance - Funds in their TrueMoney account
- Bank Account - Linked bank accounts
- Credit/Debit Card - Cards saved in TrueMoney
- Pay Next (BNPL) - Buy now, pay later option
The available options depend on the customer's TrueMoney account settings and verification level.
Why is the payment expiration only 3 minutes?
The 3-minute expiration window is designed to:
- Reduce abandoned transactions
- Ensure real-time payment confirmation
- Minimize inventory hold times
- Provide a seamless mobile checkout experience
If a customer needs more time, they can restart the payment process from checkout.
Do I need to specify the platform type?
The platform_type parameter (IOS or ANDROID) is recommended for optimal deep link behavior. It helps the TrueMoney app provide the best experience for the customer's device. If not specified, the system will attempt to detect it automatically, but explicit specification is more reliable.
What if the customer doesn't have the TrueMoney app installed?
If the TrueMoney app isn't installed, the deep link won't work. Implement a fallback that:
- Detects if the app opens successfully
- Shows a prompt to download from App Store or Google Play
- Offers alternative payment methods like TrueMoney Wallet (OTP) or other options
Can I use this payment method on desktop?
TrueMoney Jump App is designed exclusively for mobile devices. For desktop users, use:
- TrueMoney Wallet - OTP-based redirect flow
- TrueMoney QR - QR code they can scan with their phone
What are the refund limitations?
Refunds must be processed within 30 days of the original transaction. Both full and partial refunds are supported for most payment methods. Key considerations:
- Refunds return to the original funding source used by the customer
- Processing typically takes 1-3 business days
- Pay Next (BNPL) refunds may have additional requirements
- Same-day cancellations can use void instead of refund
Related Resourcesโ
- TrueMoney Wallet - OTP-based online payments
- TrueMoney QR - QR code payments
- Digital Wallets Overview - All wallet options
- Webhooks - Webhook handling
- Refunds - Refund policies