Properties
| Name | Type | Description |
|---|---|---|
| keyword | object | The keyword the report is about. |
| window | object | The window the report reads, by match time, in UTC days. |
| status | string | healthy: nothing to fix. noisy: 20 or more scored matches in the window and under 30% of them relevant. quiet: 7 days or older with no relevant match in the window. capped: at its monthly mention cap. |
| reasons | array | Why, in plain words; the first line explains the status. |
| stats | object | Computed over the keyword's matches in the window. |
| sample | object | The posts behind noiseTerms, noiseAuthors and the effects, after the keyword's current rules (a post an older rule let in is not counted). Review platforms are matched by app, not by text, and are lef |
| noiseTerms | array | Up to 10 words or phrases over-represented in the noise against the relevant posts, strongest first. The keyword's own words are left out. |
| noiseAuthors | array | Authors with 3 or more noise posts in the sample and no relevant one. |
| suggestions | array | Changes that would cut the noise, each ready for PATCH /v1/keywords/{id}. Empty when nothing is worth changing, or under 20 scored matches since the last change (a reason says so). |
| ai | object | The optional language model half of the report. |
| generatedAt | string | When the report was computed; it is cached for 5 minutes, and a change to the keyword starts a fresh one. |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/mentio-dev/json-schema/mentio-dev-keyword-health-schema.json",
"title": "KeywordHealth",
"x-generated": "2026-10-31",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/mentio-dev-api-openapi.json#/components/schemas/KeywordHealth",
"type": "object",
"properties": {
"keyword": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Keyword id (kw_...)."
},
"term": {
"type": "string",
"description": "The term as typed."
},
"group": {
"$ref": "#/$defs/GroupRef"
}
},
"required": [
"id",
"term",
"group"
],
"description": "The keyword the report is about."
},
"window": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "First day, YYYY-MM-DD, inclusive, UTC."
},
"to": {
"type": "string",
"description": "Last day, inclusive: today."
},
"days": {
"type": "integer",
"minimum": 0,
"description": "Length of the window in days."
}
},
"required": [
"from",
"to",
"days"
],
"description": "The window the report reads, by match time, in UTC days."
},
"status": {
"type": "string",
"enum": [
"healthy",
"noisy",
"quiet",
"capped",
"paused",
"new"
],
"description": "healthy: nothing to fix. noisy: 20 or more scored matches in the window and under 30% of them relevant. quiet: 7 days or older with no relevant match in the window. capped: at its monthly mention cap. paused: muted (by you, the wallet or the noise brake). new: under 7 days old and not noisy yet, or changed in the last 7 days with under 20 scored matches since the change. When the keyword's matching rules, platforms or context changed (or it was unmuted) inside the window, the status reads only the matches since then (stats.judgedSince)."
},
"reasons": {
"type": "array",
"items": {
"type": "string"
},
"description": "Why, in plain words; the first line explains the status."
},
"stats": {
"type": "object",
"properties": {
"matches": {
"type": "integer",
"minimum": 0,
"description": "Matches recorded in the window, relevant or not."
},
"relevant": {
"type": "integer",
"minimum": 0,
"description": "Scored at or above the relevance line (40)."
},
"filtered": {
"type": "integer",
"minimum": 0,
"description": "Scored under the line: the noise. Billed like any match."
},
"unscored": {
"type": "integer",
"minimum": 0,
"description": "Not scored yet, or failed to score (never billed)."
},
"noiseShare": {
"type": [
"number",
"null"
],
"minimum": 0,
"maximum": 1,
"description": "filtered / (relevant + filtered); null with nothing scored."
},
"workspaceShare": {
"type": [
"number",
"null"
],
"minimum": 0,
"maximum": 1,
"description": "This keyword's share of the workspace's matches in the window; null when the workspace matched nothing."
},
"judgedSince": {
"type": [
"string",
"null"
],
"description": "When the keyword last changed its matching rules, platforms or context (or was unmuted), when that is inside the window: the status, the reasons, noiseTerms, noiseAuthors and suggestions read only the matches since then, while these numbers keep the whole window. Null: everything reads the whole window."
},
"byPlatform": {
"type": "array",
"items": {
"type": "object",
"properties": {
"platform": {
"type": "string",
"enum": [
"bluesky",
"hackernews",
"github",
"stackoverflow",
"devto",
"reddit",
"x",
"youtube",
"news",
"linkedin",
"tiktok",
"instagram",
"appstore",
"googleplay",
"trustpilot",
"googlemaps",
"rss"
],
"description": "Platform: bluesky, hackernews, github, stackoverflow, devto, reddit, x, youtube, news, linkedin, tiktok, instagram, appstore (App Store reviews), googleplay (Google Play reviews), trustpilot (Trustpilot reviews), googlemaps (Google reviews of a place), rss (RSS and Atom feeds a keyword reads)."
},
"matches": {
"type": "integer",
"minimum": 0,
"description": "Matches on this platform in the window."
},
"relevant": {
"type": "integer",
"minimum": 0,
"description": "Of those, scored at or above the relevance line (40)."
},
"filtered": {
"type": "integer",
"minimum": 0,
"description": "Of those, scored under the line: the noise."
},
"noiseShare": {
"type": [
"number",
"null"
],
"minimum": 0,
"maximum": 1,
"description": "filtered / (relevant + filtered); null with nothing scored."
}
},
"required": [
"platform",
"matches",
"relevant",
"filtered",
"noiseShare"
]
},
"description": "One row per platform it matched on, most matches first."
},
"weekly": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "First day of the 7, YYYY-MM-DD (counted from the window's first day)."
},
"matches": {
"type": "integer",
"minimum": 0,
"description": "Matches in those 7 days."
},
"relevant": {
"type": "integer",
"minimum": 0,
"description": "Of those, relevant."
}
},
"required": [
"from",
"matches",
"relevant"
]
},
"description": "The trend, one row per 7 days of the window, oldest first; the last row may be shorter."
},
"cost": {
"type": "object",
"properties": {
"keywordDays": {
"type": "integer",
"minimum": 0,
"description": "Days in the window the keyword was charged for."
},
"keywordCents": {
"type": "integer",
"description": "Those days at the keyword rate."
},
"billableMentions": {
"type": "integer",
"minimum": 0,
"description": "Matches billed in the window, by the time they were scored."
},
"mentionCents": {
"type": "integer",
"description": "Those matches at the mention rate."
},
"billableComments": {
"type": "integer",
"minimum": 0,
"description": "Comments billed in the window under the keyword (0074)."
},
"commentCents": {
"type": "integer",
"description": "Those comments at the comment rate."
},
"totalCents": {
"type": "integer",
"description": "keywordCents, mentionCents and commentCents: its row in GET /v1/usage/breakdown for the same range."
}
},
"required": [
"keywordDays",
"keywordCents",
"billableMentions",
"mentionCents",
"billableComments",
"commentCents",
"totalCents"
],
"description": "What the keyword cost over the window at list price."
}
},
"required": [
"matches",
"relevant",
"filtered",
"unscored",
"noiseShare",
"workspaceShare",
"judgedSince",
"byPlatform",
"weekly",
"cost"
],
"description": "Computed over the keyword's matches in the window."
},
"sample": {
"type": "object",
"properties": {
"noise": {
"type": "integer",
"minimum": 0,
"description": "Noise posts read (the newest of the window, or since stats.judgedSince, at most 200), on platforms matched by text. None under 20 scored matches since a change."
},
"relevant": {
"type": "integer",
"minimum": 0,
"description": "Relevant posts read, likewise."
}
},
"required": [
"noise",
"relevant"
],
"description": "The posts behind noiseTerms, noiseAuthors and the effects, after the keyword's current rules (a post an older rule let in is not counted). Review platforms are matched by app, not by text, and are left out."
},
"noiseTerms": {
"type": "array",
"items": {
"type": "object",
"properties": {
"term": {
"type": "string",
"description": "A word or two-word phrase."
},
"noisePosts": {
"type": "integer",
"minimum": 0,
"description": "Sampled noise posts that carry it."
},
"relevantPosts": {
"type": "integer",
"minimum": 0,
"description": "Sampled relevant posts that carry it."
},
"lift": {
"type": [
"number",
"null"
],
"description": "How many times more common it is in noise than in relevant posts (smoothed); null with no relevant post to compare."
}
},
"required": [
"term",
"noisePosts",
"relevantPosts",
"lift"
]
},
"description": "Up to 10 words or phrases over-represented in the noise against the relevant posts, strongest first. The keyword's own words are left out."
},
"noiseAuthors": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The author as the platform shows them."
},
"entry": {
"type": "string",
"description": "What matching.excludedAuthors would store for them."
},
"noisePosts": {
"type": "integer",
"minimum": 0,
"description": "Sampled noise posts by them."
}
},
"required": [
"name",
"entry",
"noisePosts"
]
},
"description": "Authors with 3 or more noise posts in the sample and no relevant one."
},
"suggestions": {
"type": "array",
"items": {
"$ref": "#/$defs/KeywordSuggestion"
},
"description": "Changes that would cut the noise, each ready for PATCH /v1/keywords/{id}. Empty when nothing is worth changing, or under 20 scored matches since the last change (a reason says so)."
},
"ai": {
"type": "object",
"properties": {
"requested": {
"type": "boolean",
"description": "ai=true was asked."
},
"status": {
"type": "string",
"enum": [
"off",
"generated",
"cached",
"unavailable",
"rate_limited"
],
"description": "off: not asked. generated: written now. cached: written earlier today for the same keyword, window and settings. unavailable: the model failed, answered nothing usable or is not configured. rate_limited: the workspace's 20 model calls this hour are spent."
}
},
"required": [
"requested",
"status"
],
"description": "The optional language model half of the report."
},
"generatedAt": {
"type": "string",
"description": "When the report was computed; it is cached for 5 minutes, and a change to the keyword starts a fresh one."
}
},
"required": [
"keyword",
"window",
"status",
"reasons",
"stats",
"sample",
"noiseTerms",
"noiseAuthors",
"suggestions",
"ai",
"generatedAt"
],
"$defs": {
"GroupRef": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Group id (grp_...)."
},
"name": {
"type": "string",
"description": "The group's name."
},
"externalId": {
"type": [
"string",
"null"
],
"description": "Your own id for the group, or null."
},
"isDefault": {
"type": "boolean",
"description": "The workspace's default group, where a keyword lands when no group is named."
}
},
"required": [
"id",
"name",
"externalId",
"isDefault"
],
"description": "The group the keyword belongs to."
},
"KeywordSuggestion": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"excluded_terms",
"excluded_authors",
"required_terms",
"platforms",
"context"
],
"description": "excluded_terms and excluded_authors add to the matching rules; required_terms sets them; platforms drops the platforms that are almost all noise; context rewrites the sentence the classifier reads."
},
"values": {
"type": "array",
"items": {
"type": "string"
},
"description": "What it adds (terms, authors), drops (platforms) or writes (the context)."
},
"why": {
"type": "string",
"description": "The reason and the measured effect, in plain words."
},
"patch": {
"type": "object",
"properties": {
"term": {
"type": "string",
"minLength": 2,
"maxLength": 80,
"description": "Renames the keyword: the new term is tracked from now on, with no look-back, and the keyword keeps its id, its settings and the mentions the old term found. Wrap it in double quotes for the exact phrase only. A 409 when its group already tracks the new term."
},
"kind": {
"type": "string",
"enum": [
"brand",
"competitor",
"topic"
],
"description": "Reclassify it as brand, competitor or topic."
},
"muted": {
"type": "boolean",
"description": "A muted keyword stops polling and matching; its mentions stay."
},
"platforms": {
"type": [
"array",
"null"
],
"items": {
"type": "string",
"enum": [
"bluesky",
"hackernews",
"github",
"stackoverflow",
"devto",
"reddit",
"x",
"youtube",
"news",
"linkedin",
"tiktok",
"instagram"
]
},
"description": "Replaces the platform list; null means every platform, [] none (reviews only, when the keyword has reviewSources)."
},
"context": {
"type": [
"string",
"null"
],
"maxLength": 300,
"description": "A sentence the classifier reads for this keyword only, on top of the company profile or the group's own description (at most 300 characters): what the term means here, what to ignore. \"Arc is our browser; ignore the geometry word.\" Null clears it."
},
"matching": {
"type": "object",
"properties": {
"requiredTerms": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"maxItems": 50,
"description": "The post must ALSO contain these terms, any one of them or all of them per requiredMode. A `*` at the start or the end of an entry is a wildcard (alert* matches alerts and alerting). Empty: no requirement."
},
"requiredMode": {
"type": "string",
"enum": [
"any",
"all"
],
"description": "any: at least one required term must appear. all: every one must."
},
"requiredGroups": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"minItems": 1,
"maxItems": 10
},
"maxItems": 50,
"description": "Combinations of terms, at most 50 of 10 terms each: the post must ALSO contain every term of at least one group (an OR of ANDs). For the keyword inreach, [[\"weather\", \"alert*\"], [\"tsunami\"], [\"flash flood\"]] keeps a post about inReach weather alerts, tsunamis or flash floods, one keyword instead of three. Same phrase and wildcard rules as requiredTerms; when both are set a post must pass both. Empty: no combinations."
},
"excludedTerms": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"maxItems": 50,
"description": "A post containing any of these is dropped. A `*` at the start or the end of an entry is a wildcard (beta.* matches beta.0.1; *bot matches nightlybot)."
},
"excludedAuthors": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 500
},
"maxItems": 100,
"description": "Posts by these authors are dropped: profile or post links, @handles, u/names, Bluesky DIDs or display names, stored in canonical form like an alert's muted list."
},
"caseSensitive": {
"type": "boolean",
"description": "true: the term must appear in the case it was typed (RAG, never rag). Default false."
},
"exactPhrase": {
"type": "boolean",
"description": "true: only the exact phrase matches. false (default): a multi-word keyword also matches a post holding its words close together, in any order, plurals and spellings (non-profit, nonprofit) included; such a match is kept and billed only when the classifier scores it relevant. A term sent in double quotes sets this to true."
},
"repositories": {
"type": "object",
"properties": {
"events": {
"type": "array",
"items": {
"type": "string",
"enum": [
"new",
"traction",
"stars",
"growth"
]
},
"description": "The repository events this keyword takes. traction: a repository created in the last 30 days reached 10 stars. stars: one with 100 stars or more passed a milestone (100, 250, 500, 1,000, 2,000, 5,000 ...). growth: it gained stars fast in a week. new: every repository created, even with no stars (off by default: nearly all of them are noise for a broad keyword). Default: traction, stars, growth. Empty: no repository events."
},
"minStars": {
"type": [
"integer",
"null"
],
"minimum": 0,
"maximum": 1000000,
"description": "Only repositories with at least this many stars; null for no minimum."
},
"minWeeklyStars": {
"type": [
"integer",
"null"
],
"minimum": 25,
"maximum": 1000000,
"description": "Only repositories that gained at least this many stars in the last 7 days (25 or more). It applies to every event, and one whose last week is not known yet does not pass. null: a growth event needs 100 stars and 20% of the repository's stars in a week, the other events need no growth."
}
},
"description": "GitHub only: each field is replaced when sent, kept when omitted; null clears a minimum."
},
"subreddits": {
"type": "object",
"properties": {
"only": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"maxItems": 50,
"description": "Replaces the keyword's allowlist; [] clears it."
},
"excluded": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"maxItems": 50,
"description": "Replaces the keyword's deny list; [] clears it."
}
},
"description": "Reddit only, for this keyword alone: each list is replaced when sent, kept when omitted."
}
},
"description": "Omitted fields are untouched; an empty list clears one."
},
"cap": {
"type": [
"object",
"null"
],
"properties": {
"mentions": {
"type": "integer",
"minimum": 1,
"maximum": 1000000,
"description": "Charged items allowed per period (see per): matched mentions plus the thread comments delivered under them. Every match counts, relevant or not, the look-back a new keyword gets included, because every match bills."
},
"per": {
"type": "string",
"enum": [
"day",
"week",
"month"
],
"default": "month",
"description": "The period the cap counts in, in UTC: day (from 00:00), week (from Monday 00:00) or month (the calendar month, the default). At the cap the keyword stops until the next period starts, so a daily cap keeps mentions coming every day with a fixed ceiling on spend."
}
},
"required": [
"mentions"
],
"description": "Replaces the mention cap and its period (per, default month); null removes it. A cap above the current period's count resumes a capped keyword at once, one at or under it pauses it."
},
"comments": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "Read the comments under this keyword's relevant mentions, from 30 minutes after each post, as long as its platform's conversations last (a day to a month). Each comment delivered costs $0.008 (comments of fewer than three words are dropped, never billed) (the comments line of the bill). Off by default."
},
"maxPerPost": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "The newest comments of one thread you receive, 20 by default, 100 at most: the ceiling on what one mention's comments can cost. A comment that names the keyword is a mention too, but only among these newest ones, so it is never billed past the ceiling."
}
},
"description": "Comments under this keyword's mentions; omitted fields are untouched (on create: off, 20 per post)."
},
"display": {
"type": "object",
"properties": {
"languages": {
"type": "object",
"properties": {
"only": {
"type": "array",
"items": {
"type": "string",
"enum": [
"en",
"es",
"de",
"fr",
"pt",
"it",
"nl",
"ca",
"pl",
"tr",
"sv",
"da",
"ru",
"uk",
"ar",
"hi",
"id",
"ja",
"zh",
"ko"
]
},
"maxItems": 60,
"description": "Replaces the list; [] clears it."
},
"excluded": {
"type": "array",
"items": {
"type": "string",
"enum": [
"en",
"es",
"de",
"fr",
"pt",
"it",
"nl",
"ca",
"pl",
"tr",
"sv",
"da",
"ru",
"uk",
"ar",
"hi",
"id",
"ja",
"zh",
"ko"
]
},
"maxItems": 60,
"description": "Replaces the list; [] clears it."
}
},
"description": "By the language of the post (ISO 639-1); omitted: untouched."
},
"countries": {
"type": "object",
"properties": {
"only": {
"type": "array",
"items": {
"type": "string",
"enum": [
"us",
"ca",
"mx",
"br",
"ar",
"co",
"cl",
"pe",
"gb",
"ie",
"fr",
"de",
"es",
"pt",
"it",
"nl",
"be",
"ch",
"at",
"se",
"no",
"dk",
"fi",
"pl",
"cz",
"ro",
"gr",
"hu",
"ua",
"ru",
"lt",
"lv",
"ee",
"tr",
"il",
"ae",
"sa",
"eg",
"ng",
"ke",
"za",
"ma",
"in",
"pk",
"bd",
"lk",
"np",
"cn",
"hk",
"tw",
"jp",
"kr",
"sg",
"my",
"id",
"ph",
"vn",
"th",
"au",
"nz"
]
},
"maxItems": 60,
"description": "Replaces the list; [] clears it."
},
"excluded": {
"type": "array",
"items": {
"type": "string",
"enum": [
"us",
"ca",
"mx",
"br",
"ar",
"co",
"cl",
"pe",
"gb",
"ie",
"fr",
"de",
"es",
"pt",
"it",
"nl",
"be",
"ch",
"at",
"se",
"no",
"dk",
"fi",
"pl",
"cz",
"ro",
"gr",
"hu",
"ua",
"ru",
"lt",
"lv",
"ee",
"tr",
"il",
"ae",
"sa",
"eg",
"ng",
"ke",
"za",
"ma",
"in",
"pk",
"bd",
"lk",
# --- truncated at 32 KB (40 KB total) ---
# Full source: https://artifacts.apis.io/mentio-dev/json-schema/mentio-dev-keyword-health-schema.json
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/mentio-dev-keyword-health"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.