Zum Hauptinhalt springen

Troubleshooting

Start here

cd /opt/vodia-billing
curl https://your-domain/api/health
docker compose ps
docker compose logs api --tail 100

The health endpoint reports database state, mode, version and the ingest counters, which between them explain most problems.

Calls not appearing

Check the ingest counters in Spend, or ingest in the health response.

Nothing at all is arriving. The PBX is not sending here. Verify the CDR URL on the PBX is https://your-domain/cdr and that it is appended space-delimited rather than replacing an existing receiver. Check docker compose logs caddy --tail 50 for requests reaching the box at all.

unknown_system climbing. CDRs are arriving but the system ID is not configured. Read the hash from the counters and paste it into the system record under Systems.

unknown_domain climbing. A PBX domain that is not a configured tenant. Run Discover, then configure the tenant.

unknown_trunk climbing. A trunk not in the registry. Run Discover, then classify it under Trunks.

not_billable climbing and everything else quiet. The calls are arriving and being recognised, and the trunk is classified non-billable. That is either correct or the classification is wrong.

Calls arriving but not charged

  • The trunk is classified transit or non-billable. Check Trunks.
  • The tenant has no sell plan. Check Tenants.
  • The call is inbound. Only outbound calls are charged.
  • The call was not answered. A billable call needs a non-empty connect and end after connect.
  • No rate row matched. The call is reported as unrated, and unrated calls block finalization rather than being priced at zero. Use Rate Test on the number to see what the plan does with it.

Wrong amounts

Check in this order:

  1. Billing increments. increment_initial and increment_step on the matched rate row. This is the most common cause when reconciling against another system.
  2. Connect fee. Charged once per answered call, and easy to miss.
  3. Which row matched. Longest-prefix matching may be picking a more specific row than you expected. Rate Test shows which one.
  4. Minimum duration.
  5. Timezone. A tenant in the wrong timezone shifts calls across period boundaries.
  6. Inclusion allowance. Overflow uses the group's overflow rate only, with no connect fee.

Invoice will not finalize

The draft reports its blockers. Each one has a fix:

BlockerFix
Unreviewed trunksClassify them under Trunks
Unrated legsAdd the missing destination to the sell plan
Unapproved one-time chargesApprove them on the tenant
Unpriced recurring subtypesAdd a recurring rate for the subtype. Remember ext:* does not match hunt groups or auto attendants
No recipientsAdd billing recipients under Tenants
Duplicate periodAn invoice already exists for this tenant and period. Void it or bill a different period
Sibling already pushedAnother invoice for this period has been pushed to accounting

No email being sent

  • SMTP is not configured. Check Settings, and use the test email button.
  • The tenant has no billing recipients. Reported as no_recipients.
  • The tenant is set to be emailed by the accounting package, so Vodia Billing deliberately does not send. Check the tenant's delivery setting.
  • The invoice is not finalized. Drafts are not sent.

If SMTP is unconfigured, bill runs still prepare and finalize, and the interface says email is disabled.

Accounting push failing

  • Token expired. Alerts accounting_disconnected or accounting_expiring. Re-authorise under Accounting → Connect; mappings survive.
  • No customer mapping. Map the tenant under Accounting → Mapping.
  • No due date. Set payment terms under Terms & Reminders.
  • Already pushed. A second push is refused locally. There is no re-push; void and reissue if it genuinely needs redoing.
  • Daily ceiling reached. Xero allows 1,000 calls per day per organisation, about 300 pushed tenants. The run reports what remains; resume the next day.

Xero shows 0.00 tax

The tax type on the lines is unusable for a manual tax document. TaxType: "AVALARA" and GUID-shaped Avalara-managed values both return success with zero tax. Use the tax rates that Discover pulled from your own Xero organisation.

QuickBooks total differs from Vodia Billing

Expected. QuickBooks computes its own tax and owns the total. See QuickBooks Online.

Reminders not sending

  • Payment sync marked the invoice paid. Check the invoice.
  • The tenant is set for the accounting package to chase.
  • No recipients on the tenant.
  • The tick has not reached the configured hour yet. The hour is a floor from container boot, not an exact time.

A reminder pass that correctly sends nothing writes no log line, so silence is ambiguous. Look for scheduler activity generally in the API log.

HTTPS certificate problems

  • The domain's A record must point at this server. Check with dig +short A your-domain and compare to curl -s https://api.ipify.org.
  • Ports 80 and 443 must be open to all sources. Let's Encrypt uses multi-perspective validation.
  • docker compose logs caddy --tail 50 shows the ACME exchange.
  • A rate limit from a previous failed attempt can delay issuance. Wait rather than retrying in a loop.

Configuration seems to be ignored

Check for exported shell variables:

env | grep -E '^(DOMAIN|MONGO_URI|DB_NAME|JWT_SECRET|ENCRYPTION_KEY|PORT)='

Docker Compose reads exported shell variables ahead of .env. A stray DOMAIN= exported by an unrelated project on the same server silently overrides this configuration, and the symptom looks like a TLS or routing problem rather than a configuration one.

Locked out of an account

No email reset exists by design. From the server:

cd /opt/vodia-billing
docker compose exec mongo mongosh vodia_billing --eval \
'db.users.updateOne({email:"you@example.com"},{$set:{totp_enabled:false},$unset:{totp_secret:"",totp_pending_secret:""}})'

The next login re-enters forced 2FA setup.

Passkeys stopped working

The hostname changed. Passkeys are bound to RP_ID, which is set from DOMAIN. Each user must re-register. Log in with TOTP, which is unaffected.

Container problems

docker compose ps                      # all should be Up
docker compose logs api --tail 200 -f
docker compose logs mongo --tail 50
docker compose up -d --build # apply changed source

The API not starting immediately after an upgrade is usually index building. Watch the log and wait rather than restarting.

Getting help

support@vodia.com, with:

  • curl https://your-domain/api/health
  • docker compose ps
  • The relevant section of docker compose logs api
  • The invoice number or tenant domain concerned

Quick reference: empty or wrong invoice

SymptomAlmost always
No usage charges at allTrunks still non-billable
Recurring charges but no usageSame thing
Nothing anywhere, unknown_system climbingSystem ID not set
Nothing, unknown_domain climbingTenant not configured
Nothing, unknown_trunk climbingDiscover not re-run after a trunk was added
not_billable equals acceptedCarrier trunk classified non-billable
Usage present but no taxTax profile built but never applied to the tenant
Extensions missing from recurringext:* used, and the missing ones are hunt groups or attendants
Will not finalize, "unpriced subtype"A recurring rate is missing for that entity type
Will not finalize, "unrated legs"A destination is missing from the sell plan
Amounts slightly off vs old systemBilling increments, then connect fees, in that order
Xero shows 0.00 taxUnusable TaxType — see the Xero page
QuickBooks total differsExpected; QuickBooks owns the tax
Seat count lower than expectedHighest-count rule is correct; check the snapshot history

Quick StartWorked Example