# Reports

Three routes under `https://api.onekey.dev/v1/reports/` turn a subject into one structured answer: a brand, a creator, or a topic. Each is built only from pieces that already exist and have their own pages: search legs, profile legs, per-user post feeds, the [computed block](https://onekey.dev/docs/computed.md), rank fusion, and, in two of the reports, the optional [labels](https://onekey.dev/docs/labels.md) and [themes](https://onekey.dev/docs/themes.md).

A report never estimates anything. Every number in it is a platform field, the published [`engagement_rate`](https://onekey.dev/docs/computed.md) or cadence arithmetic, or a counted AI judgment that names its `methodology_version`. Where the data is missing the report says `null` and why. It does not fill the gap.

| Report | Route | Input | What you get |
| --- | --- | --- | --- |
| [Brand mentions](https://onekey.dev/docs/reports/brand-mentions.md) | `GET /v1/reports/brand-mentions` | `brand` | Mentions and volume per platform, top authors, top mentions, and (optional AI) sentiment, complaints, questions and themes. |
| [Creator vet](https://onekey.dev/docs/reports/creator-vet.md) | `GET /v1/reports/creator-vet` | `handle` | One handle across platforms: the platform's own profile numbers, posting cadence and recent engagement. No AI, and no authenticity score. |
| [Demand signals](https://onekey.dev/docs/reports/demand-signals.md) | `GET /v1/reports/demand-signals` | `topic` | How many recent posts on a topic show purchase intent, questions or complaints, with examples. AI-dependent: not enabled yet. |

**More reports.** Eighteen more routes with no AI step (crisis radar and post-mortem, share of voice, campaign, leads, audience questions, org radar, find accounts and others) are on [More reports](https://onekey.dev/docs/reports/composites.md). They follow the same shape and billing.

```bash
curl "https://api.onekey.dev/v1/reports/brand-mentions?brand=rust&platforms=hackernews,devto&top=3" \
  -H "x-api-key: YOUR_API_KEY"
```

## The shape every report shares

`data` holds:

| Field | Meaning |
| --- | --- |
| `report` | `brand_mentions`, `creator_vet` or `demand_signals`. |
| `methodology_version` | The version of this report's arithmetic (`brand_mentions/1`, `creator_vet/1`, `demand_signals/1`). It changes if the way a number is computed changes. |
| `inputs` | What was asked: the platforms, how they were chosen (`selection`: `explicit` or `auto`), and, for the search reports, the exact sub-query each platform got (`subqueries`, `adapted`, `skipped`). |
| `legs` | The underlying calls, one row each, exactly as in [multi-platform search](https://onekey.dev/docs/search-multi.md): status, error, price and cache state per leg. |
| `coverage` | `{answered, failed, missing_fields}`: which platforms answered, which failed (with `status` and `type`), and which fields were absent on every item of a leg. |
| `credits` | `{legs, ai, total}`. |
| `ai_methodology_version` | The AI method that produced any judgment (the test provider's method id until a production model is connected), or `null` when no AI step ran. |

`metadata.credits_charged` equals `data.credits.total`. `metadata.pipeline` lists the stages (`plan`, `fan_out`, `rerank`, `fuse`, `cluster`) with status, milliseconds and credits, as in [universal search](https://onekey.dev/docs/universal-search.md#the-pipeline).

### Coverage is part of the answer

Read `coverage` before you read the numbers. A platform that failed shows as `null` in per-platform counts, never as 0, so a platform having a bad hour does not read as "nobody mentioned this". A report whose legs all failed fails with the first leg's error and nothing is charged.

### Choosing platforms

`platforms=a,b` names them explicitly. Each must carry the role the report needs (a search endpoint, or a profile endpoint), else [`UNSUPPORTED_PLATFORM`](https://onekey.dev/docs/errors.md#unsupported-platform), and at most `max_platforms` (default 6, hard cap 12). Without `platforms`, the report uses its default pool in the same deterministic order universal search uses (stable before beta, AI-capable first, cheaper first, then by id), cut to `max_platforms`. If nothing is available, or no form of the input fits the platforms' parameter rules, the call is a free [`NO_SEARCHABLE_PLATFORMS`](https://onekey.dev/docs/errors.md#no-searchable-platforms).

Search inputs are fitted to each platform's own parameter rules like a [universal search](https://onekey.dev/docs/universal-search.md#fitting-the-query-to-each-platform) sub-query, so a tag-style search receives one keyword. The report shows this in `inputs.adapted`.

### Default pools today

| Report | Default pool |
| --- | --- |
| Brand mentions | Search platforms in the Social, Messaging & communities, News and Video categories: Bluesky, DEV Community, Hacker News, Lemmy, Mastodon, Reddit, Stack Exchange, TikTok, Twitch, X (Twitter), YouTube. |
| Creator vet | Every platform with a profile endpoint (17 today: Bluesky, crates.io, DEV Community, GitHub, GitLab, Hacker News, Huggingface, Instagram, Lemmy, Lobsters, Mastodon, Reddit, SoundCloud, TikTok, Twitch, X (Twitter), YouTube), cut to `max_platforms`, 6 unless you raise it. |
| Demand signals | Search platforms in the Social, Messaging & communities and News categories whose search accepts labels: Bluesky, DEV Community, Hacker News, Lemmy, Reddit, Stack Exchange. |

The lists are generated from the catalog and the [category mapping](https://onekey.dev/docs/categories.md), so they change when platforms are added.

### Billing

Billing is that of [multi-platform search](https://onekey.dev/docs/search-multi.md): a worst-case check first (a call whose worst case is above your balance is refused, and nothing runs), then each leg that succeeded at its own price, [cache hits](https://onekey.dev/docs/caching.md) free, failed legs refunded, your key's [credit limit](https://onekey.dev/docs/key-limits.md) applied, and one request against the [rate limit](https://onekey.dev/docs/rate-limits.md). There is no surcharge for the report itself: the total is the legs plus the AI lines. An [`Idempotency-Key`](https://onekey.dev/docs/idempotency.md) replays a report at 0 credits.

### Dry run

`dry_run=true` returns the legs, each with its endpoint, params, list price and worst-case price, plus your balance and whether it covers the worst case, for 0 credits. It works even when AI is off (`ai_enabled` says whether AI steps would run). AI steps cannot be priced beforehand, since they are metered per judged row after the rows exist, so a dry run gives `credits.ai: null`.

### AI parts

> [!NOTE] **Not enabled yet.** AI enrichment ships when a production model is connected; every number on this page comes from the pre-release test provider and will change. It is switched on per account, so nothing here describes real-world judgment quality yet. Where it is not enabled, a request that asks for it with the default `strict=true` is refused with `503 AI_UNAVAILABLE` at no charge; with `strict=false` you get the rows back unjudged. Enrichment is also switched on per platform: only the endpoints in the [table on the Labels page](https://onekey.dev/docs/labels.md#which-endpoints-accept-it) accept these parameters.

Only two reports have an AI part: [brand mentions](https://onekey.dev/docs/reports/brand-mentions.md#the-ai-part) and [demand signals](https://onekey.dev/docs/reports/demand-signals.md). Everything else in the reports, including all of [creator vet](https://onekey.dev/docs/reports/creator-vet.md), needs no AI and works when AI is not enabled. The AI parts follow the usual `strict` rule: with AI unavailable and a requested step, the default `strict=true` is a free [`AI_UNAVAILABLE`](https://onekey.dev/docs/errors.md#ai-unavailable) before anything is fetched; `strict=false` returns the data with every AI-derived count reporting `judged: 0`, at the legs' price. AI steps are priced as on [AI pricing](https://onekey.dev/docs/ai-pricing.md).

## What every report cannot do

- **Nothing is inferred.** No follower estimate, no authenticity or quality score, no sentiment guess without a judgment that names its method.
- **AI-derived counts are plumbing checks until a production method exists.** All of the recorded AI figures on the report pages come from the pre-release test provider, a keyword heuristic. On it, sentiment on plain titles is neutral by construction and `purchase_intent` is keyword matching. Use those counts to check your integration, not to draw conclusions.
- Reports are JSON only. A `Accept: text/event-stream` header is ignored, and a report is not yet a target for a [monitor](https://onekey.dev/docs/monitors.md).

## Discovery

`GET /v1/platforms` marks each endpoint a report can use with `features.reports`: search endpoints, profile endpoints and the cadence feeds. `/openapi.json` documents the three paths with `x-platforms` and `x-report` (the methodology version, default pool, default labels and cadence sources). The hosted [MCP server](https://onekey.dev/docs/mcp.md) exposes all three through one `report` tool.

## Next

- [Brand mentions](https://onekey.dev/docs/reports/brand-mentions.md), [Creator vet](https://onekey.dev/docs/reports/creator-vet.md), [Demand signals](https://onekey.dev/docs/reports/demand-signals.md).
- [Universal search](https://onekey.dev/docs/universal-search.md): the planner and the pipeline these reports share.
- [Multi-platform search](https://onekey.dev/docs/search-multi.md): the legs and billing underneath.
