# وصفة: رصيد API

> بِع رصيدًا مدفوعًا مسبقًا لواجهة API أو ميزة ذكاء اصطناعي واخصم وحدة لكل طلب. حين لا يكفي الرصيد — استجابة 402 مع رابط الشحن.

يدفع المشترون مقدمًا ثمن باقة رصيد؛ وكل طلب يستهلك بضع وحدات. يتولى Perly Pay الحساب: الاستهلاك استدعاء ذرّي واحد لا يسمح بالرصيد السالب، ولكل مشترٍ صفحة شحن خاصة. لا يُخصم شيء تلقائيًا — حين ينفد الرصيد يشحن المشتري. كل ما يخص الرصيد في [Sell credits](https://pay.perly.io/docs/credits.md)؛ وهنا الوصفة حوله.

> **ملاحظة:** مع مساعد: تنفّذ هذه الوصفة في مشروعك مهارة `sell-credits` من إضافة Perly Pay. المثال القابل للتشغيل هو `examples/api-credits` (MIT) في مستودع الإضافة.

## كيف يعمل

1. **باقة رصيد** — منتج وسعر مع `model: "credit_pack"`، و`unit_amount` بالسنتات، و`credits`. مرة لكل وضع.
2. **مستخدموك عملاء** — يُنشؤون مرة مع `external_id` (معرّف المستخدم لديك)؛ وبعدها تقبل `credits.*` هذا المعرّف.
3. **الشحن** — `credits.topUpUrl(userId)` صفحة المشتري الخاصة: يختار باقة ويدفع. كل باقة مدفوعة تضيف رصيدًا.
4. **الاستهلاك لكل طلب** — أولًا `credits.consume(userId, cost, { idempotencyKey })`، ثم العمل. الإعادة بالمفتاح نفسه تعيد الخصم الأول، لذا يُنشئ خادمك المفتاح لكل طلب ولا يأخذه أبدًا من المستدعي.
5. **لا يكفي؟** — `insufficient_credits` (409) لا يخصم شيئًا: أجب بـ `402` مع صفحة الشحن، لا بـ 500.

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

## شغّل المثال

1. **ثبّت** — `npm install` في `examples/api-credits` (Node 20.12+).
2. **المفتاح** — انسخ `.env.example` إلى `.env` واكتب مفتاح الاختبار (`sk_test_…`) في `PERLY_PAY_SECRET_KEY`.
3. **حضّر** — `npm run setup` ينشئ المنتج والسعر بمفتاحك ويطبع معرّفاتهما لـ `.env`.
4. **شغّل** — `npm start` (أو `npm run dev`)، كما يقول ملف README الخاص به.
5. **ادفع بلا محفظة** — استدعِ `POST /v1/shout` (402)، وافتح الصفحة التي يعطيها `POST /top-up`، واختر باقة، واضغط **Simulate payment** على الفاتورة، ثم استدعِ مجددًا: 200 و`X-Credits-Remaining: 499`.

## مزالق

- الاستهلاك بلا مفتاح عدم تكرار: الطلب المكرر يخصم مرتين.
- مفتاح الخصم مأخوذ مما يرسله العميل (ترويسة `Idempotency-Key`): المفتاح نفسه يعيد الخصم الأول كنجاح، فيحصل العميل على العمل مجددًا بلا دفع.
- التحقق من الرصيد ثم الخصم بخطوتين. `consume` نفسه لا يسمح بالرصيد السالب؛ والرصيد للعرض.
- العمل أولًا ثم الاستهلاك. العكس: الاستهلاك أولًا.
- معرّفات الاختبار مع مفتاح حقيقي. المنتجات والأسعار والويب هوك تنتمي إلى وضع واحد: قبل الإطلاق كرّر الإعداد بـ `sk_live_…`.
