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

概要

ZAFA PAYの決済ページをiframeで埋め込むことで、ユーザーをリダイレクトせずに自社サイト内で決済を完結させることができます。

結果通知方式

決済結果の通知方式は2種類あります。
方式説明用途
postMessageJavaScriptで親ウィンドウにイベント送信SPAなどJavaScript制御が可能な場合
リダイレクト親ウィンドウごとリダイレクトサーバーサイドで結果を処理したい場合
利用する方式は加盟店ごとに事前に設定されます。変更が必要な場合はサポートにお問い合わせください。

実装手順

1. 決済リクエストを作成

通常通りPOST /v1/paymentsで決済リクエストを作成します。レスポンスのpayment_urlを取得します。
curl -X POST https://api.sandbox.zafapay.com/v1/payments \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100,
    "currency": "usd",
    "external_id": "order_12345",
    "success_redirect_url": "https://your-site.com/success",
    "failure_redirect_url": "https://your-site.com/failure"
  }'

2. iframeに埋め込む

payment_url?mode=embeddedパラメータを追加してiframeに設定します。
<iframe
  src="https://pay.zafapay.com/checkout/req_xxx?token=xxx&mode=embedded"
  width="100%"
  height="700"
  style="border: none;"
  allow="payment"
></iframe>
mode=embeddedパラメータは必須です。これがないと、決済完了時にリダイレクトが発生します。

postMessage方式

postMessage方式が設定されている場合、決済の結果はJavaScriptのpostMessageで親ウィンドウに通知されます。

イベントを受信

window.addEventListener('message', function(event) {
  // セキュリティ: オリジンを検証
  if (event.origin !== 'https://pay.zafapay.com') {
    return;
  }

  const data = event.data;
  if (!data || !data.type) return;

  switch (data.type) {
    case 'payment_success':
      console.log('決済成功:', data.transactionId);
      // 成功処理
      break;
    case 'payment_failed':
      console.log('決済失敗:', data.error);
      // 失敗処理
      break;
    case 'payment_cancel':
      console.log('キャンセル');
      // キャンセル処理
      break;
    case 'redirect_required':
      console.log('リダイレクトが必要:', data.url);
      // 3Dセキュア等のリダイレクト処理
      window.open(data.url, '_blank');
      break;
  }
});

イベントタイプ

イベント説明含まれるデータ
payment_success決済成功transactionId, requestId
payment_failed決済失敗error, code
payment_cancelユーザーがキャンセルなし
redirect_required3Dセキュア等のリダイレクトが必要url, reason

payment_success

決済が正常に完了した場合に送信されます。
{
  "type": "payment_success",
  "transactionId": "tx_abc123",
  "requestId": "req_xyz789"
}

payment_failed

決済が失敗した場合に送信されます。
{
  "type": "payment_failed",
  "error": "カードが拒否されました",
  "code": "card_declined"
}

payment_cancel

ユーザーが「キャンセルしてサイトに戻る」をクリックした場合に送信されます。
{
  "type": "payment_cancel"
}

redirect_required

3Dセキュア認証などでリダイレクトが必要な場合に送信されます。
このイベントは特定の決済方法でのみ発生します。決済方法によっては、認証処理が自動的に行われるため、このイベントが発生しない場合があります。
{
  "type": "redirect_required",
  "url": "https://auth.example.com/3ds/...",
  "reason": "3ds_required"
}
リダイレクトが必要な場合、新しいタブ/ウィンドウで開くか、親ウィンドウでナビゲートしてください。iframe内でのリダイレクトはセキュリティ上の制限により機能しない場合があります。

完全な実装例

<!DOCTYPE html>
<html>
<head>
  <title>決済ページ</title>
</head>
<body>
  <h1>お支払い</h1>

  <div id="checkout-container">
    <!-- iframeは動的に挿入 -->
  </div>

  <script>
    // 決済URLを設定(バックエンドから取得)
    const paymentUrl = 'YOUR_PAYMENT_URL';

    // iframe埋め込み
    const container = document.getElementById('checkout-container');
    const iframe = document.createElement('iframe');
    iframe.src = paymentUrl + (paymentUrl.includes('?') ? '&' : '?') + 'mode=embedded';
    iframe.style.width = '100%';
    iframe.style.height = '700px';
    iframe.style.border = 'none';
    iframe.setAttribute('allow', 'payment');
    container.appendChild(iframe);

    // イベントリスナー
    window.addEventListener('message', function(event) {
      if (event.origin !== 'https://pay.zafapay.com') return;

      const data = event.data;
      if (!data || !data.type) return;

      switch (data.type) {
        case 'payment_success':
          alert('決済が完了しました!');
          window.location.href = '/thank-you?tx=' + data.transactionId;
          break;
        case 'payment_failed':
          alert('決済に失敗しました: ' + data.error);
          break;
        case 'payment_cancel':
          if (confirm('決済をキャンセルしますか?')) {
            window.location.href = '/cart';
          }
          break;
        case 'redirect_required':
          window.open(data.url, '_blank');
          break;
      }
    });
  </script>
</body>
</html>

セキュリティ考慮事項

1

オリジン検証

postMessageを受信する際は、必ずevent.originを検証してください。
2

HTTPS必須

iframe埋め込みはHTTPSサイトでのみ動作します。
3

Webhookとの併用

決済結果の確定にはpostMessageだけでなく、必ずサーバーサイドでWebhookを受信して検証してください。

リダイレクト方式

リダイレクト方式が設定されている場合、決済結果は親ウィンドウへのリダイレクトで通知されます。

リダイレクト先URL

決済作成時に指定したsuccess_redirect_urlfailure_redirect_urlcancel_redirect_urlにリダイレクトされます。

URLパラメータ

ステータスリダイレクト先パラメータ
成功success_redirect_url?request_id=xxx&transaction_id=xxx&status=success
失敗failure_redirect_url?request_id=xxx&transaction_id=xxx&status=failed
キャンセルcancel_redirect_url?request_id=xxx&status=cancel
  • キャンセル時は決済実行前のためtransaction_idは含まれません。
  • cancel_redirect_urlが設定されていない場合、キャンセル時はfailure_redirect_urlにリダイレクトされます。

パラメータ詳細

パラメータ説明
request_id決済リクエストID(req_で始まる)
transaction_idトランザクションID(tx_で始まる)
statussuccess / failed / cancel

実装例

// サーバーサイド(Node.js例)
app.get('/payment/callback', (req, res) => {
  const { request_id, transaction_id, status } = req.query;

  switch (status) {
    case 'success':
      // 成功処理(Webhookでも検証すること)
      res.redirect('/thank-you?order=' + request_id);
      break;
    case 'failed':
      // 失敗処理
      res.redirect('/checkout?error=payment_failed');
      break;
    case 'cancel':
      // キャンセル処理
      res.redirect('/cart');
      break;
  }
});
決済結果の確定には、URLパラメータだけでなく必ずサーバーサイドでWebhookを受信して検証してください。URLパラメータは改ざんされる可能性があります。

テスト

Sandbox環境でテストする場合は、以下のテストカードを使用できます。
カード番号結果
4242 4242 4242 4242成功
4000 0000 0000 32203Dセキュア必須
4000 0000 0000 9995残高不足で拒否
4000 0000 0000 0002一般的な拒否
有効期限は将来の日付、CVCは任意の3桁を使用してください。