---
title: "Get Team Analytics"
method: GET
path: "/api/v1/teams/{team_id}/analytics"
tags: ["teams"]
---

# Get Team Analytics

`GET /api/v1/teams/{team_id}/analytics`

## Request

- Base URL: `https://api.badgeia.com`
- URL: `https://api.badgeia.com/api/v1/teams/{team_id}/analytics`
- Auth: none declared

TEAM-003 W1-T1.1 — Owner analytics (absorbs IMPROVE-001 B3).

Read-only aggregates computed from EXISTING data:
  * per-member contribution (runs initiated, workspace agents registered,
    Team Scorecards published),
  * shared workspace-agent usage,
  * seat + monthly-run cap utilization,
  * provenance (real vs simulated) split on every run count + a 30-day
    runs/day series — simulated (mock) activity must never read as real
    performance (BRIEF-IMPROVE-002 §6/§10, mirrors the Talent Pool chips).

Gate: ``TeamPermission.VIEW_WORKSPACE_ANALYTICS`` (Owner + Admin). A member
or viewer who lacks it gets 403; a non-member stays opaque with 404,
matching the cross-tenant existence-hiding posture of
``require_team_permission``. The client cannot self-authorize — this
endpoint is the real gate.

Every query below is a plain ``COUNT(*) … GROUP BY`` on indexed columns, so
the read runs identically on Postgres and the aiosqlite test path
(CLAUDE.md rule #6). No cost is invented (no per-member cost, no LLM cost).

## Path parameters

- `team_id` string, uuid, required

## Response `200`

Successful Response

- TeamAnalyticsRead
  - `team_id` string, uuid, required
  - `plan` string, required
  - `seats_used` integer, required
  - `max_seats` integer, required
  - `monthly_run_count` integer, required
  - `monthly_run_cap` integer, nullable
  - `total_runs_initiated` integer, required
  - `total_workspace_agents` integer, required
  - `total_scorecards_published` integer, required
  - `provenance` TeamProvenanceSummaryRead, required: Workspace-wide real-vs-simulated run counts (§6 provenance honesty). ``real_runs`` = runs whose ``execution_mode`` is a positively-confirmed live execution (``real_llm`` / ``live_endpoint``); everything else — mock dice-rolls and legacy NULLs — is simulated (the conservative default, mirroring ``verification.normalize_execution_mode``). The UI must label a workspace whose runs are simulated-only with a provenance chip.
    - `real_runs` integer, required
    - `simulated_runs` integer, required
    - `total_runs` integer, required
  - `runs_window_days` integer, required
  - `runs_per_day` TeamRunsPerDayPointRead[]
    - `date` string, required
    - `real` integer, required
    - `simulated` integer, required
    - `total` integer, required
  - `members` TeamMemberContributionRead[]
    - `member_id` string, uuid, required
    - `user_id` string, uuid, nullable
    - `display_name` string, required
    - `email` string, required
    - `role` string, required
    - `runs_initiated` integer, required
    - `real_runs_initiated` integer, required
    - `simulated_runs_initiated` integer, required
    - `agents_registered` integer, required
    - `scorecards_published` integer, required
  - `shared_agents` TeamSharedAgentRead[]
    - `agent_id` string, uuid, required
    - `name` string, required
    - `ownership_scope` string, required
    - `run_count` integer, required
    - `real_run_count` integer, required
    - `simulated_run_count` integer, required

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/badgeia/apis/badge.md) · [All operations](https://skmtc.dev/badgeia/apis/badge/llms.txt) · [OpenAPI document](https://skmtc.dev/badgeia/apis/badge/revisions/7e7f7fee8b77?raw)
