Stripe Implementing Subscription Based System

Salutare.

Am zis sa va cer parerea/ajutorul in legatura cu o implementare pe care trebuie s-o fac, poate ajung mai repede la solutia buna, cu ajutorul vostru.

Trebuie sa implementez urmatorul sistem de subscriptii.

Overall Subscription Sales se refera la o anumita categorie de utilizatori care vor vinde subscriptii (ei vor face plata) catre o alta categorie de utilizatori, in interiorul platformei.
Ca si exemplu, la planul Silver, daca un client vinde subscriptii (cumpara subscriptia si o asigneaza unui alt user), in valoare de 50k$ - 100k$, el va avea o reducere de 20% la propria subscriptie.

Problema ar fi ca nu am gasit inca solutia in care Stripe poate sa-mi calculeze acasta valoare de Overall Subscription Sales si sa adapteze preturile in functie de asta. Stripe, prin tiers based pricing se bazeaza in principiu pe quantity, ceea ce nu-i chiar acelasi lucru.

Ei au o documentatie si o solutie destul de complexa in materie de subscriptii, si, desi par ca ca sunt mai multe variante care seamana cu ce am eu nevoie, parca nici una nu se potriveste perfect. Ei au urmatoarele optiuni de model pricing

  • Flat rate-Good-better-best
    • Not relevant
  • Per-seat
    • Not relevant
  • Usage-based pricing
    • asta pare sa mearga in ideea in care eu fac calculez la fiecare user valoarea de bani pe care a generat-o, considerand-o ca si un usage si i-o trimit la Stripe aceasta informatie.
  • Tiered pricing
    • asta pare sa mearga insusi prin numele pe care il are: tiers, dar totusi, ce nu-mi iese la socoteala aici e faptul ca acest pricing se bazeaza pe quantity in principiu, cand la mine nu e vorba de neaparat de quantity cat de un usage/valoare de bani generata, fie prin subscriptii monthly, sau yearly. O cantitate de 3 subscriptii yearly, nu e acelasi lucru cu o cantitate de 3 subscriptii monthly. E vorba de sume diferite de bani. Pe mine ma intereseaza in final banii cheltuiti/generati, adica Overall Subscription Sales.
  • Advances Pricing Model → Flat rate + per-seat
    • Asta la fel pare se mearga in ideea in care, per-seat putem considera ca fiecare subscriptie cumparata pentru un alt user, dar tot nu pare sa se muleze perfect

O alta idee ar fi ca sa fac o implementare mai custom, adica sa mut o parte de logica in sistemul meu, ceea ce tine de cat Overall sales subscriptions a generat fiecare client in parte si sa fac eu asignarile de subscriptie, in functie de asta. Adica sa nu ma bazez pe Stripe ca el sa-mi calculeze aceasta suma.

Voi ce parere aveti?
Multumesc.

Solutia pentru subscriptii de la stripe e printre cele mai complete si mai implementabile de pe piata.
Problema e ca o solutie de genul asta nu se va adapta niciodata 100% la nevoile tale. N-are cum, pentru ca nevoile tale se tot schimba.

1 Like

Cea mai simpla solutie e sa folosesti Stripe Credit, si creditezi similar cu un sistem de afiliere : Customer credit balance | Stripe Documentation rulezi printr-un cron fiecare zi cand se face plata de subscriptie, si creditezi cu 20% din valorea urmatoarei plati.

Edit : Iei toate subscriptiile care au next_billing_date ( sau cum ar fi ) tomorrow, si calculezi daca primesc credit, apoi aplici creditul, sau cu 1 ora inainte de billing date daca vrei sa fie mai exact.

1 Like

Multumesc de sugestii.
Deocamdata am mers pe urmatorul design, adica pe sistemul basic de la Stripe, care nu se bazeaza pe tiers sau alte pricing models, ci pur si simplu le creez eu manual, fiecare tip de subscriptie/pret in parte.

Create Subscription Plan request body

