Appearance
Recurring invoices
The recurring invoice engine is what runs at the start of each billing cycle and generates a full invoice for every active contract — without anyone clicking anything. It's the heart of the PSA's billing side.
When recurring runs fire
By default: at 00:01 in the client's time zone on the contract's billing day.
- Monthly contracts: on the day-of-month set by the contract (default: 1st).
- Quarterly: every three months on the same day.
- Annual: once a year on the contract's anniversary.
You can override the firing time per-contract or per-tenant. Most MSPs leave it at the default.
What happens during a run
For each active contract:
- Build the line list from the contract's recurring lines.
- Resolve quantities:
- Fixed lines: quantity as-set.
- Live lines (per-asset, per-user, etc.): count the current billable items.
- Apply category overlays (see below).
- Compute prorations for any asset count changes during the previous cycle.
- Build the invoice — issue date today, due date = today + payment terms.
- Push to QBO/Xero if configured (in background, retried on failure).
- Send the email if auto-send is on; otherwise leave as Draft.
The whole run typically completes within a few minutes for a tenant with hundreds of clients.
Live asset counts
This is the trick that makes OpsMerge billing actually accurate.
A traditional PSA's "100 endpoints at £15" is a static line — you update it manually when the count changes. The reality: counts drift, MSPs forget to update, the invoice underbills (lost revenue) or overbills (angry client).
OpsMerge's per-asset lines read the current count of billable assets at run time. Decommissioned an endpoint last week? It's not in this month's bill. Added 20 new agents two days before the run? They're in this month's bill (prorated by day-fraction; see below).
Asset categories and overlays
For more granular per-asset pricing, OpsMerge supports billing categories. Each asset has a billing_category (workstation / server / mobile / VM / kiosk / etc.) — typically inferred from the agent's OS edition but overridable per-asset.
Recurring lines can be scoped to a category:
- "Per workstation @ £12" — counts assets with
billing_category = workstation. - "Per server @ £40" — counts assets with
billing_category = server.
The same asset can't be in two billing categories — it's a single field, not a multi-select. If you want overlapping billing, use multiple lines with different scoping logic.
Proration
Live asset counts during the cycle change. Proration handles the maths.
The simple case:
- Cycle: 1st Jan to 31st Jan (31 days).
- Asset count on 1st: 100.
- New asset added on 15th: count → 101.
- Asset decommissioned on 25th: count → 100.
OpsMerge computes:
- 14 days at 100 → 14 × (100 × monthly rate / 31)
- 10 days at 101 → 10 × (101 × monthly rate / 31)
- 7 days at 100 → 7 × (100 × monthly rate / 31)
- Sum = invoice total for the per-asset line.
The invoice line includes a breakdown showing the day-by-day count if you want to verify.
Quantity snapshots
When an invoice is generated, OpsMerge snapshots the quantities at the moment of generation — quantity_snapshot on the invoice line. This is the audit trail: "at 00:01 on 1st Feb, this contract had 101 billable assets".
A later count change (say, you archive a client mid-March) doesn't retroactively rewrite February's invoice. The snapshot is permanent.
If you void the invoice and re-generate, a fresh snapshot is taken — which may differ from the original. The void is logged with both snapshots for traceability.
Dry-run
Before flipping auto-send on for the first time, run a dry-run of next month's billing.
Settings → PSA → Recurring → Dry-run next cycle.
OpsMerge computes what would be generated without actually issuing invoices. The output is a table of "client / contract / total" plus warnings about anything that would fail (missing service IDs, missing tax codes, expired contracts).
Use dry-run after any meaningful change — new asset category, contract restructuring, tax code changes.
Skipping a client / contract for a cycle
To skip a specific client this month:
- Client → Contracts → contract → Actions → Skip next run.
- The next scheduled run for this contract is a no-op. The cycle after that runs normally.
Useful for "client is moving offices and we agreed to credit them this month".
Catch-up runs
If a run misses (e.g. OpsMerge was in maintenance during the firing window), it catches up automatically when the system recovers. There's no manual intervention needed.
If you need to force a run for a specific contract right now:
- Client → Contracts → contract → Actions → Generate invoice now.
This bypasses the schedule and generates the next invoice immediately. Used for ad-hoc catch-up or testing.
Currency
Each contract has a currency. Most UK MSPs run everything in GBP; if you serve clients in EUR or USD, set the contract's currency accordingly. Each invoice is single-currency.
Multi-currency support is read-only for now — we can't auto-convert between, e.g. an EUR invoice and your GBP-only QBO instance. The QBO push then needs the QBO realm in the matching currency, or a manual handle.
Common patterns
"I run all my billing on the 1st of each month"
Set every contract's billing day to 1. The single big run fires once a month at 00:01 in the tenant TZ. Done.
"Different clients have different billing days based on when they signed"
Each contract has its own billing day. Most MSPs find "everyone on the 1st" easier to reconcile than "each client on their anniversary".
"I want to invoice in arrears (charge for last month, not next)"
That's the default. Invoice issued on 1st Feb covers Jan 1 to Jan 31, payable end of Feb. Recurring lines and time entries from the previous month are what bill.
If you want to invoice in advance instead (charge on 1st Feb for Feb's services), set Contract → Settings → Billing period to In advance. The same engine, different period.
"I want to bill mid-month, not start-of-month"
Contract → Settings → Billing day. Set to any day 1–31. The cycle runs on that day each month.
Common issues
Recurring invoice has zero per-asset line. The contract has no per-asset line, OR the per-asset line's filter excludes everything. Open the contract and check the line's quantity source.
A line's quantity feels wrong. Open the generated invoice and click the line — there's a "where this number came from" breakdown. Compare against your expectation. The most common cause is billing-category overlay (you set workstations to a different category than you remember).
Auto-send fired and the email went to the wrong contact. Recipient is the client's billing contact at send time. Check Client → Contacts → Billing contact. Update for future cycles; for the wrong send, void and re-send.
QBO push failed for one invoice but other invoices in the same run succeeded. The QBO sync log has per-invoice rows. Look at the failing one's error — usually missing service_id or tax_code_id on a specific line.
The dry-run output looks fine but the real run is different. Dry-run uses today's snapshot; the real run uses snapshots at firing time. If asset counts changed between dry-run and the real run (e.g. dry-run on Tuesday, real run Wednesday at midnight), the numbers move. The breakdown still tells you why.
Next
- Contracts — what feeds recurring runs
- Billing & invoices — what the recurring engine produces
- QuickBooks integration — invoice push downstream