Mentions

Query the long-running brand-mentions database built by our crawler, or force an on-demand fan-out across all four providers when you need fresh data for a brand we haven't indexed yet.

Legacy endpoint. This documents an older surface kept for back-compat with existing integrations. New integrations should use /v1/check instead — see the quickstart for the modern API.

Pricing at a glance

  • GET /v1/mentions/search — flat 10¢ per call. Pure Postgres read, no LLM calls.
  • POST /v1/mentions/crawl — flat $2.00 (200¢) per call. Live 4-provider fan-out with web_search ON, results indexed into the mentions DB for future searches.

GET /v1/mentions/search

GET/v1/mentions/search

Ask "what have the LLMs been saying about brand since date?". The crawler writes rows on a schedule; this endpoint is the read side. Use it when you need historical trends or you're checking a brand we likely already cover. If the query returns zero rows, we include up to 3 "did you mean?" suggestions via pg_trgm fuzzy match on the brand catalog.

Query parameters

FieldTypeDescription
brand
required
stringThe brand name to search for. Lowercased + whitespace-collapsed server-side before matching. 1–120 chars.
provideroptional
'openai' | 'anthropic' | 'gemini' | 'perplexity'Optional — filter to mentions sourced from a single provider.
sinceoptional
string (ISO 8601)Optional lower bound on snapshot_at. Only mentions captured at or after this time are returned.
limitoptional
numberMax rows to return. 1–100.
Default: 50

Search response

FieldTypeDescription
request_idoptional
stringUnique id for this call (use in support requests).
queryoptional
{ brand, normalized_brand, provider, since, limit }Echo of the parsed query, including the normalized_brand actually looked up.
mentionsoptional
Mention[]Rows newest first by snapshot_at, up to `limit`.
suggestionsoptional
Suggestion[]Up to 3 fuzzy-matched alternative brand names. Only populated when `mentions` is empty.
usageoptional
{ billable_units, latency_ms, cost_cents }Per-call cost. cost_cents is always 10 for this endpoint.

Top-level fields

Mention object

FieldTypeDescription
idoptional
numberRow id in brand_mentions (stable, auto-incrementing).
brandoptional
stringThe brand as it appeared in the provider response.
provideroptional
'openai' | 'anthropic' | 'gemini' | 'perplexity'Which LLM surfaced this mention.
modeloptional
stringExact model version that produced the answer.
promptoptional
stringThe crawl prompt used when the snapshot was taken.
prompt_categoryoptional
string | nullOptional bucket the prompt was tagged with.
snapshot_atoptional
string (ISO 8601)When the crawl ran.
contentoptional
string | nullProvider response excerpt (up to 500 chars).
rankoptional
number | nullPosition of the brand in the provider's answer (0-indexed). Lower is better.
sentimentoptional
'positive' | 'neutral' | 'negative' | nullClassified tone of the mention.
contextoptional
string | nullSurrounding sentence snippet.
citationsoptional
Citation[]URLs cited in the provider's answer. Always an array.
raw_response_idoptional
string | nullLinks back to the original /v1/ask response (if retained).

Suggestion object

FieldTypeDescription
brandoptional
stringSuggested brand display name.
normalized_brandoptional
stringNormalized form used for matching.
categoryoptional
string | nullBrand category if known.
similarityoptional
numberpg_trgm similarity score, 0–1 (4 decimals).

Search example

bash
curl "https://api.mentionsapi.com/v1/mentions/search?brand=Supabase&provider=openai&limit=10" \
  -H "Authorization: Bearer $MENTIONSAPI_KEY"

POST /v1/mentions/crawl

POST/v1/mentions/crawl

Flat 200¢ per call

Crawl fires a live fan-out to all four providers with web_search enabled, extracts brand mentions from each response, and writes them to the mentions database. Use it when you need fresh data and /v1/mentions/search returned empty or stale results. Auto-adds the brand to the catalog so scheduled crawls pick it up going forward.

Crawl request body

