FlexiBilling
Billing and usage metering for Python backends. FlexiBilling tracks named balances, rates usage, applies priority rules, and records ledger entries.
The core package does not depend on a database, web framework, cache, or payment
provider. Implement the async protocols in flexibilling.ports against an
existing backend, or use the optional adapters.
Install
uv add flexibilling
Optional integrations:
uv add "flexibilling[redis]"
uv add "flexibilling[sqlalchemy]"
uv add "flexibilling[fastapi]"
uv add "flexibilling[all]"
Read the full documentation for backend adapters, framework integrations, operations, and releases.
Quickstart
This example charges one unit for each metered unit. When the first balance is empty, the second rule uses prepaid units.
from decimal import Decimal
from uuid import uuid4
from flexibilling import (
AssetType,
BillingRule,
BillingService,
InMemoryBillingCache,
MetricType,
UsageRecord,
UsageService,
)
from flexibilling.adapters.memory import InMemoryBillingRepository
customer_id = uuid4()
repo = InMemoryBillingRepository(
rules=[
BillingRule(
service=UsageService.api_request,
target_asset=AssetType.units,
metric_type=MetricType.units,
conversion_rate=Decimal("1"),
),
BillingRule(
service=UsageService.api_request,
target_asset=AssetType.prepaid_units,
metric_type=MetricType.units,
conversion_rate=Decimal("1"),
priority=200,
),
]
)
cache = InMemoryBillingCache()
service = BillingService(repo, cache)
await repo.upsert_balance(
customer_id, AssetType.units, Decimal("100"), session=object()
)
record = UsageRecord(
id=1,
customer_id=customer_id,
service=UsageService.api_request,
reference_id="request-123",
units=12,
)
repo.records.append(record)
await service.process_record(record, session=object())
Asset and service names are open strings. AssetType and UsageService only
provide a few neutral conveniences for examples; applications can define their
own values without subclassing or configuring the package.
Main components
The package includes these parts:
flexibilling.enginerates usage, applies priority rules, and checks cached balances.flexibilling.service.BillingServicefunds accounts, processes usage, writes ledger entries, handles charges and refunds, and updates the cache.flexibilling.decoratorsprovidesrequires,consumes, andbilling.session(...)helpers.flexibilling.portsdefines the repository, usage, cache, and transaction protocols.flexibilling.worker.BillingWorkerprocesses pending usage records.flexibilling.adapters.redisstores balances, period totals, and activity events in Redis.flexibilling.adapters.sqlalchemyprovides an async SQLAlchemy 2 repository and schema that a host can adapt.flexibilling.integrations.fastapiprovides optional middleware and HTTP 402 helpers.
Payment identifiers are opaque strings. BillingService.fund_customer maps them
to asset grants and ignores a payment reference that it has already processed.
Monthly-quota products replace a balance. Top-ups add to it.
For an existing database, implement BillingRepository and UsageRepository
against the current models. The SQLAlchemy adapter shows one possible schema;
it is not required.
Documentation
- Quickstart covers a first usage record.
- Concepts explains balances, rules, rating, waterfalls, and ledger transactions.
- Backend integration shows how to implement the protocols or use Redis and SQLAlchemy.
- Framework integrations covers FastAPI, decorators, workers, and metrics.
- Operations covers transactions, retries, cache behavior, and production checks.
- Development and releases covers local setup, CI, docs, and PyPI publishing.
Usage sessions
from flexibilling import BillingDecorators, UsageService
billing = BillingDecorators(service=service, usage_repository=usage_repo)
async with billing.session(
customer_id=customer_id,
service=UsageService.api_request,
variant="standard",
reference_id="request-123",
) as usage:
usage.report(units=12)
The session writes one pending usage record when it reports usage. It stores
reported duration in event_metadata["duration_seconds"], so a rule can bill
elapsed time without depending on the host framework. Set
write_on_exception=False when failed operations should not create a record.
Development
uv sync --group testing --group lint --group dev
uv run pre-commit install
uv run pytest
uv run ruff check src tests examples
uv run ruff format src tests examples --check
uv run pyright --project pyproject.toml src/flexibilling
uv build
uv run mkdocs build --strict
CI runs lint and type checks, tests Python 3.11 through 3.14, and builds the distribution. A GitHub release publishes to PyPI through trusted publishing.
License
Apache-2.0. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flexibilling-0.1.0.tar.gz.
File metadata
- Download URL: flexibilling-0.1.0.tar.gz
- Upload date:
- Size: 39.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ebd9da1069a6353d308250090b1a6219d3faacde8a237a54dcb8a3c6ca8e311
|
|
| MD5 |
2d10a8a6f6ab8909f81887267f4c1ff2
|
|
| BLAKE2b-256 |
e1a0d106920fffb05a27e1da5574b51e67b692e4ec3fb3bc2306e539f2738b20
|
Provenance
The following attestation bundles were made for flexibilling-0.1.0.tar.gz:
Publisher:
release_pypi.yaml on arterialist/flexibilling-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flexibilling-0.1.0.tar.gz -
Subject digest:
8ebd9da1069a6353d308250090b1a6219d3faacde8a237a54dcb8a3c6ca8e311 - Sigstore transparency entry: 2582946825
- Sigstore integration time:
-
Permalink:
arterialist/flexibilling-py@1d5516afa1c398c39ebdc413366ca06d235f7e21 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/arterialist
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release_pypi.yaml@1d5516afa1c398c39ebdc413366ca06d235f7e21 -
Trigger Event:
release
-
Statement type:
File details
Details for the file flexibilling-0.1.0-py3-none-any.whl.
File metadata
- Download URL: flexibilling-0.1.0-py3-none-any.whl
- Upload date:
- Size: 40.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f2ca72533d353816d3996e48ac868bf16a509bd9de0d8c25fb0a54439f2a2a50
|
|
| MD5 |
43544092be8ea524c271a99bda6c7144
|
|
| BLAKE2b-256 |
439329ffac5f7a6c4a7b540ec88c70aee7a05d79d7997d043e111fcf57f2748f
|
Provenance
The following attestation bundles were made for flexibilling-0.1.0-py3-none-any.whl:
Publisher:
release_pypi.yaml on arterialist/flexibilling-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flexibilling-0.1.0-py3-none-any.whl -
Subject digest:
f2ca72533d353816d3996e48ac868bf16a509bd9de0d8c25fb0a54439f2a2a50 - Sigstore transparency entry: 2582946829
- Sigstore integration time:
-
Permalink:
arterialist/flexibilling-py@1d5516afa1c398c39ebdc413366ca06d235f7e21 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/arterialist
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release_pypi.yaml@1d5516afa1c398c39ebdc413366ca06d235f7e21 -
Trigger Event:
release
-
Statement type: