SCB Mobile Banking (SCB Easy)
Accept instant payments via SCB Easy mobile app from Siam Commercial Bank, Thailand's oldest and third-largest bank with 14+ million active users.
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
SCB Easy is the mobile banking app from Siam Commercial Bank (SCB), one of Thailand's leading financial institutions. Customers can make secure payments directly from their SCB bank accounts using their mobile app with PIN or biometric authentication.
Key Features:
- ✅ Fast confirmation - Near real-time payment verification (typically within seconds)
- ✅ 14+ million users - Large customer base in Thailand
- ✅ High limits - Up to ฿150,000 per transaction
- ✅ Trusted bank - Thailand's first bank (established 1906)
- ✅ 24/7 availability - Works anytime
- ✅ Secure authentication - PIN, fingerprint, or Face ID
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 "SCB Easy" at checkout
- Redirected to SCB payment authorization page
- Opens SCB Easy app via deep link
- Reviews transaction details
- Authenticates with PIN, fingerprint, or Face ID
- Confirms payment
- Returns to merchant website
Typical completion time: 1-3 minutes
Implementation
Step 1: Create SCB 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_scb" \
-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_scb',
amount: 100000, // THB 1,000.00
currency: 'THB'
});
<?php
$source = OmiseSource::create(array(
'type' => 'mobile_banking_scb',
'amount' => 100000,
'currency' => 'THB'
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='mobile_banking_scb',
amount=100000,
currency='THB'
)
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
source = Omise::Source.create({
type: 'mobile_banking_scb',
amount: 100000,
currency: 'THB'
})
source, err := client.Sources().Create(&operations.CreateSource{
Type: "mobile_banking_scb",
Amount: 100000,
Currency: "THB",
})
Source source = client.sources().create(new Source.CreateParams()
.type("mobile_banking_scb")
.amount(100000L)
.currency("THB"));
var source = await client.Sources.Create(new CreateSourceRequest
{
Type = "mobile_banking_scb",
Amount = 100000,
Currency = "THB"
});
Response:
{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "mobile_banking_scb",
"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/scb', async (req, res) => {
try {
const { amount, order_id } = req.body;
// Validate amount limits
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_scb',
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 SCB Easy
res.redirect(charge.authorize_uri);
} catch (error) {
console.error('SCB Easy 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') {
// Payment successful
await processOrder(charge.metadata.order_id);
res.redirect('/payment-success');
} else if (charge.status === 'failed') {
// Payment failed
res.redirect('/payment-failed?reason=' + charge.failure_message);
} else {
// Still pending
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_scb') {
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());
// Checkout page
app.post('/checkout/scb', 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_scb',
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: 'scb_easy'
}
});
// Return authorization URL
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id
});
} catch (error) {
console.error('SCB Easy 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_scb') {
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
SCB Easy supports full refunds only within 180 days:
// Full refund only
const refund = await omise.charges.refund('chrg_test_...', {
amount: 100000 // Must be full amount
});
SCB Easy does NOT support partial refunds. Only full refunds are allowed within 180 days of the original transaction.
Common Issues & Troubleshooting
Issue: Customer doesn't have SCB Easy app
Cause: Customer selected SCB but doesn't have the app installed
Solution:
- Display clear instructions
- Provide app download link
- Offer alternative payment methods
function isMobile() {
return /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
}
if (!isMobile()) {
alert('SCB Easy requires the mobile 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;
setTimeout(() => {
if (!paymentConfirmed) {
showExpiryMessage();
allowRetry();
}
}, EXPIRY_TIME);
Issue: Daily limit exceeded
Error: Transaction rejected by bank
Solution:
- Customer can adjust daily limit in SCB Easy app
- Split payment across multiple days
- Use alternative payment method
Issue: Customer closed app
Cause: Return URI not called
Solution:
- Implement webhook handling (more reliable)
- Provide order status check page
- Send email/SMS confirmation
Best Practices
1. Display Clear Instructions
<div class="scb-instructions">
<h3>Pay with SCB Easy</h3>
<ol>
<li>Ensure you have SCB Easy app installed</li>
<li>You'll be redirected to open the app</li>
<li>Authenticate with PIN, fingerprint, or Face ID</li>
<li>Review and confirm payment</li>
</ol>
<p><strong>Payment expires in 15 minutes</strong></p>
<a href="https://www.scb.co.th/en/personal-banking/digital-banking/scb-easy.html">
Download SCB Easy
</a>
</div>
2. Handle Deep Links
function openSCBApp(authorizeUri) {
// Try to open mobile app
window.location = authorizeUri;
// Fallback if app not installed
setTimeout(() => {
if (document.hidden) {
// App opened successfully
return;
}
// Show app install instructions
showInstallAppMessage();
}, 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 callback
app.post('/webhooks/omise', handleWebhook);
app.get('/payment/callback', handleCallback);
5. Validate Amount
function validateSCBAmount(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 SCB Easy?
SCB Easy is Siam Commercial Bank's mobile banking app with 14+ million users in Thailand. Customers can pay directly from their SCB bank accounts using PIN or biometric authentication.
Do customers need an SCB account?
Yes, customers must have an active SCB bank account and the SCB Easy 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 customer settings)
Customers can adjust their daily limits in the SCB Easy app.
How long does settlement take?
SCB Easy settlements typically occur within 1-2 business days. Check your Omise dashboard for specific settlement schedules.
Can I refund SCB Easy payments?
Yes, but only full refunds are supported within 180 days. Partial refunds are not available.
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 SCB Easy available 24/7?
Yes, SCB Easy is available 24/7 including weekends and holidays. However, settlement follows business day schedules.
Testing
Test Mode
SCB 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 SCB account required for testing
Test Flow:
- Create source and charge with test API keys
- Customer redirects to test
authorize_uri - Test page simulates SCB mobile banking authorization
- Use Omise Dashboard Actions to mark charge as successful/failed
- Verify webhook and return_uri handling
Testing Implementation:
// Test SCB Mobile Banking
const source = await omise.sources.create({
type: 'mobile_banking_scb',
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 SCB Easy 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 SCB 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
- Bangkok Bank Mobile - Another option
- Testing - Test SCB integration
- Refunds - Refund policies