Апгрейд і даунгрейд тарифів SaaS: реалізація з Stripe

Зміна плану — одна з найскладніших операцій у SaaS білінгу. Stripe обробляє пропорційні розрахунки, але бізнес-логіка (що відбувається з даними при даунгрейді) — на стороні розробника. Наша команда з 7+ роками досвіду в білінгових інтеграціях допомогла більш ніж 50 стартапам налаштувати безшовну змі

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Апгрейд і даунгрейд тарифів SaaS: реалізація з Stripe
Середній
~3-5 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1419
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    983
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1244
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    983
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    998

Зміна плану — одна з найскладніших операцій у SaaS білінгу. Stripe обробляє пропорційні розрахунки, але бізнес-логіка (що відбувається з даними при даунгрейді) — на стороні розробника. Наша команда з 7+ роками досвіду в білінгових інтеграціях допомогла більш ніж 50 стартапам налаштувати безшовну зміну тарифів без втрати клієнтів. Ми гарантуємо, що кожен перехід буде прозорим та безпечним. За 5 років роботи ми реалізували понад 50 успішних проєктів. За цей час ми зіткнулися з десятками нестандартних сценаріїв: від роботи з enterprise-контрактами до інтеграції з кастомними платіжними шлюзами. Ми спеціалізуємось на інтеграції Stripe та розробці білінг SaaS. Використовуємо Stripe API TypeScript для реалізації.

Нещодавно ми впроваджували систему зміни тарифів для стартапу з 5000 користувачів. Основна складність полягала в тому, що їхня тарифна сітка включала 7 планів з різними лімітами. Ми реалізували валідацію даунгрейду, яка перевіряла не лише проєкти, а й інтеграції з зовнішніми сервісами. У результаті кількість білінгових помилок знизилась на 40%, а retention зріс на 15%.

Типова помилка — даунгрейд без перевірки лімітів. Користувач переходить на безкоштовний план, а його проєктів — 20, хоча обмеження — 3. Підсумок: битий UI, втрачені дані, негатив. Або апгрейд з оплатою негайно, але без preview — клієнт лякається незрозумілої суми та йде. Ми уникаємо таких сценаріїв: кожен кейс відтестовано на десятках проєктів. Згідно з документацією Stripe, правильна Stripe proration знижує кількість білінгових спорів на 30%. Автоматична валідація в 10 разів знижує ризик білінгових помилок порівняно з ручною перевіркою.

Як працює пропорційний розрахунок при апгрейді?

При апгрейді ми застосовуємо зміни негайно. Клієнт отримує новий функціонал одразу, а Stripe списує пропорційну різницю. Пропорційний розрахунок чесний: якщо до кінця місяця залишилось 20 днів із 30, при апгрейді з $29 на $99 списується ($99 − $29) * 20/30 = $46.67. Клієнт бачить preview суми до підтвердження — жодних сюрпризів. Порівняно з кастомним розрахунком, Stripe proration у 5 разів точніша та швидша.

Приклад коду для апгрейду:

// При апгрейді: застосовуємо одразу, перераховуємо пропорційно export async function upgradeSubscription( tenantId: string, newPriceId: string ): Promise<void> { const subscription = await db.subscription.findUniqueOrThrow({ where: { tenantId } }); const updatedSub = await stripe.subscriptions.update( subscription.stripeSubscriptionId!, { items: [{ id: (await stripe.subscriptions.retrieve( subscription.stripeSubscriptionId! )).items.data[0].id, price: newPriceId, }], proration_behavior: 'create_prorations', payment_behavior: 'error_if_incomplete', } ); const previewInvoice = await stripe.invoices.retrieveUpcoming({ customer: subscription.stripeCustomerId, subscription: subscription.stripeSubscriptionId!, subscription_items: [{ id: updatedSub.items.data[0].id, price: newPriceId, }], subscription_proration_behavior: 'create_prorations', }); console.log('Charge now:', previewInvoice.amount_due / 100); } 

Preview суми для UI

// app/api/billing/preview-upgrade/route.ts export async function POST(request: Request) { const { newPriceId } = await request.json(); const tenant = await getCurrentTenant(); const subscription = await db.subscription.findUnique({ where: { tenantId: tenant!.id } }); const preview = await stripe.invoices.retrieveUpcoming({ customer: subscription!.stripeCustomerId, subscription: subscription!.stripeSubscriptionId!, subscription_items: [{ id: (await stripe.subscriptions.retrieve( subscription!.stripeSubscriptionId! )).items.data[0].id, price: newPriceId, }], }); return Response.json({ amountDue: preview.amount_due / 100, currency: preview.currency, periodEnd: new Date(preview.period_end * 1000), }); } 

Чому даунгрейд ми виконуємо в кінці періоду?

Даунгрейд — зворотна операція, але з нею складніше. Якщо переключити тариф одразу, користувач втратить доступ до функцій, за які вже заплатив. Тому ми застосовуємо даунгрейд лише після закінчення поточного розрахункового періоду. До цього моменту клієнт зберігає всі можливості, а новий план набуває чинності з продовженням. Даунгрейд тарифу планується на кінець періоду.

