---
title: "Presence per engine and per brand over a trailing window"
method: GET
path: "/visibility"
---

# Presence per engine and per brand over a trailing window

`GET /visibility`

## Request

- Base URL: `https://app.aimentiontracker.ai/api/v1`
- URL: `https://app.aimentiontracker.ai/api/v1/visibility`
- Auth: API key in header `X-API-Key`

There is no single visibility score and there will not be one. The engines disagree, so an average describes no real surface; compute one yourself if you want it, knowing exactly what went in.

## Query parameters

- `days` integer
- `brand` string

## Response `200`

OK

- object
  - `data` object, required
    - `engines` Engine[]
      - `engine` string, required: Stable slug, e.g. chatgpt. Use this for ?engine= filters.
      - `name` string, required: Display name, e.g. ChatGPT.
      - `collection_method` string, required: How this surface is read: api, scraper or serp.
      - `present` integer, required: Answers that named this brand.
      - `responses` integer, required: Answers in the window. The denominator, always returned.
      - `rate` number, nullable, required: present/responses to 3dp, or NULL below min_sample (5). Null means NOT ENOUGH ANSWERS YET and must never be rendered as 0% — doing so reports a collapse in visibility that did not happen.
      - `min_sample` integer, required: The floor below which rate is null.
      - `citations` integer: Answers from this engine that cited the brand's own domain.
      - `avg_rank_when_named` number, nullable: Mean position in the list WHEN NAMED. Null when never named.
    - `brands` BrandVisibility[]
      - `name` string, required: Brand name.
      - `role` 'self' | 'competitor', required: Yours, or a rival.
      - `present` integer, required: Answers that named this brand.
      - `responses` integer, required: Answers in the window. The denominator, always returned.
      - `rate` number, nullable, required: present/responses to 3dp, or NULL below min_sample (5). Null means NOT ENOUGH ANSWERS YET and must never be rendered as 0% — doing so reports a collapse in visibility that did not happen.
      - `min_sample` integer, required: The floor below which rate is null.
      - `citations` integer: Answers citing this brand's own domain.
      - `avg_rank_when_named` number, nullable: Mean list position when named.
      - `framing` object: How the brand was FRAMED where it appeared. Deliberately not called a sentiment score: it counts cue phrases, it does not grade tone.
        - `classified` integer: Mentions we could classify at all. The denominator here.
        - `recommended` integer: Mentions framed as a recommendation.
        - `negative` integer: Mentions framed negatively.
  - `meta` object, required
    - `generated_at` string, date-time
    - `brand` BrandRef: Which brand a response describes. Present in meta on every data endpoint.
      - `id` string, required: Pass as ?brand=.
      - `name` string, required: Display name.
    - `note` string
    - `window_days` integer

## Other responses

- `400`: brand_required, or a cursor that does not belong to this brand.
- `401`: Missing, malformed, revoked or expired key.
- `402`: The organisation has never subscribed, or the plan excludes the API.
- `403`: The key lacks the required scope.
- `404`: No such brand, or the brand has not finished setup.
- `429`: Rate limit exceeded. Carries Retry-After.

---

[API](https://skmtc.dev/aimentiontracker/apis/aimentiontracker-api.md) · [All operations](https://skmtc.dev/aimentiontracker/apis/aimentiontracker-api/llms.txt) · [OpenAPI document](https://skmtc.dev/aimentiontracker/apis/aimentiontracker-api/revisions/c3329178c84c?raw)
