Chapter 14

Destination Charges - Refunds

Toru Furukawa
Toru Furukawa
2021.12.14に更新

今日は、Destiation Charge の返金処理を見ていく。

ベースの Destination Charge

下の API 呼び出しを、ベースの Destination charge として想定する。

request
curl https://api.stripe.com/v1/payment_intents \
  -d amount=1000 \
  -d application_fee_amount=200 \
  -d "transfer_data[destination]"="acct_xxxx" \
  ...

資金フローは、下図のようになる。

Buyer           Platform                    .       Seller
Card            Bank                        .       Bank
 :                                          .
Payment Method  Platform Account            .       Connected Account
 |               ^    |       ^             .             ^
 |               |    |       | 200         .             |
 |               |    |       |             .             |
 |               |    |   [TXN3][Application Fee]<-+      |
 |               |    |                     .      |      |
 | 1000      964 |    | 1000                .  200 |      | 800
 v               |    |                     .      |      |
[Charge]         |    v                     .      |      |
[TXN1]-----------+  [TXN2]      1000        .  [TXN4]-----+
 |                  [Transfer]---------->[Charge2]
 | 36                                       .
 v                                          .
Stripe

収支は下表のようになる。

Transaction Payment Methond Platform Account Connected Account Stripe
Charge -1000 +964 0 36
Transfer 0 -1000 1000 0
Applecation Fee 0 +200 -200 0
収支 -1000 +164 +800 +36

Refunds API を呼び出す

次のように Refunds API を呼び出す。多くの場合、この呼び出しではやりたいことができないのだけれど、資金フローとデータモデルは、もっともシンプルだ。

request
curl https://api.stripe.com/v1/refunds \
  -u sk_xxxx: \
  -d payment_intent=pi_xxxx \
  -d "expand[]"=balance_transaction
response
{
  "id": "re_xxxx",
  "object": "refund",
  "amount": 1000,
  "balance_transaction": {
    "id": "txn_5",
    "amount": -1000,
    "fee": 0,
    "net": -1000,
    ...
  },
  "charge": "ch_xxxx",
  "payment_intent": "pi_xxxx",
  ...
}

資金フローは、下のようになる。

Distination Charge 時点のフロー矢印と、Blanace Transaction は割愛してある。

Buyer              Platform                         .   Seller
Card               Bank                             .   Bank
 :                                                  .
Payment Method   Platform Account                   .  Connected Account
      ^          |                                  .
      |          |                                  .
      |1000  1000|                                  .
      |          |                                  .
      |          v                                  .
     [Refund][TXN5]👈                               .
       :                                            .
       :                                            .
  [Charge]            [Transfer]                 [Charge2]

Refund オブジェクトは、Charge オブジェクトに関連づいている。Charge によって発生した取引を、逆向きに移動する取引だ。

Charge は Payment Method から Platform Account に資金を移動した。Refund は Platform Account から Payment Method に資金を移動する。Connected Account の残高には影響しない。

収支は下表になる。

Transaction Payment Methond Platform Account Connected Account Stripe
Charge -1000 +964 0 36
Transfer 0 -1000 1000 0
Applecation Fee 0 +200 -200 0
Refund +1000 -1000 0 0
収支 0 -836 800 36

Platform Account 残高から返金するので、赤字だ。Connected Account は支払いを受けたままなので、黒字だ。

おそらく、サービスレベルで想定している資金フローではないだろう。

Transfer を戻す

Connected Acocunt に Transfer で移動した資金を、逆向きに動かすには、次のように呼び出す。

request
curl https://api.stripe.com/v1/refunds \
  -u sk_xxxx: \
  -d payment_intent=pi_xxxx \
  ...

curl https://api.stripe.com/v1/transfers/tr_xxxx/reversals \
  -u sk_xxxx: \
  ...

