要約
iPay APIは、開発者が決済処理・請求書発行・金融取引をプログラムで統合できるRESTful APIです。OAuth 2.0またはAPIキー認証で利用し、支払い・返金・取引・照合のためのエンドポイントを提供。PCI DSS要件やレート制限にも準拠しています。このガイドは、認証設定・決済処理・Webhook統合・セキュリティ・デプロイ戦略の実装方法をステップごとに解説します。
はじめに
世界のデジタル決済処理市場は年間8兆ドルを超えています。Eコマース、SaaS、マーケットプレイスなどの開発者にとって、決済API統合は必須です。安全かつコンプライアンス対応で顧客からの支払いを受け入れるため、失敗時の自動再試行、照合、詐欺検出などの自動化が重要です。
このガイドでは、決済API統合プロセスの全体像を具体的な手順・サンプルコードとともに解説します。認証・決済・返金・Webhook・PCI DSS・デプロイまで、実装に役立つノウハウをまとめました。
💡 Apidogで決済APIテストを効率化
Apidogはサンドボックス決済のテスト、Webhook署名検証、レスポンスチェック、インポート/モック/シナリオ共有まで対応。実装前後の統合テストに最適です。
注意: 本ガイドはiPayおよび類似決済APIの一般的な実装パターンを解説しています。エンドポイントや認証詳細は必ず公式ドキュメントで確認してください。
iPay APIとは?
iPayのような決済APIは、金融取引を処理するRESTfulインターフェースです。主なユースケースは:
- 支払いの承認・確定
- 返金・チャージバック
- 取引履歴・レポート
- 顧客トークン化(カード保存)
- サブスクリプション・定期請求
- 請求書生成・管理
- 照合・決済
- 不正検出・防止
主な機能
| 機能 | 説明 |
|---|---|
| RESTful API | JSONベースのエンドポイント |
| OAuth 2.0 + APIキー | 安全な認証 |
| Webhook | リアルタイム決済通知 |
| トークン化 | 安全なカード保存 |
| 3Dセキュア | SCA準拠 |
| PCI DSS | レベル1準拠 |
| 多通貨対応 | 100+通貨 |
| 不正対策ツール | リスクスコアリング等 |
支払いフローの概要
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Customer │───▶│ Merchant │───▶│ Payment │
│ (Browser) │ │ (Server) │ │ Gateway │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
│ 1. Enter Card │ │
│───────────────────▶│ │
│ │ │
│ 2. Tokenize │ │
│───────────────────▶│ 3. Create Intent │
│ │───────────────────▶│
│ │ │
│ │ 4. Confirm Payment│
│ │───────────────────▶│
│ │ │
│ │ 5. Result │
│ │◀───────────────────│
│ │ │
│ 6. Receipt │ │
│◀───────────────────│ │
API環境
| 環境 | URL | 用途 |
|---|---|---|
| サンドボックス | https://sandbox.ipay.com/api |
開発・テスト |
| 本番環境 | https://api.ipay.com/api |
ライブ取引 |
開始する: 認証設定
ステップ1: iPayアカウントの作成
- iPay販売者登録ページにアクセス
- 事業確認(KYB)を完了
- 必要書類を提出(事業登録/銀行口座/身分証明)
- 承認を待つ(1~3営業日)
ステップ2: API資格情報の取得
- iPayマーチャントダッシュボードにログイン
- 設定 > APIキー へ
- 新しいAPIキーを作成
- 資格情報を安全にコピーし、環境変数で管理
# .env(git管理しないこと)
IPAY_API_KEY="live_xxxxxxxxxxxxxxxxxxxx"
IPAY_API_SECRET="secret_xxxxxxxxxxxxxxxxxxxx"
IPAY_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxx"
セキュリティ注意: サンドボックスと本番で異なるキーを必ず利用。
ステップ3: 認証方法を理解する
| 方法 | 最適用途 | セキュリティ |
|---|---|---|
| Basic認証 | サーバー間通信 | 高 |
| OAuth 2.0 | マルチテナント | より高 |
| JWT | マイクロサービス | 高 |
ステップ4: 認証済みAPIコールの実装
APIクライアントをリユーザブルに実装します。
const IPAY_BASE_URL = process.env.IPAY_SANDBOX
? 'https://sandbox.ipay.com/api'
: 'https://api.ipay.com/api';
const ipayRequest = async (endpoint, options = {}) => {
const apiKey = process.env.IPAY_API_KEY;
const apiSecret = process.env.IPAY_API_SECRET;
const authHeader = Buffer.from(`${apiKey}:${apiSecret}`).toString('base64');
const response = await fetch(`${IPAY_BASE_URL}${endpoint}`, {
...options,
headers: {
'Authorization': `Basic ${authHeader}`,
'Content-Type': 'application/json',
'Idempotency-Key': options.idempotencyKey || generateIdempotencyKey(),
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`iPay API Error: ${error.message}`);
}
return response.json();
};
function generateIdempotencyKey() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// 使用例
const account = await ipayRequest('/account');
console.log(`Merchant: ${account.business_name}`);
決済処理
支払いインテントの作成
const createPayment = async (paymentData) => {
const payment = {
amount: paymentData.amount,
currency: paymentData.currency || 'USD',
customer: paymentData.customerId,
payment_method: paymentData.paymentMethodId,
confirm: true,
description: paymentData.description,
metadata: {
orderId: paymentData.orderId,
customerId: paymentData.customerId
},
capture_method: paymentData.captureMethod || 'automatic',
statement_descriptor: paymentData.statementDescriptor || 'MYCOMPANY'
};
const response = await ipayRequest('/payments', {
method: 'POST',
body: JSON.stringify(payment),
idempotencyKey: paymentData.idempotencyKey
});
return response;
};
// 使用例
const payment = await createPayment({
amount: 2999, // $29.99
currency: 'USD',
customerId: 'cus_12345',
paymentMethodId: 'pm_67890',
description: 'Order #ORD-001',
orderId: 'ORD-001',
statementDescriptor: 'MYCOMPANY INC'
});
console.log(`支払いステータス: ${payment.status}`);
console.log(`支払いID: ${payment.id}`);
支払いステータスフロー
requires_payment_method → requires_confirmation → requires_action
→ processing → requires_capture → succeeded
→ failed
→ canceled
支払い方法
| 方法 | 種類 | 用途 |
|---|---|---|
card |
クレジット/デビット | 標準支払い |
bank_transfer |
ACH, SEPA | 低手数料送金 |
digital_wallet |
Apple/Google Pay | モバイル決済 |
buy_now_pay_later |
Klarna, Afterpay等 | 分割払い |
カード情報のトークン化
const tokenizeCard = async (cardData) => {
// 生カード情報はサーバー送信禁止。必ずクライアントでトークン化。
const response = await fetch(`${IPAY_BASE_URL}/tokens`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CLIENT_PUBLISHABLE_KEY}`
},
body: JSON.stringify({
card: {
number: cardData.number,
exp_month: cardData.expMonth,
exp_year: cardData.expYear,
cvc: cardData.cvc
}
})
});
const token = await response.json();
return token; // token.idをサーバーへ渡す
};
// サーバー側: トークンで支払い方法作成
const createPaymentMethod = async (tokenId, customerId) => {
const response = await ipayRequest('/payment_methods', {
method: 'POST',
body: JSON.stringify({
type: 'card',
token: tokenId,
customer: customerId
})
});
return response;
};
3Dセキュア認証(SCA)
const createPaymentWith3DS = async (paymentData) => {
const payment = await createPayment({
...paymentData,
confirmation_token: true
});
if (payment.status === 'requires_action') {
// クライアントで3Dセキュア認証を実行
return {
requiresAction: true,
clientSecret: payment.client_secret,
nextAction: payment.next_action
};
}
return { success: true, payment };
};
// クライアント: iPay.jsやSDKで認証チャレンジを処理
返金管理
全額返金
const refundPayment = async (paymentId, reason = null) => {
const refund = {
payment: paymentId,
reason: reason || 'requested_by_customer'
};
const response = await ipayRequest('/refunds', {
method: 'POST',
body: JSON.stringify(refund),
idempotencyKey: `refund_${paymentId}_${Date.now()}`
});
return response;
};
// 使用例
const refund = await refundPayment('pay_12345', 'duplicate');
console.log(`返金ステータス: ${refund.status}`);
console.log(`返金ID: ${refund.id}`);
一部返金
const partialRefund = async (paymentId, amount, reason = null) => {
const refund = {
payment: paymentId,
amount: amount,
reason: reason || 'requested_by_customer'
};
const response = await ipayRequest('/refunds', {
method: 'POST',
body: JSON.stringify(refund),
idempotencyKey: `refund_${paymentId}_${amount}_${Date.now()}`
});
return response;
};
// 使用例
const refund = await partialRefund('pay_12345', 1500, 'partial_ship');
console.log(`返金済み: $${refund.amount / 100}`);
返金理由コード
| 理由コード | 説明 |
|---|---|
duplicate |
重複請求 |
fraudulent |
不正取引 |
requested_by_customer |
顧客要求 |
order_canceled |
注文キャンセル |
product_not_received |
商品未配達 |
product_not_as_described |
商品説明と異なる |
顧客管理
顧客の作成
const createCustomer = async (customerData) => {
const customer = {
email: customerData.email,
name: customerData.name,
phone: customerData.phone,
metadata: {
internalId: customerData.internalId,
tier: customerData.tier
}
};
const response = await ipayRequest('/customers', {
method: 'POST',
body: JSON.stringify(customer)
});
return response;
};
// 使用例
const customer = await createCustomer({
email: 'customer@example.com',
name: 'John Doe',
phone: '+1-555-0123',
internalId: 'USR-12345',
tier: 'premium'
});
console.log(`顧客が作成されました: ${customer.id}`);
顧客に支払い方法を紐付け
const attachPaymentMethod = async (paymentMethodId, customerId) => {
const response = await ipayRequest(`/payment_methods/${paymentMethodId}/attach`, {
method: 'POST',
body: JSON.stringify({ customer: customerId })
});
return response;
};
// 使用例
await attachPaymentMethod('pm_67890', 'cus_12345');
顧客の支払い方法一覧
const getCustomerPaymentMethods = async (customerId) => {
const response = await ipayRequest(`/customers/${customerId}/payment_methods`);
return response;
};
// 使用例
const methods = await getCustomerPaymentMethods('cus_12345');
methods.data.forEach(method => {
console.log(`${method.card.brand} (下4桁: ${method.card.last4})`);
console.log(`有効期限: ${method.card.exp_month}/${method.card.exp_year}`);
});
Webhook
Webhookの設定手順
- iPayダッシュボードにログイン
- 開発者 > Webhook へ
- エンドポイントを追加 をクリック
- HTTPS URLを入力
- イベントを選択して購読
Webhookイベント
| イベント | トリガー |
|---|---|
payment.succeeded |
支払い完了時 |
payment.failed |
支払い拒否時 |
payment.refunded |
返金処理完了時 |
payment.disputed |
チャージバック申請時 |
customer.created |
新規顧客作成時 |
customer.subscription.updated |
サブスクリプション変更時 |
Webhook受信・署名検証・処理
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/ipay', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['ipay-signature'];
const payload = req.body;
// 署名検証
const isValid = verifyWebhookSignature(payload, signature, process.env.IPAY_WEBHOOK_SECRET);
if (!isValid) {
console.error('無効なWebhook署名');
return res.status(401).send('Unauthorized');
}
const event = JSON.parse(payload.toString());
switch (event.type) {
case 'payment.succeeded':
await handlePaymentSucceeded(event.data);
break;
case 'payment.failed':
await handlePaymentFailed(event.data);
break;
case 'payment.refunded':
await handlePaymentRefunded(event.data);
break;
case 'payment.disputed':
await handlePaymentDisputed(event.data);
break;
default:
console.log('未処理のイベントタイプ:', event.type);
}
res.status(200).send('OK');
});
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
async function handlePaymentSucceeded(data) {
console.log(`支払いが成功しました: ${data.id}`);
// 注文ステータス更新
await db.orders.update(data.metadata.orderId, {
status: 'paid',
paymentId: data.id,
paidAt: new Date()
});
await sendOrderConfirmation(data.metadata.orderId);
}
async function handlePaymentFailed(data) {
console.log(`支払いが失敗しました: ${data.id} - ${data.failure_code}`);
await sendPaymentFailedEmail(data.customer, data.failure_message);
await db.orders.update(data.metadata.orderId, {
status: 'payment_failed',
failureReason: data.failure_message
});
}
セキュリティとコンプライアンス
PCI DSS要件
| 要件 | 実装例 |
|---|---|
| 安全なネットワーク | HTTPS・ファイアウォール・設定管理 |
| カードデータ保護 | CVV非保存・PAN暗号化 |
| 脆弱性管理 | 定期アップデート・アンチウイルス |
| アクセス制御 | 最小特権・MFA・固有ID |
| 監視 | ロギング・侵入検知 |
| セキュリティポリシー | 文書化・定期トレーニング |
セキュリティベストプラクティス
// 1. トークン化利用(生カードデータは触らない)
const token = await tokenizeCard(cardData);
// 2. べき等性キーで重複防止
const idempotencyKey = `pay_${orderId}_${Date.now()}`;
// 3. 金額検証(改ざん防止)
if (req.body.amount !== calculatedAmount) {
throw new Error('Amount mismatch - possible tampering');
}
// 4. ロギング(カード・機密情報は絶対に記録しない)
logger.info('Payment attempted', {
orderId,
amount,
currency,
customerId,
timestamp: new Date().toISOString()
});
// 5. 環境変数でAPIキー管理
const apiKey = process.env.IPAY_API_KEY;
// 6. レート制限
const paymentLimiter = rateLimit({
windowMs: 60000,
max: 10 // 1分あたり10回まで
});
本番環境デプロイチェックリスト
- [ ] PCI DSS自己評価質問票を完了
- [ ] すべてのエンドポイントでHTTPS利用
- [ ] APIキーはシークレット管理
- [ ] Webhook署名検証を実装
- [ ] べき等性対応
- [ ] ロギング(機密情報除外)
- [ ] 不正検出ルール設定
- [ ] 返金・異議申立てフローのテスト
- [ ] 決済失敗時の運用Runbook作成
- [ ] 監視・アラート設定
- [ ] バックアップ決済プロセッサの実装
実世界のユースケース
Eコマースのチェックアウト
- 課題: 手動決済・高いカゴ落ち率
- 解決: トークン化カードによるワンページ決済
- 結果: コンバージョン率35%向上・即時決済
SaaSのサブスクリプション請求
- 課題: 請求書生成・回収の手間
- 解決: 自動再試行付サブスク決済
- 結果: 期日通り95%、管理時間80%削減
マーケットプレイスのエスクロー
- 課題: 複雑な分割支払い
- 解決: スケジュール送金付きインテント
- 結果: 業者への自動支払い、不正減少
まとめ
決済API統合のポイント:
- 生カードデータは絶対に取り扱わず、トークン化を徹底
- すべての支払い操作でべき等性実装
- Webhook署名検証で不正防止
- PCI DSS完全準拠
- 本番前はサンドボックスで徹底テスト
- ApidogでAPIテスト&コラボレーションを効率化
よくある質問
iPay APIで認証するには?
APIキー+シークレットでBasic認証、またはOAuth 2.0(マルチテナント向け)を利用。
顧客のカード情報は保存できますか?
はい、PCI DSS準拠なら可能。必ずトークン化し、iPayのボルトに保管してください。
支払い失敗時のベストプラクティスは?
指数バックオフで再試行・顧客通知・代替支払い手段の提示を実装。
べき等性とは?
同じキーの重複リクエストで結果が重複しないよう保証することで、二重請求を防げます。
テストカードでの支払いテスト方法は?
iPay公式ドキュメントのテストカード番号+サンドボックス環境を使用。
Webhook署名とは?
WebhookがiPayから発信されていることを保証する暗号署名です。
Top comments (0)