0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Stripe Connect の refund で reverse_transfer が false になる仕組みと検知方法

0
Posted at

Stripe Connect の refund で reverse_transfer が false になる仕組みと検知方法

問題

Stripe Connect でプラットフォームがアプリケーションフィーを受け取る決済を行った後、返金(refund)を発行すると、reverse_transfer パラメータのデフォルトが false になります。この状態では、プラットフォーム側のフィーは返却されず、接続先アカウントへの転送(transfer)も元に戻されません。結果として、接続先アカウントは本来返金されるべき金額を受け取れず、プラットフォーム側が不当にフィーを保持する「フィーリーク」が発生します。

仕組み

Stripe Connect の決済フローは以下のようになります。

  1. Charge 作成
    プラットフォームは application_fee_amount を指定して Charge を作成し、Stripe が接続先アカウントへの Transfer を自動生成します。このとき、transfer の amount は charge 金額からフィーを差し引いた額になります。

  2. Refund 作成
    POST /v1/refunds に charge ID と、オプションで reverse_transfer フラグを渡します。

    • reverse_transfer: true(明示的に指定) → 返金額に応じて Transfer が逆方向に調整され、プラットフォーム側のフィーも返金されます。
    • reverse_transfer: false または未指定(デフォルト) → Transfer は変更されず、プラットフォーム側のフィーは返金されません。

したがって、デフォルトの挙動では返金時にフィーが戻らず、接続先アカウントに不利益が生じます。

実装例(検知・修正)

以下は、既存の refund オブジェクトを取得し、reverse_transfer が false であるかを確認し、必要に応じて再度返金を発行してフィーを戻すサンプルコードです(Stripe Node.js ライブラリを使用)。

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

async function checkAndFixRefund(refundId) {
  // 1. refund オブジェクトを取得
  const refund = await stripe.refunds.retrieve(refundId, {
    expand: ['charge.transfer']
  });

  // 2. reverse_transfer が false か確認
  if (!refund.reverse_transfer) {
    const charge = refund.charge;
    const fee = charge.application_fee_amount; // フィー額(最小通貨単位)

    // 3. フィー分だけ追加で返金を作成(reverse_transfer: true)
    await stripe.refunds.create({
      charge: charge.id,
      amount: fee,
      reverse_transfer: true, // フィーをプラットフォーム側に戻す
      refund_application_fee: true
    });

    console.log(`Refunded fee ${fee} for charge ${charge.id}`);
  } else {
    console.log(`Refund ${refundId} already has reverse_transfer: true`);
  }
}

// 使用例
checkAndFixRefund('re_1J2abc...');

このコードは以下の手順で動作します。

  1. 対象の refund を取得し、charge とその transfer を展開。
  2. reverse_transfer フラグが false の場合、プラットフォーム側が保持している application_fee_amount 分だけ追加で refund を作成。
  3. reverse_transfer: true と refund_application_fee: true を指定することで、フィーをプラットフォーム側から接続先アカウントへ戻す。

注意点(キャベット)

  • 権限:refunds:write と application_fees:read のスコープが必要です。
  • 冪等性:同じ refund に対して複数回実行しないように、状態フラグやログで管理してください。
  • 部分返金:複数回にわたる部分返金が発生している場合は、各返金ごとにフィーの割合を計算し、合計が元のフィーを超えないように調整が必要です。
  • Instant Payouts:接続先アカウントが即時払いを利用している場合、転送のタイミングによっては追加返金が二重に処理されるリスクがあります。トランザクションログを確認し、必要に応じて手動で調整してください。
  • 手動転送:プラットフォームが手動で transfer を作成しているケースでは、上記ロジックは適用されません。手動転送のロジック別にフィーの返却フローを実装してください。

以上のように、reverse_transfer のデフォルト挙動を理解し、API レベルで適切にフラグを制御または追加返金を行うことで、フィーリークを防止し、接続先アカウントへの正しい返金を保証できます。

Learn more: https://feeguard.dev/blog/build-your-own-fee-leakage-detection?utm_source=qiita&utm_campaign=developer-education&utm_medium=social

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?