KW Knowledge base

Billing

The platform has **two separate billing surfaces**:

Mitch Wigham
Updated 24 June 2026 · 7 views

14 · Billing

The platform has two separate billing surfaces:

  1. InvoiceNinja sync (/billing) — a read-only view of invoices and quotes pulled live from InvoiceNinja, joined to portal customers and projects.
  2. 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:

  1. Open a project (/projects/<id>).
  2. Use the project's invoice/quote action (as=invoice or as=quote).
  3. 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.
  4. 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.
  • ManualRun 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

Still need help?

Log a support ticket and the team will pick it up from this page.