Developer Docs

API Reference

Everything you need to integrate CitedSpy into your workflow. Manage brands, trigger runs, and pull AI visibility data via REST API.

Base URL: https://app.citedspy.com/api/v1Rate limit: 100 req/min

Authentication

All API requests require an API key. Generate one in your dashboard under Settings > API Keys.

Include the key in the Authorization header:

curl https://app.citedspy.com/api/v1/brands \
  -H "Authorization: Bearer cspy_your_api_key_here"

API keys are prefixed with cspy_ for easy identification. Each key is scoped to a single workspace - all data returned is automatically filtered to that workspace.

API keys are hashed with SHA-256 before storage. The plaintext key is shown only once at creation. If you lose it, generate a new one.

Errors

CitedSpy uses standard HTTP status codes. All error responses follow this format:

{
  "error": "Description of what went wrong"
}
StatusMeaning
200Success
201Created (resource was created successfully)
400Bad Request (missing or invalid parameters)
401Unauthorized (invalid or missing API key)
403Forbidden (insufficient permissions)
404Not Found (resource does not exist or is not in your workspace)
429Rate Limit Exceeded (too many requests)
500Internal Server Error

Rate Limits

API requests are limited to 100 requests per minute per API key. Rate limit information is included in response headers:

HeaderDescription
X-RateLimit-LimitMaximum requests per window (100)
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the window resets

When you exceed the limit, the API returns a 429 response with a message indicating when you can retry.

Pagination

List endpoints support pagination via limit and offset query parameters:

ParameterTypeDefaultDescription
limitinteger50Number of items to return (max 200)
offsetinteger0Number of items to skip

Paginated responses include a pagination object:

{
  "data": [...],
  "pagination": {
    "limit": 50,
    "offset": 0
  }
}

Brands

GET/api/v1/brands

List all brands in your workspace.

Response

{
  "data": [
    {
      "id": "uuid",
      "name": "My Brand",
      "domain": "mybrand.com",
      "category": "SaaS",
      "description": "Project management tool",
      "aliases": ["MyBrand", "MB"],
      "owned_domains": ["mybrand.com", "mybrand.io"],
      "logo_url": "https://assets.citedspy.com/brands/...",
      "created_at": "2026-05-01T00:00:00.000Z",
      "updated_at": "2026-05-10T12:00:00.000Z"
    }
  ]
}

GET/api/v1/brands/:id

Get a single brand with its competitors and prompt count.

Path parameters

ParameterTypeDescription
iduuidThe brand ID

Response

{
  "data": {
    "id": "uuid",
    "name": "My Brand",
    "domain": "mybrand.com",
    "category": "SaaS",
    "description": "Project management tool",
    "aliases": ["MyBrand", "MB"],
    "competitors": [
      { "id": "uuid", "name": "Competitor A", "domain": "competitor-a.com" }
    ],
    "prompt_count": 12
  }
}

Prompts

Every prompt has a category (its type), which determines how it is run and what its report contains:

TypeWhat it tracks
discoveryOpen-ended questions - whether your brand surfaces at all, where, and how often
comparisonHead-to-head benchmarks against named competitors (win rate, podium rate, head-to-head verdicts)
brandedQuestions about your own brand - answer accuracy, sentiment, themes, owned-citation rate

Unrecognized or omitted values default to discovery.


GET/api/v1/prompts

List prompts. Optionally filter by brand.

Query parameters

ParameterTypeRequiredDescription
brand_iduuidNoFilter prompts by brand
statusstringNoFilter by status: active, paused, archived
limitintegerNoItems per page (default 100, max 200)
offsetintegerNoItems to skip (default 0)

Response

{
  "data": [
    {
      "id": "uuid",
      "brand_id": "uuid",
      "text": "What is the best project management tool?",
      "category": "comparison",
      "status": "active",
      "tags": ["productivity", "tools"],
      "created_at": "2026-05-01T00:00:00.000Z"
    }
  ],
  "pagination": { "limit": 100, "offset": 0 }
}

GET/api/v1/prompts/:id

Get a single prompt with its run count.

Response

{
  "data": {
    "id": "uuid",
    "brand_id": "uuid",
    "text": "What is the best project management tool?",
    "category": "comparison",
    "status": "active",
    "tags": ["productivity"],
    "run_count": 45,
    "created_at": "2026-05-01T00:00:00.000Z"
  }
}

