
# サブアカウントの自動リチャージ（カスタム決済プロバイダー）

Stripe以外のプロバイダー（銀行振込、ローカル決済ゲートウェイ、カスタム課金システムなど）を使用してサブアカウントのクレジット支払いを処理したい場合、プラットフォームが提供するWebhookとAPIのペアを使用することで、課金から付与までの一連の処理を独自に実行できます。技術的な詳細以外の概要については[エージェンシーアカウント](agency-accounts.md#option-2-custom-payment-provider)ページをご覧ください。このページでは、正確なWebhookペイロードと、その後にクレジットを付与するために呼び出すAPIについて説明します。

Webhookは、自動チャージの支払い方法の1つに過ぎません。SaaSモードで [Stripe](agency-accounts.md#option-1-connect-stripe) または [PayPal](agency-accounts.md#option-3-connect-paypal) を接続している場合、プラットフォームがクライアントの保存済みカードやPayPalアカウントに直接課金してクレジットを付与するため、このページで何かを構築する必要はありません。ご自身で決済を処理したい場合のみ、以下をお読みください。

***

## フローの概要

1. サブアカウントのクレジット残高が自動リチャージのしきい値を下回ります。
2. プラットフォームが、サブアカウントの詳細と必要なクレジット数を指定して、お客様の**Webhook URL**を呼び出します。
3. お客様のサーバーが、利用しているプロバイダーを通じて顧客に課金します。
4. お客様のサーバーが**クレジット付与API**を呼び出し、そのサブアカウントにクレジットを追加します。
5. お客様のサーバーが `200` を返し、Webhookを受信したことを通知します。

***

## 1. Webhook: `agency_sub_account_auto_recharge`

メインサイドバーの **SaaS Mode** をクリックし、**Use a Custom Payment Provider Instead** を選択する（または、設定済みの場合は **Custom Payment Provider** カードを開く）ことで、**Auto-Recharge Webhook** フィールドにWebhook URLを設定します。

### トリガー条件

サブアカウントのクレジット残高が、設定された自動リチャージのしきい値を下回ったときに実行されます。

### ペイロード

```json
{
  "event": "agency_sub_account_auto_recharge",
  "sub_account_id": "<sub-account-id>",
  "sub_account_email": "customer@example.com",
  "sub_account_name": "John Doe",
  "agency_id": "<agency-id>",
  "credits_requested": 500,
  "current_balance": 42,
  "threshold": 100,
  "price_per_credit_cents": 10,
  "price_per_credit_currency": "usd",
  "total_amount_cents": 5000,
  "timestamp": "2026-04-13T12:00:00.000Z",
  "idempotency_key": "auto_recharge_abc123_1681387200000"
}
```

| フィールド | 説明 |
|---|---|
| `event` | このWebhookでは常に `agency_sub_account_auto_recharge` となります。 |
| `sub_account_id` | クレジットが必要なサブアカウントの一意のID。 |
| `sub_account_email` | サブアカウントのメールアドレス。 |
| `sub_account_name` | サブアカウントの表示名。 |
| `agency_id` | エージェンシーアカウントの一意のID。 |
| `credits_requested` | 付与するクレジット数。これは設定したリチャージ金額ですが、残高がしきい値を大幅に下回っている場合は、残高を一度にしきい値以上に戻すために必要な金額に自動的に引き上げられます。常にペイロードの `credits_requested` 値に基づいて課金（および付与）を行ってください。リチャージ金額をハードコードしないでください。 |
| `current_balance` | Webhook送信時のサブアカウントのクレジット残高。 |
| `threshold` | リチャージをトリガーした残高のしきい値。 |
| `price_per_credit_cents` | 設定したクレジット単価（セント単位）。 |
| `price_per_credit_currency` | 価格の通貨（例: `usd`）。 |
| `total_amount_cents` | 課金総額（セント単位）（`credits_requested` × `price_per_credit_cents`）。 |
| `timestamp` | Webhookが送信された日時（ISO 8601形式）。 |
| `idempotency_key` | この特定のリチャージリクエストに対する一意のキー。サーバーが同じWebhookを複数回受信した場合にクレジットが二重に付与されるのを防ぐために使用してください。 |

### 重要な注意点

- **5分間のクールダウン** — サブアカウントに対してリチャージを試みた後、プラットフォームは少なくとも5分間は、残高がさらに低下してもそのサブアカウントに対して別のWebhookを送信しません。これにより、処理中の二重課金を防ぎます。
- **べき等キーの使用** — クレジットを付与する前に、必ず `idempotency_key` を確認してください。クレジット付与後にサーバーがクラッシュし、応答を返す前に停止した場合、プラットフォームは次のクレジット低下時にWebhookを再送する可能性があります。
- **失敗時の安全性と自己修復** — Webhook URLに到達できない、またはエラーが返された場合、クレジットは付与されません。サブアカウントがしきい値を下回っている限り、プラットフォームはWebhookを再送し続けます（5分間のクールダウンごとに1回）。残高がしきい値を超えて再び下回るのを待つ必要はありません。1回の課金失敗によって、サブアカウントが永久にリチャージされない状態になることはありません。
- **リチャージ金額をしきい値以上に設定する** — 設定するリチャージ金額は、自動リチャージのしきい値以上である必要があります。これにより、1回のリチャージで必ず残高がしきい値以上に戻ります。（しきい値を大幅に下回ってしまったサブアカウントを修正する必要がある場合、プラットフォームは不足分を自動的に全額補充します。上記の `credits_requested` を参照してください。）

***

## 2. クレジット付与API

サーバーでの支払処理が完了した後、このエンドポイントを呼び出してサブアカウントにクレジットを追加します。

### リクエスト

```http
POST https://api.dmchamp.com/v1/subaccounts/credits
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "email": "customer@example.com",
  "amount": 500,
  "description": "Auto-recharge via webhook"
}
```

| フィールド | 必須 | 説明 |
|---|---|---|
| `email` | はい | サブアカウントのメールアドレス（エージェンシー配下の既存のサブアカウントと一致する必要があります）。 |
| `amount` | はい | 付与するクレジット数。 |
| `description` | いいえ | クレジットを追加した理由を説明するメモ（クレジット取引履歴に表示されます）。 |

**認証:** APIキーをリクエストヘッダー（`X-API-Key: YOUR_API_KEY` または `Authorization: Bearer YOUR_API_KEY`）で送信してください。URLにキーを含めるとブラウザの履歴、プロキシログ、サーバーアクセスログに残ってしまうため、ヘッダーでの送信が推奨されます。`?apiKey=YOUR_API_KEY` クエリパラメータおよびJSONボディ内の `apiKey` フィールドも引き続き利用可能なため、古いインテグレーションも変更なしで動作し続けます。

### レスポンス

```json
{
  "success": true,
  "sub_account_id": "abc123xyz",
  "credits_added": 500,
  "new_balance": 542
}
```

::: tip
**ヒント:** webhookペイロードから `idempotency_key` を保存し、このエンドポイントを呼び出す前に確認してください。これにより、サーバーが同じwebhookを複数回受信した場合でも、誤ってクレジットを二重に付与することを防げます。
:::


### 毎月のリセット時に付与されたクレジットはどうなりますか

これはサブアカウントの設定方法によって異なります。

- **再販**（サブアカウントがあなたにクレジットの対価を支払う場合）：ここで付与したクレジットは購入済みクレジットとして記録され、毎月**繰り越されます**。サブアカウントが消費しなかった分は、そのまま残高として保持されます。
- **割り当て**（サブアカウントに毎月の許容量を与える場合）：リセット日に残高が毎月の許容量まで補充されるため、消費されなかった分は繰り越されません。これは意図的な仕様であり、許容量は毎月新たに付与されます。

サブアカウントの残高を新しい月間許容量と置き換えるのではなく、上乗せしたい場合は、クレジットの繰り越しを有効にしてください。

```
PUT https://api.dmchamp.com/v1/subaccounts/{subAccountUid}/limits
X-API-Key: YOUR_API_KEY
Content-Type: application/json

{
  "usageLimits": { "roll_over_to_next_month": true }
}
```

サブアカウント（またはそのサブアカウントが属するプラン）に繰越上限や有効期限が設定されている場合、リセットはその設定が適用されるタイミングで行われます。つまり、新しい許容量が追加される前に、繰り越された許容量が許可された月数分に調整され、有効期限を過ぎて未使用のまま残っていた許容量は削除されます。このエンドポイントを通じて付与されたクレジット、自動リチャージ、およびクライアント自身によるチャージは、一度限りのクレジットであり、調整（削除）されることはありません。詳細は [繰越上限の設定](sub-accounts.md#capping-what-rolls-over) を参照してください。

***

## エンドツーエンドの例

一般的なハンドラーは次のようになります。

```pseudo
on POST /your-recharge-webhook:
  payload = request.body

  if seen(payload.idempotency_key):
    return 200  // already processed, ack and exit

  charge_result = your_payment_provider.charge(
    email = payload.sub_account_email,
    amount_cents = payload.total_amount_cents,
    currency = payload.price_per_credit_currency,
  )

  if not charge_result.ok:
    return 500  // platform will retry on next balance drop

  api.post("/v1/subaccounts/credits", {
    email = payload.sub_account_email,
    amount = payload.credits_requested,
    description = "Auto-recharge via " + your_provider_name,
  })

  mark_seen(payload.idempotency_key)
  return 200
```
