メインコンテンツへスキップ

KakaoPay

シンガポールとタイでKakaoPay決済を受け付けます。複数の東南アジア市場をサポートする統合決済ウォレットです。

概要

KakaoPayは、シンガポールとタイで運営されているデジタルウォレット決済サービスで、eコマースプラットフォームと統合された便利なモバイル決済オプションを顧客に提供します。

主な機能:

  • マルチ地域 - シンガポールとタイで利用可能
  • 高速確認 - ほぼリアルタイムの支払い検証(通常数秒以内)
  • モバイル最適化 - シームレスなスマートフォン体験
  • 迅速なチェックアウト - 高速な支払い承認
  • Eコマース重視 - オンラインショッピングで人気

サポートされている地域

地域通貨最小金額最大金額
シンガポールSGD$1.00$20,000
タイTHB฿20.00฿150,000

仕組み

顧客体験:

  1. 顧客がチェックアウト時にKakaoPayを選択
  2. KakaoPay認証ページにリダイレクト
  3. KakaoTalkアプリが自動的に開く(ディープリンク)
  4. 顧客がKakaoTalkで支払いを確認
  5. パスワード/生体認証/パターンで確認
  6. マーチャントサイトに戻る
  7. 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 https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=kakaopay" \
-d "amount=1000000" \
-d "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コマース

  • 韓国のオンラインショッピングに最適
  • 高いコンバージョン率
  • 高速チェックアウト体験

デジタルコンテンツ

  • 音楽、動画、書籍
  • ゲームアイテムとサブスクリプション
  • アプリ内購入

フードデリバリー

  • 注文の迅速な支払い
  • デリバリーアプリと統合
  • レストラン支払いで人気

サービス

  • 交通(タクシー、バス、駐車場)
  • 美容・ウェルネス予約
  • イベントチケットと予約

テスト

テスト認証情報

Omiseテストモード認証情報を使用:

  • Secret Key: skey_test_YOUR_SECRET_KEY
  • Public Key: pkey_test_YOUR_PUBLIC_KEY

テスト金額

金額(KRW)予想結果
10000 - 999999成功
1000000残高不足
1000001取引拒否

テストフロー

  1. テスト認証情報でチャージを作成
  2. 上記のテスト金額を使用
  3. KakaoPayテスト環境で支払いを完了
  4. Webhookを受信したことを確認
  5. チャージステータスを確認

FAQ

KakaoPayとは何ですか?

KakaoPayは、韓国で90%以上の普及率を誇る国内で最も人気のあるメッセージングアプリであるKakaoTalkに直接統合された、韓国をリードするモバイルウォレットで、3000万人以上のユーザーを持っています。

顧客はKakaoTalkが必要ですか?

はい、KakaoPayはKakaoTalkに統合されているため、顧客はKakaoTalkアプリをインストールする必要があります。これは韓国では標準で、KakaoTalkは90%以上の普及率を持っています。

取引制限は何ですか?
  • 最小: ₩100
  • 最大: 1取引あたり₩10,000,000

制限は顧客のアカウント確認レベル(基本、確認済み、プラス)によって異なります。

決済にはどのくらいの時間がかかりますか?

KakaoPay決済は通常1〜3営業日以内に行われます。特定の決済スケジュールについては、Omiseダッシュボードを確認してください。

KakaoPay支払いを返金できますか?

はい、KakaoPayは元の取引から365日以内の全額および一部返金をサポートしています。

顧客が支払い方法を連携していない場合はどうなりますか?

顧客はKakaoPayを使用する前に、KakaoTalkで支払い方法(クレジットカード、銀行口座、またはKakao Money)を追加する必要があります。支払い方法を追加するには、KakaoTalk設定に誘導してください。

KakaoPayはデスクトップで動作しますか?

いいえ、KakaoPayにはKakaoTalkモバイルアプリが必要です。デスクトップユーザーには、クレジットカードや銀行振込などの代替支払い方法を表示する必要があります。

指示を韓国語で表示する必要がありますか?

はい! KakaoPayは韓国固有であるため、すべての指示とメッセージを韓国語(한국어)で表示することが、最高のユーザー体験のために不可欠です。

テスト

テストモード

KakaoPayは、テストAPIキーを使用してテストできます。テストモードでは:

テスト認証情報:

  • テストAPIキーを使用(skey_test_xxx)
  • 通貨: KRW(韓国ウォン)
  • テストに実際のKakaoPayアカウントは不要

テストフロー:

  1. テストAPIキーでソースとチャージを作成
  2. 顧客がテストauthorize_uriにリダイレクト
  3. テストページがKakaoPay認証をシミュレート
  4. Omiseダッシュボードアクションを使用して、チャージを成功/失敗としてマーク
  5. Webhookとreturn_uri処理を検証

テスト実装:

// KakaoPay支払いをテスト
const source = await omise.sources.create({
type: 'kakaopay',
amount: 10000, // ₩10,000
currency: 'KRW'
});

const charge = await omise.charges.create({
amount: 10000,
currency: 'KRW',
source: source.id,
return_uri: 'https://example.com/callback'
});

console.log('Test authorize URL:', charge.authorize_uri);

テストシナリオ:

  • 支払い成功: 注文完了ワークフローを検証
  • 支払い失敗: エラー処理をテスト
  • 金額制限: 最小および最大金額をテスト
  • モバイルフロー: KakaoTalkアプリへのディープリンクをテスト
  • 残高不足: ウォレット残高不足をシミュレート
  • タイムアウト: 放棄された支払いシナリオをテスト
  • Webhook配信: すべてのWebhook通知を検証

重要な注意事項:

  • テストモードは実際のKakaoPayサーバーに接続しません
  • ダッシュボードを使用して支払い結果をシミュレート
  • モバイルアプリフロー(KakaoTalk統合)をテスト
  • すべてのチャージステータスのWebhook処理を検証
  • KRW通貨の金額検証をテスト

包括的なテストガイドラインについては、テストドキュメントを参照してください。

関連リソース

次のステップ

  1. KakaoPayソースを作成
  2. リダイレクトフローを実装
  3. 返却コールバックを処理
  4. Webhookを設定
  5. 支払いフローをテスト
  6. 本番開始