Bangkok Bank Mobile Banking (Bualuang mBanking)
Accept instant payments via Bualuang mBanking from Bangkok Bank, Thailand's largest bank by assets with 18+ million customers nationwide.
Payment Flow

Step-by-step mobile banking payment process:
❶ Select Bank - Customer chooses their bank at merchant checkout
❷ Redirect to bank - System redirects to bank's payment authorization page
❸ Open banking app - Deep link automatically launches the bank's mobile app
- On iOS: Opens via Universal Links
- On Android: Opens via App Links
- Customer sees "Open in [Bank] App" prompt
❹ Authenticate - Customer logs into banking app (if not already logged in)
- PIN entry (6 digits)
- Fingerprint scan
- Face ID recognition
❺ Review payment - Transaction details displayed in app:
- Merchant name
- Payment amount
- Order reference
- Account to debit from
❻ Authorize payment - Customer confirms the transaction
- Enter additional PIN/OTP if required by bank
- Tap "Confirm Payment" button
❼ Payment processed - Bank immediately transfers funds
❽ Confirmation - Success screen shown in app
- Transaction reference number
- Receipt available for download
❾ Return to merchant - Customer redirected back to merchant website
- Automatic redirect or "Return to Merchant" button
- Order confirmation page displayed
Typical completion time: 30-90 seconds
Overview
Bualuang mBanking is the mobile banking application from Bangkok Bank, Thailand's largest bank by total assets. Customers can make secure payments directly from their bank accounts using the mobile app with PIN or biometric authentication.
Key Features:
- ✅ Largest bank - 18+ million customers, #1 in Thailand by assets
- ✅ Fast confirmation - Near real-time payment verification (typically within seconds)
- ✅ High limits - Up to ฿150,000 per transaction
- ✅ Trusted institution - Established 1944, government-backed
- ✅ 24/7 availability - Works anytime including holidays
- ✅ Secure authentication - PIN, fingerprint, or facial recognition
Supported Regions
| Region | Currency | Min Amount | Max Amount | Daily Limit |
|---|---|---|---|---|
| Thailand | THB | ฿20.00 | ฿150,000 | Varies by bank* |
*Daily limits vary based on customer's bank account settings and are not specified by Omise
How It Works
Customer Experience:
- Customer selects "Bangkok Bank" at checkout
- Redirected to Bangkok Bank payment page
- Opens Bualuang mBanking app via deep link
- Reviews transaction details in app
- Authenticates with 6-digit PIN, fingerprint, or Face ID
- Confirms payment
- Returns to merchant website
Typical completion time: 1-3 minutes
Implementation
Step 1: Create Bangkok Bank Source
- cURL
- Node.js
- PHP
- Python
- Ruby
- Go
- Java
- C#
curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=mobile_banking_bbl" \
-d "amount=100000" \
-d "currency=THB"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'mobile_banking_bbl',
amount: 100000, // THB 1,000.00
currency: 'THB'
});
<?php
$source = OmiseSource::create(array(
'type' => 'mobile_banking_bbl',
'amount' => 100000,
'currency' => 'THB'
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='mobile_banking_bbl',
amount=100000,
currency='THB'
)
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
source = Omise::Source.create({
type: 'mobile_banking_bbl',
amount: 100000,
currency: 'THB'
})
source, err := client.Sources().Create(&operations.CreateSource{
Type: "mobile_banking_bbl",
Amount: 100000,
Currency: "THB",
})
Source source = client.sources().create(new Source.CreateParams()
.type("mobile_banking_bbl")
.amount(100000L)
.currency("THB"));
var source = await client.Sources.Create(new CreateSourceRequest
{
Type = "mobile_banking_bbl",
Amount = 100000,
Currency = "THB"
});
Response:
{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "mobile_banking_bbl",
"flow": "redirect",
"amount": 100000,
"currency": "THB"
}
Step 2: Create Charge
curl https://api.omise.co/charges \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=100000" \
-d "currency=THB" \
-d "source=src_test_5rt6s9vah5lkvi1rh9c" \
-d "return_uri=https://yourdomain.com/payment/callback"
Step 3: Redirect Customer
app.post('/checkout/bangkok-bank', async (req, res) => {
try {
const { amount, order_id } = req.body;
// Validate amount
if (amount < 2000 || amount > 200000000) {
return res.status(400).json({
error: 'Amount must be between ฿20 and ฿2,000,000'
});
}
// Create source
const source = await omise.sources.create({
type: 'mobile_banking_bbl',
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
}
});
// Redirect to Bangkok Bank
res.redirect(charge.authorize_uri);
} catch (error) {
console.error('Bangkok Bank error:', error);
res.status(500).json({ error: error.message });
}
});
Step 4: Handle Return
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') {
await processOrder(charge.metadata.order_id);
res.redirect('/payment-success');
} else if (charge.status === 'failed') {
res.redirect('/payment-failed?reason=' + charge.failure_message);
} else {
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' && event.data.source.type === 'mobile_banking_bbl') {
const charge = event.data;
if (charge.status === 'successful') {
processOrder(charge.metadata.order_id);
} else if (charge.status === 'failed') {
handleFailedPayment(charge.metadata.order_id);
}
}
res.sendStatus(200);
});
Complete Implementation Example
// Express.js server
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
const app = express();
app.use(express.json());
app.post('/checkout/bangkok-bank', async (req, res) => {
try {
const { amount, order_id } = req.body;
// Validate amount
if (amount < 2000 || amount > 200000000) {
return res.status(400).json({
error: 'Amount must be between ฿20 and ฿2,000,000'
});
}
// Create source
const source = await omise.sources.create({
type: 'mobile_banking_bbl',
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,
payment_method: 'bangkok_bank'
}
});
// Return authorization URL
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id
});
} catch (error) {
console.error('Bangkok Bank 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 === 'mobile_banking_bbl') {
if (charge.status === 'successful') {
updateOrderStatus(charge.metadata.order_id, 'paid');
sendConfirmationEmail(charge.metadata.customer_email);
} else {
updateOrderStatus(charge.metadata.order_id, 'failed');
}
}
}
res.sendStatus(200);
});
app.listen(3000);
Refund Support
Bangkok Bank mobile banking does NOT support refunds or voids through Omise. Once a payment is completed, it cannot be refunded via the API. You must process refunds manually via bank transfer if needed.
Common Issues & Troubleshooting
Issue: Customer doesn't have Bualuang mBanking app
Cause: Customer selected Bangkok Bank but doesn't have app installed
Solution:
function isMobile() {
return /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
}
if (!isMobile()) {
alert('Bangkok Bank mobile banking requires the Bualuang mBanking app. Please use a mobile device or select another payment method.');
}
Issue: Payment expires
Cause: Customer didn't complete payment within time limit (15 minutes)
Solution:
// Show countdown timer
const EXPIRY_TIME = 15 * 60 * 1000; // 15 minutes
setTimeout(() => {
if (!paymentConfirmed) {
showExpiryMessage();
allowRetry();
}
}, EXPIRY_TIME);
Issue: Daily limit exceeded
Error: Transaction rejected by bank
Solution:
- Customer needs to adjust daily limit in Bualuang mBanking app settings
- Split payment across multiple days
- Use alternative payment method
Issue: App not opening
Cause: Deep link issue or app not updated
Solution:
function openBangkokBankApp(authorizeUri) {
window.location = authorizeUri;
// Fallback after 2 seconds
setTimeout(() => {
if (!document.hidden) {
showInstallAppMessage();
}
}, 2000);
}
Best Practices
1. Display Clear Instructions
<div class="bangkok-bank-instructions">
<h3>Pay with Bangkok Bank (Bualuang mBanking)</h3>
<ol>
<li>Ensure you have Bualuang mBanking app installed</li>
<li>You'll be redirected to open the app</li>
<li>Authenticate with your 6-digit PIN, fingerprint, or Face ID</li>
<li>Review and confirm the payment</li>
</ol>
<p><strong>Payment must be completed within 15 minutes</strong></p>
<a href="https://www.bangkokbank.com/en/Personal/Digital-Banking/Mobile-Banking">
Download Bualuang mBanking
</a>
</div>
2. Handle Deep Links
function openBankingApp(authorizeUri) {
// Try to open app
window.location = authorizeUri;
// Check if app opened
setTimeout(() => {
if (document.hidden) {
// App opened successfully
return;
}
// Show instructions
showInstallInstructions();
}, 2000);
}
3. Set Timeout
// 15-minute payment window
const PAYMENT_TIMEOUT = 15 * 60 * 1000;
setTimeout(() => {
if (!paymentConfirmed) {
showTimeoutMessage();
allowRetry();
}
}, PAYMENT_TIMEOUT);
4. Use Webhooks
// Webhook is more reliable than redirect callback
app.post('/webhooks/omise', handleWebhook);
// Callback is backup
app.get('/payment/callback', handleCallback);
5. Validate Amount
function validateBBLAmount(amount) {
const MIN = 2000; // ฿20.00
const MAX = 200000000; // ฿2,000,000.00
if (amount < MIN) {
return `Minimum amount is ฿${MIN / 100}`;
}
if (amount > MAX) {
return `Maximum amount is ฿${MAX / 100}`;
}
return null; // Valid
}
FAQ
What is Bualuang mBanking?
Bualuang mBanking is Bangkok Bank's official mobile banking application with 18+ million users. Customers can pay directly from their bank accounts using PIN, fingerprint, or facial recognition.
Do customers need a Bangkok Bank account?
Yes, customers must have an active Bangkok Bank account and the Bualuang mBanking app installed. The app is free on iOS and Android.
What are the transaction limits?
- Per transaction: ฿20 to ฿2,000,000
- Daily limit: Up to ฿5,000,000 (varies by account type and settings)
Customers can adjust limits in the app settings (subject to bank approval).
How long does settlement take?
Bangkok Bank mobile banking settlements typically occur within 1-2 business days. Check your Omise dashboard for specific settlement schedules.
Can I refund Bangkok Bank payments?
No, Bangkok Bank mobile banking does NOT support refunds or voids through Omise. Refunds must be processed manually via bank transfer if needed.
What if payment expires?
Payments expire after 15 minutes. Allow customers to retry with a new charge. Display a countdown timer to show remaining time.
Is Bangkok Bank available 24/7?
Yes, Bangkok Bank mobile banking is available 24/7 including weekends and holidays. However, settlement follows business day schedules.
Testing
Test Mode
Bangkok Bank Mobile Banking can be tested using your test API keys. In test mode:
Test Credentials:
- Use test API keys (skey_test_xxx)
- Currency: THB (Thai Baht)
- No actual Bangkok Bank account required for testing
Test Flow:
- Create source and charge with test API keys
- Customer redirects to test
authorize_uri - Test page simulates Bangkok Bank mobile banking authorization
- Use Omise Dashboard Actions to mark charge as successful/failed
- Verify webhook and return_uri handling
Testing Implementation:
// Test Bangkok Bank Mobile Banking
const source = await omise.sources.create({
type: 'mobile_banking_bbl',
amount: 50000, // ฿500.00
currency: 'THB'
});
const charge = await omise.charges.create({
amount: 50000,
currency: 'THB',
source: source.id,
return_uri: 'https://example.com/callback'
});
console.log('Test authorize URL:', charge.authorize_uri);
Test Scenarios:
- Successful payment: Complete redirect flow and order processing
- Failed payment: Test error handling
- Amount limits: Test ฿20 minimum and maximum amounts
- Mobile flow: Test deep-linking to Bualuang mBanking app
- Timeout: Test abandoned payment scenarios
- Return URI: Verify proper redirect after payment
- Webhook delivery: Verify all webhook notifications
Important Notes:
- Test mode doesn't connect to real Bangkok Bank servers
- Use dashboard to simulate payment status changes
- Test mobile app deep-linking
- Verify webhook handling for all charge statuses
- Test both successful and failed payment flows
For comprehensive testing guidelines, see the Testing Documentation.
Related Resources
- Mobile Banking Overview - All mobile banking options
- KBank Mobile Banking - Alternative bank
- SCB Mobile Banking - Another option
- Testing - Test Bangkok Bank integration
- Webhooks - Handle payment notifications