Skip to main content

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:

WalletRegionUsersCurrency
AlipayHKHong Kong3M+HKD
GCashPhilippines86M+PHP
KakaoPaySouth Korea30M+KRW
Touch 'n Go eWalletMalaysia18M+MYR
TrueMoneyThailand30M+THB
Changi PaySingapore-SGD
EZ-Link WalletSingapore1M+SGD
HipayMongolia2M+MNT
MPayMacau-MOP
Rabbit LINE PayThailand12M+THB
Toss PaySouth Korea10M+KRW

Supported Regions & Currenciesโ€‹

RegionCurrenciesPopular Use Cases
Southeast AsiaTHB, MYR, SGD, PHPE-commerce, travel, services
East AsiaKRW, HKD, MOPTourism, retail, digital goods
Cross-borderUSD, EUR, JPY, CNYInternational 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:

  1. Customer selects their wallet at checkout
  2. Merchant creates Alipay+ source with Omise
  3. Customer is shown QR code or redirected to wallet
  4. Customer scans QR or opens wallet app
  5. Customer confirms payment in their wallet
  6. Payment is processed through Alipay+ network
  7. Merchant receives instant confirmation

Typical completion time: 1-2 minutes

Implementationโ€‹

Step 1: Create Alipay+ Sourceโ€‹

curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=alipay_plus" \
-d "amount=50000" \
-d "currency=THB"

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);
Refund Processing Time

Refunds are processed back to the customer's original wallet within 3-7 business days, depending on the partner wallet.

Refund Policy

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:

  1. Create source and charge with test API keys for specific wallet
  2. QR code is generated or redirect URL provided
  3. Test page simulates wallet authorization
  4. Use Omise Dashboard Actions to mark charge as successful/failed
  5. 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.

Next Stepsโ€‹

  1. Create Alipay+ source
  2. Display QR code or redirect
  3. Implement status polling
  4. Set up webhook
  5. Test with various wallets
  6. Go live