CompetLab REST API
What it is
The CompetLab REST API is the programmatic surface for your competitive intelligence. It’s
a read API — every resource endpoint is a GET — that returns the same data you see in the
app, as JSON, so you can pull it into your own backend, a scheduled job, or a dashboard you
build. The free scan tools are POST endpoints — the quick ones (sitemap, AI-crawler,
fetch-url) return their result inline, and the three longer scans (tech-stack, trust-signals,
agent-adoption) return a scan you poll.
Reach for the REST API when the caller is your code. If the caller is an AI agent, the MCP server wraps this same API as agent-callable tools — pick the surface that matches who’s calling.
Base URL and versioning
Every request goes to https://api.competlab.com, and every route is versioned in the path:
https://api.competlab.com/v1/projectsThe version lives in the URL (/v1), so a future /v2 can ship without breaking /v1
callers.
Authentication
Every request needs a CL-API-Key header carrying a CompetLab API key (it starts with
cl_live_ and is 40 characters). You create keys in the dashboard under Settings → API
Keys. The full story — creating keys, the format, and auth errors — is in
Authentication.
curl https://api.competlab.com/v1/projects \
-H "CL-API-Key: YOUR_COMPETLAB_API_KEY"Resources
The API mirrors the product: your projects and competitors, the five monitored dimensions, your alerts and schedules, the Strategic Briefing, and the free scan tools.
| Group | Endpoints |
|---|---|
| Projects | GET /v1/projects · GET /v1/projects/{projectId} |
| Competitors | GET …/competitors · GET …/competitors/{competitorId} |
| AI Visibility | GET …/ai-visibility · /history · /history/{checkId} · /trend |
| Positioning · Pricing · Tech & Trust | each: GET …/{dimension} · /history · /history/{runId} |
| Content | the three above, plus GET …/content/changelog |
| Alerts · Schedules | GET …/alerts · GET …/schedules |
| Strategic Briefing | GET …/strategic-briefing |
| Free Tools | POST /v1/tools/* runs a tool (sitemap, AI-crawler, fetch-url return inline); the tech-stack / trust-signals / agent-adoption scans add GET …/scans/{scanId} to poll |
The complete, per-endpoint reference is generated from the spec in the
API Reference. The live OpenAPI document is public at
https://api.competlab.com/v1/docs/openapi.json, with Swagger UI at
https://api.competlab.com/v1/docs.
Response shape
Responses are consistently wrapped:
- A single resource returns
{ "item": { … } }. - A collection returns
{ "items": [ … ] }; paginated collections add apaginationobject withpage,limit,total,totalPages, andhasMore. - Errors return
{ "error": { "code": "…", "message": "…", "status": 400 } }, wherecodeis a machine-readable snake_case string.
null means unmeasured
One rule runs through every dimension, and it is the single most important thing to get right when you build on this data:
null means we did not measure it — never zero, never empty, never “no”. A measured 0
or false is reported as itself and is a real finding.
So hasFreePlan: false means we read the pricing page and there is no free plan.
hasFreePlan: null means we could not read the page at all. The two are different facts and
the API will not blur them: it would rather tell you nothing than tell you something it never
checked.
This matters because the failure is silent. if (!hasFreePlan) treats “we couldn’t read it”
and “they have no free plan” identically, and produces a confident sentence about a
competitor from a measurement that never happened. Branch on null explicitly, and say
“not measured” when you find it:
if (plan.hasFreePlan === null) {
// We didn't measure this — say so, or say nothing.
} else if (plan.hasFreePlan === false) {
// We measured it. There is no free plan. That's a finding.
}The same rule applies to rates and counts: a null rate had nothing to compute from, so plot
it as a break in the line rather than a zero. Per-field notes throughout the
API Reference tell you what each null specifically means.
An omitted key is a third state
Some newer fields extend that rule rather than repeat it. Where null says we tried and could
not measure this, an omitted key says reporting any value here would assert something we
never established.
Tech & Trust’s aiAccess works this way. When a competitor’s robots.txt could not be read,
assistantAccess and modelTrainingAccess are absent from the response, not empty — because
[] would claim we evaluated all six assistants and none can reach the site, which is a
completely different finding from “we couldn’t read the file.”
assistantAccess ?? [] reintroduces exactly the bug this shape exists to prevent. Branch on the
sibling measurement.status — measured, measured_no_policy_found, or could_not_measure —
before you read the arrays at all.
Note that measured_no_policy_found is a measurement: the site publishes no robots.txt, which
under the robots exclusion standard permits every crawler, so the verdicts render and are all
open. Only could_not_measure withholds them.
Rate limits
The free-tool endpoints are rate-limited per API key; the core resource endpoints aren’t
throttled today. Over-limit requests get a 429. See
Rate limits for the numbers.
Next steps
- Quickstart → — your first request in a minute.
- Authentication → — keys, format, and errors.
- API Reference → — every endpoint, generated from the spec.
FAQ
What can the CompetLab REST API do?
It's a read API over your competitive intelligence. With a CompetLab API key you can pull your projects and competitors, the five monitored dimensions (AI Visibility, Positioning, Pricing, Content, and Tech & Trust), your alerts and schedules, and your Strategic Briefing — all as JSON. It also exposes the free scan tools as POST endpoints. It returns the same data the dashboards and the MCP server use, so it's the surface you reach for when the caller is your own backend, a scheduled job, or a dashboard you build.
How do I authenticate?
With a CompetLab API key sent as a CL-API-Key header on every request. Keys start with cl_live_ and are 40 characters long, and you create them in the dashboard under Settings → API Keys (you'll need the Owner or Admin role). A key maps to your organization, so the API returns exactly what your organization can see. There's no OAuth or login step — the key travels with each request.
How is the REST API different from the MCP server?
Same data, different consumer. The REST API is for your own code — server-to-server automation, scheduled jobs, dashboards. The MCP server wraps this same API as tools an AI agent can discover and call inside a conversation. Under the hood the MCP server calls the REST API, so anything you can do through one you can do through the other; pick the surface that matches who's calling.
Is there an OpenAPI spec?
Yes. The live OpenAPI document is public at https://api.competlab.com/v1/docs/openapi.json, and interactive Swagger UI is at https://api.competlab.com/v1/docs. The per-endpoint API Reference in these docs is generated from that spec, so it stays in sync with what the API actually accepts and returns.
Can I write or change data through the API?
No. The resource endpoints are read-only GET requests — the API doesn't expose any way to change your account, projects, competitors, alerts, or settings. The only POST endpoints are the free scan tools, which run against a public URL you provide: three return their result immediately (sitemap, AI-crawler, fetch-url) and three start a scan you poll (tech-stack, trust-signals, agent-adoption). None of them modify your CompetLab data.