# Przepis: subskrypcja SaaS

> Plan miesięczny lub roczny za kryptowaluty. Każdy okres to faktura z przypomnieniami; aplikacja pyta Perly Pay, kto ma dostęp.

Kryptowaluty nie da się pobrać z portfela, więc subskrypcja odnawia się fakturą: przed końcem okresu kupujący dostaje następną, potem przypomnienia, dopóki nie zostanie opłacona. Nie ma automatycznego pobierania. Aplikacja nie liczy dni sama — pyta `entitlements.check`.

> **Uwaga:** Z asystentem: ten przepis realizuje w Twoim projekcie skill `sell-subscription` wtyczki Perly Pay. Działający przykład to `examples/saas-subscription` (MIT) w repozytorium wtyczki.

## Jak to działa

1. **Plan** — Produkt i cena z `model: "subscription"` oraz `recurring.interval` (`month`, `year`…), opcjonalnie dni próbne i dni karencji.
2. **Subskrypcja** — Faktura na tę cenę z użytkownikiem jako klientem otwiera subskrypcję i jej pierwszą fakturę. Jej opłacenie aktywuje plan.
3. **Dostęp do funkcji** — `entitlements.check({ customer_external_id, product })` → `has_access` i `ends_at`, na serwerze, przy każdej wizycie lub z krótkim cache.
4. **Nasłuchuj** — `invoice.fulfilled` — pierwsza płatność i każde odnowienie; `subscription.past_due`, `subscription.unpaid` i `subscription.ended` — żeby ostrzec i zamknąć.
5. **Zarządzanie dla kupującego** — Link do portalu klienta (`portalSessions.create`): opłacić otwarte odnowienie, zapłacić z góry albo anulować.

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

Dni karencji, zmianę planu i statusy opisano w [Subscriptions and reminders](https://pay.perly.io/docs/subscriptions.md).

## Uruchom przykład

1. **Zainstaluj** — `npm install` w `examples/saas-subscription` (Node 20.12+).
2. **Klucz** — Skopiuj `.env.example` do `.env` i wpisz klucz testowy (`sk_test_…`) w `PERLY_PAY_SECRET_KEY`.
3. **Przygotuj** — `npm run setup` tworzy produkt i cenę Twoim kluczem i drukuje ich identyfikatory do `.env`.
4. **Uruchom** — `npm start` (lub `npm run dev`), jak mówi jego README.
5. **Zapłać bez portfela** — Zasubskrybuj na stronie głównej, kliknij **Simulate payment** na fakturze, potem otwórz `/pro?user=you@example.com`: Pro jest otwarte do końca okresu.

## Pułapki

- Obiecywanie „sami pobierzemy z Twojego portfela”. Nic nie jest pobierane; mów „odnawia się fakturą”.
- Brak lub zmyślony e-mail klienta: faktury za odnowienie i przypomnienia idą właśnie tam.
- Zamykanie dostępu w pierwszej minucie spóźnienia. Zdecyduj, co znaczy `past_due` (w ramach dni karencji).
- Otwieranie dostępu, gdy kupujący wrócił z płatności. „Opłacone” znaczy tylko zweryfikowany webhook `invoice.fulfilled` albo `entitlements.check` z Twojego serwera.
