14 · Billing
The platform has two separate billing surfaces:
- InvoiceNinja sync (
/billing) — a read-only view of invoices and quotes pulled live from InvoiceNinja, joined to portal customers and projects. - Recurring (PSA) billing (
/admin/billing) — the platform's own monthly billing engine that raises a bill per customer for managed RMM devices and billable ticket time, then emails a statement.
These are independent — InvoiceNinja is an external integration; the recurring billing engine is built into the platform.
InvoiceNinja sync (/billing)
Sidebar → Billing or /billing. Requires the projects feature.
If InvoiceNinja is not configured the page shows a "Connect
InvoiceNinja" prompt linking to the integration page.
The platform does not host the InvoiceNinja accounting — InvoiceNinja remains the system of record. The portal is a read-only viewer: it lists invoices and quotes, and links out to InvoiceNinja for any edit.
Layout
+----------------------------------------------------------+
| Invoices Outstanding Quotes |
|----------------------------------------------------------|
| [Invoices (12)] [Quotes (3)] |
|----------------------------------------------------------|
| INV-042 Acme Ltd SNAG-014 Paid £1,200 £0 [Open↗]|
| INV-041 Beta Co — Sent £350 £350 |
+----------------------------------------------------------+
📷 Screenshot placeholder: screenshots/billing-invoices.png
The page shows KPI cards (invoice count + total, outstanding balance, quote count + total) and an Invoices / Quotes tab toggle.
Each row shows
- Number (links out to the InvoiceNinja edit page)
- Customer — links to the portal customer record if the InvoiceNinja
client is mapped to a
PortalCustomer - Reference — the
po_number; links to the source project if it matches a project code - Status — Draft / Sent / Partial / Paid / Cancelled for invoices; Draft / Sent / Approved / Converted / Cancelled for quotes
- Amount and Balance
- An Open in IN ↗ button
There is no in-portal invoice editor, no "+ New invoice" button on this page, no per-customer invoices tab, no subscriptions view, and no status polling — the list is fetched live each time the page loads.
Raising an invoice or quote from a project
Invoices and quotes are pushed to InvoiceNinja from the project
detail page, not from /billing:
- Open a project (
/projects/<id>). - Use the project's invoice/quote action (
as=invoiceoras=quote). - The platform ensures an InvoiceNinja client exists for the customer (creating one and caching the id if needed), builds line items from the project's billable tasks, and pushes the document.
- The project records the resulting
invoiceRef/quoteRef.
Line items come from the project's tasks: non-billable tasks are
dropped, a per-task rateCents overrides, otherwise the project's
estimated cost is split evenly across billable tasks. There is no
"from time entries" invoice builder.
To raise an invoice the project must be marked billable and have a linked customer; quotes can be raised from a non-billable project.
Configuring InvoiceNinja
The connection (INVOICENINJA_URL + INVOICENINJA_TOKEN) is set via
Admin → Integrations → InvoiceNinja. The platform talks to the
InvoiceNinja v5 REST API with the operator's X-API-TOKEN.
Recurring (PSA) billing (/admin/billing)
Admin → Billing or /admin/billing. Requires an administrator
role. This is the platform's own monthly billing engine — it does not
touch InvoiceNinja.
Each month it raises a Bill per customer for the previous month, covering two usage sources:
- Managed devices (RMM) — count of live (not uninstalled) RMM devices for the customer × the per-device monthly fee.
- Support time (billable) — billable
TICKET-kind time entries logged in the period for the customer × the default hourly rate.
Customers with no billable usage are skipped — no zero bills.
Settings
The settings card (PATCH /api/billing/monthly/settings, admin only):
| Field | Meaning |
|---|---|
| Accounts email | Where the monthly statement is emailed. Defaults to accounts@<org-domain>. |
| Per-device monthly fee | perDeviceCents — fee per managed RMM device, in pence. |
| Default hourly rate | defaultHourlyRateCents — rate per billable hour, in pence. |
| Currency | Statement currency code (e.g. GBP). |
| Tax % | taxPct — applied to each bill's subtotal. |
| Auto-send | When on, the scheduler raises + emails bills automatically at the start of each month. |
A line item is only added if its rate is set above zero.
Running a billing
- Automatic — the scheduler bills the previous month for every org with Auto-send enabled that hasn't already been billed for it.
- Manual — Run last month now (
POST /api/billing/monthly/run, admin only). The request body may carry{ month: "YYYY-MM" }; it defaults to the previous month.
Each run is idempotent on (orgId, periodMonth) — BillingRun is
unique per org+month, so re-running an already-billed month is a no-op
(returns created: false with a reason).
A run computes the bill drafts, persists a BillingRun plus one Bill
per customer (status DRAFT, reference BILL-YYYY-MM-NNN), then emails
an HTML statement to the accounts email. If the email sends, the bills
move to SENT and the run's emailStatus is SENT (SKIPPED when
there are no bills, FAILED if the send fails).
Run history & raised bills
The admin page lists:
- Billing runs — period, run time, bill count, total, emailed-to address, and email status badge.
- Raised bills — reference, customer, period, line-item summary, total, and status badge.
Run history is capped at the most recent 36 runs; raised bills at 500.
Data model
- BillingSettings — per-org config (one row per org).
- BillingRun — one per org+month; unique on
(orgId, periodMonth). - Bill — one per customer per run, with JSON line items, subtotal, tax, and total in pence.
Permissions
| Action | Role |
|---|---|
View /billing (InvoiceNinja sync) |
any authenticated user with the projects feature |
| Raise invoice/quote from a project | any authenticated user (project detail) |
View /admin/billing |
ADMIN / SUPER_ADMIN |
| Read recurring billing settings / bills / runs | any authenticated user (read endpoints) |
| Change billing settings / trigger a run | ADMIN / SUPER_ADMIN |
See also
- Admin → Integrations → InvoiceNinja
- Projects — raise invoices/quotes from project work
- Timesheets — billable ticket time feeds recurring billing