---
title: "Authed welcome strip data — watchlist + resume + credits"
method: GET
path: "/api/welcome/your-ledger"
tags: ["Welcome"]
---

# Authed welcome strip data — watchlist + resume + credits

`GET /api/welcome/your-ledger`

## Request

- Base URL: `https://www.oxfordledge.com` (the document declares no server; this is the origin it was published from)
- URL: `https://www.oxfordledge.com/api/welcome/your-ledger`
- Auth: none declared

Aggregator for the authed `/welcome` Your-Ledger tile strip.

Returns 401 for anon (require_auth handles); your-ledger.ts hydrator
swallows the 401 silently so anon HTML never paints the strip.

CISO control 1 (docs/board/audit/2026-09-23_CISO_your_ledger_mcp_usage_stat.md):
the ORIGIN says `no-store` on every 200. "Never shared" had rested on the
Cloudflare cache-rule allowlist and the hydrator's own fetch flag, neither
of which this route controls; a per-user payload states its own policy.

## Response `200`

Successful Response

- YourLedgerResponse: `GET /api/welcome/your-ledger` response — authed-only aggregator. `watchlist` + `credits` are REQUIRED (always present once authed). `resume` is Optional because users who have never started a lesson don't have a `user_learning_meta` row yet — the hydrator renders a "Start your first lesson →" CTA in that branch.
  - `watchlist` YourLedgerWatchlistItem[], required
    - `ticker` string, required
  - `credits` YourLedgerCredits, required: AI credit snapshot for the welcome pill. Same shape consumed by the topbar credit-meter (#248) — reuses get_usage_summary.
    - `used` integer, required
    - `cap` integer, required
    - `tier` string, required
    - `tier_display` string, required
  - `resume` YourLedgerResume: Last-active learning path + module — the "pick up where you left off" tile. `pathId` + `moduleId` together resolve to a deep-link URL `/?view=learn&path={pathId}&module={moduleId}`.
    - `pathId` string, required
    - `moduleId` string, required
  - `mcp` YourLedgerMcp, required: The "AI clients" stat on the authed /welcome strip. SF-MCP-USAGE-ROLLUP section 4 (docs/plans/SF-MCP-USAGE-ROLLUP.md) under CISO welcome controls 3 and 6 as amended 2026-09-23 (docs/board/audit/2026-09-23_CISO_your_ledger_mcp_usage_stat.md): the payload is exactly `{state, days_7d}`. It never carries a count of calls, a tool name, a key id/prefix/name, a timestamp or the caller kind -- the field set is pinned by tests/test_welcome_mcp_usage_contract.py, and `extra="forbid"` makes a stray key a serialization error, not a leak. state -> days_7d, enforced below so no route branch can emit a contradiction: pointer -> null (not credentialed, OR any read failed, OR the fleet has written no row in 7 days; the client paints the D-5 "Connect Claude or Codex" pointer) off -> null (credentialed, analytics opted out) none -> 0 (credentialed, read ok, no day with a lookup) used -> 1..7 (credentialed, read ok) 0 means only "read ok, zero days"; a failure is never 0.
    - `state` 'pointer' | 'off' | 'none' | 'used', required: Which AI-clients stat to paint: `pointer` (the connect how-to link), `off` (usage not recorded: analytics opted out), `none` (no lookups counted in the last 7 UTC days) or `used`.
    - `days_7d` integer, nullable: Distinct UTC days in the last 7 with at least one counted lookup. 0 only for `none`, 1-7 only for `used`, null for `pointer` and `off` -- never 0 as a failure value.

---

[API](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api.md) · [All operations](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/llms.txt) · [OpenAPI document](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/revisions/e832a1260f0b?raw)
