AI credits

Metered AI credits, with a paper trail

The optional AI module is a metered chat endpoint backed by an append-only credit ledger. It is not an image or video workbench, and it does not claim that an unconfigured provider will answer.

Checked 2026-10-22

What is already wired

`POST /api/ai/generate` accepts a signed-in session or a scoped Bearer API key. The API key is hashed at rest; revocation, account status and a fixed-window rate limit are rechecked in one atomic D1 update before the request proceeds.

The credit ledger is append-only. A request reserves credits before the provider call, then settles the actual usage afterwards. A definitive provider rejection releases the reservation; a successful call leaves the settled debit in the ledger.

Ledger and billing invariants use D1 batch statements so a request cannot both fail and leave a charge, or settle twice. Every request carries an idempotent request id.

The request lifecycle

The request first resolves an identity from the session or the API key, then applies the per-key rate limit. It reserves a credit allowance, calls the configured OpenAI-compatible provider, and settles the provider's reported usage. The response includes the result and the new balance state.

If the provider rejects the request definitively, the reservation is released. If the network or provider response is ambiguous, the endpoint fails rather than claiming a free success. The client cannot send a price, a credit amount or a paid flag.

  • Session or scoped `vib_` API key for identity.
  • Fixed-window per-key rate limit before work starts.
  • Pre-charge, provider call, then settlement.
  • Refund only on a definitive provider rejection.
  • No client-supplied amount or credit value.

Configuration

Enable the module with `CREDITS_ENABLED=true` in live mode, and configure `AI_BASE_URL`, `AI_API_KEY` and `AI_MODEL` for an OpenAI-compatible endpoint. The optional `CREDIT_PACKS` value names a server-owned price, amount and grant for one-time packs; leaving it empty keeps packs hidden.

Preview mode disables metered AI. Configuration presence is not proof that the provider accepted a request: run a real call against the configured endpoint before enabling paid usage. The [credits and billing guide](/docs/credits-and-billing) covers the ledger model and the [providers guide](/docs/providers) covers the provider adapter.

Limits

This module is chat completions only. Image, video, audio/voice and model-training workbenches are not included; they need separate providers, UI and cost controls. The endpoint does not promise a free or local model when no provider is configured.

Credit allowances and prices are server-owned. A clone should set its own numbers instead of reusing the VibeShip demo. The ledger records usage; it is not a guarantee of provider availability or a fixed per-token price.

Ledger invariants

The balance is derived from ledger rows, not stored as a mutable number. A reservation is a row, a settlement is a row, and a release is a row; the current balance is the closing value of that sequence. The database refuses an overdraft and a duplicate request id.

The ordering matters more than the label: reserve before the provider call, settle only after a response, and release on a definitive rejection. If the process dies between steps, the request id and the ledger let a retry reconcile instead of double-charging.

API keys and cost controls

A scoped Bearer key identifies a user without a browser session. The key is hashed at rest, revocation is checked on every call, and a fixed-window per-key rate limit is updated in the same atomic statement. That limit controls request frequency; the credit reserve controls spend.

Credits are a budget, not a promise of a price. Configure the allowance and pack values server-side, verify one real provider call, and watch the ledger before opening paid use. Image, video and voice generation are outside this module; adding them would need separate cost controls and UI.

Frequently asked questions

No. `AI_BASE_URL`, `AI_API_KEY` and `AI_MODEL` must name a working OpenAI-compatible endpoint, and `CREDITS_ENABLED=true` must be set in live mode. Configuration is required; the module fails closed.

Start from the template guide

The docs cover the full setup sequence: database, auth, billing, AI credits and the Cloudflare deployment.

Related guides