# Ricetta: abbonamento SaaS

> Un piano mensile o annuale in crypto. Ogni periodo è una fattura con promemoria; la tua app chiede a Perly Pay chi ha accesso.

Non si possono prelevare crypto da un wallet, quindi un abbonamento si rinnova a fattura: prima che finisca il periodo, l’acquirente riceve la successiva e poi promemoria finché non la paga. Nessun addebito automatico. La tua app non conta i giorni: chiede a `entitlements.check`.

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

## Come funziona

1. **Un piano** — Un prodotto e un prezzo con `model: "subscription"` e `recurring.interval` (`month`, `year`…), con giorni di prova e di tolleranza se vuoi.
2. **Un abbonamento** — Una fattura per quel prezzo con il tuo utente come cliente apre l’abbonamento e la sua prima fattura. Una volta pagata, il piano è attivo.
3. **Accesso alle funzioni** — `entitlements.check({ customer_external_id, product })` → `has_access` ed `ends_at`, sul server, a ogni visita o con una cache breve.
4. **Ascolta** — `invoice.fulfilled` per il primo pagamento e ogni rinnovo; `subscription.past_due`, `subscription.unpaid` e `subscription.ended` per avvisare e chiudere.
5. **Controlli per l’acquirente** — Un link al portale cliente (`portalSessions.create`): pagare un rinnovo aperto, pagare in anticipo o disdire.

**Subscribe, then gate**

```js
const invoice = await pay.invoices.create(
  { line_items: [{ price: PRO_MONTHLY }], customer: customer.id, metadata: { user: userId }, return_url },
  { idempotencyKey: `subscribe-${userId}-${today}` },
);
redirect(invoice.url); // invoice.subscription is the new subscription

const { has_access } = await pay.entitlements.check({ customer_external_id: userId, product: PRO });
```

Giorni di tolleranza, cambi di piano e stati sono in [Subscriptions and reminders](https://pay.perly.io/docs/subscriptions.md).

## Esegui l’esempio

1. **Installa** — `npm install` in `examples/saas-subscription` (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** — Abbonati dalla pagina principale, premi **Simulate payment** sulla fattura, poi apri `/pro?user=you@example.com`: Pro resta aperto fino alla fine del periodo.

## Errori comuni

- Promettere «addebiteremo dal tuo wallet». Non viene addebitato nulla; di’ «si rinnova a fattura».
- Un’email del cliente mancante o inventata: le fatture di rinnovo e i promemoria vanno lì.
- Togliere l’accesso al primo minuto di ritardo. Decidi cosa significa `past_due` (dentro i giorni di tolleranza).
- Dare l’accesso quando l’acquirente torna dal checkout. «Pagato» significa solo un webhook `invoice.fulfilled` verificato o `entitlements.check` dal tuo server.
