KakaoPay
シンガポールとタイでKakaoPay決済を受け付けます。複数の東南アジア市場をサポートする統合決済ウォレットです。
概要
KakaoPayは、シンガポールとタイで運営されているデジタルウォレット決済サービスで、eコマースプラットフォームと統合された便利なモバイル決済オプションを顧客に提供します。
主な機能:
- ✅ マルチ地域 - シンガポールとタイで利用可能
- ✅ 高速確認 - ほぼリアルタイムの支払い検証(通常数秒以内)
- ✅ モバイル最適化 - シームレスなスマートフォン体験
- ✅ 迅速なチェックアウト - 高速な支払い承認
- ✅ Eコマース重視 - オンラインショッピングで人気
サポートされている地域
| 地域 | 通貨 | 最小金額 | 最大金額 | APIバージョン |
|---|---|---|---|---|
| Singapore | SGD | $1.00 | $20,000.00 | 2017-11-02 |
| Thailand | THB | ฿20.00 | ฿150,000.00 | 2017-11-02 |
仕組み
顧客体験:
- 顧客がチェックアウト時にKakaoPayを選択
- KakaoPay認証ページにリダイレクト
- KakaoTalkアプリが自動的に開く(ディープリンク)
- 顧客がKakaoTalkで支払いを確認
- パスワード/生体認証/パターンで確認
- マーチャントサイトに戻る
- KakaoTalkで支払い通知を受け取る
通常の完了時間: 30-90秒
支払いフロー例
モバイル支払いフロー:

超高速モバイル体験:
- ❶ KakaoPayを選択 - 顧客がチェックアウト時にKakaoPayを選択
- ❷ KakaoTalkが開く - ディープリンクが即座にKakaoTalkアプリを起動
- ❸ 支払いプロンプト - KakaoTalkに取引詳細が表示
- ❹ 詳細を確認 - マーチャント名と支払い金額が表示
- ❺ 認証 - パスワード、パターン、または生体認証で確認
- ❻ 支払い完了 - 即座に処理(アジアで最速 - 20-40秒)
- ❼ 通知 - KakaoTalkで支払い確認メッセージ
- ❽ 戻る - マーチャントに自動リダイレクト
デスクトップ支払いフロー:

