CoreCited
API docs menu

Get visibility

The latest visibility score per engine, its drift band, the trend and sentiment.

GET/api/v1/brands/{brandId}/visibility

The same numbers as the dashboard. Each engine's score is the percentage of the brand's tracked prompts in which that engine named the brand in the latest weekly cycle.

AI answers move from week to week even when nothing real changed. Each score therefore comes with a drift band built from its trailing history, and isSignificant is true only when the score leaves that band. Build alerts on isSignificant, not on raw score changes.

Scores update once a week, when the brand's cycle runs. Polling more often returns the same data.

Parameters

NameInTypeDescription
brandIdpathstring (UUID)A brand id from GET /api/v1/brands.

Request

curl https://corecited.com/api/v1/brands/7d1c2b9e-4a3f-4e61-9b2a-0c5d8e7f6a14/visibility \
  -H "Authorization: Bearer $CORECITED_API_KEY"

Response

200 OK with the fields below inside data. Numbers are JSON numbers, dates are strings, and a field listed as null-able is always present, holding null when there is no value.

FieldTypeDescription
brandobjectThe brand this response is about.
brand.idstringThe brand's id. Use it in every /brands/{brandId}/… path.
brand.namestringThe brand name as configured in CoreCited.
brand.domainstringThe brand's website exactly as entered during setup. This is often a full URL such as https://www.example.com/, not a bare host.
overallVisibilitynumberThe mean of the latest per-engine scores, one decimal. 0 when nothing has run yet.
perEngineobject[]The latest score for each engine that has one.
perEngine[].slugstringEngine slug: chatgpt, claude, gemini, perplexity, ai_overview, ai_mode, deepseek, grok. Which ones appear depends on the plan and on what has run.
perEngine[].isWebGroundedbooleanTrue when the engine searches the web before answering (Perplexity, Google's AI surfaces). Only these return citations.
perEngine[].scorenumberVisibility in the latest cycle: the percentage of this brand's tracked prompts in which the engine named the brand. 0–100, one decimal.
perEngine[].datestringThe cycle this score belongs to. YYYY-MM-DD.
perEngine[].bandLownumber | nullLower edge of the normal drift band, in percentage points. null while warming up.
perEngine[].bandHighnumber | nullUpper edge of the normal drift band, in percentage points. null while warming up.
perEngine[].isSignificantbooleanTrue when this score falls OUTSIDE the drift band, a real change rather than ordinary week-to-week noise. Always false while warming up.
perEngine[].isWarmingUpbooleanTrue until 4 prior weekly scores exist for this engine. Until then there is no band and nothing is flagged.
perEngine[].noAnswerRatenumber | nullPercentage of recent runs where the surface served no answer at all (common for Google AI Overviews). Those runs are excluded from the score. null when it never happened.
trendobject (map)Score history keyed by engine slug, oldest point first, one point per engine per day. Drawn from the 120 most recent stored scores across all engines combined, so with more engines each series is shorter.
trend.{slug}[].datestringCycle date, YYYY-MM-DD.
trend.{slug}[].scorenumberVisibility that cycle, 0–100.
alertsobject[]Engines whose latest score is a significant change (isSignificant = true). Empty in a normal week.
alerts[].slugstringEngine slug.
alerts[].scorenumberThe score that fell outside its band.
signalsobjectSentiment and position of the brand across successful runs in the last 14 days.
signals.netSentimentnumber | nullNet sentiment, −100 to +100: (positive − negative) ÷ all brand mentions × 100, rounded. null with no mentions.
signals.positivenumberBrand mentions classified positive.
signals.neutralnumberBrand mentions classified neutral.
signals.negativenumberBrand mentions classified negative.
signals.avgPositionnumber | nullMean position of the brand in answers that name it (1 = named first). Lower is better. null with no mentions.
signals.mentionsnumberBrand mentions counted.

Example

200 OK
{
  "data": {
    "brand": {
      "id": "7d1c2b9e-4a3f-4e61-9b2a-0c5d8e7f6a14",
      "name": "Acme Resume",
      "domain": "https://www.acmeresume.com/"
    },
    "overallVisibility": 44,
    "perEngine": [
      {
        "slug": "chatgpt",
        "isWebGrounded": false,
        "score": 58,
        "date": "2026-09-21",
        "bandLow": 31.2,
        "bandHigh": 52.8,
        "isSignificant": true,
        "isWarmingUp": false,
        "noAnswerRate": null
      },
      {
        "slug": "ai_overview",
        "isWebGrounded": true,
        "score": 30,
        "date": "2026-09-21",
        "bandLow": null,
        "bandHigh": null,
        "isSignificant": false,
        "isWarmingUp": true,
        "noAnswerRate": 40
      }
    ],
    "trend": {
      "chatgpt": [
        {
          "date": "2026-09-14",
          "score": 40
        },
        {
          "date": "2026-09-21",
          "score": 58
        }
      ],
      "ai_overview": [
        {
          "date": "2026-09-21",
          "score": 30
        }
      ]
    },
    "alerts": [
      {
        "slug": "chatgpt",
        "score": 58
      }
    ],
    "signals": {
      "netSentiment": 53,
      "positive": 9,
      "neutral": 5,
      "negative": 1,
      "avgPosition": 2.4,
      "mentions": 15
    }
  }
}

Errors

StatusCodeWhen
401missing_keyNo key was sent in Authorization or x-api-key.
401invalid_keyThe key is malformed, unknown, or has been revoked.
402plan_requiredThe workspace is not on a plan that includes API access. This is checked on every request, so it also happens after a downgrade.
404not_foundThe brand id is not a UUID, does not exist, or belongs to another workspace. These cases are deliberately indistinguishable.
429rate_limitedThe workspace used up its requests for the current minute. All keys share one limit.
500internalSomething failed on our side. The response carries no detail by design.

Every error has the same body. See Errors for what to do about each one.