# وصفة: مفاتيح الترخيص

> بِع تطبيقًا مكتبيًا، أو CLI، أو إضافة، أو قالبًا بمفاتيح ترخيص. يتحقق التطبيق من المفتاح دون أي سر بداخله.

يُصدر Perly Pay مفتاحًا حين يُنفَّذ الدفع، ويعدّ التفعيلات على الأجهزة، ويجيب عن «هل هذا المفتاح صالح لهذا المنتج هنا؟» عبر نقاط نهاية عامة. البرنامج الذي توزّعه يستخدم `LicenseClient` — ولا يحتاج إلى مفتاح سري.

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

## كيف يعمل

1. **منتج يُصدر مفاتيح** — `issues_license: true` و`license_activation_limit` (الأجهزة لكل مفتاح)، بسعر لمرة واحدة، أو مدى الحياة، أو لمدة، أو باشتراك.
2. **البيع** — [رابط دفع](https://pay.perly.io/docs/payment-links.md) على الموقع أو فاتورة لكل مشترٍ.
3. **أرسل المفتاح** — عند ويب هوك `license.created` (كائنه هو المفتاح) أو عبر `licenseKeys.list({ customer })` بعد `invoice.fulfilled`. الإيصال لا يحوي المفتاح.
4. **التفعيل في التطبيق** — `activate({ key, product, instance_name })` باسم لا يتغير على هذا الجهاز؛ واحفظ معرّف التفعيل.
5. **التحقق عند التشغيل** — `validate({ key, product, instance })`. `valid: false` الصريح يُغلق؛ وبلا شبكة تبقى آخر إجابة سليمة سارية بضعة أيام.

**Node**

```js
import { LicenseClient } from "perly-pay";

const licenses = new LicenseClient(); // no secret key, ever
const result = await licenses.activate({ key, product: "prod_…", instance_name: deviceName });
if (!result.valid) showWhy(result.reason); // limit_reached, revoked, expired, …
```

**PHP**

```php
use Perly\Pay\LicenseClient;

$result = (new LicenseClient())->activate(['key' => $key, 'product' => 'prod_…', 'instance_name' => home_url()]);
if (!$result['valid']) echo $result['reason'];
```

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

1. **ثبّت** — `npm install` في `examples/license-keys` (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. **ادفع بلا محفظة** — `npm run buy-test -- you@example.com` يشتري نسخة في وضع الاختبار ويطبع المفتاح؛ ثم `npm run app -- activate <key>` و`npm run app -- pro hello`.

## مزالق

- مفتاح `sk_…` داخل التطبيق. سيستخرجه أي أحد؛ البرنامج الذي توزّعه يستخدم `LicenseClient` فقط.
- بلا `product` يُرفض الطلب (`parameter_missing`). مرّره دائمًا؛ ومفتاح أي شيء آخر يُجاب بـ `wrong_product`.
- `instance_name` يتغير مع كل تشغيل: كل تشغيل يستهلك تفعيلًا.
