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

PayPay

日本で6000万人以上のPayPayユーザーからの支払いを受け付けます。日本のモバイル決済ソリューションの中で最も高い普及率を誇る、国内で最も主要なQRコード決済プラットフォームです。

概要

ユーザー統計

ユーザー数は概算であり、公開されている情報に基づいています。実際のアクティブユーザー数は異なる場合があります。

PayPayは、SoftBankとYahoo Japanの合弁事業として2018年に開始された、6000万人以上のユーザー(日本の人口のほぼ半分)を持つ日本最大のキャッシュレス決済サービスです。積極的なキャッシュバックキャンペーンと広範な加盟店の採用により、PayPayは急速に市場リーダーとなり、日本の消費者をターゲットとするビジネスにとって不可欠なものとなっています。

主な機能:

  • 6000万人以上のユーザー - 日本を代表する決済アプリの1つ
  • 440万店舗以上 - 全国で利用可能
  • 顧客手数料無料 - 支払いに無料で使用
  • 即時確認 - リアルタイム決済処理
  • リワードプログラム - 購入時にPayPayボーナスポイント
  • 複数の入金源 - 銀行、クレジットカード、コンビニ

サポートされている地域

地域通貨最小金額最大金額1日の制限
日本JPY¥100¥500,000入金源により異なります*

*1日の制限は顧客の入金源と確認レベルによって異なります:

  • PayPay残高: 1日最大¥500,000(確認済みユーザー)
  • 連携銀行口座: 1日最大¥500,000
  • クレジットカード: カードの制限に従います

仕組み

顧客体験:

  1. 顧客がチェックアウト時に「PayPay」を選択
  2. PayPay支払いページにリダイレクト
  3. PayPayアプリが自動的に開く(モバイル)
  4. 取引詳細を確認
  5. 必要に応じて認証(PINまたは生体認証)
  6. ワンタップで支払いを確認
  7. PayPayボーナスポイントを獲得
  8. マーチャントウェブサイトに戻る

通常の完了時間: 30-90秒

実装

ステップ1: PayPayソースの作成

curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=paypay" \
-d "amount=100000" \
-d "currency=JPY"

レスポンス:

{
"object": "source",
"id": "src_test_5rt6s9vah5lkvi1rh9c",
"type": "paypay",
"flow": "redirect",
"amount": 100000,
"currency": "JPY"
}

ステップ2: チャージの作成

curl https://api.omise.co/charges \
-u skey_test_YOUR_SECRET_KEY: \
-d "amount=100000" \
-d "currency=JPY" \
-d "source=src_test_5rt6s9vah5lkvi1rh9c" \
-d "return_uri=https://yourdomain.com/payment/callback"

ステップ3: 顧客のリダイレクト

app.post('/checkout/paypay', async (req, res) => {
try {
const { amount, order_id, customer_email } = req.body;

// 金額を検証(¥100 - ¥500,000)
if (amount < 100 || amount > 500000) {
return res.status(400).json({
error: '金額は¥100から¥500,000の間である必要があります'
});
}

// ソースを作成
const source = await omise.sources.create({
type: 'paypay',
amount: amount,
currency: 'JPY'
});

// チャージを作成
const charge = await omise.charges.create({
amount: amount,
currency: 'JPY',
source: source.id,
return_uri: `${process.env.BASE_URL}/payment/callback`,
metadata: {
order_id: order_id,
customer_email: customer_email
}
});

// PayPayにリダイレクト
res.redirect(charge.authorize_uri);

} catch (error) {
console.error('PayPay error:', error);
res.status(500).json({ error: error.message });
}
});

ステップ4: 返却の処理

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('/payment-success');
} else if (charge.status === 'failed') {
res.redirect('/payment-failed?reason=' + charge.failure_message);
} else {
res.redirect('/payment-pending');
}
} catch (error) {
res.redirect('/payment-error');
}
});

ステップ5: Webhookの処理

app.post('/webhooks/omise', (req, res) => {
const event = req.body;

if (event.key === 'charge.complete' && event.data.source.type === 'paypay') {
const charge = event.data;

if (charge.status === 'successful') {
processOrder(charge.metadata.order_id);
sendConfirmationEmail(charge.metadata.customer_email);

// 成功した支払いをログ
console.log(`PayPay payment successful: ${charge.id}`);
} else if (charge.status === 'failed') {
handleFailedPayment(charge.metadata.order_id);
}
}

res.sendStatus(200);
});

