KBank Mobile Banking
Accept instant mobile banking payments from Kasikorn Bank (KBank), one of Thailand's largest banks with 20+ million customers using K PLUS mobile app.
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
KBank mobile banking allows customers to pay directly from their Kasikorn Bank accounts using the K PLUS mobile app. Customers authenticate the payment using their mobile banking PIN or biometrics, providing a secure and familiar payment experience.
Key Features:
- ✅ Fast confirmation - Near real-time payment verification (typically within seconds)
- ✅ Large user base - 20+ million K PLUS app users
- ✅ High limits - Up to ฿150,000 per transaction
- ✅ No card needed - Direct from bank account
- ✅ 24/7 availability - Works anytime, including weekends
- ✅ Secure - Bank-level authentication with PIN/biometrics
Supported Regions
| Region | Currency | Min Amount | Max Amount | API Version |
|---|---|---|---|---|
| Thailand | THB | ฿20.00 | ฿150,000.00 | 2017-11-02 |
How It Works
Customer Experience:
- Customer selects "KBank Mobile Banking" at checkout
- Redirected to KBank payment page
- Opens K PLUS mobile app (deep link)
- Reviews payment details
- Authenticates with PIN or biometrics
- Confirms payment in app
- Returns to merchant site
Typical completion time: 1-3 minutes
Implementation
Step 1: Create KBank 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_kbank" \
-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_kbank',
amount: 100000, // THB 1,000.00
currency: 'THB'
});
<?php
$source = OmiseSource::create(array(
'type' => 'mobile_banking_kbank',
'amount' => 100000,
'currency' => 'THB'
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='mobile_banking_kbank',
amount=100000,
currency='THB'
)
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
source = Omise::Source.create({
type: 'mobile_banking_kbank',
amount: 100000,
currency: 'THB'
})
source, err := client.Sources().Create(&operations.CreateSource{
Type: "mobile_banking_kbank",
Amount: 100000,
Currency: "THB",
})
Source source = client.sources().create(new Source.CreateParams()
.type("mobile_banking_kbank")
.amount(100000L)
.currency("THB"));
var source = await client.Sources.Create(new CreateSourceRequest
{
Type = "mobile_banking_kbank",
Amount = 100000,
Currency = "THB"
});
Response:
{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "mobile_banking_kbank",
"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"
Response:
{
"object": "charge",
"id": "chrg_test_5rt6s9vah5lkvi1rh9c",
"amount": 100000,
"currency": "THB",
"status": "pending",
"authorize_uri": "https://pay.omise.co/payments/payt_test_..."
}
Step 3: Redirect Customer
app.post('/checkout/kbank', 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_kbank',
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 KBank
res.redirect(charge.authorize_uri);
} catch (error) {
console.error('KBank payment 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_kbank') {
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/kbank', 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_kbank',
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: 'kbank_mobile'
}
});
// Return authorization URL
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id
});
} catch (error) {
console.error('KBank payment 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_kbank') {
if (charge.status === 'successful') {
// Process order
updateOrderStatus(charge.metadata.order_id, 'paid');
sendConfirmationEmail(charge.metadata.customer_email);
} else {
// Handle failure
updateOrderStatus(charge.metadata.order_id, 'failed');
}
}
}
res.sendStatus(200);
});
app.listen(3000);
Refund Support
KBank mobile banking supports full refunds only within 180 days:
// Full refund only
const refund = await omise.charges.refund('chrg_test_...', {
amount: 100000 // Must be full amount
});
KBank mobile banking does NOT support partial refunds. Only full refunds are allowed within 180 days.
Common Issues & Troubleshooting
Issue: Customer doesn't have K PLUS app
Cause: Customer selected KBank but doesn't have the mobile app installed
Solution:
- Display clear instructions before payment
- Check if user has K PLUS app installed
- Offer alternative payment methods
// Check user agent for mobile
function isMobile() {
return /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
}
if (!isMobile()) {
alert('KBank mobile banking requires the K PLUS 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 on payment page
- Allow customer to retry with new charge
- Send reminder notifications
// Expiration timer
const EXPIRY_TIME = 15 * 60 * 1000; // 15 minutes
setTimeout(() => {
if (!paymentConfirmed) {
showExpiryMessage();
allowRetry();
}
}, EXPIRY_TIME);
Issue: Return URI not called
Cause: Customer closed app before return
Solution:
- Implement webhook handling (more reliable)
- Provide order status check page
- Send email/SMS confirmation
Issue: Customer exceeds daily limit
Error: Transaction rejected by bank
Solution:
- Customer needs to adjust daily limit in K PLUS app
- Split payment across multiple days
- Use alternative payment method
Best Practices
1. Display Clear Instructions
<div class="kbank-instructions">
<h3>Pay with KBank Mobile Banking</h3>
<ol>
<li>Make sure you have the K PLUS app installed</li>
<li>You'll be redirected to open the app</li>
<li>Authenticate with your PIN or biometrics</li>
<li>Review and confirm the payment</li>
</ol>
<p><strong>Note:</strong> Payment must be completed within 15 minutes.</p>
</div>
2. Handle Mobile Deep Links
function openKBankApp(authorizeUri) {
// Try to open mobile app
window.location = authorizeUri;
// Fallback to browser if app not installed
setTimeout(() => {
if (document.hidden) {
// App opened successfully
return;
}
// Show instructions to install app
showInstallAppMessage();
}, 2000);
}
3. Set Reasonable Timeout
// 15-minute expiry
const PAYMENT_TIMEOUT = 15 * 60 * 1000;
setTimeout(() => {
if (!paymentConfirmed) {
showTimeoutMessage();
allowRetry();
}
}, PAYMENT_TIMEOUT);
4. Use Webhooks for Reliability
Don't rely solely on redirect callbacks:
// Webhook is more reliable
app.post('/webhooks/omise', handleWebhook);
// Callback is backup
app.get('/payment/callback', handleCallback);
5. Validate Amount Limits
function validateKBankAmount(amount) {
const MIN_AMOUNT = 2000; // ฿20.00
const MAX_AMOUNT = 200000000; // ฿2,000,000.00
if (amount < MIN_AMOUNT) {
return 'Minimum amount is ฿20.00';
}
if (amount > MAX_AMOUNT) {
return 'Maximum amount is ฿2,000,000.00';
}
return null; // Valid
}
FAQ
What is KBank mobile banking?
KBank mobile banking allows customers to pay directly from their Kasikorn Bank accounts using the K PLUS mobile app. Customers authenticate payments with their PIN or biometrics for secure transactions.
Do customers need the K PLUS app?
Yes, customers must have the K PLUS mobile app installed to complete payments. The app is free and available on iOS and Android.
What are the transaction limits?
- Per transaction: ฿20 to ฿2,000,000
- Daily limit: Up to ฿5,000,000 (may vary by customer's bank settings)
Customers can adjust daily limits in their K PLUS app settings.
How long does settlement take?
KBank mobile banking settlements are typically processed within 1-2 business days. Check your Omise dashboard for specific settlement schedules.
Can I refund KBank payments?
Yes, but only full refunds are supported within 180 days. Partial refunds are not available for KBank mobile banking.
What if the customer's payment expires?
Payments expire after 15 minutes of inactivity. Allow customers to retry with a new charge. Implement a countdown timer to show remaining time.
Does KBank mobile banking work 24/7?
Yes, KBank mobile banking is available 24/7, including weekends and holidays. However, settlement to your account follows business day schedules.
Testing
Test Mode
KBank 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 KBank account required for testing
Test Flow:
- Create source and charge with test API keys
- Customer redirects to test
authorize_uri - Test page simulates KBank mobile banking authorization
- Use Omise Dashboard Actions to mark charge as successful/failed
- Verify webhook and return_uri handling
Testing Implementation:
// Test KBank Mobile Banking
const source = await omise.sources.create({
type: 'mobile_banking_kbank',
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 KBank 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 KBank 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
- SCB Mobile Banking - Alternative bank
- Bangkok Bank Mobile - Another option
- Testing - Test KBank integration
- Refunds - Refund policies