
# Isi Ulang Otomatis Sub-Akun (Penyedia Pembayaran Kustom)

Jika Anda lebih memilih untuk menangani pembayaran kredit sub-akun melalui penyedia Anda sendiri alih-alih Stripe (transfer bank, gateway pembayaran lokal, sistem penagihan kustom), platform ini menyediakan pasangan webhook + API sehingga Anda dapat menjalankan seluruh siklus penagihan dan pemberian kredit sendiri. Gambaran umum non-teknis tersedia di halaman [Akun Agensi](agency-accounts.md#option-2-custom-payment-provider); halaman ini membahas payload webhook yang tepat dan panggilan API yang Anda buat untuk memberikan kredit setelahnya.

Webhook hanyalah salah satu cara pembayaran isi ulang otomatis dilakukan. Jika Anda menghubungkan [Stripe](agency-accounts.md#option-1-connect-stripe) atau [PayPal](agency-accounts.md#option-3-connect-paypal) dalam Mode SaaS, platform akan menagih kartu atau akun PayPal yang tersimpan milik klien secara otomatis dan memberikan kredit, jadi tidak ada yang perlu Anda bangun di halaman ini. Lanjutkan membaca hanya jika Anda ingin menangani pembayaran sendiri.

***

## Sekilas alur kerja

1. Saldo kredit sub-akun turun di bawah ambang batas isi ulang otomatis mereka.
2. Platform memanggil **URL webhook** Anda dengan detail sub-akun dan jumlah kredit yang mereka butuhkan.
3. Server Anda menagih pelanggan melalui penyedia mana pun yang Anda gunakan.
4. Server Anda memanggil **API Pemberian Kredit** untuk menambahkan kredit ke sub-akun tersebut.
5. Server Anda merespons `200` untuk mengonfirmasi webhook.

***

## 1. Webhook: `agency_sub_account_auto_recharge`

Konfigurasikan URL webhook dengan mengeklik **SaaS Mode** di bilah sisi utama, memilih **Use a Custom Payment Provider Instead** (atau, setelah dikonfigurasi, membuka kartu **Custom Payment Provider**), dan mengisi kolom **Auto-Recharge Webhook**.

### Kapan webhook ini dipicu

Saat saldo kredit sub-akun turun di bawah ambang batas isi ulang otomatis yang dikonfigurasi.

### Payload

```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"
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | Selalu `agency_sub_account_auto_recharge` untuk webhook ini. |
| `sub_account_id` | ID unik sub-akun yang membutuhkan kredit. |
| `sub_account_email` | Alamat email sub-akun. |
| `sub_account_name` | Nama tampilan sub-akun. |
| `agency_id` | ID unik akun agensi Anda. |
| `credits_requested` | Berapa banyak kredit yang akan diberikan. Ini adalah jumlah isi ulang yang Anda konfigurasikan, tetapi jika saldo telah turun lebih jauh di bawah ambang batas daripada jumlah tersebut, saldo akan secara otomatis dinaikkan ke jumlah yang diperlukan untuk mengembalikan saldo di atas ambang batas sekaligus. Selalu tagih (dan berikan) nilai `credits_requested` dari payload — jangan melakukan hard-code pada jumlah isi ulang Anda. |
| `current_balance` | Saldo kredit sub-akun pada saat webhook dikirim. |
| `threshold` | Ambang batas saldo yang memicu isi ulang. |
| `price_per_credit_cents` | Harga per kredit yang Anda konfigurasikan, dalam sen. |
| `price_per_credit_currency` | Mata uang untuk harga (misalnya, `usd`). |
| `total_amount_cents` | Jumlah total yang akan ditagihkan, dalam sen (`credits_requested` × `price_per_credit_cents`). |
| `timestamp` | Kapan webhook dikirim (format ISO 8601). |
| `idempotency_key` | Kunci unik untuk permintaan isi ulang khusus ini. Gunakan ini untuk mencegah pemberian kredit dua kali jika server Anda menerima webhook yang sama lebih dari sekali. |

### Catatan penting

- **Cooldown 5 menit** — Setelah upaya isi ulang untuk sub-akun, platform tidak akan mengirim webhook lain untuk sub-akun tersebut setidaknya selama 5 menit, meskipun saldo mereka turun lebih jauh. Mencegah penagihan ganda selama pemrosesan.
- **Gunakan kunci idempotensi** — Selalu periksa `idempotency_key` sebelum memberikan kredit. Jika server Anda mengalami crash setelah memberikan kredit tetapi sebelum merespons, platform mungkin mengirim ulang webhook pada penurunan kredit berikutnya.
- **Kegagalan aman dan dapat pulih sendiri** — Jika URL webhook Anda tidak dapat dijangkau atau mengembalikan kesalahan, tidak ada kredit yang diberikan. Platform terus mengirim ulang webhook (sekali per cooldown 5 menit) selama sub-akun tetap di bawah ambang batas — ini **tidak** mengharuskan saldo untuk naik kembali di atas ambang batas dan turun lagi terlebih dahulu. Satu penagihan yang terlewat tidak akan lagi membuat sub-akun tidak terisi ulang secara permanen.
- **Tetapkan jumlah isi ulang Anda pada atau di atas ambang batas** — Jumlah isi ulang yang Anda konfigurasikan harus lebih besar dari atau sama dengan ambang batas isi ulang otomatis, sehingga satu isi ulang selalu mengembalikan saldo di atas ambang batas. (Jika Anda perlu memperbaiki sub-akun yang turun jauh di bawah ambang batas, platform akan menambahkannya sesuai kekurangan secara otomatis — lihat `credits_requested` di atas.)

***

## 2. API Pemberian Kredit

Setelah server Anda memproses pembayaran, panggil endpoint ini untuk menambahkan kredit ke sub-akun.

### Permintaan

```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"
}
```

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `email` | Ya | Alamat email sub-akun (harus cocok dengan sub-akun yang ada di bawah agensi Anda). |
| `amount` | Ya | Jumlah kredit yang akan diberikan. |
| `description` | Tidak | Catatan yang menjelaskan mengapa kredit ditambahkan (ditampilkan dalam riwayat transaksi kredit). |

**Autentikasi:** Kirim kunci API Anda di header permintaan — baik `X-API-Key: YOUR_API_KEY` atau `Authorization: Bearer YOUR_API_KEY`. Header adalah cara yang direkomendasikan, karena kunci di URL akan tersimpan dalam riwayat peramban, log proksi, dan log akses server. Parameter kueri `?apiKey=YOUR_API_KEY` dan kolom `apiKey` dalam isi JSON juga masih berfungsi, sehingga integrasi lama tetap berjalan tanpa perubahan.

### Respons

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

::: tip
**Tip:** Simpan `idempotency_key` dari payload webhook dan periksa sebelum memanggil endpoint ini. Hal ini mencegah pemberian kredit dua kali secara tidak sengaja jika server Anda menerima webhook yang sama lebih dari sekali.
:::


### Apa yang terjadi pada kredit yang diberikan saat reset bulanan

Hal ini bergantung pada bagaimana sub-akun disiapkan:

- **Penjualan kembali** (sub-akun membayar Anda untuk kredit): kredit yang Anda berikan di sini dicatat sebagai kredit yang dibeli dan **diakumulasikan** setiap bulan. Berapa pun yang belum dibelanjakan oleh sub-akun akan tetap ada di saldo.
- **Alokasi** (Anda memberikan tunjangan bulanan kepada sub-akun): saldo akan diisi ulang ke tunjangan bulanan pada tanggal reset, sehingga apa pun yang tidak dibelanjakan tidak akan diakumulasikan. Ini disengaja — tunjangan diberikan baru setiap bulan.

Jika Anda ingin saldo sisa sub-akun ditambahkan ke tunjangan bulanan barunya alih-alih menggantikannya, aktifkan pengalihan kredit (credit roll-over):

```
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 }
}
```

Jika sub-akun — atau paket yang digunakannya — juga memiliki batas akumulasi (roll-over cap) atau masa berlaku yang ditetapkan, penyetelan ulang terjadi pada saat aturan tersebut diterapkan: jatah yang dibawa ke periode berikutnya dipangkas sesuai dengan jumlah bulan yang Anda izinkan, dan jatah yang tidak terpakai lebih lama dari periode masa berlaku akan dihapus, sebelum jatah baru ditambahkan. Kredit yang diberikan melalui endpoint ini, isi ulang otomatis, dan isi ulang mandiri klien adalah kredit satu kali dan tidak pernah dipangkas. Lihat [Membatasi apa yang diakumulasikan](sub-accounts.md#capping-what-rolls-over).

***

## Contoh menyeluruh

Handler yang umum terlihat seperti ini:

```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
```
