Digital Wallets
Accept payments from Southeast Asia's most popular digital wallets, reaching millions of customers across Thailand, Singapore, Malaysia, Philippines, and beyond.
Overviewโ
Payment method features, limits, user statistics, and fees are subject to change. Information is based on publicly available sources and may not reflect your specific merchant agreement. Always refer to official Omise documentation and your merchant dashboard for current, binding information.
Digital wallets (e-wallets) are mobile payment methods that allow customers to pay using their smartphone apps. These wallets are extremely popular in Southeast Asia, with high penetration rates among mobile-first consumers.
Why Digital Wallets?
- ๐ Growing market - 60%+ of SEA consumers use e-wallets regularly
- โก Instant confirmation - Real-time payment verification
- ๐ฑ Mobile-first - Optimized for smartphone users
- ๐ Secure - No card details shared with merchants
- ๐ฐ Lower friction - One-tap checkout experience
- ๐ Regional reach - Access local payment preferences
Supported Digital Walletsโ
Thailand ๐น๐ญโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| TrueMoney Wallet | 30M+ | THB | โ Yes | 1-3 days |
| Rabbit LINE Pay | 12M+ | THB | โ Yes | 1-3 days |
| ShopeePay | 8M+ | THB, SGD, MYR | โ Yes | 1-3 days |
Singapore ๐ธ๐ฌโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| GrabPay | 187M+ | SGD, MYR, THB | โ Yes | 1-3 days |
| ShopeePay | 8M+ | SGD, THB, MYR | โ Yes | 1-3 days |
Malaysia ๐ฒ๐พโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| Touch 'n Go eWallet | 18M+ | MYR | โ Yes | 1-3 days |
| Boost | 9M+ | MYR | โ Yes | 1-3 days |
| GrabPay | 187M+ | MYR, SGD, THB | โ Yes | 1-3 days |
| ShopeePay | 8M+ | MYR, SGD, THB | โ Yes | 1-3 days |
Indonesia ๐ฎ๐ฉโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| DANA | 150M+ | IDR | โ Yes | 1-3 days |
| ShopeePay | 8M+ | IDR | โ Yes | 1-3 days |
Philippines ๐ต๐ญโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| GCash | 86M+ | PHP | โ Yes | 1-3 days |
South Korea ๐ฐ๐ทโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| KakaoPay | 30M+ | KRW | โ Yes | 1-3 days |
Japan ๐ฏ๐ตโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| PayPay | 60M+ | JPY | โ Yes | 1-3 days |
China ๐จ๐ณโ
| Wallet | Users | Currencies | Refundable | Settlement |
|---|---|---|---|---|
| Alipay | 1B+ | CNY, Multi | โ Yes | 1-3 days |
| Alipay+ | 1.3B+ | Multi | โ Yes | 1-3 days |
| WeChat Pay | 1.3B+ | CNY | โ Yes | 1-3 days |
How Digital Wallets Workโ
Typical Flow:
- Customer selects their preferred wallet at checkout
- Merchant creates source and charge via Omise API
- Customer is redirected to wallet authorization page
- Wallet app opens (via deep link on mobile)
- Customer authenticates and confirms payment
- Payment is processed instantly
- Customer returns to merchant site
- Merchant receives webhook notification
Average completion time: 1-3 minutes
Implementation Overviewโ
Basic Integrationโ
- Node.js
- PHP
- Python
- Ruby
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
// Create source for wallet payment
const source = await omise.sources.create({
type: 'grabpay', // or truemoney, shopeepay, etc.
amount: 50000, // Amount in smallest currency unit
currency: 'THB' // THB, SGD, MYR, etc.
});
// Create charge
const charge = await omise.charges.create({
amount: 50000,
currency: 'THB',
source: source.id,
return_uri: 'https://yourdomain.com/payment/callback'
});
// Redirect customer to wallet
res.redirect(charge.authorize_uri);
<?php
// Create source
$source = OmiseSource::create(array(
'type' => 'grabpay',
'amount' => 50000,
'currency' => 'THB'
));
// Create charge
$charge = OmiseCharge::create(array(
'amount' => 50000,
'currency' => 'THB',
'source' => $source['id'],
'return_uri' => 'https://yourdomain.com/payment/callback'
));
// Redirect to wallet
header('Location: ' . $charge['authorize_uri']);
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
# Create source
source = omise.Source.create(
type='grabpay',
amount=50000,
currency='THB'
)
# Create charge
charge = omise.Charge.create(
amount=50000,
currency='THB',
source=source.id,
return_uri='https://yourdomain.com/payment/callback'
)
# Redirect to wallet
return redirect(charge.authorize_uri)
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
# Create source
source = Omise::Source.create({
type: 'grabpay',
amount: 50000,
currency: 'THB'
})
# Create charge
charge = Omise::Charge.create({
amount: 50000,
currency: 'THB',
source: source.id,
return_uri: 'https://yourdomain.com/payment/callback'
})
# Redirect to wallet
redirect_to charge.authorize_uri
Handling Return and Webhooksโ
// Handle return from wallet
app.get('/payment/callback', async (req, res) => {
const charge = await omise.charges.retrieve(req.query.charge_id);
if (charge.status === 'successful') {
res.redirect('/payment-success');
} else {
res.redirect('/payment-failed');
}
});
// Handle webhook (recommended)
app.post('/webhooks/omise', (req, res) => {
const event = req.body;
if (event.key === 'charge.complete') {
const charge = event.data;
if (charge.status === 'successful') {
// Process order
fulfillOrder(charge.metadata.order_id);
}
}
res.sendStatus(200);
});
Comparison Matrixโ
| Feature | GrabPay | TrueMoney | ShopeePay | Touch 'n Go | Boost | DANA | GCash |
|---|---|---|---|---|---|---|---|
| Region | SG/MY/TH | TH | Multi | MY | MY | ID | PH |
| Users | 187M+ | 30M+ | 8M+ | 18M+ | 9M+ | 150M+ | 86M+ |
| Instant | โ | โ | โ | โ | โ | โ | โ |
| Mobile Only | โ | โ | โ | โ | โ | โ | โ |
| Refunds | Full/Partial | Full/Partial | Full/Partial | Full/Partial | Full/Partial | Full/Partial | Full/Partial |
| Refund Window | 30 days | 30 days | 30 days | 30 days | 30 days | 30 days | 30 days |
Choosing the Right Walletโ
By Marketโ
Thailand
- Primary: TrueMoney (highest penetration)
- Secondary: Rabbit LINE Pay, ShopeePay
- Use case: All e-commerce, services
Singapore
- Primary: GrabPay (ride-hailing users)
- Secondary: ShopeePay (e-commerce)
- Use case: Food delivery, transportation, shopping
Malaysia
- Primary: Touch 'n Go (largest user base)
- Secondary: Boost, GrabPay
- Use case: Transportation, parking, retail
Indonesia
- Primary: DANA (largest wallet)
- Secondary: ShopeePay
- Use case: E-commerce, ride-hailing, services
Philippines
- Primary: GCash (dominant player)
- Use case: Bills, remittances, e-commerce
Japan
- Primary: PayPay (60M+ users)
- Use case: Retail, restaurants, services
South Korea
- Primary: KakaoPay (Kakao ecosystem)
- Use case: Messaging platform integrated
By Use Caseโ
E-commerce
- TrueMoney, ShopeePay, Touch 'n Go, DANA, GCash
Food Delivery
- GrabPay, ShopeePay, TrueMoney
Transportation
- GrabPay, Touch 'n Go, TrueMoney
Digital Services
- All wallets suitable
Tourism & Chinese Customers
- Alipay, WeChat Pay, Alipay+
Common Implementation Patternsโ
Multi-Wallet Checkoutโ
// Display available wallets based on currency
function getAvailableWallets(currency, country) {
const wallets = {
'THB': ['truemoney', 'rabbit_linepay', 'shopeepay'],
'SGD': ['grabpay', 'shopeepay'],
'MYR': ['touch_n_go', 'boost', 'grabpay', 'shopeepay'],
'IDR': ['dana', 'shopeepay'],
'PHP': ['gcash'],
'JPY': ['paypay'],
'KRW': ['kakaopay']
};
return wallets[currency] || [];
}
// Create payment with selected wallet
async function createWalletPayment(walletType, amount, currency) {
const source = await omise.sources.create({
type: walletType,
amount: amount,
currency: currency
});
const charge = await omise.charges.create({
amount: amount,
currency: currency,
source: source.id,
return_uri: `${baseUrl}/payment/callback`
});
return charge.authorize_uri;
}
Mobile Detectionโ
// Check if user is on mobile
function isMobileDevice() {
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
}
// Show wallet options based on device
if (!isMobileDevice()) {
// Hide mobile-only wallets
document.querySelectorAll('.mobile-wallet').forEach(el => {
el.style.display = 'none';
});
}
Amount Validationโ
// Validate amount for each wallet
const WALLET_LIMITS = {
grabpay: {
SGD: { min: 50, max: 50000 },
MYR: { min: 100, max: 150000 },
THB: { min: 2000, max: 5000000 }
},
truemoney: {
THB: { min: 2000, max: 5000000 }
},
shopeepay: {
THB: { min: 100, max: 5000000 },
SGD: { min: 10, max: 100000 },
MYR: { min: 100, max: 100000 }
}
// ... more wallets
};
function validateWalletAmount(walletType, amount, currency) {
const limits = WALLET_LIMITS[walletType]?.[currency];
if (!limits) {
return { valid: false, error: 'Wallet not available for currency' };
}
if (amount < limits.min) {
return { valid: false, error: `Minimum amount is ${limits.min}` };
}
if (amount > limits.max) {
return { valid: false, error: `Maximum amount is ${limits.max}` };
}
return { valid: true };
}
Best Practicesโ
1. Display Clear Instructionsโ
Show customers what to expect:
- App requirements
- Step-by-step process
- Estimated completion time
- Alternative methods if app not installed
2. Mobile-First Designโ
<div class="wallet-options">
<button class="wallet-button" data-wallet="grabpay">
<img src="/icons/grabpay.svg" alt="GrabPay">
<span>GrabPay</span>
<small>Instant confirmation</small>
</button>
<!-- More wallet buttons -->
</div>
3. Handle Deep Links Properlyโ
function openWalletApp(authorizeUri) {
// Try opening wallet app
window.location = authorizeUri;
// Fallback if app not installed
setTimeout(() => {
if (!document.hidden) {
showAppInstallPrompt();
}
}, 2500);
}
4. Implement Webhooksโ
Always use webhooks as primary notification method:
app.post('/webhooks/omise', async (req, res) => {
const event = req.body;
// Verify webhook signature
if (!verifyWebhookSignature(req)) {
return res.sendStatus(401);
}
if (event.key === 'charge.complete') {
await processPayment(event.data);
}
res.sendStatus(200);
});
5. Show Regional Optionsโ
// Detect customer location
const country = detectCountry(); // From IP or user selection
// Show relevant wallets
const walletsByCountry = {
'TH': ['truemoney', 'rabbit_linepay', 'shopeepay'],
'SG': ['grabpay', 'shopeepay'],
'MY': ['touch_n_go', 'boost', 'grabpay'],
'ID': ['dana', 'shopeepay'],
'PH': ['gcash']
};
displayWallets(walletsByCountry[country]);
Common Issues & Troubleshootingโ
Issue: App Not Installedโ
Solution:
function checkWalletApp(walletType) {
const appLinks = {
grabpay: {
ios: 'https://apps.apple.com/app/grab/id647268330',
android: 'https://play.google.com/store/apps/details?id=com.grabtaxi.passenger'
},
truemoney: {
ios: 'https://apps.apple.com/app/truemoney-wallet/id572488921',
android: 'https://play.google.com/store/apps/details?id=com.truemoney.wallet'
}
// ... more wallets
};
return appLinks[walletType];
}
Issue: Insufficient Balanceโ
Solution: Show clear error and offer alternatives:
if (charge.failure_code === 'insufficient_balance') {
showMessage('Insufficient wallet balance. Please top up or choose another payment method.');
showAlternativePaymentMethods();
}
Issue: Payment Timeoutโ
Solution: Set reasonable timeout and allow retry:
const TIMEOUT = 15 * 60 * 1000; // 15 minutes
setTimeout(() => {
if (!paymentCompleted) {
showTimeoutMessage();
allowRetry();
}
}, TIMEOUT);
FAQโ
Which digital wallet should I support?
Support wallets based on your target market:
- Thailand: TrueMoney (must-have), Rabbit LINE Pay, ShopeePay
- Singapore: GrabPay, ShopeePay
- Malaysia: Touch 'n Go (must-have), Boost, GrabPay
- Indonesia: DANA (must-have), ShopeePay
- Philippines: GCash (must-have)
For pan-regional coverage, consider: GrabPay, ShopeePay, Alipay+
Do digital wallets work on desktop?
Most digital wallets are mobile-only and require the customer to have the respective app installed. Desktop users should be offered alternative payment methods like credit cards or online banking.
Can I refund wallet payments?
Yes, all supported wallets allow both full and partial refunds, typically within 30 days of the original transaction.
How long does settlement take?
Most digital wallet payments settle within 1-3 business days. Check your Omise dashboard for specific settlement schedules.
What happens if customer doesn't complete payment?
Charges expire after a timeout period (typically 15 minutes). You can allow customers to retry with a new charge. Always implement proper timeout handling and show clear instructions.
Do I need separate integrations for each wallet?
No, all digital wallets follow the same integration pattern (source + charge + redirect). Only the type parameter changes. You can implement one flow that works for all wallets.
Can I save wallet information for recurring payments?
No, digital wallets don't support tokenization for recurring payments. Customers must authorize each payment. For recurring billing, use credit cards or direct debit methods.
Related Resourcesโ
- Payment Methods Overview - All available methods
- Selection Guide - Choose the right method
- QR Payments - Alternative mobile payments
- Accept Payments Guide - Implementation patterns
- Webhooks - Handle payment notifications
- Testing - Test wallet payments
Next Stepsโ
- Choose wallets - Select based on your target market
- Implement integration - Follow individual wallet guides
- Test thoroughly - Test on actual mobile devices
- Set up webhooks - Ensure reliable payment notifications
- Go live - Enable for production
Ready to start? Choose your wallet:
- GrabPay - Southeast Asia's super app
- TrueMoney - Thailand's #1 wallet
- Touch 'n Go - Malaysia's largest wallet
- DANA - Indonesia's leading wallet
- GCash - Philippines' top wallet