- name
- iblai-api-analytics
- description
- Read ibl.ai analytics via the platform API — agent (chat) analytics, content (courses/programs/pathways/skills) analytics, org-wide KPIs, per-user learning data, costs, and fine-grained LLM usage (per-model/-agent/-user cost, tokens, latency) — plus generate and download Data Reports. Scope per-agent or organization-wide. Use to pull usage, engagement, cost, catalog, or per-user analytics.
# iblai-api-analytics
Read ibl.ai analytics from the platform API. One `/api/analytics/` family serves
every scope; the query params decide what you get:
- **Agent (chat) analytics** — add `mentor_unique_id` to scope any chat metric
(topics, sessions, conversations, ratings, costs, transcripts) to one agent.
- **Content analytics** — `/api/analytics/content/`, keyed by `metric=courses` |
`programs` | `pathways` | `skills`, for catalog engagement and time spent.
- **Organization-wide analytics** — omit `mentor_unique_id` for org totals.
- **Per-user analytics** — a single user's enrollments, grades, time spent,
engagement, and cross-platform snapshot.
Reads are read-only; the only writes are Data Reports and a time-spent event.
## The schema is the contract
These endpoints live on the **Data Manager** service and its live OpenAPI schema
is the single source of truth — the URLs and params below exist for orientation
and **can drift between releases**. Validate against the schema before building
requests:
- **Schema (raw):** `https://api.iblai.app/dm/api/docs/schema/`
- **Swagger UI:** `https://api.iblai.app/dm/api/docs/`
```bash
# Confirm the analytics paths you're about to call exist verbatim:
curl -sS "https://api.iblai.app/dm/api/docs/schema/" -o /tmp/iblai_schema.yaml
grep -nE "^ /api/analytics/" /tmp/iblai_schema.yaml
```
Treat any mismatch between this skill and the schema as a bug in the skill — the
deployed schema wins.
## Auth & conventions
- **`dm_url`** = `https://api.iblai.app/dm` — analytics are **Data Manager**
endpoints reached through the gateway's `/dm` prefix. Every URL below is written
as `{dm_url}/api/analytics/<path>`; set `dm_url=https://api.iblai.app/dm` and use it
as the prefix.
- **Header:** `Authorization: Api-Token $IBLAI_API_KEY` on every request.
- **Placeholders:**
- `{platform}` = your workspace key = `$IBLAI_ORG`. On the wire it is the
`platform_key` query param and the `orgs/{platform}` / `platforms/{platform}`
path segment — same value everywhere.
- `{username}` = `$IBLAI_USERNAME`.
- `{mentor}` = an agent's unique id — **optional**: include
`mentor_unique_id={mentor}` for agent scope, omit for org-wide.
- **Shared query params (available on most endpoints):**
- `platform_key={platform}` — the workspace key (required on most reads).
- `date_filter` — `today` | `7d` | `30d` | `90d` | `all_time` | `custom`.
`custom` requires `start_date` **and** `end_date` (both `yyyy-MM-dd`).
- `mentor_unique_id={mentor}` — narrows any chat metric to one agent.
- `granularity` — `hour` | `day` | `week` | `month` (time-series endpoints).
- `usergroup_ids` — repeat to narrow results to specific user groups.
- `page` / `limit` — pagination on list/`details` endpoints.
- Each endpoint below lists its own params; **required** ones are marked and enum
values are given inline. `[¶m=value]` means optional.
- Not connected yet? Run **`/iblai-api-login`** first.
## Reads
### Agent & org chat analytics
The presence of `mentor_unique_id` is the only difference between agent scope and
org-wide scope on every endpoint here.
- **GET** `{dm_url}/api/analytics/topics/?platform_key={platform}&date_filter=30d&metric=overview[&mentor_unique_id={mentor}][&granularity=day][&usergroup_ids=]`
— Messages / Topics / Conversations KPIs.
`metric` ∈ `overview` (default) | `sessions` | `ratings` | `highlighted`.
- **GET** `{dm_url}/api/analytics/topics/details/?platform_key={platform}&date_filter=30d&page=1&limit=20&search=[&mentor_unique_id={mentor}]`
— topics table / bar chart.
- **GET** `{dm_url}/api/analytics/conversations/?platform_key={platform}&date_filter=30d&metric=conversations[&mentor_unique_id={mentor}][&granularity=day]`
— conversation counts. `metric` ∈ `conversations` | `headline`.
- **GET** `{dm_url}/api/analytics/sessions/?platform_key={platform}&date_filter=30d&metric=sessions[&mentor_unique_id={mentor}][&granularity=day]`
— sessions line chart. `metric` ∈ `sessions` | `headline`.
- **GET** `{dm_url}/api/analytics/ratings/?platform_key={platform}&date_filter=30d&metric=ratings[&mentor_unique_id={mentor}][&granularity=day]`
— thumbs / rating breakdown.
- **GET** `{dm_url}/api/analytics/time/?platform_key={platform}&date_filter=30d[&mentor_unique_id={mentor}][&granularity=hour]`
— access-time heatmap.
- **GET** `{dm_url}/api/analytics/users/?platform_key={platform}&metric=active_users&date_filter=30d[&mentor_unique_id={mentor}]`
— user KPIs. `metric` (**required**) ∈ `currently_active` | `active_users` |
`registered_users` | `active_users_last_30d`.
- **GET** `{dm_url}/api/analytics/users/details/?platform_key={platform}&date_filter=30d&page=1&limit=5&search=[&mentor_unique_id={mentor}]`
— user table.
### Transcripts
- **GET** `{dm_url}/api/analytics/messages/?platform_key={platform}&search={q}&topic={topic}&sentiment={s}&min_messages=&max_messages=&page=1&limit=20[&mentor_unique_id={mentor}][&start_date=&end_date=]`
— transcript list (one row per session). `search` matches the learner's
**email** or username and the session's first user message. Each row carries
the learner's `email`.
- **GET** `{dm_url}/api/analytics/messages/details/?platform_key={platform}&session_id={id}[&mentor_unique_id={mentor}]`
— one full transcript. `session_id` **required**. Returns `summary` +
`messages[]`. Beyond `human`/`ai`, every AI turn carries the extended
per-turn context: `documents` (retrieved sources, normalized, or `null`),
`tool_calls` (`[{name, input, output}]`; `[]` when none), `metadata`
(`{client, llm_model, llm_provider, llm_temperature}`, or `null`), and
`request_context` (the credential-stripped request payload, or `null`).
### Content analytics (courses / programs / pathways / skills)
Catalog engagement and time-spent, org-wide by default. Add `mentor_unique_id`
to scope to content consumed via one agent.
- **GET** `{dm_url}/api/analytics/content/?platform_key={platform}&metric=courses&date_filter=30d&include_overtime=false&page=1&limit=20[&mentor_unique_id={mentor}][&granularity=hour][&usergroup_ids=]`
— aggregated content analytics + paginated item list. `metric` (**required**)
∈ `course`/`courses` | `program`/`programs` | `pathway`/`pathways` |
`skill`/`skills`. `include_overtime=true` adds a 7-day time-spent series
(courses only).
- **GET** `{dm_url}/api/analytics/content/details/{content_id}/?platform_key={platform}&metric=courses&date_filter=30d&search=&page=1&limit=20[&time_metric=][&mentor_unique_id={mentor}]`
— detailed analytics for one content item (summary + per-user rows +
optional time series). `metric` **required**.
### Costs
- **GET** `{dm_url}/api/analytics/financial/?platform_key={platform}&metric=total_costs&date_filter=30d[&show_overtime=false][&comparison_days=][&fill_method=zero][&provider=][&llm_model=][&username=][&mentor_unique_id={mentor}]`
— cost KPIs / cost-per-day. `metric` (**required**) ∈ `total_costs` |
`weekly_costs` | `monthly_costs`. `fill_method` ∈ `zero` | `previous`.
- **GET** `{dm_url}/api/analytics/financial/details/?platform_key={platform}&group_by=provider&date_filter=30d&metrics=total_costs,sessions&page=1&limit=20&search=[&provider=][&llm_model=][&username=][&mentor_unique_id={mentor}]`
— cost breakdown. `group_by` (**required**) ∈ `provider` | `llm_model` |
`username` | `mentor` | `platform` | `action`. `metrics` is comma-separated.
- **GET** `{dm_url}/api/analytics/financial/invoice/?platform_key={platform}&start_date=&end_date=&include_breakdown=true[&username={username}][&usergroup_ids=]`
— invoice-style billing summary with optional per-line breakdown.
### LLM usage (cost / tokens / latency)
Fine-grained LLM cost/usage/latency for the UI, proxied from the tracing
backend and **tenant-scoped server-side** (the platform filter is injected from
your key, never taken from input). One `GET {dm_url}/api/analytics/llm-usage/`
serves three resources via the `resource` param; every `measures`, `aggregation`,
`group_by`, and `order_by` value is whitelisted (a bad value is a `400`).
- **GET** `{dm_url}/api/analytics/llm-usage/?platform_key={platform}&resource=metrics&measures=total_cost&aggregation=sum&date_filter=30d[&group_by=model][&granularity=day][&view=observations][&order_by=total_cost][&direction=desc][&limit=50][&mentor_unique_id={mentor}][&username=][&session_id=][&trace_name=][&llm_model=]`
— aggregate metrics (default resource). `measures` (comma-separated) ∈
`total_cost` | `input_tokens` | `output_tokens` | `total_tokens` | `count` |
`latency`. `aggregation` ∈ `sum` | `avg` | `count` | `min` | `max` | `p50` |
`p75` | `p90` | `p95` | `p99`. `group_by` ∈ `type` | `model` | `tags` |
`environment`. `granularity` ∈ `day` | `week` | `month` (omit for a flat
aggregate — there is no `hour`). `view` ∈ `observations` (default) | `scores`.
- **GET** `{dm_url}/api/analytics/llm-usage/?platform_key={platform}&resource=observations&page=1&limit=50[&username=][&trace_name=][&llm_model=][&trace_id={id}][&observation_id={id}]`
— row-level generation drill-down, page-paginated (`meta` carries `totalItems`
/ `totalPages`). `&trace_id={id}` scopes to one trace's observations;
`&observation_id={id}` fetches one observation. `session_id` is **rejected
`400`** here (observations can't filter by session — scope via `resource=traces`
then drill in by `trace_id`); `mentor_unique_id` is likewise **rejected** on
observations.
- **GET** `{dm_url}/api/analytics/llm-usage/?platform_key={platform}&resource=traces&order_by=timestamp&direction=desc&page=1&limit=50[&username=][&session_id=][&trace_name=][&llm_model=][&trace_id={id}][&mentor_unique_id={mentor}]`
— per-user / per-session trace listing (the drill-down the Metrics API can't
group by). `order_by` ∈ `timestamp` (default) | `name` | `username` |
View on GitHub