Skip to content

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

FigureSourceWhy that one
Spend, the spend chart, the breakdown's Spend column, routing savingstoken_usageThe 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 classgateway_requestsThe 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

MetricWhat it is
SpendThe 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.
RequestsTraced requests in the window, failures included. The sub-line counts failures and streamed requests.
Error rateRequests with a status code of 400 or above, over all requests. Amber above 1%, red above 5%.
p95 latencyThe 95th percentile of recorded latency. The sub-line carries p50 and p99.
Time to first tokenp95 and p50 over streamed requests that recorded one, with the sample count. Hidden when nothing was sampled.
TokensPrompt 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.

A total built from unpriced rows is a floorThe ledger stores 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.
When the two tables disagree, the page says sogateway_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.

ClassWhat it meansWhose move
auth401 or 403: the credential was rejected.The caller fixes its key.
quota402 or 429: the allowance is exhausted.Upgrade, top up, or wait for the reset.
validation400, 409 or 422: the request was malformed.The caller fixes the call.
providerA 5xx from upstream that is not our own 500.Retry. Not the caller's fault.
timeout504 or 408: we gave up waiting.Retry.
internal500, 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.

DimensionGrouped by
ModelThe model that served the request.
ProviderThe upstream vendor.
ModeManaged (billed by Lobstack) or your own key (billed by your provider).
API keyThe key that authenticated the call, or no key for a browser session.
ClientThe 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.
AppThe 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.

An em dash is not zeroEvery dollar figure can be null, and null renders as an em dash, not $0.00. A customer who has spent nothing and a customer whose spend cannot be read are in different situations.

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

FieldNote
idThe request id. Returned to the caller and quotable in support.
org_id, api_key_id, agent_idWho the request belonged to. The last two may be null.
routeWhich Gateway route handled it, e.g. chat.completions.
requested_model, served_model, routedWhat was asked for, what answered, and whether those differ.
providerThe upstream provider that served it.
status_codeThe HTTP status returned to the caller.
error_class, error_code, error_messageThe bucket, the provider's code, and the message truncated to 1,000 characters.
latency_ms, ttft_msTotal latency, and time to first token on streamed requests.
prompt_tokens, completion_tokens, total_tokensZero on requests that failed before inference.
cost_usdThe trace's copy of the price. Null means unpriced, which is not the same as free.
modemanaged (our provider key) or byok (yours).
streamWhether the caller asked for server-sent events.
clientThe calling app's self-reported X-Lobstack-Client or user agent, truncated to 200 characters.
client_tagThe client the call was made for, when it carried one.

How a row maps to the headers the caller saw

Response headerTrace column
x-lobstack-request-idid
x-lobstack-modelserved_model
x-lobstack-routedrouted
x-lobstack-modemode
x-lobstack-cost-usdcost_usd
x-lobstack-tierNot 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.

bash
curl "https://www.lobstack.ai/api/v1/usage?range=month&group_by=client" \
  -H "Authorization: Bearer $LOBSTACK_API_KEY"

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.

Lobstack

An AI team that asks before it acts, and an API with a receipt on every call.

© LobstackXLinkedInGitHub