DocsAPI & MCP

Conventions

The rules every response follows — scales (which fields are 0–1 fractions vs 0–100 scores), null handling, note fields, the fixed window, engine blending, and the contract-freeze policy.

Read this once and every field on every endpoint reads the same way.

Scales — the fraction rule and its exceptions

Not every numeric field is on the same scale. The rule is: rate and share fields are 0–1 fractions; scores are 0–100; everything else is a raw count or a rank. Concretely:

FieldScaleNotes
presence_rate0–1 fractionrounded to 0.001
citation_share0–1 fraction or nullunrounded
share_of_voice_fraction0–1 fractionrounded to 0.001 — prefer this over share_of_voice
win_rate, visibility_share (shopping)0–1 fractionrounded to 0.001
own_carousel_share, own_win_share (shopping)0–1 fractionrounded to 0.001
visibility0–100 scoreposition-weighted
sentiment_index0–100 score or null50 = neutral
share_of_voice0–100 percentagedeprecated — frozen legacy outlier; same number as share_of_voice_fraction × 100
avg_position, own_avg_positionrank (mean 1-based) or nulllower is better, not a fraction
run_count, appearances, carousels, citations, window_daysinteger count
Note

share_of_voice is on 0–100 (a percentage), while presence_rate and citation_share are 0–1 fractions. It shipped in v1 as the one exception to the fraction rule, so under the contract freeze it stays exactly as it is — deprecated but frozen. The additive share_of_voice_fraction carries the same number on the standard 0–1 scale; use it in new integrations and never multiply the wrong one by 100. The shopping fields follow the fraction rule — every rate/share there is 0–1, matching the shopping CSV export field names exactly.

Null is not zero

Fields that can be null are null when there is genuinely nothing to compute — never a placeholder 0:

  • citation_sharenull when no run in the window carried any citations.
  • sentiment_indexnull when no scored brand mention exists in the window.
  • avg_positionnull when the entity never appeared.
  • own_avg_position (shopping) — null on days your product wasn't on the shelf.
  • Optional shopping strings (merchant, merchant_domain, price, url) — null when the engine's payload carried none. A merchant domain is only ever derived from the product link, never guessed.

A 0 in a response is a measured zero. Mirror this in your integration: treat null as "unknown", not "zero". See Data honesty.

note fields

The shopping endpoints carry a note field — a human-readable string, or null:

  • On /api/v1/shopping: note explains an empty result, e.g. "No shopping carousels were captured for this brand's tracked prompts in this window." (totals.carousels will be 0). Report that as absence of data, never as shopping presence.
  • On /api/v1/shopping-trend: with a single collected day, note says the data is a snapshot, not a trend. Check days_observed before charting a line.

The window

The read views are computed over a fixed rolling 7-day window anchored at the brand's newest collected day. Every read response includes window_days (currently 7). There are no pagination or date-range parameters on the read API — the window is fixed. The underlying data is cached with a one-hour TTL.

Engine blending

Headline metrics (/overview, /prompts, /competitors, /sources) blend only the search-grounded engines, so the numbers keep one meaning. The exception is /answers, which returns runs from all engines unfiltered. The ten engines are: chatgpt, perplexity, gemini, aio, aimode, claude, copilot, deepseek, grok, mistral (the last two, DeepSeek and Mistral, are knowledge-only). See Metrics overview.

Contract-freeze policy

The v1 surface is stable:

  • Released fields never change meaning. A field's name and semantics are frozen once shipped. New capabilities arrive as additive fields — for example, topic folders shipped as topic_id / topic_name alongside the frozen topic (which remains the first tag), so a consumer keying on topic never sees it relabel.
  • Metric math is versioned separately (METRICS_VERSION); a computation change bumps that version rather than silently altering a field.
  • No existence leaks — an out-of-scope brand id returns the same "unknown brand" response as a nonexistent one.