More reports
Eighteen more routes under https://api.onekey.dev/v1/reports/, in the same style as brand mentions, creator vet and demand signals. Read the shared rules first: the response shape, coverage, honest nulls, dry_run, billing and idempotency are exactly those.
What is different here:
- No AI step. Nothing on this page is judged by a model. Every figure is a platform field or arithmetic that is written out below, and
methodology_version(for examplecrisis_radar/1) changes if the arithmetic does.ai_methodology_versionis alwaysnullandcredits.aiis0. - Built from endpoints that exist. Each report names the endpoints it calls (its
legs). A report that would need data the catalogue does not have is not offered; see what is not built. - Samples, not totals. Search legs return the first page of a platform's search. Where a figure is computed over those pages the report says so in
notesorsample; it never presents a page as a total. - Priced as its legs. The price is the sum of the legs that succeeded, no surcharge. A leg that fails is refunded as usual.
- Dependent legs. A few reports run a second round whose inputs come from the first (an org's top repos, a Truth Social account id). The second round is capped, billed leg by leg, skipped (and said so in
coverage.dependent_legs) if the balance no longer covers it, and priced at its cap bydry_run=true.
At a glance#
Prices are the list prices of the default legs in credits (cache hits are free; dry_run=true shows the legs and the worst case for 0 credits). A report with a platform pool takes platforms and max_platforms like the first three.
| Route | Input | Default legs | List price |
|---|---|---|---|
crisis-radar | brand | news volume and tone timelines | 10 |
crisis-postmortem | brand | up to 4 search platforms + news articles | about 17 |
share-of-voice | brands (2 to 5) | per brand: news volume + 2 search platforms | about 14 for 2 brands |
reputation | brand | App Store search + news tone | 10 |
campaign | query, start, end | news volume + up to 3 search platforms | about 12 |
devtool-pulse | query | repo search, Hacker News, Reddit, dev.to, Stack Exchange | 19 (a named repo: 15) |
launch-echo | query | Hacker News threads and comments, dev.to | 11 |
org-radar | org | org + repos listing, then dossier and top issue for the top 3 | 12 |
leads | competitor | up to 4 search platforms | about 12 |
audience-questions | topic | up to 4 search platforms | about 12 |
find-accounts | name | one user-search endpoint | 3 per platform |
brief-check | url, points | the post's own endpoint | 2 to 3 |
format-lift | platform, handle | the platform's recent-posts feed | 1 to 5 |
trend-board | country | five popular lists | 17 |
apps-lookup | title | App Store search + Google Play search | 8 |
truthsocial-pulse | handle | profile + news search, then recent posts | 6 |
voice | handle | recent posts on up to four platforms | about 11 |
handle-audit | handle | profile and posts feed on 3 platforms | about 9 |
crisis-radar#
GET /v1/reports/crisis-radar?brand=acme. Is news attention to a brand unusually high today, and has its tone dropped? Legs: gdelt.volume_timeline and gdelt.tone_timeline.
Both timelines are averaged per UTC day. For each, z = (newest day - mean of the baseline days) / sample standard deviation, where the baseline is the baseline_days days before the newest (7 to 90, default 28). With fewer than 7 baseline days, or a flat baseline, z is null with a reason. A volume spike (z up) or a tone drop (z down) at or above threshold (default 2) is a breach. The severity.grade steps up for every full standard deviation beyond the threshold: elevated, high, severe (none below it, unknown with no figure).
{"volume": {"series_days": 29, "latest_day": "2026-09-30", "latest": 12.0, "baseline_days": 28, "baseline_mean": 1.5, "baseline_sd": 0.51, "z": 20.6},
"tone": {"latest": -6.0, "z": -9.8},
"severity": {"threshold": 2.0, "breach": {"volume": true, "tone": true}, "any_breach": true, "grade": "severe", "worst_signal_z": 20.6}}Limits: the newest day may be partial. Tone is GDELT's average tone, not a share of negative posts, and there is no confirmation step: a breach means "unusual against its own history", not "a crisis".
crisis-postmortem#
GET /v1/reports/crisis-postmortem?brand=acme&top=25. Who said it first, where did it spread, and when did it peak. Legs: the search endpoint of up to 4 platforms (the brand mentions pool) plus gdelt.articles.
All dated items are merged into a timeline (oldest first, top entries). origin is the earliest item, peak the UTC day with the most items (ties: the earlier day), propagation the platforms in the order of their first item with lag_hours from the origin, daily_counts the items per day. sample counts the items, how many were dated, and per platform.
Limits: each source is one page of its search, so origin is the earliest item in that sample, not a proven first mention, and the report says so in sample.note. There is no narrative text: nothing is generated.
share-of-voice#
GET /v1/reports/share-of-voice?brands=acme,globex,initech. Two to five brands, compared. Per brand: gdelt.volume_timeline plus a search leg on each chosen platform (default 2).
- News share. Each brand's mean GDELT volume intensity over the sum of the brands' means. Intensity is each query's share of all news coverage, so the ratio is comparable between brands.
- Social share. A brand's interactions (likes + comments + shares) over all brands' interactions, across the top results of each platform's search. It is a share of the top results, not of all posts, and it is page-size limited.
leader_news and leader_social name the larger share. No blended score, no emotion overlay and no excess-share-of-voice figure is computed. Cost grows with the number of brands: every brand gets its own legs.
reputation#
GET /v1/reports/reputation?brand=acme (optional app_store_id, country). Two sources the catalogue can supply: the App Store listing (itunes.search_apps, matched to the brand by normalised title, or itunes.lookup_app when you give app_store_id) with its rating, rating_count, price and category; and the news tone summary from gdelt.tone_timeline (mean, last 7 days against the 7 before).
unavailable lists what is not there and why: Trustpilot ratings (the reviews endpoint returns links only), Google Play ratings (no rating field) and Google Business. blended_score is always null: the sources do not share a scale, and nothing is blended.
campaign#
GET /v1/reports/campaign?query=%23acme&start=2026-09-10&end=2026-09-20. A hashtag or phrase around a window. pre_days (default the campaign length, at most 30) and post_days set the windows either side. Legs: gdelt.volume_timeline (the leading # is dropped for it) and up to 3 search platforms.
- news_volume. Mean daily GDELT intensity before, during and after,
lift_during_vs_pre_pct,lift_post_vs_pre_pctandlift_post_vs_during_pct. A window the timeline does not cover isnullwith a warning (the timeline covers a few months back). - top_amplifiers and engagement_by_platform. From the dated search rows inside the window: authors ranked by interactions, and rows and interactions per platform. Rows without a date or outside the window are counted in
sample, not used.
Limits: only the news timeline measures volume. Social rows are the first page of each search, so social volume is not lifted.
devtool-pulse#
GET /v1/reports/devtool-pulse?query=acme (optional repo=owner/name). Developer-brand health in one call. Legs: github.search_repos (its top hit) or github.repo_dossier when you name the repo, then Hacker News, Reddit, dev.to and Stack Exchange searches. repo has stars, forks, open issues, language, licence and last push; mentions has, per source, the rows, their interactions, the newest date and the top items. Each source is one page of its search.
launch-echo#
GET /v1/reports/launch-echo?query=acme (optional repo). How a launch landed: Hacker News threads (hackernews.search) and comments (hackernews.search_comments), the dev.to echo (devto.search) and optionally the repo dossier. Points and comment counts are the platform's own.
org-radar#
GET /v1/reports/org-radar?org=acme&top_repos=3. A GitHub org's footprint. First round: github.org and github.org_repos. Second round (dependent): for the top top_repos (1 to 5) by stars, archived repos skipped, github.repo_dossier and github.top_issues (the most discussed issue, as the top request).
rollup sums stars, forks and open issues over the first page of the repos listing, counts languages and archived repos and gives the last push. It is a rollup of that page, not necessarily of every repo; notes says so.
leads#
GET /v1/reports/leads?competitor=Acme. Posts where people look for an alternative to, or are leaving, a named product. The search runs "Acme alternative" on up to 4 platforms, then keeps the rows whose text matches one of these phrase rules (case-insensitive, the name matched literally):
matched | Phrases |
|---|---|
alternative | "alternative to / for / of / like Acme", "Acme alternative(s)" |
switching_from | switch / move / migrate / leave / left, then "from / off / away from Acme" |
replacing | replace / ditch / drop / cancel / quit, then "Acme" |
instead_of | "instead of Acme" |
better_than | better / cheaper / simpler than Acme |
looking_for | "looking for / recommend / suggest / need ... like / than / over Acme" |
leads is ranked by interactions; stats counts the rows scanned, the leads and the matches per rule. A lead is a public post that matches a phrase: it says nothing about intent beyond the words.
audience-questions#
GET /v1/reports/audience-questions?topic=keyboards. The questions people ask about a topic. Search legs on up to 4 community, social and news platforms. A row is a question when its title or text has a "?" in its first 300 characters, or starts with an interrogative or auxiliary verb and has at least 4 words. Its intent is vs (it names two options with "vs" or "versus"), else its leading wh- word (who, what, why, how, which, where, when), yes_no for an auxiliary opener (can, should, is, do ...) or other. clusters are sorted by size, each with the top examples by interactions.
Limits: questions are found in search-result titles and text, not in comment threads.
find-accounts#
GET /v1/reports/find-accounts?name=Ada%20Lovelace (optional platforms, top). Candidate accounts for a person's or company's name on the user-search endpoints of Instagram, TikTok, Threads, Truth Social, Mastodon and X. By default only the cheapest platform is searched (2 credits); name more with platforms= and each costs its own price.
Each candidate has a match level from the name against the username and display name only: exact (the normalised name equals either), strong (every name token is in them), possible (at least half), weak. Candidates are ranked by level, then followers. They are for human review: nothing links accounts to a person.
brief-check#
GET /v1/reports/brief-check?url=https://www.tiktok.com/@ada/video/123&points=acme x1|battery&forbidden=cure. One post against a brief. The URL is resolved exactly as GET /v1/lookup does (an unknown URL is a free UNSUPPORTED_URL); the post is fetched once at that endpoint's price. points and forbidden are comma or | separated (use | when a phrase has a comma). disclosure defaults to #ad, #sponsored, #paidpartnership, paid partnership, #gifted, #partner, sponsored, advertisement, #advertisement.
Matching is literal, case-insensitive and whole-word on the caption text; a #hashtag matches only itself. passes is true when every point is found, no forbidden term is found and a disclosure term is present. Nothing in a video or image is read, and it is not legal advice.
format-lift#
GET /v1/reports/format-lift?platform=bluesky&handle=ada. Which structural hooks of a creator's own posts did better than the rest of their posts. Platforms with a recent-posts feed: Bluesky, dev.to, Hacker News, Instagram, Lobsters, Reddit, Threads, Twitch, X. One page of recent posts.
Hooks (each a plain text test): question ("?" in the first 140 characters), number (a digit in the first 8 words), how_to, list (starts with a number or "top N"), emoji_open, hashtags_3plus, has_link, short_caption (under 80 characters), long_caption (over 300). The metric is the mean engagement_rate when at least half the posts have one, else the mean interactions (metric says which). lift_pct = (mean with the hook / mean without - 1) x 100, only when at least min_n (default 3) posts are on each side; otherwise null with a reason. It describes this creator's own recent posts and is not a prediction.
trend-board#
GET /v1/reports/trend-board?country=US (optional sources, top). What is rising, with no keyword in: Google Trends (google_trends.trending), TikTok popular hashtags and videos for the country, Bluesky trending topics and Truth Social trending tags (those two are global and ignore the country; scope says which). One list per source in its own order: no fusion, no cross-source score.
apps-lookup#
GET /v1/reports/apps-lookup?title=Acme (optional country). One app title on both stores: itunes.search_apps and googleplay.search. Each store's match is the result whose title equals the query after normalising (exact), else the first containing all its words (contains). The App Store match carries rating, rating count, price and category. Google Play search returns a name and a link only, so comparison is null: there is no cross-store rating comparison.
truthsocial-pulse#
GET /v1/reports/truthsocial-pulse?handle=ada (optional news_query, top). First round: truthsocial.profile and a news search for the handle (google.news). Second round (dependent): truthsocial.user_posts with the account id the profile returned. posts has the cadence (the same arithmetic as creator vet), mean engagement and the top posts; news_echo is the news results, which are not proof the news is about this account.
voice#
GET /v1/reports/voice?handle=ada (optional platforms: any of bluesky, threads, x, truthsocial; limit up to 100). One handle's recent posts on those platforms, merged newest first. The same handle string is tried everywhere: an account that does not exist on a platform is a failed leg, never a guess. Truth Social adds a dependent round (profile, then posts).
handle-audit#
GET /v1/reports/handle-audit?handle=ada (platforms or max_platforms, default 3). The same handle across profile platforms: whether it exists, followers, the date of its last post and posts per week, and what pulling its posts costs: the feed endpoint's price per page, the page size observed and credits_per_100_items. ranking orders the platforms where the handle exists by followers, then by the newest post. No quality or authenticity score is computed.
What is not built#
Some of the same questions cannot be answered honestly from the catalogue today. They are not offered rather than faked:
| Question | Why not |
|---|---|
| AI visibility and multi-engine answers | Need paid AI-engine access that is not connected. |
| Agent-style investigation | Needs a language-model planner; nothing here is model-driven. |
| Screening a person for adverse posts | Needs judgment of a private person's posts; keyword lists would be misleading. |
| Buyer leads from comment threads | Needs search, then comments per post, then an intent judgment. leads covers the posts themselves. |
| How early a term appeared | No source sorts a platform's search oldest first; a first page is not the earliest. |
| Global versus Korean conversation gap | Needs a Naver key and cross-language term mapping. |
| Audience overlap and commenter language | Needs a profile, posts and comments fan-out per creator; not built yet. |
| Review integrity | The catalogue's review endpoints return links, not ratings or dates. |
Errors#
Bad input is refused before anything runs, free: INVALID_PARAMS (a missing or malformed parameter, an unknown one), UNSUPPORTED_PLATFORM, NO_SEARCHABLE_PLATFORMS, UNSUPPORTED_URL (brief-check). An all-legs-failed report fails with the first leg's error and charges nothing; a partial answer is a 200 whose coverage lists the failed legs.
Related#
- Reports: the shared rules.
- Universal search, Multi-platform search, Batch.
- Monitors to be told when numbers move.