Skip to main content
Three read endpoints plus one toggle, all on https://dash.square1.dev and all accepting either the ws-session cookie or a Bearer API key.
If all you need is “does this key work, and where do I stand on quota”, use GET /v1/me and GET /v1/usage instead. They are stable, whitelisted projections on the documented API host. Everything below is the dashboard’s own surface.

Account snapshot — GET /api/user/me

The dashboard’s session-of-record call. One request returns the profile, quota-pool standing, per-model usage, recent requests, and leaderboard position.
This response is not wrapped in {success, data} — it is a bare object. And its 403 is a bare string, not the usual envelope: {"error": "User not found (legacy key)"}. Unwrapping error.message here yields undefined.

The eleven top-level keys

Casing is mixed within this single response, as marked above. This is a historical wart, not a rule you can derive. Copy field names exactly.

profile

Nineteen camelCase fields. The ones with surprises:
  • createdAt and lastUsedAt are epoch milliseconds (numbers). Every other timestamp in profilelivenessBlockedAt, nextLivenessAt, passwordChangedAt, lastNickChangedAt, nicknameCooldownUntil — is an ISO 8601 string or null. The two epoch fields are a frozen older contract.
  • email is the full address, unmasked. It is your own address on your own account, so the API returns it in full; the dashboard is what masks it for display. If you log this response, you are logging an email address.
  • emailVerified is a boolean derived from a timestamp, not the timestamp.
  • passkeyCount is 0 whenever the passkey feature is off, regardless of what is stored.
  • nicknameCooldownUntil is null whenever self-service nickname change is off.
The remaining fields — arcaId, arcaType, displayName, status, isAdmin, isLegacy, username, sfwMode, needsMigration — are what their names suggest. status values are covered in Authentication.

plan

Both buckets share used / limit / remaining / used_pct / resets_at / resets_in_seconds / by_model. session additionally has active; weekly additionally has anchor_at.
  • used, limit, and remaining can all three be null at once. The operator can hide absolute figures; used_pct is always present. Treat null as “hidden”, not as zero.
  • by_model counts successful requests only, so its weighted values can sum to slightly less than the bucket’s used while requests are still in flight. pct_of_total is a proportion within by_model, so the percentages still add up.
  • by_model[].weighted is null when absolutes are hidden.
There is no field telling you whether absolutes are hidden — the flag exists internally but is not included in this response. Infer it from weighted (or used) being null.
The same standing is available in a stable, documented form from GET /v1/usage — prefer that if you only need quota.

recentRequests

Your last 20 request rows, straight from storage and therefore snake_case: id, model_id, status, created_at, input_tokens, output_tokens, tps, error.
error here is a free-form diagnostic string, not an enumerated code. Its wording is unstable and not part of any contract. If you are branching on failures, use GET /api/user/me/requests below, whose error_code values come from the documented error code set.

Your metrics — GET /api/user/me/metrics

Aggregated statistics over your own request log.
Rate limit: 120 requests/minute, shared with GET /api/user/me/requests.

Query parameters

An unrecognized range is a 400 whose message lists the allowed values.
model is not validated against the catalog — it is truncated to 128 characters and used as-is. A model id you can’t call, or one that doesn’t exist, returns an empty result rather than an error. That is deliberate: validating would turn this parameter into an oracle for models you can’t see.

Response

A bare object (no {success, data} wrapper), entirely snake_case: range · model · since · until · bucket_seconds · totals · latency · tps · tokens · tools · errors · by_model · byok · series Points worth knowing:
  • Ratios are null when the sample is empty, never 0. totals.success_rate, tokens.cache_rate, tools.with_tools_rate, and every latency.* percentile follow this rule — zero activity must not read as total failure.
  • latency reports ttfb_p50 / ttfb_p95 / duration_p50 / duration_p95 over successful rows only.
  • errors.by_code is {code, tier, count} per code, and errors.by_tier aggregates by the same three tiers described in Errors.
  • tools.choices is a truncated top-N distribution of tool_choice values, with unset folded into unset. It is client-supplied free text, so entries are length-limited.
  • byok is a subset of totals, not a separate population, and carries a by_provider breakdown of your own registered providers. It is all zeroes with an empty by_provider when you have no BYOK traffic.

Recent requests — GET /api/user/me/requests

Row-level access to your own request log.
  • limit defaults to 20 and is capped at 50.
  • Invalid limit values do not error. A non-number, a negative, or an empty string silently becomes the default; anything above the cap is clamped. Check the echoed limit if it matters.
  • This is a ceiling, not pagination — there is no cursor.
  • error_code is null on success and otherwise one of the documented error codes.
  • byok and fell_back are booleans only: whether the request used one of your own credentials, and whether it fell back to the pool. The provider itself is not on the row — per-provider figures come from the byok block of the metrics endpoint above.
Rate limit: 120 requests/minute, shared with GET /api/user/me/metrics.

SFW toggle — POST /api/user/sfw

Turns the account-level safe-mode blur on or off for generated images.
The path is /api/user/sfwnot /api/user/me/sfw. And the body and response are snake_case, unlike its /api/user/* siblings.
The response is flat — sfw_mode sits next to success, not inside a data object. Any body value other than the boolean true is read as false, so the endpoint never rejects a malformed body; it just turns the mode off. The current value is also in profile.sfwMode on GET /api/user/me.