POST/api/v1/prompts

Create a new tracking prompt.

Request body

FieldTypeRequiredDescription
brand_iduuidYesBrand to attach this prompt to
textstringYesThe prompt text to send to AI engines
categorystringNoPrompt type: discovery, comparison, or branded (default discovery)
compare_competitor_idsuuid[]NoFor comparison prompts: competitor IDs to benchmark against
tagsstring[]NoArray of tags for organizing prompts

Example

curl -X POST https://app.citedspy.com/api/v1/prompts \
  -H "Authorization: Bearer cspy_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "brand_id": "abc-123",
    "text": "What are the top CRM tools for small business?",
    "category": "comparison",
    "tags": ["crm", "small-business"]
  }'

Response (201)

{
  "data": {
    "id": "new-uuid",
    "brand_id": "abc-123",
    "text": "What are the top CRM tools for small business?",
    "category": "comparison",
    "status": "active",
    "tags": ["crm", "small-business"],
    "created_at": "2026-05-17T10:00:00.000Z"
  }
}

PATCH/api/v1/prompts/:id

Update an existing prompt.

Request body (all fields optional)

FieldTypeDescription
textstringUpdated prompt text
categorystringUpdated type: discovery, comparison, or branded
compare_competitor_idsuuid[]Competitor IDs for a comparison prompt
statusstringSet to active, paused, or archived
tagsstring[]Updated tags array

DELETE/api/v1/prompts/:id

Delete a prompt and all its associated run data.

Response

{ "success": true }

GET/api/v1/prompts/:id/report

Get a prompt's full analytics report. This is the headline read of the API.

Returns the pre-computed, type-aware report for a single prompt: core visibility metrics plus per-engine, ranking, citation and trend breakdowns. The prompt's type adds its own block - comparisonData for comparison prompts, brandedData for branded prompts, both null for discovery. Stale data is recomputed on read, so the response is always current.

Query parameters

ParameterTypeDefaultDescription
daysinteger14Lookback window in days (1-90)

Response

{
  "data": {
    "prompt": { "id": "uuid", "text": "...", "category": "comparison", ... },
    "snapshot_date": "2026-06-23",
    "computed_at": "2026-06-23T06:00:00.000Z",

    "mentionRate": 72,        "mentionRateDelta": 5,
    "avgPosition": 2.3,       "avgPositionDelta": -0.4,
    "shareOfVoice": 34,       "shareOfVoiceDelta": 2,
    "sentimentScore": 0.78,   "sentimentScoreDelta": 0.05,
    "totalRuns": 60,          "mentionedRuns": 43,

    "engineBreakdown": [
      { "name": "ChatGPT", "runs": 12, "mention": 80, "position": 1.8, "sentiment": 0.6, "sparkline": [60, 65, 71] }
    ],
    "brandRankings": [
      { "name": "My Brand", "you": true, "rate": 72, "position": 2.3, "share": 34, "sentiment": 0.78, "delta": 5 }
    ],
    "citationSources": [
      { "domain": "mybrand.com", "cites": 23, "share": 18.5, "owned": true }
    ],
    "trendData": [ { "date": "2026-06-22", "rate": 70, "engines": { "ChatGPT": 80 } } ],
    "rankingTrend": [ { "date": "2026-06-22", "entities": { "My Brand": 2.1 } } ],
    "sentimentTrend": [ { "date": "2026-06-22", "entities": { "My Brand": 0.7 } } ],
    "recentResponses": [
      { "run_id": "uuid", "engine": "ChatGPT", "mentioned": true, "position": 1, "sentiment": 0.8, "snippet": "..." }
    ],

    // Present only for comparison prompts (null otherwise):
    "comparisonData": { "winRate": 60, "podiumRate": 85, "lossRate": 15, "headToHead": [...], "recentVerdicts": [...] },
    // Present only for branded prompts (null otherwise):
    "brandedData": null
  }
}
The same report powers the prompt detail page in the dashboard. comparisonData and brandedData are only populated for prompts of that type - check the prompt's category to know which block to read.

Runs

GET/api/v1/runs

List prompt execution results.

Query parameters

ParameterTypeRequiredDescription
prompt_iduuidNoFilter by prompt
enginestringNoFilter by engine name (e.g. ChatGPT, Perplexity, Gemini, Claude, Copilot)
statusstringNoFilter by status: running, completed, failed
limitintegerNoItems per page (default 50, max 200)
offsetintegerNoItems to skip

