# Recette : clés de licence

> Vendez une app de bureau, un CLI, un plugin ou un modèle avec des clés de licence. L’app distribuée vérifie sa clé sans aucun secret à l’intérieur.

Perly Pay émet une clé quand le paiement est honoré, compte les activations par appareil et répond à « cette clé est-elle valable pour ce produit, ici ? » via des endpoints publics. Le logiciel que vous distribuez utilise `LicenseClient`, qui n’a besoin d’aucune clé secrète.

> **Note:** Avec un assistant : le skill `sell-license-keys` du plugin Perly Pay réalise cette recette dans votre projet. L’exemple exécutable est `examples/license-keys` (MIT) dans le dépôt du plugin.

## Comment ça marche

1. **Un produit qui émet des clés** — `issues_license: true` et `license_activation_limit` (appareils par clé), avec un prix unique, à vie, à durée fixe ou d’abonnement.
2. **Vendez-le** — Un [lien de paiement](https://pay.perly.io/docs/payment-links.md) sur votre site, ou une facture par acheteur.
3. **Envoyez la clé** — Sur le webhook `license.created` (son objet est la clé), ou avec `licenseKeys.list({ customer })` après `invoice.fulfilled`. Le reçu ne la contient pas.
4. **Activez dans l’app** — `activate({ key, product, instance_name })` avec un nom qui ne change pas sur cet appareil ; gardez l’id d’activation.
5. **Vérifiez au démarrage** — `validate({ key, product, instance })`. Un `valid: false` net bloque ; sans réseau, la dernière bonne réponse vaut quelques jours.

**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'];
```

## Lancez l’exemple

1. **Installez** — `npm install` dans `examples/license-keys` (Node 20.12+).
2. **Clé** — Copiez `.env.example` vers `.env` et mettez une clé de test (`sk_test_…`) dans `PERLY_PAY_SECRET_KEY`.
3. **Préparez** — `npm run setup` crée le produit et le prix avec votre clé et affiche leurs ids pour `.env`.
4. **Lancez** — `npm start` (ou `npm run dev`), comme l’indique son README.
5. **Payez sans portefeuille** — `npm run buy-test -- you@example.com` achète une copie en mode test et affiche la clé ; puis `npm run app -- activate <key>` et `npm run app -- pro hello`.

## Pièges

- Une clé `sk_…` dans l’app. N’importe qui peut l’extraire ; le code distribué n’utilise que `LicenseClient`.
- Omettre `product` : l’appel est refusé (`parameter_missing`). Passez-le toujours ; une clé pour autre chose répond `wrong_product`.
- Un `instance_name` qui change à chaque lancement : chaque démarrage consomme une activation.
