Skip to main content

概要

Webhookを使用すると、決済の完了、失敗、返金などのイベントをリアルタイムで受け取ることができます。 ZAFA PAYは決済ステータスが変更されると、登録されたURLにHTTP POSTリクエストを送信します。
署名シークレット(Webhook Secret)は、加盟店管理画面(https://app.zafapay.com)の「加盟店設定」から確認できます。

イベントタイプ

イベント説明
payment.succeeded決済が正常に完了
payment.failed決済が失敗
payment.canceled決済がキャンセル
payment.refunded返金が完了
payment.chargebackチャージバックが発生

ペイロード

event
string
イベントタイプ(例: payment.succeeded
transaction_id
string
トランザクションID
status
string
決済ステータス(succeeded, failed, canceled, refunded, chargeback
amount
number
決済金額
currency
string
通貨コード
payment_method
string
決済方法(card, depotなど)
merchant_order_id
string
加盟店側の注文ID(決済作成時にexternal_idとして指定した値)
amount_refunded
number
返金済み金額
created_at
string
トランザクション作成日時(ISO 8601形式)
timestamp
string
Webhook送信日時(ISO 8601形式)

ペイロード例

{
  "event": "payment.succeeded",
  "transaction_id": "txn_abc123",
  "status": "succeeded",
  "amount": 1000,
  "currency": "jpy",
  "payment_method": "card",
  "merchant_order_id": "order_12345",
  "amount_refunded": 0,
  "created_at": "2024-01-15T10:30:00Z",
  "timestamp": "2024-01-15T10:31:00Z"
}

署名検証

Webhookリクエストには署名ヘッダーが含まれます。この署名を検証することで、リクエストがZAFA PAYから送信されたことを確認できます。

署名ヘッダー

環境ヘッダー名
SandboxX-Zafapay-Signature-Sandbox
ProductionX-Zafapay-Signature

検証方法

署名はリクエストボディ(JSON文字列)をHMAC-SHA256でハッシュ化したものです。
Node.js
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return signature === expectedSignature;
}

// Express.jsでの使用例
app.post('/webhooks/zafapay', express.json(), (req, res) => {
  const signature = req.headers['x-zafapay-signature-sandbox'];
  const secret = process.env.ZAFAPAY_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // イベント処理
  const { event, transaction_id, status } = req.body;

  switch (event) {
    case 'payment.succeeded':
      // 決済成功時の処理
      break;
    case 'payment.failed':
      // 決済失敗時の処理
      break;
    case 'payment.refunded':
      // 返金時の処理
      break;
  }

  res.json({ received: true });
});

レスポンス

Webhookを正常に受信した場合は、HTTPステータスコード 2xx を返してください。
{
  "received": true
}

リトライ

ZAFA PAYは以下の場合にWebhookを自動的にリトライします:
  • HTTPステータスコード 2xx 以外が返された場合
  • 接続タイムアウトが発生した場合
リトライは最大3回まで、1秒、2秒、3秒の間隔で実行されます。

ベストプラクティス

1

署名を必ず検証する

不正なリクエストを防ぐため、署名検証は必須です
2

冪等性を確保する

同じイベントが複数回送信される可能性があるため、transaction_idをキーにして重複処理を防いでください
3

すぐにレスポンスを返す

Webhook処理は非同期で行い、すぐに 200 を返してください。処理に時間がかかるとタイムアウトでリトライが発生します
4

エラーをログに記録する

デバッグのため、受信したペイロードと処理結果をログに記録してください