# Tarif: API kredileri

> Bir API ya da AI özelliği için ön ödemeli kredi sat ve istek başına bir tane düş. Bakiye yetmezse yükleme bağlantılı bir 402 yanıtı.

Alıcılar bir kredi paketini önceden öder; her istek birkaç tane harcar. Kaydı Perly Pay tutar: harcama, eksiye düşürmeyen tek bir atomik çağrıdır ve her alıcının kendi yükleme sayfası vardır. Hiçbir şey kendiliğinden tahsil edilmez — krediler bitince alıcı yükler. Krediler hakkında her şey [Sell credits](https://pay.perly.io/docs/credits.md) sayfasında; burada onların etrafındaki tarif var.

> **Not:** Asistanla: bu tarifi projende Perly Pay eklentisinin `sell-credits` skill'i uygular. Çalıştırılabilir örnek, eklenti deposundaki `examples/api-credits` (MIT).

## Nasıl çalışır

1. **Kredi paketi** — `model: "credit_pack"`, sent cinsinden `unit_amount` ve `credits` ile bir ürün ve fiyat. Mod başına bir kez.
2. **Kullanıcıların müşteri olur** — `external_id` (kendi kullanıcı kimliğin) ile bir kez oluşturulur; sonra `credits.*` bu kimliği kabul eder.
3. **Yükleme** — `credits.topUpUrl(userId)` alıcının kendi sayfasıdır: bir paket seçer ve öder. Ödenen her paket kredi ekler.
4. **İstek başına harcama** — Önce `credits.consume(userId, cost, { idempotencyKey })`, sonra iş. Aynı anahtarla tekrar ilk düşümü döndürür, bu yüzden her isteğin anahtarını sunucun üretir ve asla çağırandan almaz.
5. **Yetmiyor mu?** — `insufficient_credits` (409) hiçbir şey düşmez: 500 değil, yükleme sayfasıyla `402` döndür.

**Spend one request's credits**

```js
try {
  await pay.credits.consume(userId, cost, { product: PRODUCT, action: "api", idempotencyKey: `req-${userId}-${requestId}` });
} catch (e) {
  if (e.code !== "insufficient_credits") throw e;
  return reply(402, { top_up: await pay.credits.topUpUrl(userId, { product: PRODUCT }) });
}
// now do the work
```

## Örneği çalıştır

1. **Kur** — `examples/api-credits` içinde `npm install` (Node 20.12+).
2. **Anahtar** — `.env.example` dosyasını `.env` olarak kopyala ve test anahtarını (`sk_test_…`) `PERLY_PAY_SECRET_KEY` içine yaz.
3. **Hazırla** — `npm run setup` senin anahtarınla bir ürün ve fiyat oluşturur ve `.env` için kimliklerini yazdırır.
4. **Çalıştır** — README'sinde dediği gibi `npm start` (ya da `npm run dev`).
5. **Cüzdansız öde** — `POST /v1/shout` çağır (402), `POST /top-up`'ın verdiği sayfayı aç, bir paket seç, faturada **Simulate payment**'a bas ve tekrar çağır: 200 ve `X-Credits-Remaining: 499`.

## Tuzaklar

- Idempotency anahtarı olmadan harcama: tekrarlanan istek iki kez düşer.
- Düşüm anahtarını istemcinin gönderdiğinden almak (`Idempotency-Key` başlığı): aynı anahtar ilk düşümü başarı olarak döndürür ve istemci işi ödemeden yeniden alır.
- Bakiyeyi kontrol edip sonra iki adımda düşmek. `consume` zaten eksiye düşürmez; bakiye göstermek içindir.
- Önce iş, sonra harcama. Tersi: önce harcama.
- Canlı anahtarla test kimlikleri. Ürünler, fiyatlar ve webhook'lar tek bir moda aittir: canlıya geçmeden önce kurulumu `sk_live_…` ile tekrarla.
