API reference¶
Generated from the apogee-ai-billing source with mkdocstrings. Every symbol below is exported from apogee_ai_billing, so it is part of the supported public surface.
Application · DTOs¶
BenchDTO
dataclass
¶
InvoiceDTO
dataclass
¶
RecordDTO
dataclass
¶
SubscribeDTO
dataclass
¶
Application · Use cases¶
BenchInvoicingUseCase
¶
Synthetic load: build N invoices with mixed plans + record per tenant.
execute
async
¶
Source code in apogee_ai_billing/application/use_cases/bench_invoicing_use_case.py
async def execute(self, tenants: int) -> dict[str, float]:
if tenants <= 0:
raise ValueError("tenants must be positive")
flat = FlatPlan(
code="flat", name="Flat",
monthly_usd=49.0, included_tokens=100_000,
overage_per_1k_usd=0.01,
)
tiered = TieredPlan(
code="tiered", name="Tiered",
monthly_usd=0.0,
tiers=(
PriceTier(up_to=10_000, price_per_1k_usd=0.02),
PriceTier(up_to=100_000, price_per_1k_usd=0.015),
PriceTier(up_to=-1, price_per_1k_usd=0.005),
),
)
meter = TokenMeter()
repo = InMemoryInvoiceRepository()
builder = InvoiceBuilder()
period_start = time.time() - 86400.0
start = time.perf_counter()
for i in range(tenants):
tenant = f"t-{i:05d}"
await meter.record_tokens(tenant, 50_000 + i * 10)
plan = flat if i % 2 == 0 else tiered
usage = await meter.aggregate(tenant, "tokens", since_s=period_start)
invoice = builder.build(
tenant_id=tenant,
plan=plan,
usage_units=usage,
period_start_s=period_start,
)
await repo.save(invoice)
elapsed = (time.perf_counter() - start) * 1000.0
return {
"tenants": float(tenants),
"invoices": float(await repo.count()),
"elapsed_ms": elapsed,
"invoices_per_second": (tenants / elapsed * 1000.0) if elapsed > 0 else 0.0,
}
GenerateInvoiceUseCase
¶
GenerateInvoiceUseCase(plan_repo, subscription_repo, meter, invoice_repo, builder: InvoiceBuilder | None = None)
Source code in apogee_ai_billing/application/use_cases/generate_invoice_use_case.py
execute
async
¶
execute(tenant_id: str, period_start_s: float, period_end_s: float | None = None, metric: str = 'tokens') -> Invoice
Source code in apogee_ai_billing/application/use_cases/generate_invoice_use_case.py
async def execute(
self,
tenant_id: str,
period_start_s: float,
period_end_s: float | None = None,
metric: str = "tokens",
) -> Invoice:
subscription = await self._subs.get(tenant_id)
plan = self._plans.get(subscription.plan_code)
end = period_end_s if period_end_s is not None else time.time()
usage = await self._meter.aggregate(
tenant_id, metric, since_s=period_start_s
)
invoice = self._builder.build(
tenant_id=tenant_id,
plan=plan,
usage_units=usage,
period_start_s=period_start_s,
period_end_s=end,
)
await self._invoices.save(invoice)
return invoice
ListPlansUseCase
¶
Source code in apogee_ai_billing/application/use_cases/list_plans_use_case.py
execute
async
¶
RecordUsageUseCase
¶
Source code in apogee_ai_billing/application/use_cases/record_usage_use_case.py
execute
async
¶
execute(tenant_id: str, metric: str, quantity: float, **metadata: str) -> UsageRecord
Source code in apogee_ai_billing/application/use_cases/record_usage_use_case.py
SubscribePlanUseCase
¶
Source code in apogee_ai_billing/application/use_cases/subscribe_plan_use_case.py
execute
async
¶
execute(tenant_id: str, plan_code: str) -> Subscription
Source code in apogee_ai_billing/application/use_cases/subscribe_plan_use_case.py
Domain¶
BillingPeriod
¶
Invoice
dataclass
¶
Invoice(tenant_id: str, plan_code: str, period_start_s: float, period_end_s: float, lines: tuple[InvoiceLine, ...] = (), status: InvoiceStatus = DRAFT, id: str = (lambda: f'inv-{hex[:10]}')(), issued_at_s: float = time(), metadata: dict[str, str] = dict())
InvoiceLine
dataclass
¶
InvoiceStatus
¶
Bases: str, Enum
Plan
dataclass
¶
Plan(code: str, name: str, kind: PlanKind = FLAT, period: BillingPeriod = MONTHLY, base_fee_usd: float = 0.0, included_units: int = 0, overage_price_per_1k_usd: float = 0.0, tiers: tuple[PriceTier, ...] = (), metadata: dict[str, str] = dict())
PriceTier
dataclass
¶
Subscription
dataclass
¶
Subscription(tenant_id: str, plan_code: str, started_at_s: float = time(), active: bool = True, metadata: dict[str, str] = dict())
UsageRecord
dataclass
¶
UsageRecord(tenant_id: str, metric: str, quantity: float, timestamp_s: float = time(), id: str = (lambda: f'u-{hex[:8]}')(), metadata: dict[str, str] = dict())
Domain · Enums¶
PlanKind
¶
Domain · Exceptions¶
BillingError
¶
Bases: Exception
Base for apogee-ai-billing errors.
InvoiceNotFoundException
¶
Bases: BillingError
PlanNotFoundException
¶
SubscriptionNotFoundException
¶
Domain · Protocols (ports)¶
IInvoiceRepository
¶
IMeter
¶
Bases: Protocol
record
async
¶
record(record: UsageRecord) -> None
aggregate
async
¶
list_records
async
¶
list_records(tenant_id: str, since_s: float = 0.0) -> Iterable[UsageRecord]
IPlanRepository
¶
ISubscriptionRepository
¶
Bases: Protocol
upsert
async
¶
upsert(subscription: Subscription) -> None
get
async
¶
get(tenant_id: str) -> Subscription
cancel
async
¶
Infrastructure¶
CompositeMeter
¶
Aggregates several meters under one façade. Routes by metric name.
Source code in apogee_ai_billing/infrastructure/meters/composite_meter.py
record
async
¶
record(record: UsageRecord) -> None
aggregate
async
¶
Source code in apogee_ai_billing/infrastructure/meters/composite_meter.py
list_records
async
¶
list_records(tenant_id: str, since_s: float = 0.0) -> Iterable[UsageRecord]
Source code in apogee_ai_billing/infrastructure/meters/composite_meter.py
FlatPlan
¶
FlatPlan(*, code: str, name: str, monthly_usd: float, included_tokens: int = 0, overage_per_1k_usd: float = 0.0) -> Plan
Source code in apogee_ai_billing/infrastructure/plans/factories.py
def FlatPlan(
*,
code: str,
name: str,
monthly_usd: float,
included_tokens: int = 0,
overage_per_1k_usd: float = 0.0,
) -> Plan:
return Plan(
code=code,
name=name,
kind=PlanKind.FLAT,
period=BillingPeriod.MONTHLY,
base_fee_usd=monthly_usd,
included_units=included_tokens,
overage_price_per_1k_usd=overage_per_1k_usd,
)
InMemoryInvoiceRepository
¶
InMemoryMeter
¶
In-memory meter. Records flat list, aggregates on demand.
Source code in apogee_ai_billing/infrastructure/meters/in_memory_meter.py
record
async
¶
record(record: UsageRecord) -> None
aggregate
async
¶
list_records
async
¶
list_records(tenant_id: str, since_s: float = 0.0) -> Iterable[UsageRecord]
InMemoryPlanRepository
¶
InMemoryPlanRepository(plans: Iterable[Plan] = ())
InMemorySubscriptionRepository
¶
Source code in apogee_ai_billing/infrastructure/registries/in_memory_subscription_repository.py
upsert
async
¶
upsert(subscription: Subscription) -> None
get
async
¶
get(tenant_id: str) -> Subscription
cancel
async
¶
InvoiceBuilder
¶
Builds an Invoice from a Plan + usage volume for the period.
Source code in apogee_ai_billing/infrastructure/invoices/invoice_builder.py
build
¶
build(*, tenant_id: str, plan: Plan, usage_units: float, period_start_s: float, period_end_s: float | None = None) -> Invoice
Source code in apogee_ai_billing/infrastructure/invoices/invoice_builder.py
def build(
self,
*,
tenant_id: str,
plan: Plan,
usage_units: float,
period_start_s: float,
period_end_s: float | None = None,
) -> Invoice:
if usage_units < 0:
raise ValueError("usage_units must be non-negative")
end = period_end_s if period_end_s is not None else time.time()
lines: list[InvoiceLine] = []
if plan.base_fee_usd > 0:
lines.append(_line(
description=f"{plan.name} base fee ({plan.period.value})",
quantity=1,
unit_price_usd=plan.base_fee_usd,
))
if plan.kind is PlanKind.FLAT:
overage = max(0.0, usage_units - plan.included_units)
if overage > 0 and plan.overage_price_per_1k_usd > 0:
unit = plan.overage_price_per_1k_usd / 1000.0
lines.append(_line(
description=(
f"Overage ({int(overage):,} units beyond {plan.included_units:,})"
),
quantity=overage,
unit_price_usd=unit,
))
elif plan.kind is PlanKind.TIERED:
lines.extend(_tier_lines(plan.tiers, usage_units))
elif plan.kind is PlanKind.USAGE_BASED:
unit = plan.overage_price_per_1k_usd / 1000.0
if usage_units > 0 and unit > 0:
lines.append(_line(
description=f"Usage ({int(usage_units):,} units)",
quantity=usage_units,
unit_price_usd=unit,
))
return Invoice(
tenant_id=tenant_id,
plan_code=plan.code,
period_start_s=period_start_s,
period_end_s=end,
lines=tuple(lines),
status=InvoiceStatus.OPEN,
metadata={"usage_units": str(int(usage_units))},
)
JsonInvoiceFormatter
¶
format
¶
format(invoice: Invoice) -> str
Source code in apogee_ai_billing/infrastructure/invoices/formatters.py
def format(self, invoice: Invoice) -> str:
payload = {
"id": invoice.id,
"tenant_id": invoice.tenant_id,
"plan_code": invoice.plan_code,
"status": invoice.status.value,
"period_start_s": invoice.period_start_s,
"period_end_s": invoice.period_end_s,
"issued_at_s": invoice.issued_at_s,
"total_usd": round(invoice.total_usd, 6),
"lines": [
{
"description": line.description,
"quantity": line.quantity,
"unit_price_usd": round(line.unit_price_usd, 8),
"amount_usd": round(line.amount_usd, 6),
}
for line in invoice.lines
],
"metadata": dict(invoice.metadata),
}
return json.dumps(payload, indent=2, default=str)
MarkdownInvoiceFormatter
¶
format
¶
format(invoice: Invoice) -> str
Source code in apogee_ai_billing/infrastructure/invoices/formatters.py
def format(self, invoice: Invoice) -> str:
lines = [
f"# Invoice `{invoice.id}`",
"",
f"- **Tenant**: `{invoice.tenant_id}`",
f"- **Plan**: `{invoice.plan_code}`",
f"- **Status**: {invoice.status.value}",
f"- **Total**: ${invoice.total_usd:.6f}",
"",
"| Description | Quantity | Unit price | Amount |",
"|---|---:|---:|---:|",
]
for line in invoice.lines:
lines.append(
f"| {line.description} | {line.quantity:,.2f} | "
f"${line.unit_price_usd:.8f} | ${line.amount_usd:.6f} |"
)
return "\n".join(lines)
RequestMeter
¶
Bases: InMemoryMeter
Convenience meter typed for the requests metric.
Source code in apogee_ai_billing/infrastructure/meters/in_memory_meter.py
record_request
async
¶
record_request(tenant_id: str, count: int = 1, **metadata: str) -> UsageRecord
Source code in apogee_ai_billing/infrastructure/meters/in_memory_meter.py
TieredPlan
¶
TieredPlan(*, code: str, name: str, monthly_usd: float = 0.0, tiers: tuple[PriceTier, ...]) -> Plan
Source code in apogee_ai_billing/infrastructure/plans/factories.py
TokenMeter
¶
Bases: InMemoryMeter
Convenience meter typed for the tokens metric.
Source code in apogee_ai_billing/infrastructure/meters/in_memory_meter.py
record_tokens
async
¶
record_tokens(tenant_id: str, tokens: int, **metadata: str) -> UsageRecord