デスクトップユーザー向けのQRコード方式:
- ❶ KakaoPayを選択 - 顧客がデスクトップでKakaoPayを選択
- ❷ QR生成 - システムがKakaoPay支払いQRコードを作成
- ❸ QR表示 - QRコードが画面に目立つように表示
- ❹ KakaoTalk を開く - 顧客がモバイルでKakaoTalkを起動
- ❺ QRスキャン - KakaoTalkの組み込みQRスキャナーを使用
- ❻ 支払い読み込み - アプリで取引詳細が自動入力
- ❼ 認証 - 迅速な生体認証またはパスワード確認
- ❽ 成功 - 支払い処理、デスクトップに確認表示
実装
ステップ1: KakaoPayソースの作成
- cURL
- Node.js
- PHP
- Python
- Ruby
- Go
curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=kakaopay" \
-d "amount=1000000" \
-d "currency=KRW"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'kakaopay',
amount: 1000000, // ₩10,000
currency: 'KRW'
});
console.log('KakaoPay source:', source.id);
<?php
$source = OmiseSource::create(array(
'type' => 'kakaopay',
'amount' => 1000000,
'currency' => 'KRW'
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='kakaopay',
amount=1000000,
currency='KRW'
)
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
source = Omise::Source.create({
type: 'kakaopay',
amount: 1000000,
currency: 'KRW'
})
source, err := client.Sources().Create(&operations.CreateSource{
Type: "kakaopay",
Amount: 1000000,
Currency: "KRW",
})
レスポンス:
{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "kakaopay",
"flow": "redirect",
"amount": 1000000,
"currency": "KRW"
}
ステップ2: チャージ作成とリダイレクト
app.post('/checkout/kakaopay', async (req, res) => {
try {
const { amount, order_id, customer_email, customer_name } = req.body;
// 金額を検証
if (amount < 10000) { // 最小₩100
return res.status(400).json({
error: '最小金額は₩100です'
});
}
if (amount > 1000000000) { // 最大₩10,000,000
return res.status(400).json({
error: '最大金額は₩10,000,000です'
});
}
// ソースを作成
const source = await omise.sources.create({
type: 'kakaopay',
amount: amount,
currency: 'KRW'
});
// 課金を作成
const charge = await omise.charges.create({
amount: amount,
currency: 'KRW',
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/callback`,
metadata: {
order_id: order_id,
customer_email: customer_email,
customer_name: customer_name,
payment_method: 'kakaopay'
}
});
// KakaoPayにリダイレクト
res.redirect(charge.authorize_uri);
} catch (error) {
console.error('KakaoPay error:', error);
res.status(500).json({ error: error.message });
}
});
ステップ3: 返却コールバックの処理
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 processOrder(charge.metadata.order_id);
res.redirect(`/order-success?order=${charge.metadata.order_id}`);
} else if (charge.status === 'failed') {
res.redirect(`/payment-failed?reason=${charge.failure_message}`);
} else {
res.redirect('/payment-pending');
}
} catch (error) {
res.redirect('/payment-error');
}
});
ステップ4: 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 === 'kakaopay') {
if (charge.status === 'successful') {
await fulfillOrder(charge.metadata.order_id);
await sendConfirmationEmail(charge.metadata.customer_email);
} else if (charge.status === 'failed') {
await handleFailedPayment(charge.metadata.order_id);
}
}
}
res.sendStatus(200);
});
完全な実装例
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});
const app = express();
app.use(express.json());
// KakaoPay設定
const KAKAOPAY_CONFIG = {
currency: 'KRW',
minAmount: 10000, // ₩100
maxAmount: 1000000000, // ₩10,000,000
displayName: 'KakaoPay',
timeout: 10 * 60 * 1000 // 10分
};
// KakaoPay支払いを作成
app.post('/checkout/kakaopay', async (req, res) => {
try {
const { amount, order_id, customer_email, customer_name, customer_phone } = req.body;
// 通貨を検証
if (req.body.currency && req.body.currency !== 'KRW') {
return res.status(400).json({
error: 'KakaoPayはKRW通貨のみをサポートしています'
});
}
// 金額を検証
if (amount < KAKAOPAY_CONFIG.minAmount) {
return res.status(400).json({
error: `最小金額は₩${KAKAOPAY_CONFIG.minAmount / 100}です`
});
}
if (amount > KAKAOPAY_CONFIG.maxAmount) {
return res.status(400).json({
error: `最大金額は₩${KAKAOPAY_CONFIG.maxAmount / 100}です`
});
}
// ソースを作成
const source = await omise.sources.create({
type: 'kakaopay',
amount: amount,
currency: KAKAOPAY_CONFIG.currency
});
// 課金を作成
const charge = await omise.charges.create({
amount: amount,
currency: KAKAOPAY_CONFIG.currency,
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/callback`,
metadata: {
order_id: order_id,
customer_email: customer_email,
customer_name: customer_name,
customer_phone: customer_phone,
payment_method: 'kakaopay'
}
});
// トラッキングのためログ
console.log(`KakaoPay payment initiated: ${charge.id} for order ${order_id}`);
// 認証URLを返す
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id
});
} catch (error) {
console.error('KakaoPay error:', error);
res.status(500).json({ error: error.message });
}
});
// 支払いコールバック
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?charge=${req.query.charge_id}`);
}
} catch (error) {
res.redirect('/payment-error');
}
});
// Webhookハンドラー
app.post('/webhooks/omise', async (req, res) => {
const event = req.body;
if (event.key === 'charge.complete' && event.data.source.type === 'kakaopay') {
const charge = event.data;
if (charge.status === 'successful') {
await fulfillOrder(charge.metadata.order_id);
await sendReceipt(charge.metadata.customer_email, charge);
console.log(`KakaoPay payment successful: ${charge.id}`);
} else {
await cancelOrder(charge.metadata.order_id);
console.log(`KakaoPay payment failed: ${charge.id}`);
}
}
res.sendStatus(200);
});
app.listen(3000);
返金サポート
KakaoPayは365日以内の全額および一部返金をサポートしています:
// 全額返金
const fullRefund = await omise.charges.refund('chrg_test_...', {
amount: 1000000 // 全額
});
// 一部返金
const partialRefund = await omise.charges.refund('chrg_test_...', {
amount: 500000 // 一部金額
});
console.log('Refund status:', fullRefund.status);
返金処理
返金は3〜5営業日以内に顧客のKakaoPayアカウントに処理されます。
よくある問題とトラブルシューティング
問題: 顧客がKakaoTalkを持っていない
原因: 顧客がKakaoTalkアプリを持っていない(韓国では稀)
解決策:
// KakaoTalk要件を表示
function checkKakaoTalk() {
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (!isMobile) {
alert('카카오페이는 모바일에서만 사용 가능합니다.');
return false;
}
// アプリリンクを表示
const isAndroid = /Android/i.test(navigator.userAgent);
const appLink = isAndroid
? 'https://play.google.com/store/apps/details?id=com.kakao.talk'
: 'https://apps.apple.com/kr/app/kakaotalk/id362057947';
showMessage(`카카오톡 앱이 필요합니다. <a href="${appLink}">다운로드</a>`);
return true;
}
問題: 支払い方法が連携されていない
エラー: KakaoPayに支払い方法が連携されていない
解決策:
if (charge.failure_code === 'no_payment_method') {
showMessage(
'카카오페이에 결제수단이 등록되지 않았습니다. ' +
'카카오톡에서 결제수단을 등록해주세요.'
);
showPaymentMethodSetupGuide();
}
問題: 取引限度額超過
エラー: 取引がアカウント制限を超える
解決策:
if (charge.failure_code === 'transaction_limit_exceeded') {
showMessage(
'거래 한도를 초과했습니다. ' +
'본인 인증 후 한도를 늘리거나 다른 결제수단을 이용해주세요.'
);
}
問題: 支払いタイムアウト
原因: 顧客が10分以内に支払いを完了しなかった
解決策:
const TIMEOUT = 10 * 60 * 1000;
setTimeout(() => {
if (!paymentCompleted) {
showMessage('결제 시간이 초과되었습니다. 다시 시도해주세요.');
enableRetry();
}
}, TIMEOUT);
ベストプラクティス
1. 韓国語で表示
<div class="kakaopay-payment">
<h3>카카오페이로 결제</h3>
<div class="logo">
<img src="/icons/kakaopay-logo.svg" alt="카카오페이">
</div>
<div class="instructions">
<ol>
<li>카카오톡 앱이 설치되어 있어야 합니다</li>
<li>카카오페이에 결제수단이 등록되어 있어야 합니다</li>
<li>카카오톡 앱으로 자동 이동합니다</li>
<li>비밀번호 또는 생체인증으로 결제를 승인합니다</li>
</ol>
</div>
<p class="help-text">
카카오페이가 처음이신가요?
<a href="https://www.kakaopay.com" target="_blank">자세히 보기</a>
</p>
</div>
2. モバイルのみ検出
function validateKakaoPayPayment() {
const userAgent = navigator.userAgent;
const isMobile = /Android|iPhone|iPad|iPod/i.test(userAgent);
if (!isMobile) {
return {
valid: false,
message: '카카오페이는 모바일 기기에서만 사용할 수 있습니다'
};
}
return { valid: true };
}
3. ディープリンクの処理
function openKakaoTalkApp(authorizeUri) {
// KakaoPayにリダイレクト
window.location = authorizeUri;
// アプリが開かない場合のフォールバック
setTimeout(() => {
if (!document.hidden) {
showKakaoTalkInstallPrompt();
}
}, 2000);
}
function showKakaoTalkInstallPrompt() {
const isAndroid = /Android/i.test(navigator.userAgent);
const downloadUrl = isAndroid
? 'https://play.google.com/store/apps/details?id=com.kakao.talk'
: 'https://apps.apple.com/kr/app/kakaotalk/id362057947';
if (confirm('카카오톡 앱이 설치되지 않았습니다. 다운로드 하시겠습니까?')) {
window.location = downloadUrl;
}
}
4. 金額のフォーマット
function formatKRW(amount) {
return new Intl.NumberFormat('ko-KR', {
style: 'currency',
currency: 'KRW',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(amount / 100);
}
// 使用方法
const displayAmount = formatKRW(1000000); // "₩10,000"
5. 支払い方法設定を表示
<div class="kakaopay-setup-guide">
<h4>카카오페이 결제수단 등록 방법:</h4>
<ol>
<li>카카오톡 앱 실행</li>
<li>우측 하단 점 3개 메뉴 선택</li>
<li>페이 선택</li>
<li>결제 선택</li>
<li>결제수단 관리</li>
<li>카드, 계좌, 또는 페이머니 등록</li>
</ol>
</div>
使用事例
Eコマース
- 韓国のオンラインショッピングに最適
- 高いコンバージョン率
- 高速チェックアウト体験
デジタルコンテンツ
- 音楽、動画、書籍
- ゲームアイテムとサブスクリプション
- アプリ内購入
フードデリバリー
- 注文の迅速な支払い
- デリバリーアプリと統合
- レストラン支払いで人気