# Receta: suscripción SaaS

> Un plan mensual o anual en cripto. Cada periodo es una factura con recordatorios; tu app pregunta a Perly Pay quién tiene acceso.

No se puede cobrar cripto de una billetera, así que una suscripción se renueva por factura: antes de que acabe el periodo, el comprador recibe la siguiente y luego recordatorios hasta que la paga. No hay cobro automático. Tu app no cuenta los días: pregunta a `entitlements.check`.

> **Nota:** Con un asistente: la skill `sell-subscription` del plugin de Perly Pay hace esta receta en tu proyecto. El ejemplo ejecutable es `examples/saas-subscription` (MIT) en el repositorio del plugin.

## Cómo funciona

1. **Un plan** — Un producto y un precio con `model: "subscription"` y `recurring.interval` (`month`, `year`…), con días de prueba y de gracia si quieres.
2. **Una suscripción** — Una factura por ese precio con tu usuario como cliente abre la suscripción y su primera factura. Al pagarla, el plan queda activo.
3. **Acceso a funciones** — `entitlements.check({ customer_external_id, product })` → `has_access` y `ends_at`, en el servidor, en cada visita o con una caché corta.
4. **Escucha** — `invoice.fulfilled` para el primer pago y cada renovación; `subscription.past_due`, `subscription.unpaid` y `subscription.ended` para avisar y cerrar.
5. **Controles para el comprador** — Un enlace al portal del cliente (`portalSessions.create`): pagar una renovación abierta, pagar por adelantado o cancelar.

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

Los días de gracia, los cambios de plan y los estados están en [Subscriptions and reminders](https://pay.perly.io/docs/subscriptions.md).

## Ejecuta el ejemplo

1. **Instala** — `npm install` en `examples/saas-subscription` (Node 20.12+).
2. **Clave** — Copia `.env.example` a `.env` y pon una clave de prueba (`sk_test_…`) en `PERLY_PAY_SECRET_KEY`.
3. **Prepara** — `npm run setup` crea el producto y el precio con tu clave e imprime sus ids para `.env`.
4. **Ejecuta** — `npm start` (o `npm run dev`), según diga su README.
5. **Paga sin billetera** — Suscríbete en la página principal, pulsa **Simulate payment** en la factura y luego abre `/pro?user=you@example.com`: Pro queda abierto hasta el final del periodo.

## Errores comunes

- Prometer «cobraremos de tu billetera». No se cobra nada; di «se renueva por factura».
- Un correo del cliente que falta o es inventado: las facturas de renovación y los recordatorios van ahí.
- Quitar el acceso al primer minuto de retraso. Decide qué significa `past_due` (dentro de los días de gracia).
- Dar acceso cuando el comprador vuelve del pago. «Pagado» solo significa un webhook `invoice.fulfilled` verificado o `entitlements.check` desde tu servidor.
