Billing Architecture
Qarion's billing system provides per-tenant usage tracking, hourly aggregation, automated billing cycle management, and invoice generation for multi-instance deployments.
System Flow
Key Components
BillingUsageMiddleware
ASGI middleware that intercepts every API request and records a raw usage event:
- Extracts instance ID from the request routing context
- Records the meter key (e.g.,
api_calls), timestamp, and quantity - Non-blocking — usage events are written asynchronously
Aggregation Service
The BillingAggregationService runs hourly via the run_billing_aggregation arq task:
- Queries raw usage records since the last aggregation
- Groups by instance + meter + date
- Upserts daily summaries (idempotent)
Billing Cycle Service
The BillingCycleService runs daily via run_billing_cycle:
- Identifies billing periods due for closure
- Calculates total usage per meter
- Applies pricing plan rules (flat-rate + metered components)
- Generates draft invoices with itemized line items
- Applies credit balances
Pricing Engine
Plans support two component types:
| Type | Resolution |
|---|---|
| Flat-rate | Fixed fee per billing period |
| Metered | Per-unit with optional tiered buckets (e.g., first 10K free, then $0.001/call) |
Invoice Lifecycle
Draft → Finalized → Sent → Paid
→ Overdue → Void
Data Model
| Model | Description |
|---|---|
BillingPlan | Pricing plan with components |
BillingSubscription | Tenant-to-plan binding |
BillingUsageRecord | Raw and aggregated usage data |
BillingInvoice | Generated invoice with line items |
Key Files
| File | Purpose |
|---|---|
app/middleware/billing_usage_middleware.py | Per-request usage metering |
app/services/billing_aggregation_service.py | Hourly usage roll-up |
app/services/billing_cycle_service.py | Cycle close and invoice generation |
app/services/billing_pricing_service.py | Pricing plan resolution |
app/services/billing_render_service.py | Invoice HTML rendering |