#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 per payment" is off the plan's server limit — the server limit a user meets comes only from the plan. Update 2026-10-26 (Pair 2, Jayshree): the +3 is removed completely — payments no longer raise the managed-server limit either (it now comes only from the admin setting / admin changes). |
| 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 | Own-account billing identity form: name, billing email, address, country/region names+codes, optional city, postal code, tax rows — B6.2 GET/PUT built and pushed | 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: Organization billing visibility remains a separate proposed permission rule. B6.2 own-account billing details is available to every active login (unverified allowed), regardless of organization role; never gate this form to Owner/Admin.
After provider pull: B6.1/B6.2 preserved as rebased commits 29b3379/4d22ce2, both built/pushed. Combined-copy1211 tests/7473 assertions and quality checks backend-reported passed. B6.3 wallet now built and pushed; B6.4 Add credits built locally/not pushed/not activated; B6.5 onwards unbuilt.
B6.3 wallet built (Pair2/pushed): own-account GET /api/v1/account/wallet returns USD paid/free/promo/total exact decimal strings and as_of. Spend promo→free→paid; ordinary shortage deducts nothing. No public mutations, top-up/history/receipt API or imports. No promo-lot expiry dates returned. Paid debt blocks account deletion409 even when total is positive. Wallet states.
Wallet finalization: B6.3 local commit 0fd63c0, independent review and1318 tests/8332 assertions backend-reported passed; still not pushed. No screen/rule changes, no payments/imports, host scheduling still unverified.
Latest B6.4 (Pair2): Add credits quotes/checkout/status/confirm/free-code APIs43–47 built locally, not pushed or live activated. All gateways need keys/webhooks/return integration; Instamojo additionally needs verified merchant/API proof. No real payment/cards/auto-recharge/history/receipts/imports.1605 tests9194 assertions backend-reported; no frontend/provider-sandbox proof, host scheduling unverified. Exact screen states and blockers. Unresolved real payments now block account deletion409.
B6.5 BUILT LOCALLY / NOT ACTIVATED (2026-10-12): published cards/auto-recharge contracts49–62 are locally built, not pushed/activated. Paid-only daily23:00UTC,thresholdUSD1–2000,rechargeUSD10–2000beforetax;explicit default, no immediate charge; not available for India (billing country or India-issued card, as V7 — option hidden), recovery preserves same payment. Draft screen contracts. No real keys/charges/host scheduler proof.
Latest B6.5 status (2026-10-12 10:35): 6.4 + 6.5 pushed to GitHub; later local follow-ups: card APIs answer directly (0ff3da9) and auto-recharge is not available for India (billing country or India-issued card, as V7) — the India mandate API (old 62) was removed (e65e8c3). Real payments still not activated; no real keys/charges or host scheduler change. Frontend/consent/provider proof still required.