AT A GLANCE
  • Base URL: https://api.botscope.ai/api/v1
  • Authenticate with a Bearer API key created in Settings → Developers.
  • Every response is JSON, wrapped in { "data": ... }.
  • The API is read-only — it never changes your data or spends credits.
  • Included on all paid plans. Rate limit: 120 requests/minute per key.
  • Machine-readable spec: openapi.json (OpenAPI 3.1).

This reference describes v1. We’ll add endpoints over time; existing responses won’t change shape without a new version.

SECT.01 Authentication.

Create a key in the dashboard under Settings → Developers → Create key. The full key (prefixed bsk_) is shown once — store it safely; you can’t retrieve it again, only revoke it. Send it as a Bearer token on every request:

curl -H "Authorization: Bearer bsk_your_key_here" \
  https://api.botscope.ai/api/v1/projects

A key only reads the organisation it was created in. Treat it like a password — anyone with the key can read your data. Revoking a key from the same page takes effect immediately.


SECT.02 Quickstart.

export BSK="bsk_your_key_here"
export BASE="https://api.botscope.ai/api/v1"

# 1. List your projects
curl -s -H "Authorization: Bearer $BSK" "$BASE/projects"

# 2. Read a project's visibility overview
PID="<a project id from step 1>"
curl -s -H "Authorization: Bearer $BSK" "$BASE/projects/$PID/visibility"

SECT.03 Endpoints.

MethodPathDescription
GET/projectsList all projects in your organisation
GET/projects/{id}A single project’s configuration
GET/projects/{id}/scansPaginated scan history (newest first)
GET/projects/{id}/visibilityOverall + L1–L4 scores, trends, citations, share of voice
GET/projects/{id}/share-of-voiceOwn brand vs competitor mention share
GET/projects/{id}/competitorsOwn brand + tracked competitors by median mentions
GET/projects/{id}/categoriesPer-category share of voice, providers, trend, top competitors
GET/projects/{id}/responsesPaginated index of raw LLM responses
GET/projects/{id}/responses/{responseId}One response with brand detections + citations
GET/projects/{id}/adsHow often sponsored ads appear on ChatGPT, with the sample size
GET/projects/{id}/ads/trendAd coverage per scan, oldest first
GET/projects/{id}/ads/advertisersWho is advertising against your prompts, with ad share of voice
GET/projects/{id}/ads/promptsWhich prompts trigger ads, and the advertisers on each
GET/projects/{id}/ads/creativesDeduplicated ad creatives with first/last seen
GET/projects/{id}/ads/competitor-overlapPrompts where a tracked competitor is advertising
GET/projects/{id}/products/catalogThe tracked-product catalog (own and competitor models)
GET/projects/{id}/products/mentionsHow often tracked models are mentioned in answers, with the sample size
GET/projects/{id}/products/mentions/leaderboardModels ranked by mentions, with per-model sentiment
GET/projects/{id}/products/mentions/promptsWhich models each prompt recommends
GET/projects/{id}/products/mentions/trendProduct mentions per scan, oldest first
GET/projects/{id}/products/shoppingHow often ChatGPT shows its shopping carousel, with the sample size
GET/projects/{id}/products/shopping/trendCarousel appearance per scan
GET/projects/{id}/products/shopping/productsCarousel products with latest price, rating and merchant link
GET/projects/{id}/products/shopping/brand-shareCarousel placements grouped by product brand
GET/projects/{id}/products/shopping/merchantsWhich merchants the carousel sends buyers to
GET/projects/{id}/products/shopping/promptsWhich prompts trigger a shopping carousel
GET/projects/{id}/products/shopping/price-history/{productId}Displayed price per scan and country for one product

The ads endpoints cover sponsored placements observed beneath ChatGPT answers — there is no public ad library for ChatGPT, so this is built purely from your own scans. They take no provider parameter, because ads only exist on the scraped ChatGPT interface. Every ad response carries its sampleSize alongside any rate: ad serving is contextual and varies between identical prompts, so a coverage figure without its denominator will mislead. A coverageRate of null means nothing was measured — which is not the same as no ads.

Example response — visibility (numbers are medians across the resolved scans, matching the dashboard):

