Orbit
Idempotent billing engine, enforced by the database

Recurring billing that cannot bill you twice.

Orbit runs the full life of a subscription business: plans, subscriptions, recurring invoices, payments and revenue reporting, with an idempotent billing engine enforced by the database itself. Offline-first, on your own PostgreSQL.

0

duplicate invoices, ever

₹1,639.62

invoice just generated

100%

offline, no internet

Billing run just completed, 00:05 UTC · automatic
Confirmed

INV-2026-00006

Acme Stores Pvt Ltd · due Nov 15

from SUB-2026-00001
period 2026-10-01 → 2026-11-01

Brightloop CRM (Odoo), Oct 1 → Nov 111,559.001,559.00
GST 18%——280.62
LAUNCH200, launch discount——−200.00
Total due₹1,639.62

UNIQUE(subscription_id, period_start) — the database refuses a second invoice for this period

Live artifact from the demo dataset, every number computed by the engine

How things run today.

Renewals get missed, invoices go out wrong, and nobody can say how much recurring revenue the company actually has. Orbit replaces that whole month.

  • Subscriptionstracked in a spreadsheet
  • Renewalsremembered by whoever notices first
  • Invoicestyped up by hand every month
  • Paymentsmatched by scrolling bank statements
  • Revenue reportsbuilt manually, once a quarter

One billing month at Brightloop, every scene, handled.

From a new customer signing up to the finance lead closing the month: the seven moments that break a spreadsheet workflow, each a working part of Orbit.

01Admin · Staff · Customer

Accounts & roles

Customers self-signup with a real password policy and hashed, single-use reset links staged in a mail outbox. Admin, staff and customer see three different systems behind one login, RBAC enforced server-side, citext-unique emails.

024 plan flags · 2 tax profiles

Catalog, plans & variants

Products with attributes and variants, the Odoo brand adds ₹560 with price_extra. Plans carry billing period, minimum quantity, availability windows and per-plan flags: auto-close, closable-early, pausable, renewable.

03Full status history

Quote → subscription

Sales starts from a quotation template with pre-filled lines and a validity window, then walks one state machine: Draft → Quotation → Confirmed → Active → Closed, with every transition recorded by actor and timestamp.

04Idempotent by constraint

Billing day

Hundreds of subscriptions due at once become invoices with snapshot lines, per-line tax, discounts and gapless numbers. Re-run the same day and the database reports “0 created · 4 skipped (already billed)”, nothing billed twice, nothing skipped, catch-up built in.

05LAUNCH200 · SEAT10

Discounts that apply themselves

Admin-set rules, percent or fixed, minimums, date windows, usage limits, product or subscription scope. The next invoice carries the discount on its own line, stops on expiry or exhaustion, and keeps a usage ledger.

06Overdue → reminder in 1 click

Payments & dunning

Record a payment by UPI, card, cash, transfer or cheque; the invoice flips to Paid inside the same transaction, overpayments rejected. Overdue invoices surface instantly, and one click stages a reminder in the outbox.

07MRR movement · aging · CSV

The finance lead

Active subscriptions, revenue received, amount owed, overdue aging buckets, MRR and ARR with movement (new · expansion · contraction · churn), renewal forecast, revenue by plan, one summary, filterable, exportable to CSV.

The engine is the product.

Most subscription tools promise careful billing. Orbit makes it a database-level property you can demonstrate, not a convention you hope for.

  • Never twice. A UNIQUE(subscription_id, period_start) constraint makes a duplicate period physically impossible.

  • Never concurrent. pg_try_advisory_xact_lock serializes billing runs — cron and the button cannot overlap.

  • Never skipped. The catch-up loop invoices every missed period after downtime, one invoice per period, capped at 12.

  • Never partial. Each subscription runs under a SAVEPOINT: one failure rolls back only that subscription, never the run.

-- a billing run, replayed the same day

orbit> billing.run(asOf: today)

{ created: 4, skipped: 0, errors: 0 }

orbit> billing.run(asOf: today)

{ created: 0, skipped: 4 (already billed), errors: 0 }

-- the constraint that makes it true

UNIQUE(subscription_id, period_start)

The mechanics, drawn.

No abstractions: the lifecycle a subscription walks, the pipeline the engine runs every billing day, and exactly how one invoice gets its total.

Subscription lifecyclestate machine, every transition audited
DRAFTQUOTATIONCONFIRMEDACTIVECLOSEDpause / resumePAUSED
Billing day, as a pipelineidempotent by constraint
Due subscriptionsstatus = ACTIVEnext_billing_date ≤ todayEngineadvisory lockone run at a timeInvoicesnapshot lines · taxdiscounts · gapless no.Paymentauto-PAIDsame transactionDashboardMRR · agingrenewalsUNIQUE(subscription_id, period_start)
Anatomy of one invoiceINV-2026-00006, computed by the engine
Linessnapshot, never recomputed₹1,559.00TaxGST 18%+ ₹280.62DiscountLAUNCH200− ₹200.00Grand totalINV-2026-00006₹1,639.62+−=invoice_lines are snapshots — totals never recomputed from live prices

From catalog to collected, in four moves.

1

Catalog

Admin adds products, variants, plans, taxes

2

Subscribe

Template → quotation → confirmed → active

3

Bill

Engine invoices every due period, idempotently

4

Collect

Payments settle invoices; overdue gets chased

Admin

Owns the system: products, plans, taxes, discount rules, staff, billing runs, outbox, audit trail.

Staff

Runs the month: quotations, subscriptions, invoices, payments, billing day — no staff mgmt, no discount rules.

Customer

A portal of their own: subscriptions, invoices, print, pause/resume/renew — only their data, ever.

Prove it, don’t claim it.

Every figure below is reproducible: volume-seed the database, run the EXPLAIN ANALYZE kit, or execute the flow verifier. Numbers ship with their scripts.

10,007

subscriptions seeded for the perf proof

10.55 ms

slowest dashboard query (budget: 2 s)

17

CHECK constraints holding business rules

142

automated tests on the billing core

12/12

end-to-end flows verified green

0

external dependencies, runs fully offline

Built like the ledger it keeps.

Local-first by design: the whole demo runs with the WiFi off — local PostgreSQL, a node-cron billing worker, and mail staged in an outbox table instead of SMTP. No fonts from a CDN, no cloud APIs, no mocks.

  • Next.js 15 + TypeScriptone codebase, App Router
  • tRPC v11end-to-end typesafe API, server-side RBAC
  • Prisma 6schema-as-code, migrations, citext emails
  • PostgreSQL 18 (local)18 tables, 3NF, 17 CHECK constraints
  • Tailwind v4 + shadcnachromatic ledger design system
  • Vitest + CI gatenpm ci · typecheck · lint · test · build on every push

Put your revenue in orbit.

Create an account and run your first billing day in minutes, or sign in to the demo workspace and watch the engine skip an already-billed one.

Try the demo workspace

Demo only

Three seeded accounts, three different views of the same system.

  • Admin

    everything: catalog, discounts, billing runs, staff, outbox

    admin@orbit.localAdmin@Orbit1
  • Staff

    day-to-day: subscriptions, invoices, payments, billing day

    staff@orbit.localStaff@Orbit1
  • Customer

    the portal: Acme's own subscriptions and invoices only

    customer@acme.testCust@Orbit1

Seeded demo accounts — the entire workspace resets with one seed run. Not for any real deployment.