Mergi la conținut

Ghiduri practice

Abonamente pentru un SaaS

Catalog, înscriere, încasare inițială, reînnoiri și controlul accesului, fără un portal de plată separat.

Exemple server-side cu SDK-urile oficiale Monedo. Înlocuiește identificatorii și configurația cu resursele propriei instalări. Datele din exemple nu sunt tranzacții reale.

1. Definește produsul și politica de preț

Separă produsul comercial de prețul recurent. Creează produsul și un preț cu monedă, interval și model de calcul. Înregistrează priceId în catalogul serverului tău; nu accepta orice preț trimis de browser. Poți folosi per_unit, volume sau graduated conform schemei API, iar prices.quote calculează oferta pentru cantitatea cerută. O ofertă nu este o plată și nu activează accesul.

  • Folosește valori întregi în subdiviziunile monedei pentru sumele Payments.
  • Nu recalcula pe client treptele de tarifare ca sursă de adevăr.
  • Prețurile noi și schimbările contractuale trebuie prezentate clientului înainte de confirmare.
  • Pentru price_data verifică schema completă din referință; nu îl trimite simultan cu price.

2. Creează abonamentul și deschide Checkout

customerId și priceId provin din aceeași instalare și același mediu. Creează clientul o singură dată pentru identitatea locală, păstrează asocierea și reutilizeaz-o. signupId trebuie persistat; generarea unui ID nou la fiecare refresh anulează protecția de idempotency. Exemplul este pentru încasarea proprie; distribuțiile recurente se declară separat la crearea abonamentului.

subscription.mjs · Node.js / server
import { MonedoPayments } from '@monedo/payments';

// Customer and price IDs must belong to the same installation and environment.
// Persist signupId; retries must reuse the same IDs, quantity and return URLs.
export async function createSubscriptionCheckout({ apiKey, signupId, customerId, priceId, quantity = 1, returnOrigin, fetch }) {
  const monedo = new MonedoPayments({ apiKey, fetch });
  const subscription = await monedo.subscriptions.create({
    customer: customerId,
    price: priceId,
    quantity,
  }, { idempotencyKey: `signup_${signupId}_subscription_v1` });
  const session = await monedo.checkoutSessions.create({
    subscription: subscription.id,
    success_url: `${returnOrigin}/subscription/return`,
    cancel_url: `${returnOrigin}/subscription/cancel`,
  }, { idempotencyKey: `signup_${signupId}_checkout_v1` });
  if (!session.checkout_url) throw new Error('Checkout URL unavailable; retrieve the session before retrying');
  return { subscriptionId: subscription.id, sessionId: session.id, url: session.checkout_url };
}

// Update access from the retrieved subscription's `entitled` and `access_until`.
// Do not grant permanent access from a redirect or from the first payment alone.

3. Leagă accesul de starea abonamentului

Păstrează subscriptionId pe contul utilizatorului și citește entitled împreună cu access_until. Nu acorda acces nelimitat pentru că prima plată a reușit. Evenimentele și recitirea abonamentului actualizează drepturile la activare, reînnoire, recuperare și anulare. O citire fără succes este o problemă temporară de sincronizare, nu dovada că utilizatorul și-a anulat contractul.

SituațieComportament în aplicație
Înscriere incompletăAfișezi reluarea checkoutului; nu promiți acces activ.
Plată în procesareAștepți confirmarea și păstrezi operația identificabilă.
Reînnoire nereușităArăți starea actuală și opțiunea de recuperare; respecți entitled/access_until.
Anulare la final de perioadăExplici data încetării; nu retragi automat accesul deja plătit.
Schimbare de planCreezi o schimbare și obții acceptarea noilor condiții, nu suprascrii unilateral contractul.

4. Testează ciclul, nu doar prima plată

  • Prima plată cu și fără autentificare suplimentară.
  • Reînnoire reușită, reînnoire refuzată și recuperarea facturii restante.
  • Anulare la sfârșitul perioadei și efectul asupra accesului.
  • Schimbare de preț/cantitate și consimțământul clientului.
  • Evenimente duplicate, întârziate și venite în ordine inversă.
  • Refundul unei plăți și anularea abonamentului sunt operații distincte; testează ambele.