mentio-dev · Schema

Keyword

CompanySocial ListeningAI IntegrationSDKsReal-time Monitoring

Properties

Name Type Description
id string Keyword id (kw_...).
term string
kind string
muted boolean Not polled or matched. Paused by you, by the wallet (see pausedForBalance) or by the noise brake (see pausedForNoise). A keyword at its mention cap is not muted (see pausedForCap).
pausedForBalance boolean Muted by the wallet for lack of balance; a top-up resumes it, unmuting by hand needs balance too.
pausedForNoise boolean Muted by the noise brake: on a workspace running on its welcome credit, at least 20 of its matches were scored and under 30% were relevant. A change of its required or excluded terms, platforms or con
pausedForCap boolean At its monthly mention cap: not matched until the first of next month (UTC) or until the cap is raised. Not muted: it keeps its place and its daily keyword charge.
cap objectnull The mention cap and its period, or null for none.
comments object Comments under this keyword's mentions: when enabled, the comments of every mention scored relevant are read from 30 minutes after the post, on a schedule per platform (for a day on Reddit, Hacker New
display object Which of this keyword's mentions you see, by language and country. Both are read by the classifier, so a hidden post is still matched, classified and billed like any other; it is kept out of the menti
group object
platforms arraynull Platforms the term is searched on; null means every platform, [] none (the keyword only collects reviews).
feeds array RSS and Atom feeds this keyword reads; empty for none.
readsWorkspaceFeeds boolean true (the default): the keyword also reads every feed of the workspace (GET /v1/feeds), on top of its own `feeds`. false: its own feeds alone.
reviewSources array Where this keyword collects reviews from (App Store and Google Play apps, Trustpilot pages, Google Maps places); empty for none.
context stringnull 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 brow
matching object Matching rules applied before a mention is stored; a rejected post is never billed.
stats object Computed over this workspace's matches.
polling array Poll health per platform polled on a schedule. Live feeds (Bluesky) have no entry.
createdAt string ISO 8601 timestamp, UTC.
View JSON Schema on GitHub

JSON Schema

