Skip to main content

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

Mobile Banking 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

RegionCurrencyMin AmountMax AmountDaily Limit
ThailandTHB฿20.00฿150,000Varies by bank*

*Daily limits vary based on customer's bank account settings and are not specified by Omise

How It Works

Customer Experience:

  1. Customer selects "KBank Mobile Banking" at checkout
  2. Redirected to KBank payment page
  3. Opens K PLUS mobile app (deep link)
  4. Reviews payment details
  5. Authenticates with PIN or biometrics
  6. Confirms payment in app
  7. Returns to merchant site

Typical completion time: 1-3 minutes

Implementation

Step 1: Create KBank Source

curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=mobile_banking_kbank" \
-d "amount=100000" \
-d "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
});
No Partial Refunds

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>
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:

  1. Create source and charge with test API keys
  2. Customer redirects to test authorize_uri
  3. Test page simulates KBank mobile banking authorization
  4. Use Omise Dashboard Actions to mark charge as successful/failed
  5. 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.

Next Steps

  1. Create KBank source
  2. Implement redirect flow
  3. Set up webhook handling
  4. Test payment flow
  5. Go live