Per-customer usage dashboards with Client Tokens
25 minBy the end every signed-in user will have a live chart of their own AI spend, fetched safely from the browser with a short-lived, scoped Client Token so no Bearer key ever touches the client.
- • A Ringside API key (completed the quickstart)
- • A Next.js app with working server-side auth (any provider)
- • A chart library (recharts works, or plain CSS bars)
- • Users already making Ringside calls tagged with FC-Customer
- • 25 minutes
Lazy-create an FC-Customer per user
// idempotent on external_id
Every signed-in user needs a 1:1 Ringside Customer so their spend is bucketed. Use the user's own id as external_id and look it up via ext:<id>.
On first login you 404, then POST to create. On every subsequent login the GET returns the existing row with no dupes, no race. Run this in your auth callback or on any server-side page load.
ext: lookups are Ringside's idempotency primitive. You never need to store the cus_... id in your own database - your user id is already the key.
Mint a Client Token
// short-lived, scoped, origin-locked
A Client Token is a signed JWT scoped to one customer and one endpoint whitelist. It expires in 60-3600 seconds and can't be refreshed. Mint a new one on every page load (or every 4 minutes, whichever is sooner).
origin binds the token to your domain; allowed_endpoints keeps it from reading anything other than this one customer's row.
Expose /api/mint-client-token
// server-side gatekeeper
Browser code can't mint its own token; that would require exposing your Bearer key. Proxy through a Next.js route handler that first checks your own session, then calls Ringside with the server-side key.
Return the Ringside response straight through. Your server stays small; your Bearer key stays in your env vars.
Treat this route like a mint for physical tokens: if your own auth is compromised an attacker only gets a 5-minute window to read one customer's spend. No broader blast radius.
Poll /v1/customers/:id from the browser
// Authorization: Client <jwt>
Fetch the token once on mount, then poll /v1/customers/:id every 5 seconds with Authorization: Client <jwt>.
The response has spend_usd_mtd, request_count_mtd, and any budgets you've set. Wire it straight to state.
If the token expires mid-poll you'll get 401 invalid_client_token. Re-call /api/mint-client-token on that failure - or preemptively rotate at token.expires_at minus 30s.
Chart the numbers
// recharts or CSS bars
Widen the allowed_endpoints to include /v1/usage with group_by=day and feed the resulting array straight into a Recharts <LineChart>.
If you'd rather not add a chart lib, a grid of CSS flex bars with height: {spend / max * 100}% works fine and ships zero JS.
You built it.
Every signed-in user sees their own live AI spend. Your Bearer key never left the server. Tokens expire in minutes. Budgets, alerts, and rate limits are a header away.