mentio-dev-keyword-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/mentio-dev/json-schema/mentio-dev-keyword-schema.json",
  "title": "Keyword",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/mentio-dev-api-openapi.json#/components/schemas/Keyword",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Keyword id (kw_...)."
    },
    "term": {
      "type": "string"
    },
    "kind": {
      "type": "string",
      "enum": [
        "brand",
        "competitor",
        "topic"
      ]
    },
    "muted": {
      "type": "boolean",
      "description": "Not polled or matched. Paused by you, by the wallet (see pausedForBalance) or by the noise brake (see pausedForNoise). A keyword at its mention cap is not muted (see pausedForCap)."
    },
    "pausedForBalance": {
      "type": "boolean",
      "description": "Muted by the wallet for lack of balance; a top-up resumes it, unmuting by hand needs balance too."
    },
    "pausedForNoise": {
      "type": "boolean",
      "description": "Muted by the noise brake: on a workspace running on its welcome credit, at least 20 of its matches were scored and under 30% were relevant. A change of its required or excluded terms, platforms or context resumes it (when the balance covers another day), and so does unmuting; a top-up does not."
    },
    "pausedForCap": {
      "type": "boolean",
      "description": "At its monthly mention cap: not matched until the first of next month (UTC) or until the cap is raised. Not muted: it keeps its place and its daily keyword charge."
    },
    "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."
        },
        "used": {
          "type": "integer",
          "minimum": 0,
          "description": "Charged items (matches plus thread comments) counted in the current period: today, this week from Monday or this month, UTC. The keyword pauses when it reaches mentions."
        },
        "welcome": {
          "type": "boolean",
          "description": "Set by Mentio, not you: a workspace on its welcome credit collects at most 200 mentions a keyword a month. The first top-up removes it."
        },
        "own": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Your own cap. With welcome true, the cap the keyword gets back at the first top-up (null for none); otherwise the same as mentions. Sending mentions: 200 back while welcome is true changes nothing."
        },
        "ownPer": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "day",
            "week",
            "month"
          ],
          "description": "The period of your own cap (null when own is null); with welcome false, the same as per."
        },
        "resumesAt": {
          "type": [
            "string",
            "null"
          ],
          "description": "While paused for its cap (pausedForCap): when its next period starts and it matches again. Null otherwise."
        }
      },
      "required": [
        "mentions",
        "used",
        "welcome",
        "own",
        "ownPer",
        "resumesAt"
      ],
      "description": "The mention cap and its period, or null for none."
    },
    "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."
        }
      },
      "required": [
        "enabled",
        "maxPerPost"
      ],
      "description": "Comments under this keyword's mentions: when enabled, the comments of every mention scored relevant are read from 30 minutes after the post, on a schedule per platform (for a day on Reddit, Hacker News and Bluesky, a week on GitHub, Stack Overflow and DEV, a month on YouTube) (new comments only, at most maxPerPost a thread, comments of fewer than three words dropped), on Hacker News, Bluesky, GitHub, Stack Overflow, DEV, YouTube and Reddit. List them with GET /v1/mentions/{id}/comments."
    },
    "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": "When non-empty, a post whose language (ISO 639-1) is known and not listed is hidden, a language (ISO 639-1) the classifier recognises but does not name included. A post whose language (ISO 639-1) nobody could tell is always shown."
            },
            "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": "A post whose language (ISO 639-1) is listed is hidden."
            }
          },
          "required": [
            "only",
            "excluded"
          ],
          "description": "By the language the post is written in."
        },
        "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": "When non-empty, a post whose author's country (ISO 3166-1 alpha-2) is known and not listed is hidden, a author's country (ISO 3166-1 alpha-2) the classifier recognises but does not name included. A post whose author's country (ISO 3166-1 alpha-2) nobody could tell is always shown."
            },
            "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",
                  "np",
                  "cn",
                  "hk",
                  "tw",
                  "jp",
                  "kr",
                  "sg",
                  "my",
                  "id",
                  "ph",
                  "vn",
                  "th",
                  "au",
                  "nz"
                ]
              },
              "maxItems": 60,
              "description": "A post whose author's country (ISO 3166-1 alpha-2) is listed is hidden."
            }
          },
          "required": [
            "only",
            "excluded"
          ],
          "description": "By where the author is, as the classifier read their profile and the post."
        }
      },
      "required": [
        "languages",
        "countries"
      ],
      "description": "Which of this keyword's mentions you see, by language and country. Both are read by the classifier, so a hidden post is still matched, classified and billed like any other; it is kept out of the mentions list, the exports, MCP search, alerts and digests (includeHidden=true on GET /v1/mentions shows it). Read when the mentions are read, so changing a list applies to older mentions too."
    },
    "group": {
      "$ref": "#/$defs/GroupRef"
    },
    "platforms": {
      "type": [
        "array",
        "null"
      ],
      "items": {
        "type": "string",
        "enum": [
          "bluesky",
          "hackernews",
          "github",
          "stackoverflow",
          "devto",
          "reddit",
          "x",
          "youtube",
          "news",
          "linkedin",
          "tiktok",
          "instagram"
        ]
      },
      "description": "Platforms the term is searched on; null means every platform, [] none (the keyword only collects reviews)."
    },
    "feeds": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/KeywordFeed"
      },
      "description": "RSS and Atom feeds this keyword reads; empty for none."
    },
    "readsWorkspaceFeeds": {
      "type": "boolean",
      "description": "true (the default): the keyword also reads every feed of the workspace (GET /v1/feeds), on top of its own `feeds`. false: its own feeds alone."
    },
    "reviewSources": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ReviewSource"
      },
      "description": "Where this keyword collects reviews from (App Store and Google Play apps, Trustpilot pages, Google Maps places); empty for none."
    },
    "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."
        },
        "subreddits": {
          "type": "object",
          "properties": {
            "only": {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              "maxItems": 50,
              "description": "When non-empty, this keyword takes Reddit posts from these subreddits ONLY and `excluded` is ignored. r/name or name, stored bare and lowercase."
            },
            "excluded": {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              "maxItems": 50,
              "description": "Reddit posts from these subreddits are dropped for this keyword. r/name or name."
            }
          },
          "required": [
            "only",
            "excluded"
          ],
          "description": "Reddit only, for this keyword alone; the workspace filters' own subreddit lists (GET /v1/filters) still apply to every keyword, and a post must pass both."
        },
        "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."
            }
          },
          "required": [
            "events",
            "minStars",
            "minWeeklyStars"
          ],
          "description": "GitHub only: which repository events naming this keyword become mentions. An event outside the rule is dropped before it is stored, so it is never billed."
        }
      },
      "required": [
        "requiredTerms",
        "requiredMode",
        "requiredGroups",
        "excludedTerms",
        "excludedAuthors",
        "caseSensitive",
        "exactPhrase",
        "subreddits",
        "repositories"
      ],
      "description": "Matching rules applied before a mention is stored; a rejected post is never billed."
    },
    "stats": {
      "type": "object",
      "properties": {
        "mentions": {
          "type": "integer",
          "minimum": 0,
          "description": "Every match ever, relevant or not: the number billing counts."
        },
        "relevant": {
          "type": "integer",
          "minimum": 0,
          "description": "Matches scored at or above the relevance threshold."
        },
        "last7d": {
          "type": "integer",
          "minimum": 0,
          "description": "Matches published in the last 7 days."
        },
        "thisMonth": {
          "type": "integer",
          "minimum": 0,
          "description": "Matches recorded this calendar month (UTC), plus the thread comments delivered under this keyword's mentions: the count a cap compares against."
        },
        "lastMentionAt": {
          "type": [
            "string",
            "null"
          ],
          "description": "Newest matched post; null until the first one."
        },
        "feedback": {
          "type": "object",
          "properties": {
            "relevant": {
              "type": "integer",
              "minimum": 0,
              "description": "Mentions a person marked relevant."
            },
            "notRelevant": {
              "type": "integer",
              "minimum": 0,
              "description": "Mentions a person marked not relevant: the noise the classifier let through."
            }
          },
          "required": [
            "relevant",
            "notRelevant"
          ],
          "description": "Your verdicts on this keyword's mentions (PATCH /v1/mentions/{id} relevant)."
        },
        "noise": {
          "type": "object",
          "properties": {
            "scored": {
              "type": "integer",
              "minimum": 0,
              "description": "Matches of the last 14 days (by match time) the classifier has scored."
            },
            "relevant": {
              "type": "integer",
              "minimum": 0,
              "description": "Of those, the ones scored relevant."
            },
            "noisy": {
              "type": "boolean",
              "description": "At least 20 scored matches in the last 14 days and under 30% of them relevant: tighten the keyword with required terms, excluded terms or context. Every match bills, relevant or not."
            }
          },
          "required": [
            "scored",
            "relevant",
            "noisy"
          ],
          "description": "Relevance over the last 14 days of scored matches, so a keyword tightened today stops being flagged within two weeks."
        },
        "health": {
          "type": "string",
          "enum": [
            "healthy",
            "noisy",
            "quiet",
            "capped",
            "paused",
            "new"
          ],
          "description": "The keyword's health over the same 14 days as `noise`, by the rule GET /v1/keywords/{id}/health applies to its own window: paused (muted), capped (at its mention cap), noisy (20 or more scored matches, under 30% relevant), new (under 7 days old and not noisy, or changed in the last 7 days with under 20 scored matches since), quiet (7 days or older, nothing relevant), else healthy. Judged on the matches since the keyword's last change to its matching rules, platforms or context (or its unmute) when that is inside the 14 days, so a keyword tightened today is not flagged on the noise the change removed; `noise` itself keeps the whole 14 days. Always 14 days, while the endpoint reads 30 by default, so the two can differ for the same keyword. The health endpoint says why and what to change."
        },
        "cost": {
          "type": "object",
          "properties": {
            "keywordDays": {
              "type": "integer",
              "minimum": 0,
              "description": "Days this month the keyword was charged for: unmuted at the daily tick. A keyword created today reads 0 until tomorrow's tick."
            },
            "keywordCents": {
              "type": "integer",
              "description": "Those days at the keyword rate ($5 a month, 500/30 cents a day), rounded once on the total."
            },
            "billableMentions": {
              "type": "integer",
              "minimum": 0,
              "description": "Matches billed this month, counted when they were scored (the clock the ledger settles by), so it can trail thisMonth by the matches still being scored and never counts one that failed to score."
            },
            "mentionCents": {
              "type": "integer",
              "description": "Those matches at $0.008 each, rounded once on the total."
            },
            "billableComments": {
              "type": "integer",
              "minimum": 0,
              "description": "Comments billed this month under this keyword: comments delivered in its threads and comments it matched, each once per workspace."
            },
            "commentCents": {
              "type": "integer",
              "description": "Those comments at $0.008 each, rounded once on the total."
            },
            "totalCents": {
              "type": "integer",
              "description": "keywordCents plus mentionCents plus commentCents: what this keyword has cost this month, in USD cents."
            }
          },
          "required": [
            "keywordDays",
            "keywordCents",
            "billableMentions",
            "mentionCents",
            "billableComments",
            "commentCents",
            "totalCents"
          ],
          "description": "What this keyword has cost this calendar month (UTC) at list price: exactly its row in GET /v1/usage/breakdown?month=<this month> (same tables, same rounding). The wallet's ledger, which settles once a day, is what can differ from these list-price numbers, and only by cumulative rounding."
        }
      },
      "required": [
        "mentions",
        "relevant",
        "last7d",
        "thisMonth",
        "lastMentionAt",
        "feedback",
        "noise",
        "health",
        "cost"
      ],
      "description": "Computed over this workspace's matches."
    },
    "polling": {
      "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)."
          },
          "lastPolledAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Newest poll of this platform for the term; null until the first one."
          },
          "emptyPolls": {
            "type": "integer",
            "description": "Consecutive polls that found nothing new; the scheduler slows down as it grows."
          }
        },
        "required": [
          "platform",
          "lastPolledAt",
          "emptyPolls"
        ]
      },
      "description": "Poll health per platform polled on a schedule. Live feeds (Bluesky) have no entry."
    },
    "createdAt": {
      "type": "string",
      "description": "ISO 8601 timestamp, UTC."
    }
  },
  "required": [
    "id",
    "term",
    "kind",
    "muted",
    "pausedForBalance",
    "pausedForNoise",
    "pausedForCap",
    "cap",
    "comments",
    "display",
    "group",
    "platforms",
    "feeds",
    "readsWorkspaceFeeds",
    "reviewSources",
    "context",
    "matching",
    "stats",
    "polling",
    "createdAt"
  ],
  "$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."
    },
    "KeywordFeed": {
      "type": "object",
      "properties": {
        "url": {
          "type": "string",
          "description": "The feed itself (after redirects): what is polled."
        },
        "title": {
          "type": [
            "string",
            "null"
          ],
          "description": "The feed's own title, when it has one."
        },
        "connectedAt": {
          "type": "string",
          "description": "When this keyword started reading the feed: nothing published before it is a live mention."
        }
      },
      "required": [
        "url",
        "title",
        "connectedAt"
      ]
    },
    "ReviewSource": {
      "type": "object",
      "properties": {
        "platform": {
          "type": "string",
          "enum": [
            "appstore",
            "googleplay",
            "trustpilot",
            "googlemaps"
          ],
          "description": "appstore (Apple App Store), googleplay (Google Play), trustpilot (a company's Trustpilot page) or googlemaps (a place's Google reviews)."
        },
        "id": {
          "type": "string",
          "description": "The id on the platform: app id, package name, Trustpilot domain, Google Place ID or cid."
        },
        "url": {
          "type": "string",
          "description": "The review page: the store listing, the Trustpilot page or the Google Maps place."
        },
        "countries": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Storefronts read, lowercase two-letter codes; empty on Trustpilot and Google Maps."
        },
        "language": {
          "type": [
            "string",
            "null"
          ],
          "description": "Google Play's review language; null elsewhere."
        },
        "connectedAt": {
          "type": "string",
          "description": "When this keyword started collecting the page's reviews."
        }
      },
      "required": [
        "platform",
        "id",
        "url",
        "countries",
        "language",
        "connectedAt"
      ]
    }
  }
}

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.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/mentio-dev-keyword"
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.