Skip to main content
All five v2 report endpoints share one request and response shape: Visibility, Citations, Sentiment, Query Fanouts, and Answers. Learn it once and every report works the same way.
All v2 endpoints accept names or UUIDs anywhere a filter takes a value. Get UUIDs from GET /v1/org/models, /v1/org/regions, /v1/org/personas, /v1/org/assets, /v1/org/categories, and the per-category …/topics, …/tags, …/prompts endpoints.

Common request fields

FieldTypeNotes
category_idUUID (required)The category to query.
start_date / end_datedate (required)YYYY-MM-DD, Eastern Time, inclusive on both ends.
scopeowned · allRestrict to your owned assets/domains, or rank everything. Defaults vary per report.
group_bystring[]Break results into rows by dimension (see Grouping).
metricsstring[]Which metrics to compute. Returned as named fields on each row.
intervalday · week · monthBucket size when grouping by date. Default day.
filtertreeand/or/not/leaf tree (see Filters).
sort{ field, dir }Order rows (where supported).
limit150Rows per page. Default 10.
cursorstringPage token from info.next_cursor.
Unlike the v1 reports (where end_date is exclusive), v2 end_date is inclusive. To get June 9–15, send start_date: "2026-06-09", end_date: "2026-06-15".

Grouping

group_by turns one aggregate row into one row per value. Each grouped field is echoed back on the row:
// group_by: ["model"]  →  each row carries the model it's for
{ "asset": { "name": "Profound", "owned": true }, "model": { "id": "…", "name": "ChatGPT" }, "visibility_score": 0.52 }
  • Group by date (with interval) for a time series.
  • Rows carry a rank when grouped by a non-date dimension.
  • Available dimensions differ per report; see each endpoint’s reference.

Metrics

Request the metrics you want; they come back as named fields on each row (no positional arrays, no info.query lookup):
{ "rank": 1, "visibility_score": 0.48, "share_of_voice": 0.077, "average_position": 2.5 }

Scope and asset selection

  • scope: owned limits to assets/domains you own; all ranks across everything.
  • Visibility only: pick the asset(s) with the separate assets param: a name (is), a list (in, which overrides scope), or { op, value }. A selection returns all matches and ignores limit.
  • Sentiment requires an asset (sentiment is per-brand).

Filters

filter is a recursive tree, max depth 3, supported by all five reports:
{
  "and": [
    { "or":  [ { "field": "model", "op": "is", "value": "ChatGPT" },
               { "field": "model", "op": "is", "value": "Perplexity" } ] },
    { "not": { "field": "region", "op": "is", "value": "United States" } }
  ]
}
Node types: { "and": [ … ] }, { "or": [ … ] }, { "not": <node> }, and leaves { "field", "op", "value" }.

Operators

OperatorMeaning
is / not_isExact match / negated
in / not_inMatch any value in a list (non-empty) / negated
contains / not_containsSubstring (case-sensitive)
contains_case_insensitive / not_contains_case_insensitiveSubstring (case-insensitive)
matchesRegex (pattern ≥ 3 chars)
existsHas any value; only on tag / persona (wrap in not for “none”)
value is a single value, or a list for in / not_in. Names or UUIDs; contains / matches match on names.

Two filter layers

Fields fall into two layers. They combine with and; or/not can’t mix layers (doing so returns 422). Prompt layer (full tree, full operator set): model, topic, region, persona, prompt, tag. Entity / citation layer (top-level and leaves only, varies per report):
ReportEntity-layer fields
VisibilityThe entity (asset) uses the assets param, not filter.
Citationsdomain (full ops, subdomain-aware), page (full ops), analysis_type (visibility·sentiment·factcheck·all), citation_category (owned·competition·social·earned_media·earned_institutions·pr_wire·other·custom)
Sentimenttheme / claim: is/in, single value, name or id
Query Fanoutsanalysis_type (visibility·sentiment·factcheck·all), is/in
Answersanalysis_type is prompt-level (visibility·sentiment·factcheck; is/in/not_in; omit = all). domain/page are top-level and leaves: is one value or in a list (exact cited-URL match)
For citations, filter domain in the domains report and page when you group_by: ["page"]; each filters its own report’s entity.

Sorting

Where supported, sort is { "field": "<metric>", "dir": "asc" | "desc" }. The field must be a requested, sortable metric (or date when grouped by date). Citations has no sort: it’s always ranked most-cited first.

Pagination

Responses return limit rows plus info.next_cursor. Pass that token back as cursor to get the next page; next_cursor is null on the last page.

Streaming

Every endpoint has a /stream variant (Server-Sent Events): a summary event (the info block), then one result event per row. limit/cursor are ignored; it returns everything by default. Pass max_results to cap.

Response shape

Every report returns { info, data }:
{
  "info": {
    "total_results": 8427,
    "count": 10,
    "next_cursor": "…",
    "models": ["ChatGPT", "Google Gemini", "..."],
    "start_date": "2026-06-09",
    "end_date": "2026-06-15",
    "filter": null
  },
  "data": [
    { "rank": 1, "visibility_score": 0.48 }
  ]
}
info echoes the resolved query (models in scope, the applied filter, dates, pagination); data is the rows, with metrics as named fields and any group_by dimensions attached.