stapel-billing
Payments and billing: per-user credit wallets held as expiry-aware credit lots over an immutable ledger, reservations (hold/capture/release) for work priced only after it runs, one-off credit packages and subscription plans, Stripe-backed checkout and customer portal, idempotent webhooks and a service-to-service debit endpoint.
Part of the Stapel framework — composable Django apps that deploy as a monolith or as microservices without changing module code.
Install
pip install stapel-billing
At a glance
| Fact | Value |
|---|---|
| Version | 0.8.0 |
| Python | >=3.11 (3.11, 3.12, 3.13, 3.14) |
| HTTP operations | 10 |
| Config axes | 1 |
| Usage surface | 23 |
| Extension points | 5 |
| Error codes | 55 |
| Fleet dependencies | stapel-auth (optional) · stapel-core |
Documentation
Errors: English · Español · Русский · OpenAPI · capabilities.json · llms.txt (for agents)
Quick start
# settings.py
INSTALLED_APPS = [
...
'stapel_billing',
]
from stapel_billing.tasks import get_billing_beat_schedule
CELERY_BEAT_SCHEDULE = {
**get_billing_beat_schedule(), # credit expiry, hold sweep, reconcile
}
Register the beat schedule (or run the three callables in stapel_billing.tasks
from your own cron): credits granted with an expiry only expire because
something runs. System check stapel_billing.W105 says so if nothing does.
Wallets are lots
A wallet is a set of CreditLot rows — each one knows where its credits came
from (purchase, subscription, grant, adjustment, hold_release) and
when they die (expires_at, NULL = never). Spend walks the lots
expiring-soonest first, so a subscription bundle is used before the
non-expiring credits a customer paid cash for. Wallet.balance is a
maintained cache of that total, recomputed from the lots inside the same row
lock as every mutation.
from stapel_billing import credit, debit, hold, capture, release
from stapel_billing.models import LotSource, TransactionType
credit(user=user, credits=3000, type=TransactionType.SUBSCRIPTION_BONUS,
source=LotSource.SUBSCRIPTION, expires_at=sub.current_period_end)
held = hold(user=user, credits=15, type=TransactionType.AI_CHARGE,
idempotency_key=f"mic:{recording_id}")
try:
used = do_the_work()
except Exception:
release(hold_id=held.id) # credits go back with their original expiry
else:
capture(hold_id=held.id, actual_credits=used)
Bus events
Emits
| payment.completed | schema | A payment transaction completed successfully. |
| subscription.changed | schema | User subscription plan or status changed. |
Consumes
| user.deleted | schema |
| user.deletion_initiated | schema |
License
MIT — see LICENSE.
This page is assembled by stapel-readme from docs/readme.md plus the contract artifacts in docs/. Edit the prose in docs/readme.md; the badges, facts and links above and below it are generated — do not hand-edit README.md.
Release files for stapel-billing 0.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| stapel_billing-0.8.0.tar.gz | 121.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| stapel_billing-0.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 222.5 kB
Release files / stapel_billing-0.8.0.tar.gz
| Download URL | stapel_billing-0.8.0.tar.gz |
|---|---|
| Size | 121.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5dec6a1ed60bf6a18ad6c7c75bb2fbee1768d11429d72a1fa6293fd59901c01e
|
|
BLAKE2b-256 checksum How to use checksums |
a7185e77fe06bb4fca9f965f2b2debae2a3dc3e36d3c8897cc6373d16e50bcb1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.
Transparency logRelease files / stapel_billing-0.8.0-py3-none-any.whl
| Download URL | stapel_billing-0.8.0-py3-none-any.whl |
|---|---|
| Size | 100.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8539c0999a013776264c5371b1da5e691f2a58001c6c24b049d457c55a8eadff
|
|
BLAKE2b-256 checksum How to use checksums |
912afe29ae99c47fac981e38891734a6846fcc26b9fe9b08f8bfdad803a0df84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.
Transparency log