Debriefing Competitors API
Competitors this workspace tracks.
Competitors this workspace tracks.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/debriefing-io:debriefing-io-competitors-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Debriefing Read Competitors API
version: 1.0.0
summary: Read competitors, signals, digests, and battlecards for one workspace.
description: 'A JSON API for one organization. Create an API key in Settings → Integrations.
The same key authenticates the MCP endpoint at `POST /mcp`.
Every key reads. A key writes only through a scope ticked when the key is made. The one
scope today is `watchlist:add`, which lets `POST /api/v1/competitors` add a competitor and
nothing else. Existing keys have no scopes and stay read-only.
Clients may name themselves in the `X-Debriefing-Source` header, a short lowercase slug
such as `google-sheets-addon`. A competitor added through the API records it.
Every request is scoped to the organization that owns the key. The free week that unlocks
the dashboard does not unlock this API. A paid subscription is required.
Blank fields are omitted from response objects. Empty summary domains are omitted from a
competitor dossier.
Every error is RFC 9457 problem details, sent as `application/problem+json`, with a
machine-readable `code` and a `hint`. See the `Problem` schema and
https://debriefing.io/developers#errors.
This file is also served as JSON at `/openapi.json`.'
contact:
name: Debriefing
url: https://debriefing.io
servers:
- url: https://debriefing.io
description: Production
security:
- bearerAuth: []
- apiKeyHeader: []
tags:
- name: Competitors
description: Competitors this workspace tracks.
paths:
/api/v1/competitors:
get:
tags:
- Competitors
operationId: listCompetitors
summary: List tracked competitors
description: 'Returns every competitor this workspace actively monitors, ordered by priority then
tracked date. Paused, removed, and pending-approval links are left out. Not paginated.'
responses:
'200':
description: The watchlist for this workspace.
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
type: array
items:
$ref: '#/components/schemas/CompetitorSummary'
meta:
$ref: '#/components/schemas/WatchlistMeta'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
post:
tags:
- Competitors
operationId: addCompetitor
summary: Add a competitor to the watchlist
description: 'Needs a key with the `watchlist:add` scope. A read-only key gets 403
`insufficient_scope`. Adds one competitor to the core watchlist from its website, the
same as adding it in the app: it uses one competitor slot, and Debriefing starts
monitoring it. When every slot is in use the answer is 402 `plan_limit_reached` with an
`upgrade_url`.
Idempotent by domain. When the website''s domain is already tracked, the answer is 200
with the existing competitor and `created: false`. Nothing is duplicated.
The competitor records the key that added it and the `X-Debriefing-Source` header.'
x-required-scope: watchlist:add
security:
- bearerAuth:
- watchlist:add
- apiKeyHeader:
- watchlist:add
parameters:
- name: X-Debriefing-Source
in: header
required: false
schema:
type: string
pattern: ^[a-z0-9][a-z0-9._-]{0,63}$
description: The client that sends the request, for attribution. For example `google-sheets-addon`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- website_url
properties:
website_url:
type: string
maxLength: 500
description: The competitor's website or domain, such as `acme.example` or `https://acme.example`.
responses:
'200':
description: The domain is already tracked. The existing competitor.
content:
application/json:
schema:
$ref: '#/components/schemas/AddCompetitorResult'
'201':
description: The competitor was added.
content:
application/json:
schema:
$ref: '#/components/schemas/AddCompetitorResult'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PlanLimitReached'
'403':
$ref: '#/components/responses/InsufficientScope'
'422':
$ref: '#/components/responses/UnprocessableContent'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
/api/v1/competitors/{id}:
get:
tags:
- Competitors
operationId: getCompetitor
summary: Get a competitor dossier
description: 'Returns the company record and the current intelligence reads for one competitor this
workspace tracks. Signals and the battlecard stay on their own routes; this response
names them under `links`.'
parameters:
- $ref: '#/components/parameters/CompetitorId'
responses:
'200':
description: The stored dossier for this competitor.
content:
application/json:
schema:
type: object
required:
- data
properties:
data:
$ref: '#/components/schemas/CompetitorDetail'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
components:
responses:
UnprocessableContent:
description: A value is not valid, for example a website_url that is not a public website.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-unprocessable_content
title: Unprocessable content
status: 422
detail: website_url must be a valid URL.
code: unprocessable_content
hint: Correct the value that the detail names. Then send the request again.
instance: /api/v1/competitors
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: website_url must be a valid URL.
InternalError:
description: An error occurred on the server. The body holds no internal detail.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-internal_error
title: Internal error
status: 500
detail: An error occurred on the server.
code: internal_error
hint: Send the request again later. If the error continues, email team@debriefing.io with the request_id.
instance: /api/v1/signals
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: An error occurred on the server.
NotFound:
description: No matching record in this workspace.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-not_found
title: Not found
status: 404
detail: No such competitor.
code: not_found
hint: Check the path and the id. The list routes, such as /api/v1/competitors, give the ids that this key can read.
instance: /api/v1/competitors/999
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: No such competitor.
Unauthorized:
description: Missing, wrong, or revoked API key.
headers:
WWW-Authenticate:
schema:
type: string
example: Bearer realm="Debriefing API"
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-invalid_api_key
title: API key missing or not valid
status: 401
detail: A valid API key is required.
code: invalid_api_key
hint: 'Send a valid key as Authorization: Bearer dbk_… or as X-API-Key. A workspace admin creates keys in Organization settings, under Integrations.'
instance: /api/v1/competitors
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: A valid API key is required.
BadRequest:
description: A parameter is not valid. For example, `since` is not an ISO 8601 time.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-invalid_request
title: Invalid request
status: 400
detail: since must be an ISO 8601 time.
code: invalid_request
hint: Correct the parameter that the detail names. Then send the request again.
instance: /api/v1/signals
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: since must be an ISO 8601 time.
PaymentRequired:
description: The key's organization does not have a paid subscription.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-paid_plan_required
title: Paid plan required
status: 402
detail: Choose a paid plan to use this feature.
code: paid_plan_required
hint: Choose a paid plan for this workspace on /pricing. The free week does not include the API.
instance: /api/v1/competitors
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: Choose a paid plan to use this feature.
InsufficientScope:
description: The key does not have the scope this route needs.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-insufficient_scope
title: Key scope missing
status: 403
detail: Adding a competitor needs a key with the watchlist:add scope. This key is read-only.
code: insufficient_scope
hint: This key is read-only. A workspace admin can create a key with the scope this route names, in Organization settings, under Integrations.
instance: /api/v1/competitors
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: Adding a competitor needs a key with the watchlist:add scope. This key is read-only.
PlanLimitReached:
description: 'Every competitor slot on the plan is in use. The body carries `upgrade_url` and
`competitor_slots`. A workspace without a paid plan gets `paid_plan_required` instead.
'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-plan_limit_reached
title: Plan limit reached
status: 402
detail: Acme tracks 5 of the 5 core competitors its plan allows.
code: plan_limit_reached
hint: Every competitor slot on this plan is in use. Remove a competitor in the app, or an admin can choose a larger plan at upgrade_url.
instance: /api/v1/competitors
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: Acme tracks 5 of the 5 core competitors its plan allows.
upgrade_url: https://debriefing.io/pricing
competitor_slots:
limit: 5
used: 5
remaining: 0
TooManyRequests:
description: This address sent more than 600 requests in one minute.
headers:
Retry-After:
description: Seconds to wait before the next request.
schema:
type: integer
example: 60
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
example:
type: https://debriefing.io/developers#errors-rate_limited
title: Too many requests
status: 429
detail: This address sent more than 600 requests in one minute.
code: rate_limited
hint: Wait for the number of seconds in the Retry-After header. Then send the request again.
instance: /api/v1/signals
request_id: 5f1c2b7e-9a41-4c1e-8d0e-2b1f3a6c7d80
error: This address sent more than 600 requests in one minute.
schemas:
CompetitorSummary:
type: object
required:
- id
- name
- watch
properties:
id:
type: integer
name:
type: string
website_url:
type: string
format: uri
category:
type: string
watch:
type: string
enum:
- core
- horizon
tracked_since:
type: string
format: date-time
url:
type: string
format: uri
description: Link to the competitor page in the app.
WatchlistMeta:
type: object
required:
- key_scopes
- competitor_slots
properties:
key_scopes:
type: array
items:
type: string
enum:
- watchlist:add
description: The scopes of the key that sent the request. Empty for a read-only key.
competitor_slots:
$ref: '#/components/schemas/CompetitorSlots'
CompetitorDetail:
type: object
required:
- id
- name
- watch
description: 'Company identity, workspace relationship, and current rolled-up reads. Internal fields
such as Brandfetch ids, discovery source, feature aliases, pricing snapshot ids, funding
source counts, comparison scores, and team notes are not included.
'
properties:
id:
type: integer
name:
type: string
description:
type: string
website_url:
type: string
format: uri
category:
type: string
industry:
type: string
company_type:
type: string
business_model:
type: string
company_size:
type: integer
founding_year:
type: integer
headquarters:
type: object
properties:
city:
type: string
country:
type: string
target_customer:
type: string
ownership:
type: object
properties:
type:
type: string
parent_company_name:
type: string
public:
type: boolean
ticker:
type: string
urls:
type: object
additionalProperties:
type: string
format: uri
description: 'Present keys may include `pricing`, `docs`, `changelog`, `careers`, `linkedin`,
`github`, `x`, `youtube`, `facebook`, `instagram`, and `tiktok`.
'
watch:
type: string
enum:
- core
- horizon
priority:
type: integer
tracked_since:
type: string
format: date-time
workspace:
type: object
properties:
relative_risk:
type: string
relative_opportunity:
type: string
icp_overlap:
type: object
additionalProperties: true
reads:
$ref: '#/components/schemas/CompetitorReads'
freshness:
type: object
properties:
state_updated_at:
type: string
format: date-time
last_signal_at:
type: string
format: date-time
last_snapshot_at:
type: string
format: date-time
links:
type: object
properties:
signals:
type: string
description: Relative path to list signals for this competitor.
example: /api/v1/signals?competitor_id=42
battlecard_id:
type: integer
description: Generated battlecard id when one exists.
url:
type: string
format: uri
description: Link to the competitor page in the app.
CompetitorSlots:
type: object
required:
- limit
- used
- remaining
properties:
limit:
type: integer
used:
type: integer
remaining:
type: integer
Problem:
type: object
description: 'RFC 9457 problem details, sent as `application/problem+json`. Every 4xx and 5xx
response of the read API has this shape. Branch on `code`, not on `detail` or `title`.
The `type` URL points at the row for the code on /developers.
'
required:
- type
- title
- status
- detail
- code
- hint
properties:
type:
type: string
format: uri
description: Documentation URL for this code, `https://debriefing.io/developers#errors-<code>`.
title:
type: string
description: Short summary of the code. The same for every problem with this code.
status:
type: integer
description: The HTTP status code.
detail:
type: string
description: What went wrong with this request.
code:
type: string
description: Machine-readable error code. Stable.
enum:
- invalid_request
- invalid_api_key
- paid_plan_required
- plan_limit_reached
- forbidden
- insufficient_scope
- not_found
- unprocessable_content
- rate_limited
- internal_error
hint:
type: string
description: What the client can do next.
instance:
type: string
description: The request path.
request_id:
type: string
description: The request id. Send it to support when you report an error.
error:
type: string
deprecated: true
description: The same text as `detail`. Kept for clients that read the old `{ "error" }` body.
upgrade_url:
type: string
format: uri
description: With `plan_limit_reached`. Where an admin chooses a larger plan.
competitor_slots:
$ref: '#/components/schemas/CompetitorSlots'
CompetitorReads:
type: object
description: 'Domain summaries from `competitor_state`. A domain appears only when something is
stored. Nested empty values are pruned. Shapes follow the research rollups and may gain
keys over time.
'
properties:
positioning:
type: string
product:
type: object
additionalProperties: true
pricing:
type: object
additionalProperties: true
ai:
type: object
additionalProperties: true
hiring:
type: object
additionalProperties: true
description: Includes `estimated_headcount` when known.
funding:
type: object
additionalProperties: true
description: Includes `estimated_revenue_text` and `ownership_summary` when known.
traffic:
type: object
additionalProperties: true
market:
type: object
additionalProperties: true
regulation:
type: object
additionalProperties: true
tech_stack:
type: object
additionalProperties: true
integrations:
type: object
additionalProperties: true
release_cadence:
type: object
additionalProperties: true
fortnight:
type: object
properties:
written_at:
type: string
format: date-time
sentences:
type: array
items:
type: object
additionalProperties: true
AddCompetitorResult:
type: object
required:
- data
- created
properties:
data:
$ref: '#/components/schemas/CompetitorSummary'
created:
type: boolean
description: True when this request added the competitor. False when it was already tracked.
parameters:
CompetitorId:
name: id
in: path
required: true
schema:
type: integer
description: Competitor id from the watchlist.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: dbk_
description: 'Send `Authorization: Bearer dbk_…`. The plain token is shown once when the key is
created. Only a SHA-256 digest is stored.
'
apiKeyHeader:
type: apiKey
in: header
name: X-API-Key
description: Alternative to Bearer. Send the same `dbk_…` token.