# Ricetta: chiavi di licenza

> Vendi un’app desktop, una CLI, un plugin o un template con chiavi di licenza. L’app verifica la chiave senza alcun segreto al suo interno.

Perly Pay emette una chiave quando il pagamento viene consegnato, conta le attivazioni per dispositivo e risponde a «questa chiave è valida per questo prodotto qui?» con endpoint pubblici. Il programma che distribuisci usa `LicenseClient`, che non ha bisogno di una chiave segreta.

> **Nota:** Con un assistente: la skill `sell-license-keys` del plugin Perly Pay realizza questa ricetta nel tuo progetto. L’esempio eseguibile è `examples/license-keys` (MIT) nel repository del plugin.

## Come funziona

1. **Un prodotto che emette chiavi** — `issues_license: true` e `license_activation_limit` (dispositivi per chiave), con un prezzo una tantum, a vita, a durata o un abbonamento.
2. **Vendilo** — Un [link di pagamento](https://pay.perly.io/docs/payment-links.md) sul tuo sito o una fattura per acquirente.
3. **Consegna la chiave** — Con il webhook `license.created` (il suo oggetto è la chiave) o con `licenseKeys.list({ customer })` dopo `invoice.fulfilled`. La ricevuta non contiene la chiave.
4. **Attiva nell’app** — `activate({ key, product, instance_name })` con un nome che non cambia su quel dispositivo; salva l’id dell’attivazione.
5. **Verifica all’avvio** — `validate({ key, product, instance })`. Un `valid: false` netto blocca; senza rete, l’ultima risposta buona vale per qualche giorno.

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

## Esegui l’esempio

1. **Installa** — `npm install` in `examples/license-keys` (Node 20.12+).
2. **Chiave** — Copia `.env.example` in `.env` e metti una chiave di test (`sk_test_…`) in `PERLY_PAY_SECRET_KEY`.
3. **Prepara** — `npm run setup` crea il prodotto e il prezzo con la tua chiave e stampa i loro id per `.env`.
4. **Avvia** — `npm start` (o `npm run dev`), come dice il suo README.
5. **Paga senza wallet** — `npm run buy-test -- you@example.com` compra una copia in modalità test e stampa la chiave; poi `npm run app -- activate <key>` e `npm run app -- pro hello`.

## Errori comuni

- Una chiave `sk_…` dentro l’app. Chiunque può estrarla; il programma che distribuisci usa solo `LicenseClient`.
- Senza `product`, la chiamata viene rifiutata (`parameter_missing`). Passalo sempre; la chiave di qualsiasi altra cosa risponde `wrong_product`.
- Un `instance_name` che cambia a ogni avvio: ogni avvio consuma un’attivazione.
