ShopeePay Jump App
Accept payments with app-to-app redirection to the ShopeePay mobile app for a seamless mobile checkout experience.
Overviewโ
ShopeePay Jump App is an app-to-app redirection payment method that deep links customers directly from your mobile app or website to the ShopeePay mobile app for payment authorization. This provides a faster, more native mobile experience compared to QR code scanning.
Key Features:
- โ App-to-app redirection - Direct deep link to ShopeePay app
- โ Multiple payment options - Wallet, cards, bank accounts, SPayLater
- โ 3 markets - Thailand, Singapore, Malaysia
- โ Fast checkout - Native app experience
- โ Platform detection - iOS and Android support
- โ 180-day refund window - Full and partial refunds
Contact support@omise.co to enable ShopeePay Jump App for your merchant account.
Supported Regionsโ
| Region | Currency | Min Amount | Max Amount | API Version |
|---|---|---|---|---|
| Thailand | THB | เธฟ20.00 | เธฟ150,000.00 | 2017-11-02 |
| Singapore | SGD | $1.00 | $20,000.00 | 2017-11-02 |
| Malaysia | MYR | RM1.00 | RM9,999.00 | 2017-11-02 |
Payment Options by Regionโ
| Payment Option | Thailand | Singapore | Malaysia |
|---|---|---|---|
| Wallet Balance | โ | โ | โ |
| Credit Card | โ | โ | โ |
| Direct Debit / Bank | โ | โ | โ |
| SPayLater (BNPL) | โ | โ | โ |
How It Worksโ
Payment Flow:
- Customer selects ShopeePay on mobile device
- Merchant creates source with
shopeepay_jumpapptype - Customer is redirected via deep link
- ShopeePay app opens automatically
- Customer selects payment method (wallet, card, SPayLater)
- Customer authenticates and confirms
- Customer returns to merchant app/site
- Webhook confirms payment status
Typical completion time: 30 seconds - 2 minutes
Implementationโ
Step 1: Create Sourceโ
- cURL
- Node.js
- PHP
- Omise.js
curl https://api.omise.co/sources \
-u $OMISE_PUBLIC_KEY: \
-d "amount=50000" \
-d "currency=THB" \
-d "type=shopeepay_jumpapp" \
-d "platform_type=ANDROID"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'shopeepay_jumpapp',
amount: 50000, // THB 500.00
currency: 'THB',
platform_type: 'ANDROID' // or 'IOS'
});
<?php
$source = OmiseSource::create([
'type' => 'shopeepay_jumpapp',
'amount' => 50000,
'currency' => 'THB',
'platform_type' => 'ANDROID'
]);
?>
Omise.setPublicKey(omise_public_key);
Omise.createSource('shopeepay_jumpapp', {
amount: 50000,
currency: 'THB',
platform_type: detectPlatform() // 'IOS' or 'ANDROID'
}, function(statusCode, response) {
console.log(response);
});
function detectPlatform() {
const ua = navigator.userAgent;
if (/iPhone|iPad|iPod/.test(ua)) return 'IOS';
if (/Android/.test(ua)) return 'ANDROID';
return 'ANDROID'; // Default
}
Step 2: Create Chargeโ
curl https://api.omise.co/charges \
-u $OMISE_SECRET_KEY: \
-d "amount=50000" \
-d "currency=THB" \
-d "return_uri=https://example.com/payment/complete" \
-d "source=src_test_xxx"
Combined Requestโ
Create source and charge in one request:
curl https://api.omise.co/charges \
-u $OMISE_SECRET_KEY: \
-d "amount=50000" \
-d "currency=THB" \
-d "return_uri=https://example.com/payment/complete" \
-d "source[type]=shopeepay_jumpapp" \
-d "source[platform_type]=ANDROID"
Step 3: Redirect Customerโ
// Detect platform and redirect
function redirectToShopeePay(authorizeUri) {
// The authorize_uri contains the deep link
window.location.href = authorizeUri;
}
// After creating charge
redirectToShopeePay(charge.authorize_uri);
Step 4: Handle Returnโ
app.get('/payment/complete', async (req, res) => {
try {
// Get charge status
const chargeId = req.query.charge;
const charge = await omise.charges.retrieve(chargeId);
if (charge.status === 'successful') {
await fulfillOrder(charge.metadata.order_id);
res.redirect('/order-success');
} else if (charge.status === 'failed') {
res.redirect('/payment-failed?error=' + charge.failure_code);
} else {
// Still pending - wait for webhook
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') {
const charge = event.data;
if (charge.source.type === 'shopeepay_jumpapp') {
if (charge.status === 'successful') {
fulfillOrder(charge.metadata.order_id);
} else if (charge.status === 'failed') {
handleFailedPayment(charge);
}
}
}
res.status(200).send('OK');
});
Complete Implementation Exampleโ
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
const app = express();
app.use(express.json());
// Checkout endpoint
app.post('/checkout/shopeepay-jumpapp', async (req, res) => {
try {
const { amount, currency, order_id, platform_type } = req.body;
// Validate currency
if (!['THB', 'SGD', 'MYR'].includes(currency)) {
return res.status(400).json({
error: 'Currency not supported. Use THB, SGD, or MYR.'
});
}
// Validate platform
const platform = ['IOS', 'ANDROID'].includes(platform_type)
? platform_type
: 'ANDROID';
// Create source
const source = await omise.sources.create({
type: 'shopeepay_jumpapp',
amount: amount,
currency: currency,
platform_type: platform
});
// Create charge with 20-minute expiry
const charge = await omise.charges.create({
amount: amount,
currency: currency,
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/complete`,
metadata: {
order_id: order_id
}
});
// Return deep link URL
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id,
expires_at: charge.expires_at
});
} catch (error) {
console.error('ShopeePay Jump App error:', error);
res.status(500).json({ error: error.message });
}
});
// Return handler
app.get('/payment/complete', async (req, res) => {
const chargeId = req.query.charge;
try {
const charge = await omise.charges.retrieve(chargeId);
if (charge.status === 'successful') {
res.redirect(`/order-confirmation?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 === 'shopeepay_jumpapp') {
if (charge.status === 'successful') {
processOrder(charge.metadata.order_id);
sendConfirmationEmail(charge);
} else {
notifyPaymentFailure(charge);
}
}
}
res.sendStatus(200);
});
app.listen(3000);
Mobile App Integrationโ
iOS (Swift)โ
func openShopeePayJumpApp(authorizeUri: String) {
guard let url = URL(string: authorizeUri) else { return }
UIApplication.shared.open(url, options: [:]) { success in
if !success {
// ShopeePay app not installed - show fallback
self.showAppStorePrompt()
}
}
}
Android (Kotlin)โ
fun openShopeePayJumpApp(authorizeUri: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(authorizeUri))
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// ShopeePay app not installed - show fallback
showPlayStorePrompt()
}
}
React Nativeโ
import { Linking } from 'react-native';
const openShopeePayJumpApp = async (authorizeUri) => {
try {
const supported = await Linking.canOpenURL(authorizeUri);
if (supported) {
await Linking.openURL(authorizeUri);
} else {
// Fallback to app store
showAppStorePrompt();
}
} catch (error) {
console.error('Failed to open ShopeePay:', error);
}
};
Charge Expirationโ
Default charge expiration is 20 minutes. You can customize this up to 60 minutes:
curl https://api.omise.co/charges \
-u $OMISE_SECRET_KEY: \
-d "amount=50000" \
-d "currency=THB" \
-d "source=src_test_xxx" \
-d "return_uri=https://example.com/complete" \
-d "expires_at=2024-12-31T23:59:59Z"
Charge Status Valuesโ
| Status | Description |
|---|---|
pending | Awaiting customer authorization in ShopeePay app |
successful | Payment completed |
failed | Payment declined or error |
expired | Customer didn't complete within expiry window |
Failure Codesโ
| Code | Description |
|---|---|
payment_expired | Authorization window expired |
payment_rejected | ShopeePay declined transaction |
insufficient_balance | Insufficient wallet balance |
failed_processing | General processing error |
Refundsโ
ShopeePay Jump App supports full and partial refunds within 180 days:
// Full or partial refund
const refund = await omise.charges.refund('chrg_test_xxx', {
amount: 25000 // Partial refund of THB 250.00
});
Refunds and voids are not available for "off-us" transactions (payments made with cards or bank accounts not directly through ShopeePay wallet).
Best Practicesโ
- Detect platform - Always detect and pass the correct
platform_type(IOS/ANDROID) - Handle app not installed - Provide fallback if ShopeePay app isn't installed
- Mobile-only - This method requires a mobile device with ShopeePay app
- Set appropriate expiry - Match expiration to your checkout session
- Webhook priority - Always use webhooks for order fulfillment
FAQโ
What is the difference between ShopeePay Jump App and ShopeePay QR?
ShopeePay Jump App (shopeepay_jumpapp): App-to-app redirection that deep links directly to the ShopeePay mobile app. Better for mobile app integrations.
ShopeePay QR (shopeepay): Displays a QR code that customers scan with their ShopeePay app. Works on both desktop and mobile.
What payment methods can customers use?
Customers can pay using:
- ShopeePay Wallet Balance - All regions
- Credit/Debit Cards - Thailand, Singapore
- Direct Debit / Bank Account - Thailand only
- SPayLater (BNPL) - Thailand, Singapore
The available options depend on the customer's region and account settings.
What is SPayLater?
SPayLater is Shopee's Buy Now Pay Later service that allows customers to pay in installments. It's available in Thailand and Singapore. Customers apply for SPayLater credit through the Shopee app.
Do I need to specify the platform type?
The platform_type parameter (IOS or ANDROID) is optional but recommended. It helps optimize the deep link for the customer's device. If not specified, the system will attempt to detect it automatically.
What if the customer doesn't have the ShopeePay app installed?
If the ShopeePay app isn't installed, the deep link won't work. Implement a fallback that:
- Detects if the app opens successfully
- Redirects to app store if not
- Offers alternative payment methods
How long does the customer have to complete payment?
By default, customers have 20 minutes to complete the payment. You can extend this to up to 60 minutes using the expires_at parameter when creating the charge.
Can I use this on desktop?
ShopeePay Jump App is designed for mobile devices. For desktop users, use ShopeePay QR instead, which displays a QR code they can scan with their phone.
Related Resourcesโ
- ShopeePay QR - QR code payment method
- Digital Wallets Overview - All wallet options
- Webhooks - Webhook handling
- Refunds - Refund policies