Developer Docs

Build with CiteFit

Query brand visibility data, trigger scans, and integrate CiteFit into your own workflows — via the REST API or the MCP server for AI agent use.

Authentication

API Keys

All programmatic access uses a Bearer API key. Keys carry the prefix bp_ and are shown only once at creation.

Generate a key

  1. 1Go to Dashboard → Account → API Keys.
  2. 2Click New API key, give it a label, and copy the full key immediately — it is shown only once.
  3. 3You may hold up to 10 active keys per account. Revoke unused keys to stay within the limit.

Using the key

Pass the key as a Bearer token in every request:

Authorization: Bearer bp_<your-key>

Requests without a valid key receive 401 Unauthorized.

Security note: API keys are stored as SHA-256 hashes only. CiteFit cannot recover the raw value after creation. Never commit keys to version control — use environment variables or a secrets manager.
REST API

REST API

Standard JSON over HTTPS. All request and response bodies use Content-Type: application/json.

Base URL

https://www.citefit.com

Brands

MethodPathDescription
GET/api/brandsList all tracked brands
POST/api/brandsCreate a brand
GET/api/brands/:idGet a brand
PATCH/api/brands/:idUpdate a brand
DELETE/api/brands/:idDelete a brand
curl https://www.citefit.com/api/brands \
  -H "Authorization: Bearer bp_<your-key>"

Scans

MethodPathDescription
POST/api/run-scanTrigger a manual scan
GET/api/scan-status/:jobIdPoll scan progress
# Trigger a scan
curl -X POST https://www.citefit.com/api/run-scan \
  -H "Authorization: Bearer bp_<your-key>" \
  -H "Content-Type: application/json" \
  -d '{"brand_id": "<uuid>"}'

# → {"job_id": "f9e8d7c6-...", "status": "pending"}
# Poll for completion
curl https://www.citefit.com/api/scan-status/f9e8d7c6-... \
  -H "Authorization: Bearer bp_<your-key>"

# → {"status": "running", "progress": {"current": 4, "total": 12, "step": "chatgpt"}}

status progresses: pendingrunningcomplete or error. The endpoint honours If-None-Match / ETag for efficient polling.

Visibility & insights

MethodPathDescription
GET/api/alerts/:brandIdUnseen visibility alerts
GET/api/recommendations/:brandIdAI-generated recommendations
GET/api/competitive-delta/:brandIdCompetitive comparison
GET/api/seo-health/:brandIdSEO health snapshot

Plan limits

PlanScan intervalOn-demand cap
ProEvery 3 days per brand
UltraUnlimited25 scans / day across all brands

Exceeding limits returns 429 with a descriptive error message.

MCP

MCP Server

CiteFit implements the MCP 2025-03-26 spec over HTTP + SSE. Connect any MCP-compatible AI client directly to your brand data.

Endpoint

https://www.citefit.com/api/mcp

Protocol

MCP 2025-03-26 (Streamable HTTP)

POST

JSON-RPC 2.0 request / response

GET

SSE keep-alive stream

Connect a client

Add CiteFit to your MCP client config (Claude Desktop, Cursor, Continue, etc.):

// mcp-config.json
{
  "mcpServers": {
    "citefit": {
      "url": "https://www.citefit.com/api/mcp",
      "headers": {
        "Authorization": "Bearer bp_<your-key>"
      }
    }
  }
}

The server advertises its capabilities during the initialize handshake and lists its tools via tools/list. Machine-readable metadata is available at /.well-known/mcp/server-card.json.

SSE connection limits

The GET /api/mcp endpoint accepts up to 2 concurrent SSE connections per API key. Exceeding this returns 429 with Retry-After: 60. The server sends a keep-alive ping every 25 seconds and releases the connection slot automatically on client disconnect.

MCP Tools

Tool reference

All tools return a content array with a single text item containing JSON. On failure, isError: true is set and text contains the error message.

list_brandsno arguments required

List all brands tracked by the authenticated user.

// request
{"name": "list_brands", "arguments": {}}

// response text (JSON)
[
  {
    "id": "a1b2c3d4-...",
    "name": "Acme Corp",
    "domain": "acme.com",
    "competitors": ["Globex"],
    "created_at": "2025-03-01T12:00:00Z"
  }
]
get_brand

Get a single brand including all its prompts.

