v1.0 Dashboard Public Profile GitHub
✅ Complete Phase 7

Phase 7 — Billing System

Hybrid subscription + wallet billing — tenants choose a plan with a monthly call quota, top up their wallet via Stripe or Razorpay, and pay per minute after quota is exhausted.

What It Does

KaiVox bills tenants using a two-layer model: a monthly subscription plan that includes free call minutes, and a prepaid wallet that is charged per minute when the quota runs out. The wallet is topped up by the tenant at any time. The Super Admin manages plans, adjusts wallets, and monitors low-balance alerts.

Key Routes

URLDescription
GET /billingBilling overview (current plan, wallet balance, usage)
GET /billing/plansAvailable plans — upgrade/downgrade
POST /billing/subscribe/{planId}Change plan
GET /billing/topupWallet top-up form
POST /billing/topup/stripeInitiate Stripe Checkout Session
GET /billing/topup/stripe/successStripe success callback — verifies and credits wallet
POST /billing/topup/razorpayCreate Razorpay order
POST /billing/topup/razorpay/verifyVerify Razorpay signature and credit wallet
GET /billing/historyWallet transaction history + invoices
GET /super-admin/plansSuper Admin: manage subscription plans
GET /super-admin/billingSuper Admin: platform billing overview

Key Files

TypePath
Serviceapp/Services/BillingService.php — chargeForCall(), wallet deduction
Controllerapp/Http/Controllers/BillingController.php
Modelapp/Models/SubscriptionPlan.php
Modelapp/Models/Subscription.php
Tablesubscription_plans — name, monthly_price, call_quota_minutes, per_minute_rate, features
Tablesubscriptions — tenant_id, plan_id, status, trial_ends_at, current_period_start
Tablewallet_transactions — tenant_id, type, amount, balance_before, balance_after, reference, notes
Columntenants.wallet_balance — current prepaid balance
Columntenants.wallet_low_threshold — triggers low_wallet automation

Plans

PlanMonthly PriceFree MinutesOverage Rate
StarterFree / $XX50 min/month$0.01/min
Pro$XX/month200 min/month$0.008/min
EnterpriseCustomUnlimitedCustom

Exact pricing is managed by Super Admin — values in the table above are examples.

How Call Billing Works

Call ends → Vobiz/Twilio sends hangup webhook
        ↓
BillingService::chargeForCall($tenant, $durationSeconds)
        ↓
1. Convert seconds to minutes (round up to nearest minute)
2. Check subscriptions.quota_used vs subscription_plans.call_quota_minutes
3. If quota remaining → deduct from quota (free, no wallet charge)
4. If quota exhausted → calculate cost at plan per_minute_rate
5. Check tenants.wallet_balance ≥ cost
6. If sufficient → deduct from wallet, create wallet_transaction record
7. If insufficient → log failure, flag account for low wallet
8. Check if wallet_balance < wallet_low_threshold → fire low_wallet automation trigger

What's Complete

  • Subscription plan CRUD (Super Admin) — create, edit, toggle active
  • Tenant plan selection and upgrade/downgrade flows
  • 14-day free trial (trial_ends_at set on subscription creation)
  • Wallet top-up via Stripe Checkout Session flow
  • Wallet top-up via Razorpay order + signature verification
  • BillingService::chargeForCall() — quota then wallet deduction
  • Wallet transaction history (all credits and debits with reasons)
  • Invoice / billing history page
  • Super Admin billing overview (all tenant wallets, low-balance alerts)
  • Super Admin manual wallet adjustment (add/deduct with reason note)
  • BillingService wired into VobizService and TwilioService hangup handlers

Dynamic Pricing Control (2026-05-21)

Super Admin can increase or decrease any pricing metric at GET /super-admin/pricing. Changes are audited and can be scheduled or applied immediately.

URLDescription
GET /super-admin/pricingPricing control dashboard
POST /super-admin/pricing/plans/{plan}/update-nowApply price change immediately
POST /super-admin/pricing/plans/{plan}/scheduleSchedule change for 1st of next month
POST /super-admin/pricing/plans/{plan}/cancel-changeCancel a pending scheduled change
POST /super-admin/pricing/platform/update-nowUpdate platform base rates immediately
POST /super-admin/pricing/platform/scheduleSchedule platform rate change
POST /super-admin/pricing/feature-plan-mapUpdate which plan each feature requires
POST /super-admin/pricing/apply-dueManually trigger due scheduled changes
  • Scheduled changes — set price_effective_date → applies on 1st of that month via daily 00:05 scheduler
  • Tenant notice — yellow banner on tenant dashboard + billing page showing upcoming price change
  • Yearly plan protection — banner tells yearly subscribers their current cycle is unaffected
  • Audit trail — all changes logged to pricing_changes table with old/new values, who made the change, and when it applied
  • Metrics supported: monthly price, yearly price, per-minute rate, per-SMS rate, per-WhatsApp rate, discount percentage
TypePath
Serviceapp/Services/Billing/PricingService.php
Controllerapp/Http/Controllers/SuperAdmin/PricingController.php
Viewresources/views/super-admin/pricing.blade.php
Partialresources/views/partials/pricing-change-notice.blade.php
Tablepricing_changes — full audit history
Columnsplans.next_price_monthly/yearly, next_per_minute_rate, price_effective_date

What's Deferred

  • Automatic recurring Stripe subscription (currently manual plan tracking)
  • Prorated billing on plan change mid-cycle
  • Email receipts for top-ups and invoices (blocked locally; works on Hostinger)
  • Tax handling (GST for India, VAT for EU)