Response

{
  "data": [
    {
      "id": "uuid",
      "prompt_id": "uuid",
      "engine_id": "uuid",
      "engine_name": "ChatGPT",
      "status": "completed",
      "scheduled_at": "2026-05-17T08:00:00.000Z",
      "completed_at": "2026-05-17T08:00:03.200Z",
      "raw_response_text": "Based on my research, the top project...",
      "token_cost_usd": 0.0034
    }
  ],
  "pagination": { "limit": 50, "offset": 0 }
}

GET/api/v1/runs/:id

Get a single run with its citations and mentions.

Response

{
  "data": {
    "id": "uuid",
    "prompt_id": "uuid",
    "engine_id": "uuid",
    "engine_name": "Perplexity",
    "status": "completed",
    "raw_response_text": "Here are the top tools...",
    "token_cost_usd": 0.0021,
    "citations": [
      {
        "id": "uuid",
        "url": "https://mybrand.com/features",
        "domain": "mybrand.com",
        "position_in_response": 2,
        "snippet": "MyBrand offers advanced analytics..."
      }
    ],
    "mentions": [
      {
        "id": "uuid",
        "brand_or_competitor_id": "uuid",
        "entity_type": "brand",
        "sentiment": "positive",
        "snippet": "MyBrand is highly recommended for...",
        "position_in_response": 1
      }
    ]
  }
}

POST/api/v1/runs/trigger

Queue a prompt run across AI engines. Returns immediately; runs execute asynchronously.

Request body

FieldTypeRequiredDescription
prompt_iduuidYesThe prompt to run
enginesstring[]NoSpecific engines to run (default: all available). Values: ChatGPT, Perplexity, Gemini, Claude, Copilot

Example

curl -X POST https://app.citedspy.com/api/v1/runs/trigger \
  -H "Authorization: Bearer cspy_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt_id": "abc-123",
    "engines": ["ChatGPT", "Perplexity"]
  }'

Response

{
  "data": {
    "runs": [
      { "run_id": "uuid", "engine": "ChatGPT", "status": "pending" },
      { "run_id": "uuid", "engine": "Perplexity", "status": "pending" }
    ],
    "queued": 2,
    "total": 2
  }
}
Runs are queued and execute asynchronously (per-engine concurrency, with automatic retry on rate limits). The response returns immediately with status: "pending" - poll GET /runs/:id or GET /runs?prompt_id=... until each run reaches completed.

Competitors

GET/api/v1/competitors

List competitors for a specific brand.

Query parameters

ParameterTypeRequiredDescription
brand_iduuidYesThe brand to get competitors for

Response

{
  "data": [
    {
      "id": "uuid",
      "brand_id": "uuid",
      "name": "Competitor A",
      "domain": "competitor-a.com",
      "aliases": ["CompA", "Comp-A"],
      "logo_url": "https://assets.citedspy.com/...",
      "created_at": "2026-05-01T00:00:00.000Z"
    }
  ]
}

Dashboard

GET/api/v1/dashboard/:brandId

Get aggregated dashboard metrics for a brand.

Path parameters

ParameterTypeDescription
brandIduuidThe brand ID

Query parameters

ParameterTypeDefaultDescription
daysinteger14Number of days for the analysis window

Response

{
  "data": {
    "brand_id": "uuid",
    "snapshot_date": "2026-05-17",
    "computed_at": "2026-05-17T06:00:00.000Z",
    "mention_rate": 72,
    "mention_rate_delta": 5,
    "avg_position": 2.3,
    "avg_position_delta": -0.4,
    "share_of_voice": 34,
    "share_of_voice_delta": 2,
    "visibility_score": 68,
    "visibility_score_delta": 4,
    "prompts_tracked": 25,
    "sentiment_score": 0.78,
    "total_runs": 150,
    "total_mentions": 108,
    "prompt_type_counts": { "discovery": 18, "comparison": 5, "branded": 2 },
    "engine_breakdown": [
      { "engine": "ChatGPT", "mention_rate": 80, "avg_position": 1.8 },
      { "engine": "Perplexity", "mention_rate": 65, "avg_position": 3.1 }
    ],
    "competitor_stats": [
      { "name": "Competitor A", "mention_rate": 45, "share_of_voice": 22 }
    ],
    "top_citations": [
      { "domain": "mybrand.com", "count": 34, "url": "https://mybrand.com/features" }
    ],
    "trend_data": [
      { "date": "2026-05-10", "mention_rate": 68, "position": 2.5 },
      { "date": "2026-05-11", "mention_rate": 70, "position": 2.4 }
    ],

    // Per prompt-type rollups (null when no prompts of that type exist):
    "discovery_stats": { "mentionRate": 71, "avgPosition": 2.3, "shareOfVoice": 45, "enginesCovering": 5 },
    "comparison_stats": { "winRate": 60, "podiumRate": 85, "lossRate": 15, "headToHead": [...] },
    "branded_stats": { "answerScore": 70, "sentimentScore": 0.4, "coMentionRate": 35, "ownedCitationRate": 60 }
  }
}

