Browse docs
Your First Project

Charge Credits For It

One decorator argument makes the endpoint paid: anonymous calls get refused, users get charged per call, and the ledger records everything.

Updated Aug 2026
On this page

This is where the boilerplate earns its price. You'll make the QR endpoint cost 1 credit per call, and the framework will do everything that normally takes weeks: refuse anonymous calls, charge per call, refund on errors, and keep an auditable ledger.

1. One argument

In apps/app_endpoints/qr_code/endpoints.py, change the decorator line:

@endpoint(slug="qr-code", description="Turn any text or link into a QR code image.", credits_cost=1)

Reload:

.\scripts\stack-up.ps1 -Reload

That's the entire billing integration. No Stripe code, no middleware, no charge logic in your run().

2. Watch it refuse

An anonymous call (no API key) now gets HTTP 401. A logged-in user with an empty balance gets this instead:

{"error": {"code": "insufficient_credits", "message": "Need 1 credit(s); balance is 0. Top up at /dashboard/billing/.", "required": 1, "available": 0}}
Two curl calls refused: 401 auth_required without a key, then 402 insufficient_credits with a real key and no balance
Both responses re-run for this page. Same endpoint, same body; the only difference is the Authorization header.

Both straight from our lab run. Note what you did NOT build: the refusal message, the error code, the pointer to the top-up page.

3. Grant yourself credits

You're the operator, so give the demo user some balance: open the admin console (the private URL from setup), go to Users, open [email protected], and use Adjust credits to add 10. The adjustment is written to the ledger with your name and reason.

4. Make paid calls

Call the endpoint 3 times with your API key:

Invoke-RestMethod -Uri http://127.0.0.1:8000/api/v1/qr-code -Method Post -Headers @{Authorization='Bearer mcpsk_YOUR_KEY'} -ContentType 'application/json' -Body '{"text":"paid call"}'

Then look at the dashboard's usage page, or the admin's call log. From our run, after granting 10 and calling 3 times:

balance: 7
ledger: adjust  +10  reason='docs walkthrough grant'
ledger: consume  -1  (x3)
calllog: qr-code status=200 credits_charged=1  (x3)
calllog: qr-code status=402 credits_charged=0  (the refusal from step 2)
The dashboard's recent activity table showing three qr-code calls charged 1 credit each, one 402 charged nothing, and a balance of 7
The same run, on the dashboard. The refused call is logged and charged nothing; the free call above it is the Try-it you ran before turning billing on.

Calls made from Claude over MCP hit the same meter. One billing brain, every surface.

Do I need Stripe?

No. Credits work standalone: you grant them manually (or on any trigger you like), the framework enforces them. Connect Stripe later and users buy credit packs and subscriptions themselves; the repo's docs/BILLING.md walks through the whole setup, and docs/recipes/credit-only-mode.md covers running credits-only forever.

Errors refund automatically

If your run() raises an exception after the charge, the framework refunds the call. Your users never pay for your bugs. That behavior is tested in the suite.

Your first project is complete: a paid, AI-callable, documented API. Next stop: Make It Yours.

Stop wiring plumbing. Start selling endpoints.

Django and FastMCP boilerplate for Claude Code: one Python class becomes a REST endpoint, an MCP tool and live docs, with billing, credits and OAuth wired. The stack behind ToolerBox.

Get it for $79 →