Authentication — bearer keys, workspace scoping, and demo mode
Bearer API keys for REST and MCP, agency master keys with workspace scoping, sandbox test keys, and a unique no-signup demo mode so AI agents can integrate before the user has an account.
CitationBench uses bearer API keys for both the REST API and the hosted MCP server. There's also a demo mode that lets AI agents build, test, and integrate against the real API before the user has an account.
Quick reference
| Header | Authorization: Bearer sk_live_*** |
| MCP alternative | passed as a connection header at install time |
| Workspace scoping | X-Workspace-Id: ws_*** header (agency master keys only) |
| Live keys | sk_live_*** — production, real credits |
| Test keys | sk_test_*** — sandbox, fake credits, mocked third-party calls |
| Demo mode | no key required — see below |
Demo mode
Build first, sign up later. Every CitationBench endpoint — REST and MCP — responds to unauthenticated requests in demo mode. The response shapes are identical to the real ones, so your integration can be wired end-to-end before the user creates an account.
Why demo mode exists
AI agents (Claude Code, Cursor, ChatGPT, custom agents) are increasingly the first thing that touches a developer API. We want an agent to be able to:
- Discover CitationBench via the MCP catalog or docs site
- Read the API
- Build an integration against it
- Test that the integration works against real-shape responses
- Only then ask the human user to sign up + provide an API key
You shouldn't have to interrupt the agent to make the user create an account just to confirm the integration runs.
What demo mode does
- REST: any request without
Authorization(or withAuthorization: Bearer demo) returns a demo-mode response with the same shape as a live response. TheX-CitationBench-Mode: demoheader is set on every demo response so you can detect it. - MCP: connect without a header and the server registers itself in demo mode. Every tool call returns a demo response.
- Demo responses are deterministic and shape-complete — every field a live response would carry is present, populated with realistic synthetic values.
- No state is persisted. Demo mode is stateless; the data you "create" in demo mode doesn't exist between calls. Useful for shape-checking, not for testing flows that depend on prior state.
- No real third parties are called. DataForSEO, Ahrefs, Apollo, Instantly, Google — none of them are touched in demo mode.
What demo mode does NOT do
- It does not run real agents, so you can't measure real latency or LLM behavior.
- It does not preserve state across calls (no "look up the keyword I just created").
- It does not enforce real workspace scoping or quotas.
- It does not return real SERP / citation / ranking data.
Switching from demo to live
The contract is the same. Add Authorization: Bearer sk_live_*** to your existing code and everything starts running for real. No request-shape changes. No new endpoints to discover.
The agent flow that should win:
[agent] integrates with CitationBench in demo mode
[agent] confirms all tool calls return the expected shapes
[agent] tells the user: "Integration is ready. To run for real,
sign up at citationbench.com and paste your API key here."
[user] signs up, pastes sk_live_***
[agent] re-runs the same code paths against live dataExample
# Demo mode — no key needed
curl -X POST https://api.citationbench.com/v1/research/keyword \
-H "Content-Type: application/json" \
-d '{ "seed": "project management software", "limit": 50 }'
# → 202 Accepted
# X-CitationBench-Mode: demo
#
# {
# "invocationId": "inv_demo_***",
# "agentId": "agt_demo_***",
# "skill": "research.keyword",
# "status": "RUNNING",
# "estimatedCost": { "credits": 0, "durationSeconds": 0 },
# "demoMode": true,
# "links": { ... }
# }
# Then GET the invocation — demo mode returns a complete, deterministic result
curl https://api.citationbench.com/v1/agent/invocations/inv_demo_xxxx
# → 200 OK
# X-CitationBench-Mode: demo
# {
# "invocationId": "inv_demo_xxxx",
# "agentId": "agt_demo_xxxx",
# "skill": "research.keyword",
# "status": "SUCCEEDED",
# "result": { /* full structured output with synthetic keywords */ },
# "raw": "...",
# "files": ["agent-workspace/keywords-full.csv", ...],
# "demoMode": true
# }# MCP demo mode — no header at install
claude mcp add citationbench https://mcp.citationbench.com/mcp
# Tools light up immediately; every call returns a demo response.Detecting demo mode at runtime
Every demo response carries:
- HTTP header
X-CitationBench-Mode: demo - The string
demosomewhere ininvocationId,agentId, and similar IDs (inv_demo_***,agt_demo_***) - A
demoMode: truefield on the top-level body
if (response.headers["x-citationbench-mode"] === "demo") {
console.warn("Running in demo mode — sign up to run live.");
}Live keys
Create one at https://app.citationbench.com/api-keys. Two flavors:
sk_live_***— production. Bills real credits. Hits real third-party services.sk_test_***— sandbox. Free. Hits sandbox endpoints (e.g., DataForSEO sandbox) where available; otherwise mocked. State persists per test key.
Using live keys
curl -X POST https://api.citationbench.com/v1/research/keyword \
-H "Authorization: Bearer sk_live_***" \
-H "Content-Type: application/json" \
-d '{ "seed": "project management software", "limit": 50 }'# MCP
claude mcp add citationbench https://mcp.citationbench.com/mcp \
--header "Authorization: Bearer sk_live_***" \
--header "X-Workspace-Id: ws_***"Key scope
A key is one of two scopes:
- Workspace-scoped (default): bound to one workspace. The
X-Workspace-Idheader is ignored. - Agency master: can act on any sub-workspace the agency owns. You must pass
X-Workspace-Id: ws_***on every request, or use theworkspaces.bulk_actionendpoint.
Rotation and revocation
# List
curl -H "Authorization: Bearer sk_live_***" \
https://api.citationbench.com/v1/auth/keys
# Create a new one
curl -X POST -H "Authorization: Bearer sk_live_***" \
https://api.citationbench.com/v1/auth/keys \
-d '{ "name": "ci-bot", "scope": "WORKSPACE", "workspaceId": "ws_***" }'
# Revoke
curl -X DELETE -H "Authorization: Bearer sk_live_***" \
https://api.citationbench.com/v1/auth/keys/akey_***Revocation is immediate. In-flight invocations using the revoked key continue to completion; new calls are rejected with 401.
Workspace scoping
| You have | Header to send | Notes |
|---|---|---|
Workspace-scoped sk_live_*** | none needed | The key knows its workspace |
Workspace-scoped sk_test_*** | none needed | Same |
Agency master sk_live_*** | X-Workspace-Id: ws_*** | Required on every per-workspace call |
| Agency master targeting many at once | none | Use POST /v1/workspaces/bulk-action |
Errors
| Status | Code | Cause |
|---|---|---|
| 401 | unauthorized | Missing or invalid Authorization header on an endpoint that does not allow demo mode |
| 401 | key_revoked | Key has been revoked |
| 401 | key_expired | Key reached its expiresAt |
| 403 | workspace_forbidden | Key can't act on the requested X-Workspace-Id |
| 403 | agency_key_required | Endpoint requires an agency master key |
A note on safety
A small set of write endpoints — anything that touches external accounts on behalf of a real user (publishing to a connected CMS, sending real outreach emails, submitting URLs to Google) — do not respond in demo mode. They require a live key. An agent can still inspect their shape via GET /v1/agent/skills/{slug} and the inventory.
Related
Quickstart — MCP
Add the hosted CitationBench MCP server to Claude Code, Cursor, Claude Desktop, Windsurf, ChatGPT Apps, or any MCP client. Make your first agentic SEO tool call in sixty seconds.
Workspaces & multi-brand
Setup guide for running CitationBench across multiple brands. Solo workspace vs agency master key with per-workspace scoping, plus cross-workspace bulk operations.