Alipay+
Accept payments from 12+ partner wallets across Asia-Pacific with combined 1.3B+ registered accounts in Asia-Pacific through a single Alipay+ integration.
Overviewโ
Alipay+ is Ant Group's cross-border digital payment and marketing solution that connects multiple e-wallets across Asia-Pacific. With one integration, you can accept payments from GCash (Philippines), KakaoPay (South Korea), Touch 'n Go eWallet (Malaysia), and many other regional wallets.
Key Features:
- โ Massive reach - 12+ partner wallets with combined 1.3B+ registered accounts*
- โ Single integration - One API for multiple wallets
- โ Cross-border - Accept payments from tourists and international customers
- โ Fast confirmation - Near real-time payment verification (typically within seconds)
- โ Multi-currency - Support for 17+ currencies
- โ Marketing tools - Promotions and loyalty features
Partner Walletsโ
Alipay+ connects you to these major digital wallets:
| Wallet | Region | Users | Currency |
|---|---|---|---|
| AlipayHK | Hong Kong | 3M+ | HKD |
| GCash | Philippines | 86M+ | PHP |
| KakaoPay | South Korea | 30M+ | KRW |
| Touch 'n Go eWallet | Malaysia | 18M+ | MYR |
| TrueMoney | Thailand | 30M+ | THB |
| Changi Pay | Singapore | - | SGD |
| EZ-Link Wallet | Singapore | 1M+ | SGD |
| Hipay | Mongolia | 2M+ | MNT |
| MPay | Macau | - | MOP |
| Rabbit LINE Pay | Thailand | 12M+ | THB |
| Toss Pay | South Korea | 10M+ | KRW |
Supported Regions & Currenciesโ
| Region | Currencies | Popular Use Cases |
|---|---|---|
| Southeast Asia | THB, MYR, SGD, PHP | E-commerce, travel, services |
| East Asia | KRW, HKD, MOP | Tourism, retail, digital goods |
| Cross-border | USD, EUR, JPY, CNY | International payments |
Minimum Transaction: Varies by currency (typically $1 USD equivalent) Maximum Transaction: Varies by partner wallet (typically $10,000 USD equivalent)
How It Worksโ
Payment Flow:
- Customer selects their wallet at checkout
- Merchant creates Alipay+ source with Omise
- Customer is shown QR code or redirected to wallet
- Customer scans QR or opens wallet app
- Customer confirms payment in their wallet
- Payment is processed through Alipay+ network
- Merchant receives instant confirmation
Typical completion time: 1-2 minutes
Implementationโ
Step 1: Create Alipay+ Sourceโ
- cURL
- Node.js
- PHP
- Python
- Ruby
curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=alipay_plus" \
-d "amount=50000" \
-d "currency=THB"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'alipay_plus',
amount: 50000, // เธฟ500.00
currency: 'THB'
});
console.log('Alipay+ source:', source.id);
console.log('QR code:', source.scannable_code.image.download_uri);
<?php
$source = OmiseSource::create(array(
'type' => 'alipay_plus',
'amount' => 50000,
'currency' => 'THB'
));
echo "QR Code: " . $source['scannable_code']['image']['download_uri'];
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='alipay_plus',
amount=50000,
currency='THB'
)
print(f"QR Code: {source.scannable_code['image']['download_uri']}")
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
source = Omise::Source.create({
type: 'alipay_plus',
amount: 50000,
currency: 'THB'
})
puts "QR Code: #{source.scannable_code.image.download_uri}"
Response:
{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "alipay_plus",
"flow": "redirect",
"amount": 50000,
"currency": "THB",
"scannable_code": {
"type": "qr",
"image": {
"download_uri": "https://api.omise.co/...",
"object": "document"
}
}
}
Step 2: Display QR Code or Redirectโ
Option A: QR Code (In-Store/Desktop)
app.post('/checkout/alipay-plus', async (req, res) => {
try {
const { amount, currency } = req.body;
// Create source
const source = await omise.sources.create({
type: 'alipay_plus',
amount: amount,
currency: currency
});
// Create charge
const charge = await omise.charges.create({
amount: amount,
currency: currency,
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/callback`
});
// Display QR code
res.render('payment-qr', {
qr_code_url: source.scannable_code.image.download_uri,
charge_id: charge.id
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
QR Code Display Template:
<div class="alipay-plus-payment">
<h2>Scan to Pay with Alipay+</h2>
<img src="{{ qr_code_url }}" alt="Alipay+ QR Code" class="qr-code">
<div class="supported-wallets">
<p>Scan with any of these wallets:</p>
<div class="wallet-logos">
<img src="/icons/gcash.png" alt="GCash">
<img src="/icons/kakaopay.png" alt="KakaoPay">
<img src="/icons/tng.png" alt="Touch 'n Go">
<img src="/icons/truemoney.png" alt="TrueMoney">
<img src="/icons/alipay-hk.png" alt="AlipayHK">
</div>
</div>
<div class="instructions">
<ol>
<li>Open your wallet app</li>
<li>Tap "Scan" or "Pay"</li>
<li>Scan the QR code above</li>
<li>Confirm the payment</li>
</ol>
</div>
<div id="payment-status">
<p>Waiting for payment...</p>
<div class="spinner"></div>
</div>
</div>
<script>
// Poll for payment status
const chargeId = '{{ charge_id }}';
const pollInterval = setInterval(async () => {
const response = await fetch(`/api/charges/${chargeId}/status`);
const data = await response.json();
if (data.status === 'successful') {
clearInterval(pollInterval);
window.location = '/payment-success';
} else if (data.status === 'failed') {
clearInterval(pollInterval);
window.location = '/payment-failed';
}
}, 3000); // Check every 3 seconds
// Timeout after 10 minutes
setTimeout(() => {
clearInterval(pollInterval);
document.getElementById('payment-status').innerHTML =
'<p>Payment timeout. Please try again.</p>';
}, 600000);
</script>
Option B: Redirect (Mobile)
app.post('/checkout/alipay-plus-mobile', async (req, res) => {
try {
const { amount, currency } = req.body;
const source = await omise.sources.create({
type: 'alipay_plus',
amount: amount,
currency: currency
});
const charge = await omise.charges.create({
amount: amount,
currency: currency,
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/callback`
});
// Redirect to Alipay+ page
res.redirect(charge.authorize_uri);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
Step 3: Handle Payment Callbackโ
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 fulfillOrder(charge.metadata.order_id);
res.redirect('/payment-success');
} else if (charge.status === 'failed') {
res.redirect('/payment-failed');
} else {
res.redirect('/payment-pending');
}
} catch (error) {
res.redirect('/payment-error');
}
});
Step 4: Handle Webhookโ
app.post('/webhooks/omise', async (req, res) => {
const event = req.body;
if (event.key === 'charge.complete') {
const charge = event.data;
if (charge.source.type === 'alipay_plus') {
if (charge.status === 'successful') {
await processOrder(charge.metadata.order_id);
await sendConfirmation(charge.metadata.customer_email);
}
}
}
res.sendStatus(200);
});
Complete Implementation Exampleโ
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
const app = express();
app.use(express.json());
// Currency configuration
const SUPPORTED_CURRENCIES = ['THB', 'MYR', 'SGD', 'PHP', 'KRW', 'HKD'];
const CURRENCY_LIMITS = {
THB: { min: 2000, max: 1000000 },
MYR: { min: 500, max: 500000 },
SGD: { min: 100, max: 100000 },
PHP: { min: 5000, max: 1000000 },
KRW: { min: 100000, max: 10000000 },
HKD: { min: 100, max: 100000 }
};
// Create Alipay+ payment
app.post('/checkout/alipay-plus', async (req, res) => {
try {
const { amount, currency, order_id, customer_email } = req.body;
// Validate currency
if (!SUPPORTED_CURRENCIES.includes(currency)) {
return res.status(400).json({
error: `Currency ${currency} not supported for Alipay+`
});
}
// Validate amount
const limits = CURRENCY_LIMITS[currency];
if (amount < limits.min || amount > limits.max) {
return res.status(400).json({
error: `Amount must be between ${limits.min} and ${limits.max} ${currency}`
});
}
// Create source
const source = await omise.sources.create({
type: 'alipay_plus',
amount: amount,
currency: currency
});
// Create charge
const charge = await omise.charges.create({
amount: amount,
currency: currency,
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/callback`,
metadata: {
order_id: order_id,
customer_email: customer_email,
payment_method: 'alipay_plus'
}
});
// Return QR code and authorize URI
res.json({
charge_id: charge.id,
qr_code_url: source.scannable_code.image.download_uri,
authorize_uri: charge.authorize_uri,
expires_at: new Date(Date.now() + 10 * 60 * 1000).toISOString()
});
} catch (error) {
console.error('Alipay+ error:', error);
res.status(500).json({ error: error.message });
}
});
// Check charge status (for polling)
app.get('/api/charges/:chargeId/status', async (req, res) => {
try {
const charge = await omise.charges.retrieve(req.params.chargeId);
res.json({
status: charge.status,
paid: charge.paid,
failure_message: charge.failure_message
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Payment callback
app.get('/payment/callback', async (req, res) => {
try {
const charge = await omise.charges.retrieve(req.query.charge_id);
if (charge.status === 'successful') {
res.redirect(`/order-confirmation?order=${charge.metadata.order_id}`);
} else {
res.redirect(`/payment-failed?reason=${charge.failure_message}`);
}
} catch (error) {
res.redirect('/payment-error');
}
});
// Webhook handler
app.post('/webhooks/omise', async (req, res) => {
const event = req.body;
if (event.key === 'charge.complete' && event.data.source.type === 'alipay_plus') {
const charge = event.data;
if (charge.status === 'successful') {
await fulfillOrder(charge.metadata.order_id);
await sendReceipt(charge.metadata.customer_email, charge);
}
}
res.sendStatus(200);
});
app.listen(3000);
Refund Supportโ
Alipay+ supports full and partial refunds within 180 days:
// Full refund
const fullRefund = await omise.charges.refund('chrg_test_...', {
amount: 50000
});
// Partial refund
const partialRefund = await omise.charges.refund('chrg_test_...', {
amount: 25000 // Half refund
});
console.log('Refund status:', fullRefund.status);
Refunds are processed back to the customer's original wallet within 3-7 business days, depending on the partner wallet.
Refund windows and policies are subject to change. Always verify current refund capabilities via the Omise API documentation or your merchant dashboard.
Common Issues & Troubleshootingโ
Issue: QR code not scanningโ
Cause: Customer using incompatible wallet app
Solution:
// Display supported wallets prominently
const supportedWallets = [
'GCash', 'KakaoPay', 'Touch \'n Go',
'TrueMoney', 'AlipayHK', 'Rabbit LINE Pay'
];
// Show message
showMessage(`Please scan with: ${supportedWallets.join(', ')}`);
Issue: Currency not supported by customer's walletโ
Cause: Customer's wallet doesn't support merchant's currency
Solution: Alipay+ handles currency conversion automatically. Ensure you're using a supported currency.
Issue: Payment timeoutโ
Cause: Customer didn't complete payment within 10 minutes
Solution:
const QR_TIMEOUT = 10 * 60 * 1000; // 10 minutes
setTimeout(() => {
if (!paymentCompleted) {
showMessage('QR code expired. Please generate a new one.');
enableRetry();
}
}, QR_TIMEOUT);
Issue: Cross-border restrictionsโ
Cause: Some wallets have cross-border payment limits
Solution: Check partner wallet documentation for cross-border limits and inform customers accordingly.
Best Practicesโ
1. Display Supported Walletsโ
<div class="alipay-plus-info">
<h3>Pay with Alipay+ Partner Wallets</h3>
<div class="wallet-grid">
<div class="wallet-item">
<img src="/icons/gcash.svg" alt="GCash">
<span>GCash (PH)</span>
</div>
<div class="wallet-item">
<img src="/icons/kakaopay.svg" alt="KakaoPay">
<span>KakaoPay (KR)</span>
</div>
<div class="wallet-item">
<img src="/icons/tng.svg" alt="Touch 'n Go">
<span>Touch 'n Go (MY)</span>
</div>
<!-- More wallets -->
</div>
</div>
2. Responsive QR Code Displayโ
.qr-code {
width: 100%;
max-width: 300px;
height: auto;
display: block;
margin: 20px auto;
border: 10px solid white;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
@media (max-width: 768px) {
.qr-code {
max-width: 250px;
}
}
3. Poll for Payment Statusโ
async function pollPaymentStatus(chargeId) {
const maxAttempts = 200; // 10 minutes (200 * 3 seconds)
let attempts = 0;
const poll = setInterval(async () => {
attempts++;
try {
const response = await fetch(`/api/charges/${chargeId}/status`);
const data = await response.json();
if (data.status === 'successful') {
clearInterval(poll);
window.location = '/payment-success';
} else if (data.status === 'failed') {
clearInterval(poll);
window.location = '/payment-failed';
} else if (attempts >= maxAttempts) {
clearInterval(poll);
showTimeout();
}
} catch (error) {
console.error('Poll error:', error);
}
}, 3000);
}
4. Multi-Channel Supportโ
// Detect device and show appropriate flow
function initAlipayPlusPayment(amount, currency) {
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (isMobile) {
// Redirect to wallet selection
createPaymentAndRedirect(amount, currency);
} else {
// Show QR code
createPaymentAndShowQR(amount, currency);
}
}
5. Clear Instructionsโ
<div class="payment-instructions">
<h4>How to pay:</h4>
<ol>
<li>Open your wallet app (GCash, KakaoPay, Touch 'n Go, etc.)</li>
<li>Tap "Scan" or "Scan QR"</li>
<li>Point your camera at the QR code above</li>
<li>Verify the amount and tap "Pay"</li>
<li>Enter your PIN or use biometric authentication</li>
</ol>
<p class="help-text">Need help? <a href="mailto:support@omise.co">Contact support</a></p>
</div>
FAQโ
What is Alipay+ and how is it different from Alipay?
Alipay+ is a cross-border payment network that connects 12+ regional e-wallets across Asia-Pacific. Regular Alipay is just the Chinese wallet. With Alipay+, you can accept payments from GCash, KakaoPay, Touch 'n Go, and other partner wallets through one integration.
Which wallets can customers use?
Customers can pay with: GCash (Philippines), KakaoPay (South Korea), Touch 'n Go eWallet (Malaysia), TrueMoney (Thailand), AlipayHK (Hong Kong), Rabbit LINE Pay (Thailand), Toss Pay (South Korea), and other Alipay+ partner wallets.
Do I need separate integrations for each wallet?
No! That's the benefit of Alipay+. One integration gives you access to all partner wallets. Customers can pay with any supported wallet by scanning the Alipay+ QR code.
Does Alipay+ support cross-border payments?
Yes, Alipay+ is designed for cross-border payments. It handles currency conversion automatically. For example, a tourist from the Philippines can pay in your local currency using their GCash wallet.
How long does settlement take?
Settlement typically occurs within 3-7 business days, depending on your merchant agreement and the customer's wallet.
Can I refund Alipay+ payments?
Yes, full and partial refunds are supported within 180 days of the original transaction.
What are the transaction limits?
Limits vary by partner wallet and customer verification level. Generally:
- Minimum: $1 USD equivalent
- Maximum: $10,000 USD equivalent per transaction
Check with specific partner wallets for detailed limits.
Testingโ
Test Modeโ
Alipay+ wallets can be tested using your test API keys. In test mode:
Test Credentials:
- Use test API keys (skey_test_xxx)
- Test supported currencies based on wallet region
- No actual wallet accounts required for testing
Test Flow:
- Create source and charge with test API keys for specific wallet
- QR code is generated or redirect URL provided
- Test page simulates wallet authorization
- Use Omise Dashboard Actions to mark charge as successful/failed
- Verify webhook and payment status handling
Testing Implementation:
// Test different Alipay+ wallets
const testWallets = [
{ type: 'gcash', currency: 'PHP', amount: 10000 },
{ type: 'kakaopay', currency: 'KRW', amount: 10000 },
{ type: 'touch_n_go', currency: 'MYR', amount: 10000 }
];
for (const wallet of testWallets) {
const source = await omise.sources.create({
type: wallet.type,
amount: wallet.amount,
currency: wallet.currency
});
const charge = await omise.charges.create({
amount: wallet.amount,
currency: wallet.currency,
source: source.id
});
console.log(`Test ${wallet.type}:`, charge.authorize_uri || charge.source.scannable_code);
}
Test Scenarios:
- Successful payment: Verify order completion for each wallet
- Failed payment: Test error handling
- Multiple wallets: Test each Alipay+ wallet separately
- QR vs Redirect: Test both QR and redirect flows
- Amount limits: Verify limits per wallet and currency
- Currency validation: Ensure correct currency per wallet
- Timeout: Test abandoned payment scenarios
- Webhook delivery: Verify all webhook notifications
Important Notes:
- Test mode doesn't connect to real wallet servers
- Use dashboard to simulate payment outcomes
- Test each wallet type individually
- Verify webhook handling for all wallets
- Test both QR code and redirect flows
- Validate currency requirements per wallet
For comprehensive testing guidelines, see the Testing Documentation.
Related Resourcesโ
- Digital Wallets Overview - All wallet options
- GCash - Philippines wallet
- KakaoPay - South Korea wallet
- Touch 'n Go - Malaysia wallet
- Alipay - Chinese Alipay
- QR Payments - Alternative QR methods
- Refunds - Refund policies