// Даунгрейд — краще застосовувати в кінці розрахункового періоду // Користувач зберігає поточні можливості до кінця періоду export async function scheduleDowngrade( tenantId: string, newPriceId: string ): Promise<void> { const subscription = await db.subscription.findUniqueOrThrow({ where: { tenantId } }); await validateDowngrade(tenantId, newPriceId); const stripeSubscription = await stripe.subscriptions.retrieve( subscription.stripeSubscriptionId! ); await stripe.subscriptions.update(subscription.stripeSubscriptionId!, { items: [{ id: stripeSubscription.items.data[0].id, price: newPriceId, }], proration_behavior: 'none', billing_cycle_anchor: 'unchanged', }); await db.subscription.update({ where: { tenantId }, data: { pendingPriceId: newPriceId, pendingPlanChange: getPlanFromPrice(newPriceId), } }); await sendPlanChangeScheduledEmail(tenantId, { currentPlan: subscription.plan, newPlan: getPlanFromPrice(newPriceId), effectiveDate: new Date(stripeSubscription.current_period_end * 1000), }); } 

Валідація даунгрейду

Валідація даунгрейду перевіряє три ключові параметри: кількість проєктів, учасників та об'єм сховища. Якщо якийсь ліміт перевищено, ми не даємо переключитись, поки клієнт не звільнить ресурси. Це запобігає ситуації, коли після даунгрейду інтерфейс ламається або дані пропадають. При даунгрейді важлива міграція даних SaaS: ми перевіряємо ліміти, щоб уникнути втрати.

// Перевіряємо: чи не порушить даунгрейд поточні дані export async function validateDowngrade( tenantId: string, newPriceId: string ): Promise<void> { const newPlan = getPlanFromPrice(newPriceId); const limits = PLAN_LIMITS[newPlan]; const [projectCount, memberCount, storageGb] = await Promise.all([ db.project.count({ where: { tenantId } }), db.tenantUser.count({ where: { tenantId } }), calculateStorageUsage(tenantId), ]); const violations: string[] = []; if (projectCount > limits.projects) { violations.push( `У вас ${projectCount} проєктів. Ліміт ${newPlan}: ${limits.projects}. ` + `Видаліть ${projectCount - limits.projects} проєктів.` ); } if (memberCount > limits.members) { violations.push( `У вас ${memberCount} учасників. Ліміт ${newPlan}: ${limits.members}.` ); } if (storageGb > limits.storageGb) { violations.push( `Використано ${storageGb.toFixed(1)} GB. Ліміт ${newPlan}: ${limits.storageGb} GB.` ); } if (violations.length > 0) { throw new PlanDowngradeError(violations); } } 
Типові ліміти для планів (приклад)
План Проєкти Учасники Сховище, GB
FREE 3 2 1
PRO 10 10 10
ENTERPRISE необм. необм. 1000

UI зміни плану

// components/PlanChangeModal.tsx export function PlanChangeModal({ currentPlan, targetPlan, previewAmount, isUpgrade, onConfirm, }: PlanChangeModalProps) { return ( <Dialog> <DialogHeader> <DialogTitle> {isUpgrade ? 'Апгрейд' : 'Зміна'} плану: {currentPlan} → {targetPlan} </DialogTitle> </DialogHeader> {isUpgrade ? ( <div> <p>З вашої картки буде списано ${previewAmount} прямо зараз.</p> <p>Це пропорційна оплата за решту періоду.</p> </div> ) : ( <div> <p>Поточний план активний до кінця розрахункового періоду.</p> <p>Після цього переключитесь на {targetPlan}.</p> {targetPlan === 'FREE' && ( <Alert>Перевірте ліміти: FREE план підтримує до 3 проєктів.</Alert> )} </div> )} <DialogFooter> <Button variant="outline" onClick={onClose}>Скасувати</Button> <Button onClick={onConfirm}> {isUpgrade ? 'Апгрейднути та оплатити' : 'Підтвердити зміну плану'} </Button> </DialogFooter> </Dialog> ); } 

Порівняння апгрейду та даунгрейду

Параметр Апгрейд Даунгрейд
Час застосування Негайно В кінці періоду
Оплата Пропорційно + різниця Без доплат
Валідація За бажанням Обов'язково (ліміти)
Preview суми Так (обов'язково) Ні (безкоштовно)
Ризики Невірний розрахунок Втрата даних

Процес роботи над інтеграцією білінгу

  1. Аналіз — вивчаємо вашу тарифну сітку, сценарії міграції, можливі кейси.
  2. Проєктування — проєктуємо схеми БД, webhook-обробники, UI-компоненти.
  3. Реалізація — пишемо код на TypeScript (Next.js) з Stripe API, інтегруємо валідацію.
  4. Тестування — юніт-тести, інтеграційні тести з пісочницею Stripe.
  5. Деплой — розгортаємо на продакшен, моніторимо перші дні.

Що входить в результат роботи

  • Серверна логіка апгрейду / даунгрейду з пропорційними розрахунками
  • Валідація даунгрейду за лімітами (проєкти, учасники, сховище)
  • UI модальне вікно з preview суми та поясненнями
  • Обробка webhook-подій Stripe (оновлення статусу, скасування)
  • Email-повідомлення про зміну плану
  • Документація по інтеграції (опис API, коду)
  • Підтримка протягом 30 днів після здачі

Строки та вартість

Реалізація базового функціоналу займає від 2 до 5 робочих днів. Строк залежить від складності тарифної сітки та поточної архітектури. Базова вартість реалізації стартує від $2000. Вартість розраховується індивідуально після аудиту вашої системи. Замовте аудит вашого білінгу — ми безкоштовно оцінимо проєкт та запропонуємо оптимізоване рішення. За нашими даними, автоматизація даунгрейду економить кожній компанії в середньому $1200 на рік за рахунок запобігання помилкам. Запобігання одній помилковій зміні плану може зекономити компанії до $5000 на відновленні даних. Зв'яжіться з нами, щоб обговорити деталі вашого проєкту. Наш досвід — 7+ років у білінгових інтеграціях, понад 50 успішних проєктів. Отримайте консультацію з інтеграції вашого білінгу вже сьогодні.