Reference

API & MCP server

Everything OptimizeCamp measures about your AI visibility is available outside the app — same numbers, same access rules. There are two doors in: point your AI assistant at the MCP server and just ask, or build on the REST API.

Availability & quotas

PlanAPI + MCPRequests / day
StarterNot included
ProIncluded5,000
AgencyIncluded20,000

Quotas are per workspace per UTC day, shared across REST and MCP. Reads never cost anything beyond quota; the one paid action is triggering an on-demand run, which uses your plan’s on-demand run credits (1 credit covers up to 50 prompts) — exactly like the in-app Run now button. Everything you read reflects the two answer engines OptimizeCamp tracks today, ChatGPT and Google AI Overviews — see Answer engines we track.

Create an API key

Open Settings → API access

On any project’s settings page. Keys belong to the workspace, not the project — one key reads every project you track. Up to 5 active keys.

Name it — and decide if it can trigger runs

Keys are read-only unless you check “Allow this key to trigger tracking runs”. Leave that off for anything that only needs to read (dashboards, most assistant setups).

Copy the secret

It looks like oc_live_… and is shown once — OptimizeCamp stores only a hash. Revoking a key in the same screen cuts it off immediately.

Connect your AI assistant (MCP)

The MCP endpoint speaks Streamable HTTP:

https://optimizecamp.com/api/mcp

claude.ai / ChatGPT — no key needed

Add a custom connector

In your assistant’s connector settings, add the endpoint URL above as a custom connector.

Sign in and approve

You’re sent to OptimizeCamp to sign in (if you aren’t already) and shown exactly what the connection can see before you approve it.

Ask

That’s it — the assistant can now answer from your workspace’s real tracked data.

Assistant connections are read-only

The consent screen promises read-only access, so OAuth connections can’t spend your run credits or change anything. To let an assistant trigger runs, connect it with an API key that has the runs permission instead.

Claude Code, Cursor & other clients — with a key

claude mcp add --transport http optimizecamp \
  https://optimizecamp.com/api/mcp \
  --header "Authorization: Bearer oc_live_…"

Any MCP client that can send an Authorization header works the same way.

Things worth asking

  • “How’s my AI visibility this week — what moved and why?”
  • “Which prompts am I losing, and who’s winning them?”
  • “Which sources do AI answers cite for my category — am I on them?”
  • “Pick my top content gap and draft an outline that would close it.”
ToolThe question it answers
list_projectsWhich brands/sites does this workspace track?
get_visibility_overviewHow are we doing in AI search right now?
get_visibility_trendHow has our visibility changed over time?
get_prompt_performanceWhich prompts are we winning — and losing?
get_share_of_voiceHow do we compare to competitors?
get_citationsWhere do AI answers get their information?
get_earned_sourcesWhich third-party pages already cite us?
get_content_gapsWhat should we fix or write next?
trigger_visibility_runMeasure again, right now.

REST API

Base URL https://optimizecamp.com/api/v1, authenticated with a bearer key. Project ids are UUIDs, but every {id} also accepts the project’s domain.

curl -H "Authorization: Bearer oc_live_…" \
  https://optimizecamp.com/api/v1/projects/acme.com
{
  "project": { "id": "…", "name": "Acme", "domain": "acme.com", … },
  "overview": {
    "measuredAt": "2026-07-20",
    "visibilityScore": 62.4,
    "mentionRate": 71.4,
    "citationRate": 42.9,
    "positionScore": 58.3,
    "sentimentIndex": 64.0,
    "shareOfVoice": 38.2,
    "deltas": { "visibilityScore": 4.1, "mentionRate": 7.2, … },
    "deltaBasis": "week",
    "platforms": { "chatgpt": 66.1, "google_ai_overview": 58.7 },
    "lockedHistory": false
  }
}
MethodPathReturns
GET/projectsThe workspace’s tracked brands/sites.
GET/projects/{id}Project facts + the latest overview (scores, deltas, per-platform).
GET/projects/{id}/trend?months=NDaily Visibility Score series with the top-competitor overlay.
GET/projects/{id}/promptsPer-prompt results over the last 30 measurement days.
GET/projects/{id}/share-of-voiceBrand vs competitors on the latest measured day.
GET/projects/{id}/citationsCited domains, ranked, with brand/competitor ownership flags.
GET/projects/{id}/earned-sourcesThird-party pages already earning you citations.
GET/projects/{id}/content-gapsRanked content opportunities with opportunity scores.
GET/projects/{id}/visibility.csvThe daily rollup as CSV — identical to the in-app export.
GET/projects/{id}/runsThe latest tracking run’s status.
POST/projects/{id}/runsStarts an on-demand run (runs permission; uses run credits).

Timeline endpoints honor your plan’s history-access window, the same as the app.

Triggering runs

POST /projects/{id}/runs starts a fresh measurement through the exact same path as the in-app button — same credit hold, same one-run-at-a-time guard. It needs a key with the runs permission, answers 202 with the new run, and you poll GET /projects/{id}/runs until the status is completed, partial or failed. A second POST while a run is live answers 409. Workspaces with an inactive subscription keep read access but can’t start runs.

Errors

Every failure is { "error": { "code", "message" } } with a matching HTTP status:

CodeHTTPMeaning
unauthorized401Missing, unknown, or revoked credential.
insufficient_scope403The key lacks the required permission.
plan_gated403The plan doesn’t include API access — or the workspace is read-only, for writes.
not_found404No such project in this workspace.
invalid_request400A parameter didn’t validate.
insufficient_credits402Out of on-demand run credits this period.
conflict409A run is already in progress.
rate_limited429Daily quota reached; Retry-After says when it resets (midnight UTC).
unavailable503Runs temporarily paused — retry shortly.