Leyla mağazadan kitablar alır və «Prowid Shop Plus» istəyir: ayda 9.90 AZN-ə pulsuz çatdırılma. O, hər ay «Ödə» düyməsinə basmayacaq: pul imtina edənə qədər özü çıxılmalıdır. Bu — abunəlikdir və onun üç çətinliyi var: müntəzəm çıxarışlar, tarifin dəyişdirilməsi və ləğvi, bəzən keçməyən kartlar. Bütün bunları Stripe Billing öz üzərinə götürür, bizə isə giriş vəziyyətini öz bazamızda saxlamaq qalır.

Abunəliyin obyektləri

Product — nə satırıq («Prowid Shop Plus»), Price — nə qədər və nə qədər tez-tez (9.90 AZN, recurring.interval: 'month'), Customer — alıcı. Subscription — alıcı ilə qiymət arasındakı müqavilə: «hər ay 9.90 AZN çıx». Hər dövrdə Stripe Invoice (hesab) buraxır və onu PaymentIntent vasitəsilə ödəyir (dərs 041). Bənzətmə: idman zalı abunəliyi: müqavilə birdir, hesab isə hər ay gəlir.

Stripe Billing obyektləri: Product və Price, Customer, Subscription, Invoice və PaymentIntent, sizin bazanızda isə webhook-ların yenilədiyi User və Subscription cədvəlləri
Stripe Billing obyektləri: Product və Price, Customer, Subscription, Invoice və PaymentIntent, sizin bazanızda isə webhook-ların yenilədiyi User və Subscription cədvəlləri

Stripe öz obyektlərini saxlayır, sizin baza isə vəziyyətin surətini: kim abunə olub və hansı tarixə qədər. Tətbiq Stripe-ı yox, öz bazanızı oxuyur.

Qiymət və abunə rejimində Checkout

Product və təkrarlanan Price bir dəfə yaradılır, Dashboard-da və ya skriptlə:

js
// scripts/create-plus.js  (run once)
import { stripe } from '../src/stripe.js';

const product = await stripe.products.create({ name: 'Prowid Shop Plus' });

const price = await stripe.prices.create({
  product: product.id,
  currency: 'azn',
  unit_amount: 990, // 9.90 AZN every month
  recurring: { interval: 'month' },
});

console.log(price.id); // price_... -> PLUS_PRICE_ID in .env

Qiymətin id-sini .env-də PLUS_PRICE_ID kimi saxlayın. Alıcıya Customer lazımdır: onu ilk abunəlikdə yaradıb stripeCustomerId-ni User-də yadda saxlayırıq. Sonra mode: 'subscription' ilə Checkout Session:

js
// src/billing.js
import { stripe } from './stripe.js';
import { prisma } from './db.js';
import { handleOnce } from './idempotent.js';

export async function startSubscription(req, res) {
  const user = req.user; // from your auth middleware, never from the body
  let customerId = user.stripeCustomerId;

  if (!customerId) {
    const customer = await stripe.customers.create(
      { email: user.email, metadata: { userId: String(user.id) } },
      { idempotencyKey: `user-${user.id}-customer` },
    );
    customerId = customer.id;
    await prisma.user.update({
      where: { id: user.id },
      data: { stripeCustomerId: customerId },
    });
  }

  const session = await stripe.checkout.sessions.create({
    mode: 'subscription',
    customer: customerId,
    line_items: [{ price: process.env.PLUS_PRICE_ID, quantity: 1 }],
    success_url: `${process.env.APP_URL}/plus/thanks`,
    cancel_url: `${process.env.APP_URL}/plus`,
  });
  res.json({ url: session.url });
}