完全な実装例

// Express.jsサーバー
const express = require('express');
const omise = require('omise')({
secretKey: process.env.OMISE_SECRET_KEY
});

const app = express();
app.use(express.json());

app.post('/checkout/paypay', async (req, res) => {
try {
const { amount, order_id, customer_email, customer_name } = req.body;

// 金額を検証(¥100 - ¥500,000)
if (amount < 100 || amount > 500000) {
return res.status(400).json({
error: '金額は¥100から¥500,000の間である必要があります'
});
}

// 推定PayPayボーナスポイントを計算(例: 0.5%)
const estimatedBonus = Math.floor(amount * 0.005);

// ソースを作成
const source = await omise.sources.create({
type: 'paypay',
amount: amount,
currency: 'JPY'
});

// チャージを作成
const charge = await omise.charges.create({
amount: amount,
currency: 'JPY',
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: 'paypay',
estimated_bonus: estimatedBonus
}
});

// 認証URLを返す
res.json({
authorize_uri: charge.authorize_uri,
charge_id: charge.id,
estimated_bonus: estimatedBonus
});

} catch (error) {
console.error('PayPay error:', error);
res.status(500).json({ error: error.message });
}
});

// コールバックハンドラー
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') {
const bonus = charge.metadata.estimated_bonus || 0;
res.redirect(`/order-success?order=${charge.metadata.order_id}&bonus=${bonus}`);
} else {
res.redirect(`/payment-failed?charge=${chargeId}`);
}
} catch (error) {
res.redirect('/payment-error');
}
});

// Webhookハンドラー
app.post('/webhooks/omise', (req, res) => {
const event = req.body;

if (event.key === 'charge.complete') {
const charge = event.data;

if (charge.source.type === 'paypay') {
if (charge.status === 'successful') {
updateOrderStatus(charge.metadata.order_id, 'paid');
sendConfirmation(charge.metadata.customer_email, {
amount: charge.amount,
bonus: charge.metadata.estimated_bonus
});

console.log(`PayPay payment successful: ${charge.id}`);
} else {
updateOrderStatus(charge.metadata.order_id, 'failed');
console.log(`PayPay payment failed: ${charge.id}`);
}
}
}

res.sendStatus(200);
});

// ヘルパー関数
async function updateOrderStatus(orderId, status) {
await db.orders.update({ id: orderId }, { status: status });
}

async function sendConfirmation(email, details) {
// PayPayボーナス情報を含むメール確認を送信
}

app.listen(3000);

返金サポート

PayPayは60日以内全額および一部返金をサポートしています:

// 全額返金
const fullRefund = await omise.charges.refund('chrg_test_...', {
amount: 100000
});

// 一部返金
const partialRefund = await omise.charges.refund('chrg_test_...', {
amount: 50000 // 半額返金
});
返金タイムライン
  • 返金は1〜2営業日以内に処理されます
  • 顧客はPayPay残高で返金を受け取ります
  • PayPayボーナスポイントは自動的に調整されます
  • 元の取引から60日以内にサポート
返金ポリシー

返金期間とポリシーは変更される場合があります。Omise APIドキュメントまたはマーチャントダッシュボードで常に現在の返金機能を確認してください。

よくある問題とトラブルシューティング

問題: PayPayアプリがインストールされていない

原因: 顧客がPayPayアプリをインストールしていない

解決策:

function checkPayPayApp() {
const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);

if (isMobile) {
return `
<div class="paypay-app-check">
<p>PayPayアプリが必要です。</p>
<div class="download-links">
<a href="https://play.google.com/store/apps/details?id=jp.ne.paypay.android.app">
<img src="/images/google-play-badge-jp.png" alt="Google Playで入手">
</a>
<a href="https://apps.apple.com/jp/app/paypay/id1435783608">
<img src="/images/app-store-badge-jp.png" alt="App Storeからダウンロード">
</a>
</div>
</div>
`;
}
}

問題: 残高不足

原因: 顧客のPayPay残高が少なく、バックアップ支払い方法がない

解決策:

<div class="paypay-balance-info">
<h3>PayPayの残高が不足しています</h3>
<p>以下の方法でチャージしてください:</p>

<ul class="charge-methods">
<li>🏦 <strong>銀行口座</strong> - リアルタイムチャージ</li>
<li>🏧 <strong>セブン銀行ATM</strong> - 現金チャージ</li>
<li>🏪 <strong>ローソン</strong> - レジでチャージ</li>
<li>💳 <strong>クレジットカード</strong> - 登録して自動チャージ</li>
<li>👥 <strong>PayPay残高の送受信</strong> - 友達から受け取る</li>
</ul>

