GET/v1/products/{productId}/findings
List what was found in a product
Returns the findings of the product's monitored uploads (every release on
the market, and the latest upload), each naming its upload and release: a
vulnerability carried by two monitored releases is two findings. The ones
for vulnerabilities known to be exploited come first, then by severity, then
newest. That order is the order to
work in: an actively exploited vulnerability is what starts the Cyber
Resilience Act's 24-hour report.
Whether a vulnerability is exploited is resolved when the request is
answered, not stored on the finding, because a vulnerability becomes
exploited later and that moment is what matters.
Requires the scope findings:read.
Scope: findings:read
Parameters
Responses
200 The product's findings. FindingList
{
"findings": [
{
"id": "a1c3e5f7-0b2d-4e6f-8a91-b2c3d4e5f607",
"component": {
"name": "golang.org/x/net",
"version": "0.38.0",
"purl": "pkg:golang/golang.org/x/net@0.38.0"
},
"vulnerability": {
"id": "GHSA-qppj-fm5r-hxr3",
"summary": "HTTP/2 rapid reset can cause excessive work in net/http",
"severity": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"severity_type": "CVSS_V3",
"url": "https://osv.dev/vulnerability/GHSA-qppj-fm5r-hxr3"
},
"evidence": "range",
"matched_range": ">=0, <0.38.1",
"state": "open",
"exploited": true,
"exploited_cve": "CVE-2023-44487",
"exploited_since": "2023-10-10",
"ransomware": false,
"first_seen_at": "2026-09-19T05:02:18Z",
"last_seen_at": "2026-09-21T05:01:47Z",
"sbom_id": "5d7e9f10-2b4c-4d6e-8f90-a1b2c3d4e5f6",
"release": "2.4.1"
}
],
"total": 7,
"exploited": 1
}
Example
curl --fail-with-body -sS \
-H "Authorization: Bearer $BITHIVE_TOKEN" \
"https://app.bithive-it.com/v1/products/$PRODUCTID/findings"
POST/v1/products/{productId}/decisions
Record a VEX statement on a product's findings
Records the account's own statement about one or more named releases of the
product and one vulnerability: whether the release is affected, and why. One
statement is written per release, so a statement can be given to every
monitored release carrying the same component version at once. Each release
must be one a finding of the product for the vulnerability was made in.
A statement is never edited. A change is a new statement that names the one it
supersedes, and the newest is the current decision. The token acts as the user
who created it: an Owner, Administrator or Member records where no statement is
current, and only an Owner or Administrator replaces a current one.
Each status has its own rules, based on the VEX profile of CSAF 2.0: not_affected
takes a justification or an impact_statement, or both, and no action;
affected takes an action_category and an action_statement and no
justification; fixed and under_investigation take neither. A member the
status does not take is refused, not dropped.
A statement never changes a case or its deadlines.
Takes an Idempotency-Key. Requires the scope findings:decide.
Scope: findings:decide
Parameters
Request body
{
"releases": [
"2.4.1",
"2.5.0"
],
"vulnerability": "GHSA-qppj-fm5r-hxr3",
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path"
}
Responses
201 The statements, one per release. DecisionList
{
"decisions": [
{
"id": "0d1e2f30-4a5b-4c6d-8e7f-90a1b2c3d4e5",
"release": "2.4.1",
"vulnerability": "GHSA-qppj-fm5r-hxr3",
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"decided_at": "2026-10-30T09:15:00Z",
"stale": false
}
]
}
400 The body is not the JSON the contract names, or a query parameter is missing. Problem
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Send the decision as a JSON object with the members the contract names."
}
409 A request with the same Idempotency-Key is still running. Problem
Example
422 The statement breaks a rule of its status, or names no release, or the Idempotency-Key was sent with another request. Problem
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"detail": "not_affected needs a justification or an impact_statement."
}
Example
curl --fail-with-body -sS -X POST \
-H "Authorization: Bearer $BITHIVE_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @new-decision.json \
"https://app.bithive-it.com/v1/products/$PRODUCTID/decisions"
GET/v1/products/{productId}/decisions/history
Read the statements on one release and vulnerability
Returns every statement recorded about one release of the product and one
vulnerability, newest first. The first is the current decision.
Requires the scope findings:read.
Scope: findings:read
Parameters
Responses
400 The body is not the JSON the contract names, or a query parameter is missing. Problem
Example
Example
curl --fail-with-body -sS \
-H "Authorization: Bearer $BITHIVE_TOKEN" \
"https://app.bithive-it.com/v1/products/$PRODUCTID/decisions/history"
GET/v1/products/{productId}/vex
Download a product's VEX document
Returns the product's current statements as an OpenVEX document (v0.2.0) or a
CycloneDX VEX (specification 1.6). Each release is named by the package URL its
own SBOM gives its subject, or else by urn:bithive:product:<product id>:<release>.
A finding without a statement is not in the document, and the document names
no person, only when each statement was made.
The token acts as the user who created it, who must be an Owner or Administrator.
An account can export at most three VEX documents an hour.
Requires the scope findings:read.
Scope: findings:read
Parameters
Responses
200 The VEX document.
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "urn:uuid:11111111-2222-4333-8444-555555555555",
"author": "ACME GmbH",
"timestamp": "2026-10-31T12:00:00Z",
"version": 1,
"tooling": "BitHive Reporting Desk",
"statements": [
{
"vulnerability": {
"name": "GHSA-qppj-fm5r-hxr3"
},
"timestamp": "2026-10-30T09:15:00Z",
"products": [
{
"@id": "urn:bithive:product:6f1c2a3b-4d5e-4f60-8a71-9b0c1d2e3f40:2.4.1",
"subcomponents": [
{
"@id": "pkg:golang/golang.org/x/net@0.38.0"
}
]
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path"
}
]
}
400 The body is not the JSON the contract names, or a query parameter is missing. Problem
Example
409 The product has no statement yet. An OpenVEX v0.2.0 document needs at least
one statement, so `format=openvex` is refused until a statement is recorded;
`format=cyclonedx` returns an empty `vulnerabilities` list. Nothing is
exported, nothing is written to the audit log, and the refusal does not count
against the three exports an hour.
Problem
Example
Example
curl --fail-with-body -sS \
-H "Authorization: Bearer $BITHIVE_TOKEN" \
"https://app.bithive-it.com/v1/products/$PRODUCTID/vex"
GET/v1/products/{productId}/coverage
Read how much of a product can be checked
Returns how many components of the product's latest upload we can check,
and names what it cannot. Results depend on the completeness of the bill of
materials, so the uncovered part is named rather than merely subtracted: a
client can see which ecosystems are not covered and why.
A component is not monitored when it carries no package identifier (common
in firmware built with Yocto or Buildroot), when it names no version, or
when it belongs to an ecosystem whose matching is not yet proven.
Requires the scope findings:read.
Scope: findings:read
Parameters
Responses
200 What the product's latest upload could be checked against. Coverage
{
"sbom_id": "5d7e9f10-2b4c-4d6e-8f90-a1b2c3d4e5f6",
"components": 412,
"monitored": 389,
"monitored_percent": 94.4,
"not_monitored": [
{
"reason": "no package identifier",
"components": 14
},
{
"reason": "ecosystem not supported yet",
"ecosystem": "alpine",
"components": 9
}
]
}
Example
curl --fail-with-body -sS \
-H "Authorization: Bearer $BITHIVE_TOKEN" \
"https://app.bithive-it.com/v1/products/$PRODUCTID/coverage"