# Recette : abonnement SaaS

> Une offre mensuelle ou annuelle payée en crypto. Chaque période est une facture avec rappels ; votre app demande à Perly Pay qui a accès.

On ne peut pas prélever de la crypto dans un portefeuille : un abonnement se renouvelle donc par facture. Avant la fin de chaque période, l’acheteur reçoit la suivante, puis des rappels jusqu’au paiement. Il n’y a pas de prélèvement automatique. Votre app ne compte jamais les jours : elle interroge `entitlements.check`.

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

## Comment ça marche

1. **Une offre** — Un produit et un prix avec `model: "subscription"` et `recurring.interval` (`month`, `year`…), avec en option des jours d’essai et de grâce.
2. **Abonnement** — Une facture pour ce prix avec l’utilisateur comme client ouvre l’abonnement et sa première facture. La payer active l’offre.
3. **Contrôler l’accès** — `entitlements.check({ customer_external_id, product })` → `has_access` et `ends_at`, côté serveur, à chaque visite ou avec un cache court.
4. **Écoutez** — `invoice.fulfilled` pour le premier paiement et chaque renouvellement ; `subscription.past_due`, `subscription.unpaid` et `subscription.ended` pour avertir et bloquer.
5. **Laissez l’acheteur gérer** — Un lien vers l’espace client (`portalSessions.create`) pour payer le renouvellement ouvert, payer d’avance ou résilier.

**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 });
```

Voir [Subscriptions and reminders](https://pay.perly.io/docs/subscriptions.md) pour les jours de grâce, les changements d’offre et les statuts.

## Lancez l’exemple

1. **Installez** — `npm install` dans `examples/saas-subscription` (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** — Abonnez-vous sur la page d’accueil, touchez **Simulate payment** sur la facture, puis ouvrez `/pro?user=you@example.com` : Pro est débloqué jusqu’à la fin de la période.

## Pièges

- Dire « nous débitons votre portefeuille automatiquement ». Rien n’est prélevé ; dites « renouvelé par facture ».
- Un e-mail client absent ou inventé : les factures de renouvellement et les rappels y partent.
- Bloquer dès la première minute de retard. Décidez ce que `past_due` (pendant les jours de grâce) signifie pour l’accès.
- Donner l’accès au retour de la page de paiement. Seuls un webhook `invoice.fulfilled` vérifié ou `entitlements.check` depuis votre serveur signifient « payé ».