または、次にような一発呼び出しもできる。発生する副作用は同じだ。ただし、上の呼び出しでは、API 呼び出しごとに amount を個別に指定できるが、下の呼び出しでは自動的に計算される。このアドベントカレンダーの主なトピックではないので、省略する。

request
curl https://api.stripe.com/v1/refunds \
  -u sk_xxxx: \
  -d payment_intent=pi_xxxx \
  -d reverse_transfer=true \
  -d "expand[]"=balance_transaction \
  -d "expand[]"="transfer_reversal.balance_transaction" \
  -d "expand[]"="transfer_reversal.destination_payment_refund" \
  ...
response
{
  "id": "re_xxxx",
  "amount": 1000,
  "balance_transaction": {
    "id": "txn_5",
    "net": -1000,
    ...
  },
  "charge": "ch_xxxx",
  "transfer_reversal": {
    "id": "trr_xxxx",
    "object": "transfer_reversal",
    "amount": 1000,
    "balance_transaction": {
      "id": "txn_6",
      "amount": 1000,
      "fee": 0,
      "net": 1000,
      "source": "tr_xxxx",
      ...
    },
    "destination_payment_refund": {
      "id": "pyr_xxxx",
      "amount": 1000,
      "charge": "py_xxxx",
      ...
    },
  }
}

Transfer Reversal オブジェクトが、Tranfer オブジェクトを巻き戻す。その資金は、pyr_xxxx という ID の Refund オブジェクトからだ。これは、決済時の Charge に対応する。

Buyer              Platform                         .   Seller
Card               Bank                             .   Bank
 :                                                  .
Payment Method   Platform Account                   .  Connected Account
      ^          |        ^                         .
      |          |        |                         .
      |1000  1000|        | 1000                    .
      |          |        |                         .
      |          v        |                         .
     [Refund][TXN5]       |                         .
       :                 [TXN6]   👇         1000   . 👇
       :                 [Transfer Reversal]<----[Refund2]
       :                      :                   : .
       :                      :                   : .
  [Charge]            [Transfer]                 [Charge2]

Connected Account の立場から、Refund2 を見てみよう。

request
curl https://api.stripe.com/v1/refunds/pyr_xxxx \
  -u sk_xxxx: \
  -H "Stripe-Account:acct_xxxx" \
  -d "expand[]"=balance_transaction
response
{
  "id": "pyr_xxxx",
  "object": "refund",
  "amount": 1000,
  "balance_transaction": {
    "id": "txn_7",
    "net": -1000,
    "source": "py_xxxx",
    ...
  },
  "source_transfer_reversal": "trr_xxxx"
  ...
}

資金フローは下図のようになる。Refund2 に関連する Balance Transaction は、Connected Account の残高を 1000 円減らして、Transfer Reversal に移動させている。その先には、Platform Account がある。

Buyer              Platform                         .   Seller
Card               Bank                             .   Bank
 :                                                  .
Payment Method   Platform Account                   .  Connected Account
      ^          |        ^                         .             |
      |          |        |                         .             |
      |1000  1000|        | 1000                    .             | 1000
      |          |        |                         .             |
      |          v        |                         .             |
     [Refund][TXN5]       |                         .  👇         |
       :                 [TXN6]              1000   .[TXN7]<------+
       :                 [Transfer Reversal]<----[Refund2]
       :                      :                   : .
       :                      :                   : .
  [Charge]            [Transfer]                 [Charge2]

収支は、下表のようになる。

Transaction Payment Methond Platform Account Connected Account Stripe
Charge -1000 +964 0 36
Transfer 0 -1000 1000 0
Applecation Fee 0 +200 -200 0
Refund +1000 -1000 0 0
Reversal 0 +1000 -1000 0
収支 0 164 -200 36

Conncted Acount の残高がマイナスになる。これは、決済時に Application Fee として引かれた 200 円がそのままだからだ。

Application Fee を戻す

Application Fee を、Platform Account から Connected Account に返すには、以下のように API を呼び出す。

