
# Alitilin automaattinen lataus (mukautettu maksupalveluntarjoaja)

Jos haluat hoitaa alitilien krediittimaksut oman palveluntarjoajasi kautta Stripin sijaan (pankkisiirrot, paikalliset maksunvälittäjät, mukautetut laskutusjärjestelmät), alusta tarjoaa webhook- ja API-parin, joiden avulla voit suorittaa koko veloitus- ja myöntämisprosessin itse. Ei-tekninen yleiskatsaus löytyy [Agency Accounts](agency-accounts.md#option-2-custom-payment-provider) -sivulta; tämä sivu käsittelee webhookin tarkkaa hyötykuormaa ja API-kutsua, jonka teet krediittien myöntämiseksi sen jälkeen.

Webhook on vain yksi tapa, jolla automaattiset täydennykset maksetaan. Jos yhdistit [Stripe](agency-accounts.md#option-1-connect-stripe)- tai [PayPal](agency-accounts.md#option-3-connect-paypal)-tilin SaaS-tilassa, alusta veloittaa asiakkaan tallennetun kortin tai PayPal-tilin automaattisesti ja myöntää krediitit, joten tällä sivulla ei ole mitään, mitä sinun tarvitsisi rakentaa. Jatka lukemista vain, jos haluat hoitaa maksun itse.

***

## Prosessi lyhyesti

1. Alitilin krediittisaldo laskee automaattisen latauksen kynnyksen alapuolelle.
2. Alusta kutsuu **webhook-URL-osoitettasi** alitilin tiedoilla ja tiedolla siitä, kuinka monta krediittiä se tarvitsee.
3. Palvelimesi veloittaa asiakasta käyttämäsi palveluntarjoajan kautta.
4. Palvelimesi kutsuu **Grant Credits API** -rajapintaa lisätäkseen krediitit kyseiselle alitilille.
5. Palvelimesi vastaa `200` vahvistaakseen webhookin vastaanotetuksi.

***

## 1. Webhook: `agency_sub_account_auto_recharge`

Määritä webhook-URL napsauttamalla **SaaS Mode** pääsivupalkista, valitsemalla **Use a Custom Payment Provider Instead** (tai avaamalla **Custom Payment Provider** -kortti, kun se on määritetty) ja täyttämällä **Auto-Recharge Webhook** -kenttä.

### Milloin se laukeaa

Kun alitilin krediittisaldo laskee määritetyn automaattisen latauksen kynnyksen alapuolelle.

### Hyötykuorma

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

| Kenttä | Kuvaus |
|---|---|
| `event` | Aina `agency_sub_account_auto_recharge` tälle webhookille. |
| `sub_account_id` | Krediittejä tarvitsevan alitilin yksilöllinen ID. |
| `sub_account_email` | Alitilin sähköpostiosoite. |
| `sub_account_name` | Alitilin näyttönimi. |
| `agency_id` | Agency-tilisi yksilöllinen ID. |
| `credits_requested` | Myönnettävien krediittien määrä. Tämä on määritetty lataussummasi, mutta jos saldo on laskenut kynnysarvon alapuolelle enemmän kuin kyseinen summa kattaisi, se nostetaan automaattisesti siihen määrään, joka tarvitaan saldon nostamiseksi takaisin kynnyksen yläpuolelle yhdellä kertaa. Veloita (ja myönnä) aina hyötykuorman `credits_requested`-arvon mukaisesti — älä kovakoodaa lataussummaasi. |
| `current_balance` | Alitilin krediittisaldo webhookin lähetyshetkellä. |
| `threshold` | Latauksen laukaissut saldokynnys. |
| `price_per_credit_cents` | Määritetty hinta per krediitti sentteinä. |
| `price_per_credit_currency` | Hinnan valuutta (esim. `usd`). |
| `total_amount_cents` | Veloitettava kokonaissumma sentteinä (`credits_requested` × `price_per_credit_cents`). |
| `timestamp` | Webhookin lähetysajankohta (ISO 8601 -muoto). |
| `idempotency_key` | Yksilöllinen avain tätä latauspyyntöä varten. Käytä tätä estääksesi krediittien myöntämisen kahdesti, jos palvelimesi vastaanottaa saman webhookin useammin kuin kerran. |

### Tärkeitä huomautuksia

- **5 minuutin jäähtymisaika** — Alitilin latausyrityksen jälkeen alusta ei lähetä uutta webhookia kyseiselle alitilille vähintään 5 minuuttiin, vaikka saldo laskisi entisestään. Tämä estää päällekkäiset veloitukset käsittelyn aikana.
- **Käytä idempotenssiavainta** — Tarkista aina `idempotency_key` ennen krediittien myöntämistä. Jos palvelimesi kaatui krediittien myöntämisen jälkeen mutta ennen vastaamista, alusta saattaa lähettää webhookin uudelleen seuraavan saldon laskun yhteydessä.
- **Virheet ovat turvallisia ja itsekorjautuvia** — Jos webhook-URL-osoitteesi ei ole tavoitettavissa tai se palauttaa virheen, krediittejä ei myönnetä. Alusta jatkaa webhookin lähettämistä (kerran 5 minuutin jäähtymisajalla), niin kauan kuin alitili pysyy kynnyksen alapuolella — se **ei** vaadi, että saldon täytyisi ensin nousta kynnyksen yläpuolelle ja laskea uudelleen. Yksittäinen epäonnistunut veloitus ei voi enää jättää alitiliä pysyvästi ilman latausta.
- **Aseta lataussumma kynnyksen tasolle tai sen yläpuolelle** — Määritetyn lataussummasi on oltava suurempi tai yhtä suuri kuin automaattisen latauksen kynnys, jotta yksi lataus palauttaa saldon aina kynnyksen yläpuolelle. (Jos joudut korjaamaan alitilin, joka on pudonnut kauas kynnyksen alapuolelle, alusta täydentää sen automaattisesti koko vajeen verran — katso `credits_requested` yllä.)

***

## 2. Grant Credits API

Kun palvelimesi on käsitellyt maksun, kutsu tätä päätepistettä lisätäksesi krediitit alitilille.

### Pyyntö

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

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `email` | Kyllä | Alitilin sähköpostiosoite (täytyy vastata olemassa olevaa alitiliä agencysi alla). |
| `amount` | Kyllä | Myönnettävien krediittien määrä. |
| `description` | Ei | Huomautus, joka kuvaa krediittien lisäämisen syytä (näkyy krediittien tapahtumahistoriassa). |

**Todennus:** Lähetä API-avaimesi pyynnön otsikossa – joko `X-API-Key: YOUR_API_KEY` tai `Authorization: Bearer YOUR_API_KEY`. Otsikot ovat suositeltu tapa, koska URL-osoitteessa oleva avain päätyy selaimen historiaan, välityspalvelimen lokeihin ja palvelimen pääsylokeihin. `?apiKey=YOUR_API_KEY`-kyselyparametri ja `apiKey`-kenttä JSON-rungossa toimivat myös edelleen, joten vanhemmat integraatiot jatkavat toimintaansa muuttumattomina.

### Vastaus

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

::: tip
**Vinkki:** Tallenna `idempotency_key` webhook-hyötykuormasta ja tarkista se ennen tämän päätepisteen kutsumista. Tämä estää hyvitysten myöntämisen vahingossa kahdesti, jos palvelimesi vastaanottaa saman webhookin useammin kuin kerran.
:::


### Mitä myönnetyille krediiteille tapahtuu kuukausittaisessa nollauksessa

Tämä riippuu siitä, miten alitili on määritetty:

- **Jälleenmyynti** (alitili maksaa sinulle krediiteistä): tässä myöntämäsi krediitit kirjataan ostetuiksi krediiteiksi ja ne **siirtyvät** joka kuukausi. Kaikki se, mitä alitili ei ole käyttänyt, jää saldoon.
- **Allokointi** (annat alitilille kuukausittaisen kiintiön): saldo täydennetään kuukausittaiseen kiintiöön nollauspäivänä, joten käyttämättä jäänyt osuus ei siirry eteenpäin. Tämä on tarkoituksellista – kiintiö myönnetään uudelleen joka kuukausi.

Jos haluat, että alitilin jäljelle jäänyt saldo lisätään uuden kuukausittaisen kiintiön päälle sen sijaan, että se korvattaisiin, ota krediittien siirto käyttöön:

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

Jos alitilillä – tai sen tilauspaketilla – on myös siirtojen yläraja tai vanhenemisaika, nollaus tapahtuu sillä hetkellä, kun nämä astuvat voimaan: siirrettävää saldoa karsitaan sallittujen kuukausien mukaisesti, ja vanhenemisikkunaa pidempään käyttämättä jäänyt saldo poistetaan ennen uuden saldon lisäämistä. Tämän päätepisteen kautta myönnetyt krediitit, automaattiset lataukset ja asiakkaan omat täydennykset ovat kertaluonteisia krediittejä, eikä niitä koskaan karsita. Katso [Siirtojen ylärajan määrittäminen](sub-accounts.md#capping-what-rolls-over).

***

## Päästä päähän -esimerkki

Tyypillinen käsittelijä näyttää tältä:

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