<p class="amount-needed">必要金額: <strong>¥{{amount}}</strong></p>
</div>

問題: 1日の制限を超過

原因: 顧客が1日または1か月の制限に達した

解決策:

function handlePayPayLimitExceeded() {
return {
error: '利用限度額を超過しました',
message: 'PayPayの1日または1か月の利用限度額に達しました。',
solutions: [
{
title: '本人確認を完了する',
description: '本人確認済みアカウントは¥500,000/日まで利用可能',
steps: [
'PayPayアプリを開く',
'アカウント > 本人確認',
'身分証明書をアップロード',
'審査完了まで数時間待つ'
]
},
{
title: '別の支払い方法を使用',
description: 'クレジットカードや他の決済方法をご利用ください'
},
{
title: '明日再試行',
description: '利用限度額は毎日0時にリセットされます'
}
]
};
}

問題: 支払い認証に失敗

原因: 顧客がPINまたは生体認証に失敗

解決策:

function handleAuthenticationError() {
return `
<div class="auth-error">
<h3>認証に失敗しました</h3>
<p>以下をお試しください:</p>
<ul>
<li>PINコードを再入力してください</li>
<li>生体認証を再試行してください</li>
<li>PayPayアプリを再起動してください</li>
<li>PINをお忘れの場合は、PayPayアプリで再設定してください</li>
</ul>
<button onclick="retryPayment()">再試行</button>
</div>
`;
}

問題: 支払いタイムアウト

原因: 顧客が制限時間内に支払いを完了しなかった

解決策:

// 5分の支払いウィンドウ
const PAYMENT_TIMEOUT = 5 * 60 * 1000;

setTimeout(() => {
if (!paymentConfirmed) {
showMessage('お支払いの有効期限が切れました。もう一度やり直してください。');
enableRetryButton();
}
}, PAYMENT_TIMEOUT);

ベストプラクティス

1. PayPayのメリットを表示(日本語UI)

<div class="paypay-benefits">
<img src="/images/paypay-logo.svg" alt="PayPay" height="40">
<h3>PayPayで支払う</h3>
<ul class="benefits-list">
<li>✓ 即時決済確認</li>
<li>✓ PayPayボーナスポイント獲得</li>
<li>✓ 安全なPIN/生体認証</li>
<li>✓ 手数料無料</li>
<li>✓ 日本全国440万店舗以上で利用可能</li>
</ul>
<p class="bonus-note">
🎁 この購入で<strong>約{{points}}円相当</strong>のPayPayボーナスを獲得
</p>
</div>

2. バイリンガルサポートを提供

function getPayPayInstructions(language = 'ja') {
const instructions = {
'ja': {
title: 'PayPayでのお支払い方法',
steps: [
'「PayPayで支払う」をクリック',
'PayPayアプリが自動的に開きます',
'取引内容を確認',
'PINまたは生体認証で認証',
'お支払いを確定'
]
},
'en': {
title: 'How to pay with PayPay',
steps: [
'Click "Pay with PayPay"',
'PayPay app will open automatically',
'Review transaction details',
'Authenticate with PIN or biometric',
'Confirm payment'
]
}
};

return instructions[language] || instructions['ja'];
}

3. モバイルディープリンクの処理

function openPayPayApp(authorizeUri) {
const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);

if (isMobile) {
// PayPayアプリを開こうとする
window.location = authorizeUri;

// 2秒後のフォールバック
setTimeout(() => {
if (!document.hidden) {
showInstallAppMessage();
}
}, 2000);
} else {
// デスクトップ: QRコードまたはWebインターフェースを表示
window.location = authorizeUri;
}
}

4. 金額制限の検証

function validatePayPayAmount(amount) {
const MIN = 100; // ¥100
const MAX = 500000; // ¥500,000

if (amount < MIN) {
return `最小金額は¥${MIN}です`;
}

if (amount > MAX) {
return `最大金額は¥${MAX}です`;
}

return null; // 有効
}

5. PayPayボーナス推定値の表示

function calculatePayPayBonus(amount) {
// 基本レート: 0.5%(キャンペーンにより異なる)
const baseRate = 0.005;
const bonusAmount = Math.floor(amount * baseRate);

return {
amount: bonusAmount,
formatted: `¥${bonusAmount.toLocaleString('ja-JP')}`,
message: `この購入で約${bonusAmount}円相当のPayPayボーナスを獲得できます`
};
}

