Strategic Briefing
REST endpoints for Strategic Briefing. Base URL https://api.competlab.com; every request needs a CL-API-Key header (see Authentication). Responses wrap in { item } or { items }; errors in { error }.
Get the current state of this project’s strategic briefing
/v1/projects/{projectId}/strategic-briefingGet the current state of this project’s strategic briefing — the synthesized, as-of competitive read (what changed, what it means, what to do). This is the ANALYZED briefing; for the raw monitoring data use the per-dimension dashboards (e.g. /pricing), and for the monitored-competitor roster use /competitors.
This returns the LATEST run, whatever state it is in. meta.status is that run’s raw lifecycle status and is the field to branch on:
done— the run finished.item,coverageandcontainsare populated; this is the readable edition.running— a briefing is being generated right now.itemis null;meta.progresscarries the step it is on and when it started. A typical run finishes in about 90 minutes and a healthy one can take up to ~2 hours — budget rather than busy-wait, and do not treat a run as late before then.failed— the most recent attempt ended without producing an edition.itemis null. A failed run does not resume the ~30-day cycle, so surface it rather than waiting it out.null— this project has never had a briefing run at all. This is the only value that means the project genuinely has nothing.
When meta.status is not done, THIS RUN has no content — which says nothing about whether the project has a briefing. A previously published edition is usually still readable: call GET /v1/projects/{projectId}/strategic-briefing/history to list the editions and …/history/{runId} to read one. Never report that no briefing is available on the strength of a null item — check history first.
A missing or non-accessible project returns 404 project_not_found; the briefing lifecycle itself never 404s.
Sections — lean by default. sections selects what to return and defaults to ["hub"] — the executive digest AND the navigation map. Each hub diagnosis row carries a deepDive pointer naming the dimension to read next; prefix it with deep- to form the section value (a pointer of ai-visibility → request sections=deep-ai-visibility). Valid sections: hub, actions, competitors, the thirteen deep-<dimension> deep-dives, or all for the full document. Charts are off by default (includeCharts=false returns each chart’s title + note only); pass includeCharts=true for the full data series.
Returned with any finished edition, regardless of sections: coverage (methodology and data-quality caveats — read these before quoting any figure) and contains (the list of sections this edition actually holds, so you can pick what to fetch next instead of requesting slots blind). Both are null whenever meta.status is not done, which says nothing about whether earlier editions exist — check …/history.
Reading the numbers: the AI Visibility Score is 0–100 (higher is better); an AI rank is ordinal (lower is better); action impact is 1–4 (higher is more critical); action effort is bucketed as effortMinutes (<30 | 30-120 | >120, or null when the briefing gave that action no estimate — report it as unsized rather than as quick). A project’s next briefing is scheduled approximately 30 days after its last successful one.
Path parameters
| Name | Type | Description |
|---|---|---|
projectId | string | Project ID |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
sections | array<string> | Which sections to return. Defaults to [“hub”] — the executive digest and navigation map. Pass specific sections to go deeper (e.g. a hub diagnosis pointer of ai-visibility maps to deep-ai-visibility), or all for the full document. Prefer deriving deep-<dimension> values from the hub diagnosis pointers rather than requesting slots blind — the response’s contains array lists exactly which sections exist for this edition, in this same vocabulary. | |
includeCharts | boolean | Include full chart series data. Defaults to false — each chart returns its title and note only, with no underlying numbers. Pass true for the full series. Default false. |
Request
curl "https://api.competlab.com/v1/projects/507f1f77bcf86cd799439011/strategic-briefing?sections=hub&includeCharts=false" \
-H "CL-API-Key: YOUR_COMPETLAB_API_KEY"Response 200 OK
Example
{
"meta": {
"runId": "6a3950c06bda450a1372048e",
"status": "done",
"editionNumber": 4,
"startedAt": "2026-06-22T14:20:02.110Z",
"briefingDate": "2026-06-22T15:51:24.443Z",
"progress": {
"step": "researching",
"startedAt": "2026-07-27T06:00:11.002Z",
"updatedAt": "2026-07-27T06:41:03.771Z"
}
},
"item": {
"hub": {
"kind": "hub",
"blocks": [
{
"type": "headline",
"verdict": "Pricing pressure is rising."
}
]
}
},
"coverage": {
"type": "coverage",
"items": [
"review counts are directional"
]
},
"contains": [
"hub",
"actions",
"competitors",
"deep-ai-visibility",
"deep-pricing"
]
}Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scope | The CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope. |
| 404 | project_not_found | No project matches the id in the path. |
Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.
{
"error": {
"code": "api_key_invalid",
"message": "Invalid API key",
"status": 401
}
}List this project’s briefing editions
/v1/projects/{projectId}/strategic-briefing/historyList this project’s Strategic Briefing runs, newest first — one cheap metadata row each, never briefing content.
Each row carries runId (pass it to …/history/{runId} to read that edition in full), briefingDate, status, the derived editionNumber, and headline — that edition’s one-line verdict, so you can pick which one to open without fetching every one.
Runs that failed or are still generating are included, with editionNumber, briefingDate and headline null. A gap between two editions is therefore explained rather than left unexplained.
Use this to answer “what did we say in April”, to trace how a read has changed over time, or — when GET /strategic-briefing reports a running or failed status — to find the last edition that is actually readable. For the current state use GET /strategic-briefing, not this.
Paginated with page and limit; check pagination.hasMore to fetch further pages. Briefings are produced roughly monthly, so this list is typically short.
Path parameters
| Name | Type | Description |
|---|---|---|
projectId | string | Project ID |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | number | Page number (1-indexed). Default 1. Min 1. | |
limit | number | Number of items per page. Default 20. Range 1–100. |
Request
curl "https://api.competlab.com/v1/projects/507f1f77bcf86cd799439011/strategic-briefing/history?page=1&limit=20" \
-H "CL-API-Key: YOUR_COMPETLAB_API_KEY"Response 200 OK
Example
{
"items": [
{
"runId": "6a3950c06bda450a1372048e",
"editionNumber": 4,
"briefingDate": "2026-06-22T15:51:24.443Z",
"documentDate": "2026-06-22",
"status": "done",
"headline": "Pricing pressure is rising in your segment."
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 47,
"totalPages": 3,
"hasMore": true
}
}Paginated — pass page and limit query parameters and follow pagination.hasMore to page through the full set.
Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scope | The CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope. |
Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.
{
"error": {
"code": "api_key_invalid",
"message": "Invalid API key",
"status": 401
}
}Get one briefing edition by id
/v1/projects/{projectId}/strategic-briefing/history/{runId}Get one strategic briefing edition by runId, in exactly the same shape as GET /strategic-briefing.
Take the runId from GET /strategic-briefing/history (or from meta.runId on a current read). Accepts the same sections and includeCharts options, with the same ["hub"] default.
A runId naming a run that failed or is still generating returns 200 with meta.status set accordingly and item null — that run genuinely produced no edition, which is an answer rather than an error. A malformed id returns 400 invalid_run_id; an id that does not belong to this project returns 404 run_not_found.
Use this to read or quote a specific past edition. For the current state use GET /strategic-briefing.
Path parameters
| Name | Type | Description |
|---|---|---|
runId | string | Briefing run ID, from meta.runId or a history row |
projectId | string | Project ID |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
sections | array<string> | Which sections to return. Defaults to [“hub”] — the executive digest and navigation map. Pass specific sections to go deeper (e.g. a hub diagnosis pointer of ai-visibility maps to deep-ai-visibility), or all for the full document. Prefer deriving deep-<dimension> values from the hub diagnosis pointers rather than requesting slots blind — the response’s contains array lists exactly which sections exist for this edition, in this same vocabulary. | |
includeCharts | boolean | Include full chart series data. Defaults to false — each chart returns its title and note only, with no underlying numbers. Pass true for the full series. Default false. |
Request
curl "https://api.competlab.com/v1/projects/507f1f77bcf86cd799439011/strategic-briefing/history/6a3950c06bda450a1372048e?sections=hub&includeCharts=false" \
-H "CL-API-Key: YOUR_COMPETLAB_API_KEY"Response 200 OK
Example
{
"meta": {
"runId": "6a3950c06bda450a1372048e",
"status": "done",
"editionNumber": 4,
"startedAt": "2026-06-22T14:20:02.110Z",
"briefingDate": "2026-06-22T15:51:24.443Z",
"progress": {
"step": "researching",
"startedAt": "2026-07-27T06:00:11.002Z",
"updatedAt": "2026-07-27T06:41:03.771Z"
}
},
"item": {
"hub": {
"kind": "hub",
"blocks": [
{
"type": "headline",
"verdict": "Pricing pressure is rising."
}
]
}
},
"coverage": {
"type": "coverage",
"items": [
"review counts are directional"
]
},
"contains": [
"hub",
"actions",
"competitors",
"deep-ai-visibility",
"deep-pricing"
]
}Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_parameters · invalid_run_id · invalid_check_id | Bad request — the payload failed validation. |
| 401 | api_key_missing · api_key_invalid · api_key_revoked · api_key_expired · insufficient_scope | The CL-API-Key is missing, malformed, revoked, expired, or lacks the required scope. |
| 404 | run_not_found | No run matches the id in the path. |
Every error uses the shared { error: { code, message, status } } envelope; code is one of the values listed above.
{
"error": {
"code": "invalid_parameters",
"message": "Domain is required",
"status": 400
}
}