Skip to main content
All guidesGuide

Step-by-step: add per-token, per-request billing to your FastAPI AI API.

AI APIs charge by usage — per token, per request, or per document processed. This guide walks through integrating Stripe's usage-based billing with FastAPI, from metering events to webhook handling. FastAPI AI Kit ships with this integration pre-built — this guide explains the architecture.

1

Set up Stripe products and prices

Create a metered price in Stripe that charges per unit (token, request, or document). Configure the billing interval and unit amount in your Stripe Dashboard or via the API.

step-1.py
import stripe

stripe.api_key = settings.STRIPE_SECRET_KEY

# Create a metered price (run once during setup)
price = stripe.Price.create(
    currency="usd",
    unit_amount=1,  # $0.01 per 1000 tokens
    recurring={"interval": "month", "usage_type": "metered"},
    product=settings.STRIPE_PRODUCT_ID,
)
2

Record usage after each API call

After every LLM call, report the token usage to Stripe as a metering event. Use idempotency keys to prevent double-counting.

step-2.py
async def record_usage(subscription_item_id: str, tokens: int) -> None:
    stripe.SubscriptionItem.create_usage_record(
        subscription_item_id,
        quantity=tokens,
        timestamp=int(time.time()),
        action="increment",
        idempotency_key=f"{subscription_item_id}-{uuid4()}",
    )
3

Handle Stripe webhooks

Set up a webhook endpoint to handle subscription lifecycle events — creation, cancellation, payment failures. Verify the webhook signature to prevent spoofing.

step-3.py
@router.post("/webhooks/stripe")
async def stripe_webhook(request: Request):
    payload = await request.body()
    sig = request.headers.get("stripe-signature")
    try:
        event = stripe.Webhook.construct_event(payload, sig, settings.STRIPE_WEBHOOK_SECRET)
    except ValueError:
        raise HTTPException(400, "Invalid payload")
    except stripe.error.SignatureVerificationError:
        raise HTTPException(400, "Invalid signature")

    if event["type"] == "customer.subscription.deleted":
        await deactivate_api_keys(event["data"]["object"]["customer"])
    return {"status": "ok"}
4

Integrate metering into your LLM middleware

Create a middleware or dependency that automatically tracks token usage for every LLM call and reports it to Stripe, so billing happens without any per-endpoint code.

step-4.py
class BillingMiddleware:
    async def __call__(self, key: APIKey, response: LLMResponse):
        total_tokens = response.prompt_tokens + response.completion_tokens
        await record_usage(key.stripe_subscription_item_id, total_tokens)
        await db_log_usage(key.id, total_tokens, response.model)
5

Add a customer portal link

Give your customers a way to manage their billing, update payment methods, and view invoices via Stripe's hosted customer portal.

step-5.py
@router.post("/billing/portal")
async def create_portal_session(user: User = Depends(get_current_user)):
    session = stripe.billing_portal.Session.create(
        customer=user.stripe_customer_id,
        return_url=f"{settings.FRONTEND_URL}/dashboard",
    )
    return {"url": session.url}

Skip the setup, start building

Everything in this guide is already implemented and configured in FastAPI AI Kit. Clone the repo and start building your product features immediately.

Ready to ship your AI backend this weekend?

Join developers who skipped weeks of boilerplate and went straight to building.

Read the docs
No subscriptions · One-time payment · Lifetime updates