要約
iPay APIは、開発者が決済処理、請求書発行、金融取引をプログラムで統合することを可能にします。OAuth 2.0とAPIキー認証を使用し、支払い、返金、取引、照合のためのRESTfulエンドポイントを提供します。PCI DSSコンプライアンス要件と業界標準のレート制限に従います。このガイドでは、認証設定、決済処理、Webhook統合、セキュリティコンプライアンス、本番環境へのデプロイ戦略について説明します。
はじめに
世界のデジタル決済処理は年間8兆ドルを超えます。Eコマースプラットフォーム、SaaSアプリケーション、またはマーケットプレイスソリューションを構築する開発者にとって、決済APIの統合は選択肢ではなく、顧客からの支払いを安全かつコンプライアンスに準拠して受け入れるために不可欠です。
現実として、企業は支払い失敗、手動による照合、支払い詐欺により収益の5~10%を失っています。堅牢な決済API統合は、決済処理を自動化し、スマートな再試行ロジックで失敗を減らし、自動照合を可能にし、不正検出を実装します。
このガイドでは、決済APIの統合プロセス全体を順を追って説明します。認証設定、決済処理、返金管理、Webhook処理、PCI DSS準拠、セキュリティのベストプラクティス、および本番環境へのデプロイ戦略について学びます。読み終える頃には、本番環境に対応した決済統合を完成させることができるでしょう。
ボタン
注意: このガイドは、iPayおよび類似の決済プロセッサーに適用される一般的な決済API統合パターンを扱っています。特定のエンドポイントURLや認証の詳細は異なる場合がありますので、実装の詳細については常に公式のiPayドキュメントを参照してください。
iPay APIとは?
iPayのような決済APIは、金融取引を処理するためのRESTfulなインターフェースを提供します。APIが扱う内容は以下の通りです。
- 支払いの承認と確定
- 返金とチャージバック
- 取引履歴とレポート
- 顧客のトークン化(保管)
- サブスクリプションと定期請求
- 請求書生成と管理
- 照合と決済
- 不正検出と防止
主な機能
| 機能 | 説明 |
|---|---|
| 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アカウントの作成
APIにアクセスする前に:
- iPay販売者登録ページにアクセス
- 事業確認 (KYB) を完了
- 必要書類を提出:
- 事業登録
- 銀行口座の詳細
- 公的身分証明書
- 承認を待つ(1~3営業日)
ステップ2: API資格情報の取得
API資格情報を生成:
- iPayマーチャントダッシュボードにログイン
- 設定 > APIキー に移動
- 新しいAPIキーを作成
- 資格情報を安全にコピー
# .env file (NEVER commit to git)
IPAY_API_KEY="live_xxxxxxxxxxxxxxxxxxxx"
IPAY_API_SECRET="secret_xxxxxxxxxxxxxxxxxxxx"
IPAY_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxx"
セキュリティに関する注意: サンドボックスと本番環境で異なるキーを使用してください。
ステップ3: 認証方法を理解する
iPayは複数の認証方法をサポートしています:
| 方法 | 最適な用途 | セキュリティレベル |
|---|---|---|
| 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;
// Basic authentication (Base64 encoded)
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, // In smallest currency unit (cents)
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', // 'automatic' or 'manual'
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 Pay、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; // Send token.id to your server
};
// サーバーサイド: トークンを使用して支払い方法を作成
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 // Return client secret for 3DS
});
if (payment.status === 'requires_action') {
// クライアントは3Dセキュア認証を完了する必要があります
return {
requiresAction: true,
clientSecret: payment.client_secret,
nextAction: payment.next_action
};
}
return { success: true, payment };
};
// クライアントサイド: 3Dセキュア認証を処理
// 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, // In smallest currency unit
reason: reason || 'requested_by_customer'
};
const response = await ipayRequest('/refunds', {
method: 'POST',
body: JSON.stringify(refund),
idempotencyKey: `refund_${paymentId}_${amount}_${Date.now()}`
});
return response;
};
// 使用例 - $29.99の支払いから$15.00を返金
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の設定
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;
// Webhook署名を検証
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要件
決済統合は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()
// ログに記録しないでください: カード番号、CVV、支払い方法の詳細すべて
});
// 5. 機密情報には環境変数を使用
const apiKey = process.env.IPAY_API_KEY; // ハードコードしない
// 6. 支払いエンドポイントにレート制限を実装
const paymentLimiter = rateLimit({
windowMs: 60000,
max: 10 // 1分あたり10回の支払い試行
});
本番環境デプロイチェックリスト
ライブ決済を処理する前に:
- [ ] PCI DSS自己評価質問票を完了する
- [ ] すべてのエンドポイントでHTTPSを使用する
- [ ] APIキーを安全なシークレット管理に保存する
- [ ] Webhook署名検証を実装する
- [ ] すべての支払い操作にべき等性を追加する
- [ ] 包括的なロギングを設定する(機密データなし)
- [ ] 不正検出ルールを設定する
- [ ] 返金および異議申し立てのフローをテストする
- [ ] 支払い失敗時のランブックを作成する
- [ ] 監視とアラートを設定する
- [ ] バックアップ決済プロセッサーを実装する
実世界のユースケース
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から送信されたものであり、悪意のあるアクターからではないことを検証する暗号化署名です。