6. 信頼性のためWebhooksを使用

// Webhookは主要な通知方法
app.post('/webhooks/omise', handleWebhook);

// コールバックはUI更新のバックアップ
app.get('/payment/callback', handleCallback);

// 注文処理のためにコールバックのみに依存しない

FAQ

PayPayとは何ですか?

PayPayは、6000万人以上のユーザー(日本の人口のほぼ半分)を持つ日本最大のモバイル決済サービスです。2018年に開始され、ユーザーはQRコードでキャッシュレス決済を行い、友達にお金を送り、PayPayボーナスポイントを獲得できます。日本全国440万店舗以上で利用可能です。

顧客は日本の銀行口座が必要ですか?

必ずしも必要ありません。顧客は以下の方法でPayPayアカウントに入金できます:

  • 日本の銀行口座(最も一般的)
  • クレジットカード(Visa、Mastercard、JCB)
  • コンビニまたはATMで現金
  • 他のPayPayユーザーから送金を受け取る

ただし、ほとんどのPayPayユーザーは日本の銀行口座を持つ日本在住者です。

取引制限は何ですか?

制限は入金源と確認レベルによって異なります:

  • 1取引あたり: ¥100 - ¥500,000
  • 未確認アカウント: ¥100,000/日、¥500,000/月
  • 確認済みアカウント: ¥500,000/日、¥2,000,000/月
  • ブルーバッジ(法人): より高い制限が利用可能
顧客はPayPayボーナスをどのように獲得しますか?

顧客は購入時に自動的にPayPayボーナスポイントを獲得します。基本レートは通常0.5%ですが、PayPayは頻繁に高いボーナスレート(時には20〜30%まで)を提供するキャンペーンを実施しています。ボーナス金額は以下に依存します:

  • 基本支払いボーナス(0.5%)
  • キャンペーンボーナス
  • 支払い方法(PayPay残高 vs クレジットカード)
  • マーチャント固有のキャンペーン
PayPay支払いを返金できますか?

はい、PayPayは元の取引から60日以内の全額および一部返金をサポートしています。返金は1〜2営業日以内に顧客のPayPay残高に返され、獲得したPayPayボーナスは自動的に調整されます。

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

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

PayPayは24時間365日利用可能ですか?

はい、PayPay決済は週末や休日を含む24時間365日処理できます。ただし、マーチャントアカウントへの決済は営業日のスケジュールに従います。

日本語サポートを提供する必要がありますか?

はい、強く推奨されます。多くの若い日本人ユーザーは英語インターフェースを操作できますが、日本語サポートを提供することでコンバージョン率が大幅に向上します。最低限、以下を提供してください:

  • 日本語の支払いボタン(「PayPayで支払う」)
  • 日本語のエラーメッセージ
  • 日本語の基本的な指示
PayPayとLINE Payの違いは何ですか?

どちらも日本で人気がありますが、PayPayの市場シェアははるかに高いです:

  • PayPay: 6000万人以上のユーザー、No.1の市場シェア、QRコード重視、広範な受け入れ
  • LINE Pay: 4000万人のユーザー、LINEメッセージングと統合、LINEエコシステムに適している

日本で最大のリーチを得るには、両方を受け入れることを検討してください。

テスト

テストモード

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

テスト認証情報:

  • テストAPIキーを使用(skey_test_xxx)
  • 通貨: JPY(日本円)
  • テストに実際のPayPayアカウントは不要

テストフロー:

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

テスト実装:

// PayPay支払いをテスト
const source = await omise.sources.create({
type: 'paypay',
amount: 100000, // ¥100,000
currency: 'JPY'
});

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

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

テストシナリオ:

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

重要な注意事項:

  • テストモードは実際のPayPayサーバーに接続しません
  • ダッシュボードを使用して支払い結果をシミュレート
  • モバイルアプリフロー(PayPayアプリ統合)を徹底的にテスト
  • すべてのチャージステータスのWebhook処理を検証
  • UIで日本語サポートをテスト
  • JPY通貨処理を検証(小数点なし)

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

関連リソース

次のステップ

  1. PayPayソースを作成
  2. リダイレクトフローを実装
  3. Webhook処理を設定
  4. 日本語サポートを追加
  5. 支払いフローをテスト
  6. 本番開始