CitationBenchTalk to Sales
Get started

REST API quickstart — first CitationBench call in five minutes

Get a CitationBench API key, make your first REST call, see real keyword data — five minutes. Try demo mode first with zero signup required for shape-complete responses.

Get an API key, make your first call, see a real result. Five minutes.

Step 0 (optional) — try without signing up

You don't need an account to make your first call. CitationBench has demo mode — every endpoint responds without auth, returning shape-complete synthetic data.

curl https://api.citationbench.com/v1/agent/skills
{
  "skills": [
    { "slug": "bootstrap_brand",  "name": "Bootstrap a brand", ... },
    { "slug": "rank_monitor",     "name": "Monitor ranks",     ... },
    ...
  ]
}

X-CitationBench-Mode: demo will be in the response headers. Once you've shape-checked your integration, sign up and swap in a live key.


Step 1 — Create an API key

  1. Go to https://app.citationbench.com/api-keys
  2. Click Create key
  3. Pick a scope (defaults to your workspace; agency master if you have an agency account)
  4. Copy the sk_live_*** value — you won't see it again

Set it locally:

export CITATIONBENCH_API_KEY=sk_live_***
export WORKSPACE_ID=ws_***  # the workspace you want to act on

Step 2 — Your first call: run keyword research

curl -X POST https://api.citationbench.com/v1/research/keyword \
  -H "Authorization: Bearer $CITATIONBENCH_API_KEY" \
  -H "X-Workspace-Id: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "seed":  "project management software",
    "depth": "fast",
    "limit": 50
  }'

You get back an invocation handle:

{
  "invocationId": "inv_01HVZ...",
  "agentId": "agt_01HVZ...",
  "skill": "research.keyword",
  "status": "RUNNING",
  "estimatedCost": { "credits": 3, "durationSeconds": 30 },
  "links": {
    "self": "https://api.citationbench.com/v1/agent/invocations/inv_01HVZ...",
    "events": "https://api.citationbench.com/v1/agent/invocations/inv_01HVZ.../events"
  }
}

Step 3 — Wait for it

You have two choices.

Poll

INV=inv_01HVZ...

while true; do
  STATUS=$(curl -sf -H "Authorization: Bearer $CITATIONBENCH_API_KEY" \
    https://api.citationbench.com/v1/agent/invocations/$INV | jq -r '.status')
  [[ "$STATUS" =~ ^(SUCCEEDED|FAILED|CANCELLED)$ ]] && break
  echo "  status: $STATUS"
  sleep 5
done

Subscribe (SSE)

curl -N -H "Authorization: Bearer $CITATIONBENCH_API_KEY" \
  https://api.citationbench.com/v1/agent/invocations/$INV/events

Step 4 — Read the result

curl -H "Authorization: Bearer $CITATIONBENCH_API_KEY" \
  https://api.citationbench.com/v1/agent/invocations/$INV
{
  "invocationId": "inv_***",
  "agentId":      "agt_***",
  "skill":        "research.keyword",
  "status":       "SUCCEEDED",
  "creditsUsed":  3,
  "result": {
    "afterLimit": 50,
    "keywords": [
      { "id": "kw_***", "keyword": "project management software", "intentLabels": ["PURCHASE"], "volume": 18100, "kd": 64 },
      ...
    ]
  },
  "raw":   "Ran 2 discovery methods (fast). Dedup left 50 keywords. Labeling assigned intent ...",
  "files": ["agent-workspace/keywords-full.csv", "agent-workspace/labeling-notes.md"]
}

The result.keywords are now persistent in your workspace — query them via:

curl -G -H "Authorization: Bearer $CITATIONBENCH_API_KEY" \
  https://api.citationbench.com/v1/keywords \
  --data-urlencode "intent=PURCHASE" \
  --data-urlencode "limit=10"

Step 5 — Read the agent's files

The agent wrote a few files during the run. Fetch one:

curl -H "Authorization: Bearer $CITATIONBENCH_API_KEY" \
  https://api.citationbench.com/v1/agent/files/agent-workspace/labeling-notes.md/raw

Returns the markdown content — the agent's own narration of why it labeled each keyword the way it did.


What you just learned

  • Every long-running operation returns an invocation handle (invocationId, agentId, skill).
  • The universal response envelope is { result, raw, files } — typed result, agent narration, and any files the agent wrote.
  • You can poll or stream invocations.
  • All persistent data (keywords, content, etc.) is queryable via plain GET endpoints.

Next

On this page