FieldTypeDescription
brand
required
stringThe brand to crawl. 1–120 chars. Lowercased + trimmed on insert into brand_catalog.
promptoptional
stringCustom crawl prompt. Default: "What are the best alternatives, competitors, or similar services to \"<brand>\"? List at least 10…". 1–2000 chars.
categoryoptional
stringOptional category tag written to brand_catalog alongside the brand. 1–60 chars.

Crawl response

FieldTypeDescription
request_idoptional
stringUnique id for this crawl call.
brandoptional
stringBrand display name, trimmed.
normalized_brandoptional
stringLowercased, whitespace-collapsed form.
promptoptional
stringThe prompt actually used (custom or the default template).
mentionsoptional
CrawlMention[]Only mentions of the queried brand (subset of all inserted rows). Each has brand, provider, model, snapshot_at, rank, sentiment, context, content_excerpt.
total_mentions_foundoptional
numberTotal rows inserted into brand_mentions across every brand the LLMs surfaced (includes competitors, not just the queried brand).
providersoptional
ProviderResult[] | ProviderError[]Raw per-provider outputs, same shape as /v1/ask — includes content, model, tokens, latency_ms, citations, or an error object on failure.
usageoptional
{ billable_units, latency_ms, cost_cents }cost_cents is always 200 for a successful crawl.

Crawl example

bash
curl https://api.mentionsapi.com/v1/mentions/crawl \
  -H "Authorization: Bearer $MENTIONSAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brand": "Supabase",
    "category": "postgres-hosting"
  }'

TypeScript SDK

typescript
import { MentionsAPIClient } from "@mentionsapi/sdk";

const client = new MentionsAPIClient({ apiKey: process.env.MENTIONSAPI_KEY! });

// Read the mentions database (10¢ per call).
const hits = await client.mentionsSearch({
  brand: "Supabase",
  provider: "openai",
  limit: 20,
});

// Empty? Kick off a fresh crawl ($2.00), then re-read.
if (hits.mentions.length === 0) {
  await client.mentionsCrawl({ brand: "Supabase" });
  const retry = await client.mentionsSearch({ brand: "Supabase" });
  console.log(retry.mentions);
}

Pagination

GET /v1/mentions/search returns up to limit rows (max 100), newest first by snapshot_at. Cursor-based pagination is not yet available — iterate by narrowing the since window (e.g. re-query with since = oldest_row.snapshot_at after processing a page). We plan to ship next_cursor in a future release.

Python

python
import os
import httpx

BASE = "https://api.mentionsapi.com"
headers = {"Authorization": f"Bearer {os.environ['MENTIONSAPI_KEY']}"}

# Search (10¢)
r = httpx.get(
    f"{BASE}/v1/mentions/search",
    params={"brand": "Supabase", "limit": 20},
    headers=headers,
)
r.raise_for_status()
data = r.json()

if not data["mentions"]:
    # Kick off an on-demand crawl ($2.00)
    httpx.post(
        f"{BASE}/v1/mentions/crawl",
        json={"brand": "Supabase"},
        headers=headers,
        timeout=60.0,
    ).raise_for_status()

Errors

FieldTypeDescription
invalid_requestoptional
400Malformed query or body — missing brand, out-of-range limit, empty normalized brand, etc.
invalid_api_keyoptional
401Bearer token missing, malformed, or revoked.
insufficient_creditsoptional
402Your credit balance is below the call price (10¢ for search, 200¢ for crawl). Response includes balance_cents and required_cents.
rate_limitedoptional
429Tier rate limit exceeded. Honor the Retry-After header.
internal_erroroptional
500Database query failed (search) or an unexpected server-side failure. Retry, or contact support with the request_id from the response body.

See the full error reference for payload shape and retry guidance.

Response headers

FieldTypeDescription
X-RateLimit-Limitoptional
numberYour account's rate-limit ceiling for the current window.
X-RateLimit-Remainingoptional
numberCalls remaining in the current window before 429s begin.
Retry-Afteroptional
number (seconds)Sent on 429 responses. Sleep at least this long before retrying.

The unique call identifier is returned in the JSON body as request_id.