{
  "data": {
    "projectId": "1d7367ae-...",
    "overall": 34.6,
    "overallTrend": 2.1,
    "l1": { "layer": "L1", "name": "Entity Recognition", "score": 61.2, "trend": 1.0 },
    "l3": { "layer": "L3", "name": "Category Inclusion", "score": 4.93, "trend": 0.2 },
    "totalCitations": 59,
    "lastScanAt": "2026-05-10T11:36:01.588Z",
    "shareOfVoice": { "ownBrandShare": 0.27, "competitors": [] },
    "comparedTo": { "kind": "previous_scan", "overall": 32.5 }
  }
}

SECT.04 Parameters.

Most read endpoints accept a selector for which data to aggregate. With none, they use the latest scan.

ParamDescription
providerFilter to one provider, e.g. openai, google_ai_overview.
scanIdPin to a specific scan (from the scans list). Takes precedence over a date range.
from / toISO-8601 date window. Both required together. Aggregated across scans in range.
layerResponses only — filter to a visibility layer: L1, L2, L3, L4.
limitPage size for scans/responses, 1–200 (default 50). Out-of-range values are clamped.
beforeKeyset cursor — pass the previous response’s pagination.nextBefore.
# One provider
curl -s -H "Authorization: Bearer $BSK" \
  "$BASE/projects/$PID/visibility?provider=google_ai_overview"

# A date window (both from & to required)
curl -s -H "Authorization: Bearer $BSK" \
  "$BASE/projects/$PID/visibility?from=2026-04-01T00:00:00Z&to=2026-05-31T23:59:59Z"

# A specific scan
curl -s -H "Authorization: Bearer $BSK" \
  "$BASE/projects/$PID/visibility?scanId=<scan-id>"

SECT.05 Pagination.

List endpoints return a pagination object. When nextBefore is non-null, pass it as before for the next (older) page; null means you’ve reached the end.

{ "data": [ ... ], "pagination": { "limit": 20, "nextBefore": "2026-05-10T09:53:43.562Z" } }

SECT.06 Rate limits.

Each key is limited to 120 requests per minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix epoch second). Exceeding it returns 429 with a Retry-After header.


SECT.07 Errors.

Errors share one shape:

{ "error": { "code": "not_found", "message": "Project not found", "details": null } }
StatuscodeWhen
401unauthorizedMissing or malformed Authorization header
401invalid_api_keyUnknown, revoked, or expired key
403feature_not_availableYour plan doesn’t include API access
404not_foundResource doesn’t exist or belongs to another org
422validation_errorInvalid query/path parameter (see details)
429rate_limitedPer-key rate limit exceeded

For privacy, a resource in another organisation returns 404, not 403 — the API never discloses whether something you can’t see exists.


SECT.08 MCP server.

Prefer to use BotScope from an AI assistant? We host a remote MCP server that exposes these endpoints as tools, so Claude and other MCP clients can read your data directly. Authenticate with the same bsk_ key as a Bearer header.

URL: https://mcp.botscope.ai/mcp (Streamable HTTP) · …/sse (legacy).

Twenty-six read tools: list_projects, get_project, list_scans, get_visibility, get_share_of_voice, get_competitors, get_categories, list_responses, get_response; ads — get_ad_coverage, get_ad_trend, get_ad_advertisers, get_ad_prompts, get_ad_creatives, get_ad_competitor_overlap; product tracking — get_product_catalog, get_product_mentions, get_product_mention_leaderboard, get_product_mention_prompts, get_product_mention_trend, get_shopping_coverage, get_shopping_trend, get_shopping_products, get_shopping_merchants, get_shopping_prompts and get_shopping_price_history.

Claude Code (one line; replace with a real key):

claude mcp add --transport http botscope https://mcp.botscope.ai/mcp --header "Authorization: Bearer bsk_your_key_here"

Cursor / Windsurf / generic mcp.json:

{
  "mcpServers": {
    "botscope": {
      "url": "https://mcp.botscope.ai/mcp",
      "headers": { "Authorization": "Bearer bsk_your_key_here" }
    }
  }
}

Questions or feedback? Email [email protected].