PayPay
日本で6000万人以上のPayPayユーザーからの支払いを受け付けます。日本のモバイル決済ソリューションの中で最も高い普及率を誇る、国内で最も主要なQRコード決済プラットフォームです。
概要
ユーザー数は概算であり、公開されている情報に基づいています。実際のアクティブユーザー数は異なる場合があります。
PayPayは、SoftBankとYahoo Japanの合弁事業として2018年に開始された、6000万人以上のユーザー(日本の人口のほぼ半分)を持つ日本最大のキャッシュレス決済サービスです。積極的なキャッシュバックキャンペーンと広範な加盟店の採用により、PayPayは急速に市場リーダーとなり、日本の消費者をターゲットとするビジネスにとって不可欠なものとなっています。
主な機能:
- ✅ 6000万人以上のユーザー - 日本を代表する決済アプリの1つ
- ✅ 440万店舗以上 - 全国で利用可能
- ✅ 顧客手数料無料 - 支払いに無料で使用
- ✅ 即時確認 - リアルタイム決済処理
- ✅ リワードプログラム - 購入時にPayPayボーナスポイント
- ✅ 複数の入金源 - 銀行、クレジットカード、コンビニ
サポートされている地域
| Region | Currency | Min Amount | Max Amount | API Version |
|---|---|---|---|---|
| Japan | JPY | ¥100 | ¥1,000,000 | 2017-11-02 |
仕組み
顧客体験:
- 顧客がチェックアウト時に「PayPay」を選択
- PayPay支払いページにリダイレクト
- PayPayアプリが自動的に開く(モバイル)
- 取引詳細を確認
- 必要に応じて認証(PINまたは生体認証)
- ワンタップで支払いを確認
- PayPayボーナスポイントを獲得
- マーチャントウェブサイトに戻る
通常の完了時間: 30-90秒
実装
ステップ1: PayPayソースの作成
- cURL
- Node.js
- PHP
- Python
- Ruby
- Go
- Java
- C#
curl https://api.omise.co/sources \
-u skey_test_YOUR_SECRET_KEY: \
-d "type=paypay" \
-d "amount=100000" \
-d "currency=JPY"
const omise = require('omise')({
secretKey: 'skey_test_YOUR_SECRET_KEY'
});
const source = await omise.sources.create({
type: 'paypay',
amount: 100000, // ¥100,000
currency: 'JPY'
});
<?php
$source = OmiseSource::create(array(
'type' => 'paypay',
'amount' => 100000,
'currency' => 'JPY'
));
?>
import omise
omise.api_secret = 'skey_test_YOUR_SECRET_KEY'
source = omise.Source.create(
type='paypay',
amount=100000,
currency='JPY'
)
require 'omise'
Omise.api_key = 'skey_test_YOUR_SECRET_KEY'
source = Omise::Source.create({
type: 'paypay',
amount: 100000,
currency: 'JPY'
})
source, err := client.Sources().Create(&operations.CreateSource{
Type: "paypay",
Amount: 100000,
Currency: "JPY",
})
Source source = client.sources().create(new Source.CreateParams()
.type("paypay")
.amount(100000L)
.currency("JPY"));
var source = await client.Sources.Create(new CreateSourceRequest
{
Type = "paypay",
Amount = 100000,
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アカウントは不要
テストフロー:
- テストAPIキーでソースとチャージを作成
- 顧客がテスト
authorize_uriにリダイレクト - テストページがPayPay認証をシミュレート
- Omiseダッシュボードアクションを使用して、チャージを成功/失敗としてマーク
- 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通貨処理を検証(小数点なし)
包括的なテストガイドラインについては、テストドキュメントを参照してください。
関連リソース
- デジタルウォレット概要 - すべての電子ウォレットオプション
- Konbini - 日本のコンビニ支払い
- Pay-easy - 日本のオンラインバンキング
- マルチ通貨 - 通貨処理
- テスト - PayPay統合をテスト
- 返金 - 返金ポリシー