{
    "name": "Silver",
    "description": "Silver Description",
    "monthlyPrice": 105.35,
    "yearlyPrice": 1074.57,
    "partnerTierDiscounts": [
        {
            "name": "Partner Tier 1",
            "salesUpTo": 50000,
            "discountPercentage": 15
        },
        {
            "name": "Partner Tier 2",
            "salesUpTo": 100000,
            "discountPercentage": 20
        },
        {
            "name": "Partner Tier 3",
            "salesUpTo": 150000,
            "discountPercentage": 25
        },
        {
            "name": "Partner Tier 4",
            "salesUpTo": -1,
            "discountPercentage": 30
        }
    ],
    "diskQuota": 512
}

SubscriptionPlan DB Model

export interface PartnerTierDiscount {
    name: string;
    salesUpTo: number;
    discountPercentage: number;
    stripePriceID: string;
}

interface SubscriptionsAttrs {
  name: string;
  description?: string;
  diskQuota: number;
  monthly: {
      price: number;
      stripePriceID: string;
  };
  yearly: {
      price: number;
      stripePriceID: string;
  }
  partnerTierDiscounts: PartnerTierDiscount[];
  stripeProductID: string;
}

StripeService.createSubscriptionPlan() method

export class StripeService {

    static async createSubscriptionPlan({name, monthlyPrice, yearlyPrice, partnerTierDiscounts }: CreateSubscriptionPlan): Promise<CreateSubscriptionPlanResponse> {
        const params: Stripe.ProductCreateParams = {
            name: name,
            id: convertToSlug(name),
        }

        const product = await stripe.products.create(params);

        const getPriceParams = ({price, nickname, interval, metadata}: BasicPriceParams): Stripe.PriceCreateParams => ({
            product: product.id,
            nickname: nickname,
            currency: 'usd', // TODO: auto detect the currency
            recurring: {
                interval: interval,
            },
            unit_amount_decimal: price.toString(),
            metadata: metadata,

        });

        const monthlyProductPricePromise = stripe.prices.create(getPriceParams({
            price: +monthlyPrice.toFixed(2) * 100, // stripe requires 2 digits comma
            nickname: `Monthly ${name}`,
            interval: 'month'
        }));

        const yearlyProductPricePromise = stripe.prices.create(getPriceParams({
            price: +yearlyPrice.toFixed(2) * 100, // stripe requires 2 digits comma
            nickname: `Yearly ${name}`,
            interval: 'year'
        }));

        const [monthlyProductPrice, yearlyProductPrice] = await Promise.all([
            monthlyProductPricePromise,
            yearlyProductPricePromise
        ])

        const partnerTierPrices: Stripe.Price[] = [];
        (partnerTierDiscounts || []).map(async (tier: PartnerTierDiscount) => {
            const monthlyUnitAmount = subtractPercent(monthlyPrice, tier.discountPercentage);
            const yearlyUnitAmount = subtractPercent(yearlyPrice, tier.discountPercentage);

             const monthlyProductPricePromise = stripe.prices.create(getPriceParams({
                price: +monthlyUnitAmount.toFixed(2) * 100, // stripe requires 2 digits comma
                nickname: `Monthly ${name}: ${tier.name}; Sales Up To: ${tier.salesUpTo}`,
                interval: 'month',
                metadata: {...tier},
            }));

            const yearlyProductPricePromise = stripe.prices.create(getPriceParams({
                price: +yearlyUnitAmount.toFixed(2) * 100, // stripe requires 2 digits comma
                nickname: `Yearly ${name}: ${tier.name}; Sales Up To: ${tier.salesUpTo}`,
                interval: 'year',
                metadata: {...tier}
            }));

            const [monthlyProductPrice, yearlyProductPrice] = await Promise.all([
                monthlyProductPricePromise,
                yearlyProductPricePromise
            ])

            partnerTierPrices.push(monthlyProductPrice, yearlyProductPrice)

        });

        return {product, monthlyProductPrice, yearlyProductPrice, partnerTierPrices }
    }
}