ArgumentTypeRequiredDescription
brand_idstring (UUID)yesBrand identifier
get_visibility

Get daily visibility snapshots (mention rate, average position) for a brand. Returns up to 90 days × 3 platforms by default.

ArgumentTypeRequiredDescription
brand_idstring (UUID)yesBrand identifier
platformstringnochatgpt | perplexity | google_aio
fromISO datenoLower bound e.g. 2025-01-01
toISO datenoUpper bound
// response text sample
[
  {
    "date": "2025-03-15",
    "platform": "chatgpt",
    "mention_rate": 0.62,
    "avg_position": 2.1,
    "total_prompts": 8,
    "mentioned_count": 5,
    "scan_count": 1
  }
]
get_recent_results

Most recent scan results for a brand across all platforms.

ArgumentTypeRequiredDescription
brand_idstring (UUID)yesBrand identifier
limitinteger 1–100noMax results (default 20)
get_recommendations

AI-generated recommendations for improving brand visibility.

ArgumentTypeRequiredDescription
brand_idstring (UUID)yesBrand identifier
include_dismissedbooleannoInclude dismissed items (default false)
get_alerts

Unseen visibility alerts for a brand.

ArgumentTypeRequiredDescription
brand_idstring (UUID)yesBrand identifier
trigger_scan

Trigger a manual brand scan. Runs asynchronously — poll the returned poll_url to track progress. The same plan limits as the REST API apply.

ArgumentTypeRequiredDescription
brand_idstring (UUID)yesBrand to scan
// response text
{
  "job_id": "f9e8d7c6-...",
  "status": "pending",
  "poll_url": "/api/scan-status/f9e8d7c6-..."
}

Error reference

HTTP status codes

StatusMeaning
400Malformed JSON or invalid JSON-RPC request
401Missing or invalid API key
402Free trial ended — upgrade required
429Rate limit or too many SSE connections
500Internal server error

JSON-RPC error codes (MCP)

CodeMeaning
-32700Parse error
-32600Invalid request
-32601Method not found
-32602Invalid params
-32603Internal error
-32001Unauthorized (application-level)
Examples

Code examples

cURL — list brands

curl https://www.citefit.com/api/brands \
  -H "Authorization: Bearer bp_<your-key>"

Python — MCP client

import httpx, json

API_KEY = "bp_<your-key>"
BASE    = "https://www.citefit.com/api/mcp"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

def rpc(method, params=None, *, id=1):
    r = httpx.post(BASE, headers=HEADERS, json={
        "jsonrpc": "2.0", "id": id, "method": method, "params": params or {}
    })
    r.raise_for_status()
    return r.json()

# Handshake
rpc("initialize", {
    "protocolVersion": "2025-03-26",
    "clientInfo": {"name": "my-script", "version": "1.0.0"},
    "capabilities": {},
})

# Fetch brands
result = rpc("tools/call", {"name": "list_brands", "arguments": {}}, id=2)
brands = json.loads(result["result"]["content"][0]["text"])

# Visibility for the first brand
vis = rpc("tools/call", {
    "name": "get_visibility",
    "arguments": {"brand_id": brands[0]["id"], "platform": "chatgpt"},
}, id=3)
print(json.loads(vis["result"]["content"][0]["text"]))

TypeScript — trigger scan and poll

const API_KEY = "bp_<your-key>";
const MCP_URL = "https://www.citefit.com/api/mcp";

async function rpc(method: string, params = {}, id = 1) {
  const res = await fetch(MCP_URL, {
    method: "POST",
    headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ jsonrpc: "2.0", id, method, params }),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// Handshake
await rpc("initialize", {
  protocolVersion: "2025-03-26",
  clientInfo: { name: "my-agent", version: "1.0.0" },
  capabilities: {},
});

// Trigger a scan
const { result } = await rpc("tools/call", {
  name: "trigger_scan",
  arguments: { brand_id: "<uuid>" },
}, 2);

const { job_id, poll_url } = JSON.parse(result.content[0].text);

// Poll until done
while (true) {
  const r = await fetch(`https://www.citefit.com${poll_url}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  const job = await r.json();
  if (job.status === "complete" || job.status === "error") { console.log(job); break; }
  await new Promise((res) => setTimeout(res, 3_000));
}

Ready to integrate?

Generate your first API key from the account settings page.

Go to Account Settings