Metrics explained

FieldDescription
mention_ratePercentage of runs where your brand was mentioned (0-100)
avg_positionAverage position of your brand mention in responses (1 = first mentioned)
share_of_voiceYour brand's mentions as % of total mentions (brand + competitors)
visibility_scoreBlended 0-100 score across all three prompt types (discovery, comparison, branded)
sentiment_scoreAverage sentiment score (-1 to 1, where 1 is most positive)
prompt_type_countsCount of active prompts of each type: discovery, comparison, branded
discovery_stats / comparison_stats / branded_statsPer-type metric rollups; each is null when you have no prompts of that type
*_deltaChange compared to the previous period of equal length

Citations

GET/api/v1/citations

List URLs cited by AI engines in their responses.

Query parameters

ParameterTypeRequiredDescription
run_iduuidNoFilter by specific run
brand_iduuidNoFilter citations for a specific brand's prompts
limitintegerNoItems per page (default 50, max 200)
offsetintegerNoItems to skip

Response

{
  "data": [
    {
      "id": "uuid",
      "run_id": "uuid",
      "url": "https://mybrand.com/blog/guide",
      "domain": "mybrand.com",
      "position_in_response": 1,
      "snippet": "According to MyBrand's guide..."
    }
  ],
  "pagination": { "limit": 50, "offset": 0 }
}

Mentions

GET/api/v1/mentions

List brand and competitor mentions detected in AI responses.

Query parameters

ParameterTypeRequiredDescription
brand_iduuidNoFilter by brand
entity_typestringNoFilter: brand or competitor
sentimentstringNoFilter: positive, neutral, or negative
limitintegerNoItems per page (default 50, max 200)
offsetintegerNoItems to skip

Response

{
  "data": [
    {
      "id": "uuid",
      "run_id": "uuid",
      "brand_or_competitor_id": "uuid",
      "entity_type": "brand",
      "sentiment": "positive",
      "snippet": "MyBrand is one of the leading solutions for...",
      "position_in_response": 2
    }
  ],
  "pagination": { "limit": 50, "offset": 0 }
}

Sentiment values

ValueDescription
positiveBrand mentioned favorably (recommended, praised, highlighted as a top choice)
neutralBrand mentioned factually without strong positive or negative framing
negativeBrand mentioned negatively (criticized, listed as inferior, warned against)

Engines

GET/api/v1/engines

List AI engines with your workspace's on/off selection.

Response

{
  "data": [
    { "id": "uuid", "name": "ChatGPT",    "model_version": "gpt-5", "enabled": true,  "available": true },
    { "id": "uuid", "name": "Perplexity", "model_version": "sonar", "enabled": true,  "available": true },
    { "id": "uuid", "name": "Gemini",     "model_version": "...",   "enabled": false, "available": true },
    { "id": "uuid", "name": "Claude",     "model_version": "...",   "enabled": true,  "available": true },
    { "id": "uuid", "name": "Copilot",    "model_version": "...",   "enabled": false, "available": false }
  ]
}
FieldDescription
enabledWhether you have switched this engine on for your workspace - runs only execute on enabled engines
availableWhether the engine is configured platform-side (has a working API key) and able to accept runs
model_versionThe specific model version used for this engine

Toggle engines on or off for your workspace in Settings > Engines. Your plan caps how many can be enabled at once.

Need help with the API?

Our team can help you build custom integrations and troubleshoot any issues.

Contact support Back to docs