#Billing
Phase 3 deferred billing to "its own phase", and that phase has now been written. Billing data (plans, payments, receipts…) is stored in Central and v7 users' billing moves to V8 (R5). V8 requirement Rules exist, endpoints do not Missing — nothing on this page can be built until the billing API is published. Where a row below still says V7 only, the backend doc has not spoken about it.
#What Phase 6 settles
| # | Rule V8 requirement |
|---|---|
| 6.1 | Stripe, PayPal, Instamojo, each with on/off and test/live mode. The user sees only enabled gateways |
| 6.2 | Billing details (name, address, country, tax number) live on the account that pays and are copied onto every receipt |
| 6.3 | Wallet = paid + free + promo credits; promo credits expire; spend order as V7. V7's server credits are dropped |
| 6.4 | Top-up: minimum from settings, maximum $4,000 per payment, promo codes (not at or below the minimum), tax as V7, credit added only after the gateway confirms, each payment credited once. V7's "+3 server limit" per payment is dropped (2026-10-05) — the server limit comes only from the plan |
| 6.5 | Stripe saved card + auto-recharge when credits fall to the user's minimum |
| 6.6 | Low-credit reminder minimum set by the user, $1–$1,000 |
| 6.7 | Payments and charges list, and a receipt for every payment with billing details and tax |
| 6.8–6.11 | Managed servers: admin price list per provider / region / size (DigitalOcean, Vultr, Linode, Hetzner); create needs one month's price in credit; hourly rate = monthly ÷ (days in month × 24), full hours, paid credits only; usage per server |
| 6.12–6.13 | Negative balance = managed servers only (corrected 2026-10-05, see below). Starts when paid credits reach 0 or below and the dates are saved once: reminders → due date (+4 d) → expire date (+3 d) → deletion date (+7 d); trial 2 / 2 / 4, all V7 defaults. On the expire date servers with no apps and no databases are deleted and the others are powered off (Central asks each server's OSS panel); the rest are deleted on the deletion date. Adding credit stops the process, clears the saved dates and ends trial mode — but does not power a server back on |
#V7 model: prepaid wallet credits
| Concept | V7 storage | Notes |
|---|---|---|
| Wallet balance | users.credits, users.free_credits, users.server_credits | Per user, not per organization. V8 keeps paid / free / promo and drops server_credits, whose leftover is added to paid credits at migration (6.3) V8 requirement. The exact spend order is "as V7" and is still not written out Assumption |
| Wallet history | wallet_histories (type debit/credit, service, amount, links to invoice/transaction/organization) | |
| Transactions | transactions: base, discount, tax, final amount, gateway, status (0 failed · 1 success · 2 pending · 3 refund), conversion_rate, payment_link, refund fields, promo code, affiliate commission | |
| Charges | charges: service, amounts, status, hourly counters (total_spent_hours, total_unpaid_hours) | Usage-based charges (e.g. hourly managed servers) |
| Invoices | invoices: invoice_number, status, amount, name, address, tax_numbers, organization_id (nullable) | |
| Billing details | user_billing_details / organization billing details | Name, address, tax IDs |
| Cards | Stripe customer (stripe_id, pm_type, pm_last_four) | |
| Auto-recharge | stripe_auto_charges: is_enabled, min_credit, charge_amount | Daily job at 23:00 tops up when the balance < min |
| Low-credit reminder | users.reminder_minimum_credit | Daily reminder email |
| Negative balance | users.negative_period | Must be paid before deleting the account (V8 3.7 keeps this) |
#Features (V7 → V8 status)
| Feature | V7 | V8 |
|---|---|---|
| Wallet / balance | Yes | Kept (6.3) V8 requirement — D-4 answered |
| Credits (paid + free + promo) | Yes | Kept, promo credits expire. Server credits dropped (6.3) V8 requirement |
| Add credit (top-up) | POST /user/wallet: amount min = minimum_transaction setting, max 4000, gateway, optional promo, optional plan purchase | Same rules confirmed (6.4): minimum from settings, max $4,000, promo not at or below the minimum, credited only once and only after the gateway confirms V8 requirement. The "+3 server limit" bonus is dropped (2026-10-05). No endpoint yet Missing |
| Transactions | GET /payment, receipt GET /payment-receipt/{key}/receipt | Payments and charges in one history, receipt per payment (6.7) V8 requirement. No endpoint yet Missing |
| Payment methods | Stripe cards: list, setup intent, add, set default, delete | Stripe saved card kept (6.5) V8 requirement. No endpoint yet Missing |
| Invoices | GET /organizations/{org}/invoices, download/view POST …/invoices/{number}/{action} | Phase 6 says receipt, not invoice, and puts billing details on the account rather than the organization (6.2, 6.7) V8 requirement. Whether V7's organization invoices survive under that name is unstated Open question |
| Auto-recharge | GET/POST /stripe-auto-charge | Kept (6.5): charges the chosen amount when credits fall to the user's minimum V8 requirement |
| Low-credit reminder | users.reminder_minimum_credit | Kept (6.6), user-set between $1 and $1,000 V8 requirement |
| Payment history | Transactions + wallet history | Kept (6.7) V8 requirement |
| Taxes | tax_amount exists on transactions/charges. How it's calculated isn't visible in the inspected code (spend helper returns tax_amount: 0 by default) | "Tax as V7 (Instamojo, or Stripe for India)" (6.4) — the trigger is named, the calculation and display rule are still not Open question D-22 |
| Currency | USD in all V7 messages ("$"). conversion_rate (default 80.08) converts to INR for Instamojo | Phase 6 writes every amount in $ but states no currency rule Open question D-22 |
| Subscription payments | Deducted from credits, recorded as charges | Confirmed by Phase 7 (7.5) V8 requirement |
| Managed servers (hourly) | Hourly charges on managed/premium servers | Specified (6.8–6.11): admin price list, hourly rate from the monthly price, paid credits only, usage per server V8 requirement |
| Negative balance | users.negative_period + deletion flow | Specified for managed servers (6.12–6.13) V8 requirement. The V7 wallet track (days 1–15 for plan-billed servers) is not being rebuilt; plan expiry covers it (7.12) |
| Pending charges | GET /user/charges/pending-pay/show, pay pending | Not mentioned by Phase 6 Open question |
| Credit expiry | Daily credit:expire job | Confirmed for promo credits (6.3) V8 requirement |
#Payment gateways
Answered by Phase 6 (6.1), 2026-10-05 V8 requirement: V8 keeps all three V7 gateways — Stripe, PayPal and Instamojo. Each has its own on/off switch, test/live mode and keys, read from the database until the admin panel exists, and the user sees only the enabled ones. So D-5 is closed: the frontend builds the gateway choice from the API and hard-codes no gateway. Stripe is still the only gateway that can save a card and drive auto-recharge (6.5).
#Payment flow (must keep)
Confirmed by Phase 6 (6.4): credits are added only after the gateway confirms the payment, and each payment is credited once. So the rule the frontend already followed is now a written backend rule: the return page shows "Confirming payment…" and asks the API, and never treats a redirect back from the gateway as success. V8 requirement
- BE creates a pending transaction (status 2) with a unique key and returns the gateway URL. V7 only
payment/{key}/execute - The browser goes to the gateway.
- The gateway returns to Central's return page. FE shows "Confirming payment…" and asks BE for the status. It never trusts query parameters.
- BE verifies with the gateway (
payment/{key}/verify), and ideally also through a server-to-server webhook. V7 relies on the verify call. Webhooks for Stripe/PayPal aren't visible in the V7 routes Missing. - On success: credits added, wallet history written, then the plan purchased if one was attached. On failure: the transaction is marked failed (a 30-minute
transaction:failedjob also expires stale pending ones). V7 only - FE polls the transaction until it's
success/failed(timeout → "still processing, we'll email you") and then refreshes wallet, subscription and invoices.
#Billing screens (concept from the demo, data from API only)
| Route | Content | Demo |
|---|---|---|
/billing | Overview: balance, current plan, this month's spend, last receipt, alerts (low balance, failed payment, negative-balance track) | Demo UI only overview |
/billing/wallet | Paid / free / promo balances, add credit, auto-recharge status, recent wallet activity, balance trend | Demo UI only wallet · V8 requirement 6.3 |
/billing/transactions | Paginated history of payments and charges, with status, gateway and the receipt on payment rows | Demo UI only · V8 requirement 6.7 |
/billing/usage | Managed servers: hours used, amount so far this month, last charged, per server | V8 requirement 6.11 |
/billing/payment-methods | Cards (Stripe) | V7 only · V8 requirement 6.5 |
/billing/auto-recharge | Toggle, threshold, amount, and the low-credit reminder minimum | Demo UI only V7 only · V8 requirement 6.5, 6.6 |
/billing/settings | Billing details (name, address, country, tax number) — account level | Demo UI only V7 only · V8 requirement 6.2 |
Screen-by-screen spec: FE: Billing screens. The demo also has Invoices and Lifetime pages; Phase 6 says receipt rather than invoice, and lifetime is still parked (D-4).
#Permissions
V7 organization permissions Usage Summary (charges), Invoices and Plan are hidden and owner-only by default (admin_default = 0). Billing is the owner's business. V7 only Phase 6 points the same way: billing details are stored on the account that pays (6.2). Keep in V8: Billing = Owner only unless a role explicitly grants it.