Console
Usage
What the Gateway served, what it cost, and whether it worked — one page, one window, and every figure labelled with the window it covers.
/dashboard/usage covers the whole organization, with optional filters for one API key or one client. It used to share this job with a separate API monitor page; that page is now part of this one, and /dashboard/api redirects here.
Org-scoped rather than runtime-scoped, because spend belongs to the organization and the invoice is cut per org.
Two tables, and which figure comes from which
| Figure | Source | Why that one |
|---|---|---|
| Spend, the spend chart, the breakdown's Spend column, routing savings | token_usage | The priced ledger. The allowance is metered from it and invoices are cut from it. |
| Requests, error rate, latency, time to first token, tokens, failures by class | gateway_requests | The request trace. It has a row for every request, including ones that failed before a token existed. |
A line under the headline says the same thing. Money comes from one table only, so the Spend total, the breakdown's Spend column and the allowance panel below cannot disagree because they read different tables.
Time windows
The period control offers This month and the last 7, 14, 30 or 90 days. This month is the default. It runs from the first of the month in UTC to now, which is the same window the allowance is metered over. The other four are rolling windows that run back to the minute. The chosen window is kept in the URL and carried across the Console, so Overview, Usage and Logs always show the same period.
Every figure carries a badge naming its window: This month, Last 7 days, and so on. The allowance panel has its own window, the calendar month, and its badge always says so. Overview's Health band has its own window too, the last 24 hours.
The headline row
| Metric | What it is |
|---|---|
| Spend | The sum of priced ledger rows in the window. When some of it ran on your own provider key, the sub-line splits what Lobstack billed from what ran on your key. |
| Requests | Traced requests in the window, failures included. The sub-line counts failures and streamed requests. |
| Error rate | Requests with a status code of 400 or above, over all requests. Amber above 1%, red above 5%. |
| p95 latency | The 95th percentile of recorded latency. The sub-line carries p50 and p99. |
| Time to first token | p95 and p50 over streamed requests that recorded one, with the sample count. Hidden when nothing was sampled. |
| Tokens | Prompt and completion tokens from the trace. |
The percentiles are computed over the raw values, sorted. They are not an average of per-bucket averages, which produces a p95 nobody ever experienced.
The two charts
Spend per day is one bar per UTC day of ledger spend. Requests per day stacks failures on top of successes. Both draw every day in the window, including days with no traffic. The trace records every request that reached the Gateway, so an empty day is a real zero. A day containing unpriced rows gets a marker above the bar and is not filled in, because there is no amount to draw.
cost_usd as null when the meter could not price a call. Those rows are counted and never added in as zero. Where any row is unpriced, the figure carries a “+”, the count is stated above the headline, and nothing priced at all renders as an em dash, not $0.00.gateway_requests and token_usage are two separate writes, and either can fail alone. That happened for three days from 8 September 2026. When traced requests are missing from the priced ledger, a banner says how many, and warns that Spend understates what was served.Failures by class
When there are errors in the window, they are split into six classes, sorted by count. Each class says whose move it is.
| Class | What it means | Whose move |
|---|---|---|
| auth | 401 or 403: the credential was rejected. | The caller fixes its key. |
| quota | 402 or 429: the allowance is exhausted. | Upgrade, top up, or wait for the reset. |
| validation | 400, 409 or 422: the request was malformed. | The caller fixes the call. |
| provider | A 5xx from upstream that is not our own 500. | Retry. Not the caller's fault. |
| timeout | 504 or 408: we gave up waiting. | Retry. |
| internal | 500, and anything thrown that we could not classify. | Ours. Quote the request id. |
An unknown throw is classified as internal, not provider. Blaming upstream by default would hide our own crashes. A seventh label, unclassified, appears only on rows written before the taxonomy existed.
Breakdown
One table, cut by the dimension you choose. Each row has requests, errors, tokens, spend and p95 for that group alone. The columns sort, the Spend column adds up to the Spend total, and a download button saves the table as CSV.
| Dimension | Grouped by |
|---|---|
| Model | The model that served the request. |
| Provider | The upstream vendor. |
| Mode | Managed (billed by Lobstack) or your own key (billed by your provider). |
| API key | The key that authenticated the call, or no key for a browser session. |
| Client | The client tag the call was made for: from the key, the x-lobstack-client-tag header, or metadata.client. Budgets and statements live in Clients. |
| App | The calling application's self-reported x-lobstack-client header, e.g. lobstack-app/0.8.0, shown as Lobstack app (as is the older lob-bot/…). A label, never an authorization input. |
The period, the key and client filters, and the chosen dimension are all in the URL, so a link opens the same view for somebody else.
The allowance panel
The allowance panel ignores the period control and always counts the calendar month, the period the allowance resets on. With This month selected, the Spend headline and the managed spend in the allowance cover the same window.
When the totals are a floor
The route reads at most 20,000 rows per window from each table. When that cap is reached, the page says so and the sums are a floor rather than a total. Unpriced rows make a figure a floor too. In both cases the page says so, and no total is presented as exact when it is not.
What a trace row contains
| Field | Note |
|---|---|
| id | The request id. Returned to the caller and quotable in support. |
| org_id, api_key_id, agent_id | Who the request belonged to. The last two may be null. |
| route | Which Gateway route handled it, e.g. chat.completions. |
| requested_model, served_model, routed | What was asked for, what answered, and whether those differ. |
| provider | The upstream provider that served it. |
| status_code | The HTTP status returned to the caller. |
| error_class, error_code, error_message | The bucket, the provider's code, and the message truncated to 1,000 characters. |
| latency_ms, ttft_ms | Total latency, and time to first token on streamed requests. |
| prompt_tokens, completion_tokens, total_tokens | Zero on requests that failed before inference. |
| cost_usd | The trace's copy of the price. Null means unpriced, which is not the same as free. |
| mode | managed (our provider key) or byok (yours). |
| stream | Whether the caller asked for server-sent events. |
| client | The calling app's self-reported X-Lobstack-Client or user agent, truncated to 200 characters. |
| client_tag | The client the call was made for, when it carried one. |
How a row maps to the headers the caller saw
| Response header | Trace column |
|---|---|
x-lobstack-request-id | id |
x-lobstack-model | served_model |
x-lobstack-routed | routed |
x-lobstack-mode | mode |
x-lobstack-cost-usd | cost_usd |
x-lobstack-tier | Not stored. The tier is on the response only. |
The request id is on successful responses, on error responses, and inside the error body. It is the fastest way from “something went wrong at 14:02” to the row that explains it. To see a single request, use Logs, which reads the same table.
The same numbers, programmatically
The page is a client of GET /api/v1/usage and adds no arithmetic of its own. A key with the usage:read scope reads the identical response. range accepts month, 7d, 14d, 30d and 90d, and defaults to 7d when omitted. group_by accepts the dimensions above as model, provider, mode, key, client and app, plus day. Filter to one client with client=<tag>, or client=__untagged__ for calls with no tag.
The response carries spend (the ledger), summary (the trace) and window, the exact start and end that were summed. More on the credential in API keys.