request
curl https://api.stripe.com/v1/refunds \
  -u sk_xxxx: \
  -d payment_intent=pi_xxxx \
  ...

curl https://api.stripe.com/v1/transfers/tr_xxxx/reversals \
 -u sk_xxxx: \
 ...

curl https://api.stripe.com/v1/application_fees/fee_xxxx/refunds \
 -u sk_xxxx: \
 ...

または、次にように一発で呼び出してもよい。

request
curl https://api.stripe.com/v1/refunds \
  -u sk_xxxx: \
  -d payment_intent=pi_xxxx \
  -d reverse_transfer=true \
  -d refund_application_fee=true \
  ...

レスポンスは refund_application_fee の副作用の結果を返さない。そこで、別の API を呼び出す。

request
curl https://api.stripe.com/v1/application_fees/fee_xxxx/refunds \
  -u sk_xxxx: \
  ...
response
{
  "id": "fr_xxxx",
  "amount": 200,
  "balance_transaction": "txn_7",
  ...
}

Balance Transaction が展開できないので、明示的に取得する。

request
curl https://api.stripe.com/v1/balance_transactions/txn_7 \
  -u sk_xxxx: \
  ...
response
{
  "id": "txn_7",
  "amount": -200,
  "fee": 0,
  "net": -200,
  ...
}

資金フローは下図のようになる。Balance Transaction の行き先がいまいち分からない。いや分かるんだけど、レスポンスは保持していない。

Buyer              Platform                         .   Seller
Card               Bank                             .   Bank
 :                                                  .
Payment Method   Platform Account                   .  Connected Account
      ^          |        ^     |                   .             |
      |          |        |     | 200               .             | 1000
      |          |        |     v                   .             |
      |          |        |    [TXN8]               .             |
      |          |        |     [Application Fee Refund]👈        |
      |          |        |               :         .             |
      |1000  1000|        |       [Application Fee] .             |
      |          |        |                         .             |
      |          v        | 1000                    .             |
     [Refund][TXN5]       |                         .             |
       :                 [TXN6]              1000   .[TXN7]<------+
       :                 [Transfer Reversal]<----[Refund2]
       :                      :                   : .
       :                      :                   : .
  [Charge]            [Transfer]                 [Charge2]

Connected Account の観点からデータを取得してみる。

request
curl https://api.stripe.com/v1/balance_transactions \
  -u sk_xxxx: \
  -H "Stripe-Account: acct_xxxx" \
);
response
{
  "id": "txn_8",
  "amount": 200,
  "fee": 0,
  "net": 200,
  ...
}

資金フローは下図のようになる。

Buyer              Platform                         .   Seller
Card               Bank                             .   Bank
 :                                                  .
Payment Method   Platform Account                   .  Connected Account
      ^          |        ^     |                   .     ^       |
      |          |        |     | 200               . 200 |       | 1000
      |          |        |     v                   .     |       |
      |          |        |    [TXN8]               . [TXN9]👈    |
      |          |        |     [Application Fee Refund]          |
      |          |        |               :         .             |
      |1000  1000|        |       [Application Fee] .             |
      |          |        |                         .             |
      |          v        | 1000                    .             |
     [Refund][TXN5]       |                         .             |
       :                 [TXN6]              1000   .[TXN7]<------+
       :                 [Transfer Reversal]<----[Refund2]
       :                      :                   : .
       :                      :                   : .
  [Charge]            [Transfer]                 [Charge2]

収支をまとめると下表になる。

Transaction Payment Methond Platform Account Connected Account Stripe
Charge -1000 +964 0 36
Transfer 0 -1000 1000 0
Applecation Fee 0 +200 -200 0
Refund +1000 -1000 0 0
Reversal 0 +1000 -1000 0
Applecation Fee Refund 0 +200 -200 0
収支 0 -36 0 36

まとめ

Destination Charge の返金を見てきた。決済が発生したときの手数料をどうするのか。は、また今度。明日はチャージバックを見ていく。