Zum Hauptinhalt springen

Release Notes

1.0.0-beta

First release of Vodia Billing.

Standalone billing middleware for Vodia PBX fleets: ingest CDRs, rate calls against your own rate sheets, count seats and DIDs from daily snapshots, compute tax, issue and deliver invoices, hand them to Xero or QuickBooks Online, chase payment, and watch for toll fraud.

What is in this release

Call rating

  • CDR ingest from any number of Vodia PBX systems over the PBX webcdr webhook
  • Archive CSV recovery import with a dry run that reports already_rated per row
  • Rate sheets by header name: per-minute, per-call and free charge types, connect fees, billing increments, minimum durations, longest-prefix matching
  • Sell and cost plans per tenant, giving margin on calls
  • Inclusion groups: allowances per period with an overflow rate, per customer or per extension
  • Trunk registry with billable, transit and non-billable classification, and trunk groups for multi-carrier estates
  • Rate Test: what a given number costs a given tenant, on both sides, before any invoice exists
  • Call reclassification against another destination, audited, refused once invoiced
  • Integer micro-unit money throughout; no floating-point currency arithmetic

Recurring charges

  • Flat, entity and number bases
  • Monthly, quarterly and annual frequencies, billed in advance with the covered range printed on the line
  • Quantities taken as the highest count observed in the period's daily snapshots
  • Trailing-window quantities for annual and quarterly per-seat charges
  • Concurrent-call peak capture, six snapshot passes per day
  • Optional cost per row, giving margin on seats and DIDs
  • Hardware and one-time charge catalogue, with approval required before invoicing

Tax

  • Per-bucket components across usage, recurring and goods
  • Percentage and flat components, flat components counting entity line quantities
  • Compound components
  • Tax profiles built once and applied to tenants as a copy, so an edit cannot re-cut an issued invoice
  • Discounts before tax, reaching each bucket's base individually
  • Credits after tax, recorded as adjustment links so a void restores them
  • External tax authority mode for QuickBooks Online

Invoicing

  • Draft, finalize, send and void lifecycle
  • Fleet-wide gapless numbering, allocated as the last step of a successful finalization
  • Seven finalization guards: unreviewed trunks, unrated legs, unapproved one-time charges, unpriced recurring subtypes, missing recipients, duplicate period, sibling already pushed
  • Periods cut on call start, so recovered calls land on the correct invoice
  • Detail frozen at finalization
  • Template library with branding and thirteen languages, per-key fallback to English
  • Revocable, audited, invoice-scoped share links carrying no cost or margin

Bill runs

  • Restartable prepare, finalize, send and push stages
  • Blocked tenants reported and skipped without consuming invoice numbers or stopping the run
  • Per-invoice send state, so a retry re-sends only what failed
  • Scheduled runs, once per billing period, restart-safe
  • Pacing and day budgets against accounting API ceilings

Accounting

  • Xero: Vodia Billing computes tax, Xero records it; create-only PUT so a push cannot overwrite an authorised invoice
  • QuickBooks Online: QuickBooks computes tax and emails the invoice, and its total is treated as authoritative
  • OAuth connection with single-flight token refresh
  • Customer, account and item mapping, with auto-bind proposals
  • Payment sync back from the accounting package
  • Push blockers evaluated locally before any API call

Payment

  • Configurable due-date rules, overridable per tenant
  • Reminder schedules relative to the due date, overridable per tenant
  • Overdue and never-sent overdue detection with grace and escalation thresholds
  • Credits and manually recorded payments

Export and delivery

  • Typed charge rows: usage, recurring, one-time; included calls as 0.00 rows
  • Watermarked on rating time, automatic per-currency split, sha256 manifests
  • Immutable files; a retry re-sends the stored bytes
  • SFTP with .part rename, HTTP POST/PUT with verifiable headers, and email attachment
  • Per-file, per-destination attempt tracking with partial-delivery reporting

Fraud detection

  • Twenty detectors across usage, billing and accounting
  • High-risk bursts evaluated at ingest as well as on the daily sweep
  • Out-of-hours windows with configurable non-working days, evaluated in the tenant's timezone
  • Per-tenant threshold overrides; zero disables a rule
  • Dry-run preview running the same code as the live sweep
  • Optional automatic extension disable on the PBX, reversible and audited, defaulting to report-only

Reporting

  • Tenant by month margin, split by basis, loss-makers flagged, included-call cost surfaced; partner-only
  • Spend view with ingest counters, trends and per-destination breakdown

Platform

  • Three containers: Caddy, Node.js/Fastify API, MongoDB 7
  • One-command installer for Ubuntu 24.04, with mandatory DNS validation
  • Automatic TLS via Let's Encrypt
  • Mandatory two-factor authentication: TOTP or WebAuthn passkeys
  • Three roles, with viewer enforced read-only at the API by method
  • AES-256-GCM encryption at rest for all stored credentials
  • Audit log of administrative and financial actions
  • Automatic forward-only database migrations on startup

Requirements

  • Ubuntu 24.04 LTS, 2 vCPU, 4 GB RAM, 40 GB disk
  • A resolvable domain name with an A record pointing at the server
  • Ports 80 and 443 reachable from the internet
  • A Vodia PBX with a dedicated administrator account

Installing

apt-get install -y wget unzip
cd /opt
wget https://cdn.vodia.net/vodia-billing/vodia-billing.zip
unzip vodia-billing.zip
cd vodia-billing
bash install.sh

InstallationQuick Start

Deploying alongside an existing billing system

Run both systems for one to two billing cycles

If Vodia Billing is replacing an existing billing system, run both in parallel for one to two full billing cycles before switching.

The PBX CDR URL field is space-delimited, so both receivers can be listed at once and both systems receive every record:

https://oldbilling.example.com/cdr https://billing.example.com/cdr

Bill the same period in both systems and reconcile per tenant before any Vodia Billing invoice reaches a customer.

For the parallel period, configure bill run schedules with finalize, email and export all unticked. That produces drafts only, which is exactly what you want while comparing.

Where the two systems disagree, check in this order:

  1. Billing incrementsincrement_initial and increment_step
  2. Connect fees — charged once per answered call, easy to overlook
  3. Timezone at period boundaries — calls near midnight on the first or last day of the period
  4. Which rate row matched — longest-prefix matching may pick a more specific row than the old system did
  5. Recurring quantity — the highest count observed in the period, not the count on the last day

Use Rate Test on any call that disagrees, and check one specific call rather than a monthly total.

Worked Example works a complete invoice through by hand, which is the fastest way to reconcile.

Notes for first deployments

  • Back up /opt/vodia-billing/.env off the server before anything else. It holds the key that decrypts every stored PBX and accounting credential.
  • Every trunk starts non-billable. Classify your carrier trunks or nothing is charged.
  • ext:* does not match hunt groups or auto attendants; price those subtypes separately.
  • Applying a tax profile copies it onto the tenant. Editing the profile later does not change tenants that already have it.
  • Verify the tax figure on the first invoice pushed to any new Xero organisation, in Xero, before it reaches a customer.
  • On QuickBooks tenants, a difference between the QuickBooks total and the Vodia Billing total is expected — QuickBooks computes the tax and owns the total.
  • Leave automatic fraud response in report mode until thresholds are proven against real traffic.
  • spend_spike and usage_silent need history and will not fire usefully for the first few weeks.

Support

support@vodia.com, with the output of curl https://your-domain/api/health, the relevant section of docker compose logs api, and the invoice number or tenant domain concerned.