Find the insights and best practices about our product.
Bills of Materials

This endpoint returns Cranium's representation of the repositories and projects scanned in your tenant, so you can track scan status and vulnerability counts programmatically.

List Bills of Materials

Returns a paginated list of Bills of Materials (BOMs) for your tenant. A BOM represents one scanned repository or project and is the anchor object for the Public API: both the Technology Vulnerabilities and Arena Model Vulnerabilities endpoints reference a BOM by billOfMaterialsId.

Request

GET /api/public/billofmaterials

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_BOM_Read

Query Parameters

Parameter

Type

Value

limit

integer

Results per page. Maximum 200.

cursor

string

Sync cursor. Omit on the first call to begin from the beginning. Pass

nextCursor

from the previous response on subsequent calls.

updatedAfter

ISO 8601 timestamp

Return only records updated at or after this timestamp. Use to recover a lost cursor or reset to a known point in time.

Response Fields

Field

Type

Rules

billOfMaterialsId

GUID

Unique identifier for the BOM. Stable across updates.

name

string

BOM name, typically the repository or project name.

description

string or null

Optional description.

repositoryUrl

string or null

URL of the scanned repository. Null when the BOM is self-attested.

repositoryOrganization

string or null

Organization that owns the linked repository. Null when the BOM has no linked repository.

repositoryProject

string or null

Project that contains the linked repository. Provided for Azure DevOps, GitLab and Bitbucket repositories. Always null for GitHub, which has no project level, and null when the BOM has no linked repository.

vcsIntegrationId

GUID or null

Identifier of the VCS integration that scanned this repository, if any.

vcsIntegrationName

string or null

Name of the VCS integration that scanned this repository. Null when no integration is associated.

aiSystemIds

array of GUID

AI Systems this BOM belongs to. Empty when the BOM has not been assigned to an AI System.

lastScanStatus

string

One of Completed, Failed, InProgress, NotStarted, Pending, Queued, Unscanned.

lastScanStatusMessage

string or null

Additional detail on the scan status, when available.

totalVulnerabilitiesCount

integer

Total technology vulnerabilities found on this BOM.

totalResolvedVulnerabilitiesCount

integer

Of those, the count marked resolved.

modelCount

integer

Number of AI models associated with this BOM.

dataSetCount

integer

Number of datasets associated with this BOM.

technologyCount

integer

Number of technology packages/dependencies associated with this BOM.

infrastructureCount

integer

Number of infrastructure components associated with this BOM.

createdDate

ISO 8601 timestamp

When the BOM was created.

updatedDate

ISO 8601 timestamp

When the BOM was last modified. This is the field the sync cursor tracks.

Sample Response

{
"data": [
{
"billOfMaterialsId": "b7e23c1a-4f9d-4b2e-8c1a-9f6e3d4c5a7b",
"name": "my-ml-service",
"description": "Production fraud-detection model serving infrastructure",
"repositoryUrl": "https://github.com/contoso/my-ml-service",
"repositoryOrganization": "contoso",
"repositoryProject": null,
"vcsIntegrationId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"vcsIntegrationName": "Our GitHub",
"aiSystemIds": ["a2d78b6f-9c4c-4a7d-d16f-4e1d8c9b0f20"],
"lastScanStatus": "Completed",
"lastScanStatusMessage": null,
"totalVulnerabilitiesCount": 12,
"totalResolvedVulnerabilitiesCount": 3,
"modelCount": 2,
"dataSetCount": 1,
"technologyCount": 47,
"infrastructureCount": 0,
"createdDate": "2026-01-10T08:00:00Z",
"updatedDate": "2026-04-14T15:32:00Z"
},
{
"billOfMaterialsId": "c8f34d2b-5e0e-4c3f-9d2b-0a7f4e5d6b8c",
"name": "fraud-detection-pipeline",
"description": null,
"repositoryUrl": "https://github.com/contoso/fraud-detection-pipeline",
"repositoryOrganization": "contoso",
"repositoryProject": null,
"vcsIntegrationId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"vcsIntegrationName": "Our GitHub",
"aiSystemIds": [],
"lastScanStatus": "InProgress",
"lastScanStatusMessage": "Scanning packages (74/120)",
"totalVulnerabilitiesCount": 0,
"totalResolvedVulnerabilitiesCount": 0,
"modelCount": 0,
"dataSetCount": 0,
"technologyCount": 0,
"infrastructureCount": 0,
"createdDate": "2026-05-20T12:14:00Z",
"updatedDate": "2026-06-02T09:58:21Z"
},
{
"billOfMaterialsId": "d9a45e3c-6f1f-4d4a-ae3c-1b8a5f6e7c9d",
"name": "customer-support-bot",
"description": "LLM-backed customer support assistant",
"repositoryUrl": "https://bitbucket.org/contoso/support-bot",
"repositoryOrganization": "contoso",
"repositoryProject": "SUP",
"vcsIntegrationId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"vcsIntegrationName": "Bitbucket Support Team",
"aiSystemIds": [
"a2d78b6f-9c4c-4a7d-d16f-4e1d8c9b0f20",
"b3e89c7a-0d5d-4b8e-e27a-5f2e9d0a1f31"
],
"lastScanStatus": "Failed",
"lastScanStatusMessage": "Could not resolve dependency manifest: requirements.lock not found",
"totalVulnerabilitiesCount": 8,
"totalResolvedVulnerabilitiesCount": 8,
"modelCount": 1,
"dataSetCount": 0,
"technologyCount": 23,
"infrastructureCount": 0,
"createdDate": "2025-11-03T14:22:00Z",
"updatedDate": "2026-06-01T20:11:09Z"
}
],
"pagination": {
"limit": 100,
"nextCursor": "eyJ1cGRhdGVkQXQiOiIyMDI2LTA2LTAxVDIwOjExOjA5WiIsImlkIjoiZDlhNDVlM2MifQ==",
"hasMore": true
},
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-06-02T10:00:00Z"
}
}

aiSystemIds lists every AI System this BOM belongs to. A BOM can be associated with more than one AI System, and the array is empty when the BOM hasn't been assigned to any. vcsIntegrationId and vcsIntegrationName identify the VCS integration that scanned the repository, denormalized for convenience; both are null when no integration is associated. repositoryOrganization and repositoryProject identify where the linked repository lives. Both are null when the BOM has no linked repository. repositoryProject is provided for Azure DevOps, GitLab and Bitbucket, and is always null for GitHub. updatedDate advances whenever the BOM's scan status or any of its counts change, so it's the field the sync cursor tracks. hasMore: false with a non-null nextCursor is the normal end-of-feed state; store the cursor and replay it on your next poll.

While a scan is in progress (lastScanStatus: "InProgress"), counts read zero until the scan completes. When a scan fails, counts reflect the last successful scan, and lastScanStatusMessage gives the reason. Counts give totals only. To read the items themselves, use the Bill of Materials item feeds, for example GET /api/public/billofmaterials/technologies.

Error Responses

  • 400 VALIDATION_FAILED: the cursor is invalid, or cursor and updatedAfter were supplied together.
  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_BOM_Read.
  • 500 INTERNAL_ERROR: an unexpected server error.

Trigger a CodeSensor Scan

Queues a CodeSensor scan for a specific Bill of Materials. Use this to trigger a scan programmatically, for example as a step in a CI/CD pipeline after a merge.

Request

POST /api/public/billofmaterials/{billOfMaterialsId}/scan

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_BOM_Scan. This is granted separately from Api_BOM_Read, so a client that can list Bills of Materials cannot necessarily trigger scans on them.

Response Fields

A successful request returns 200 OK, not 201 Created. Nothing is created at a retrievable URL: the call queues asynchronous work and hands back its identifier. A 200 means the scan was accepted, not that it finished; results arrive minutes later.

Field

Type

Rules

billOfMaterialsId

GUID

Identifier of the Bill of Materials the scan was queued for.

jobId

GUID

Identifier for the queued scan job. Not retrievable through a separate endpoint.

Sample Response

{
"data": {
"billOfMaterialsId": "8f2c41d6-93b7-4a5e-b0c2-7d1e4f8a92b3",
"jobId": "5e91b47c-2a08-4c63-9f4d-1b6e83d0a5c7"
},
"pagination": null,
"error": null,
"meta": {
"requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"timestamp": "2026-09-21T09:14:22Z"
}
}

Record the returned jobId for support correlation, then poll List Bills of Materials (or the single-BOM lookup) every 30–60 seconds until lastScanStatus reaches Completed or Failed; once complete, pull findings from the Technology Vulnerabilities endpoint using your existing sync cursor. This endpoint is not idempotent: if a request times out and you retry it, a 409 CONFLICT response may mean the original request actually succeeded. Treat that as confirmation the scan is queued, not a failure, and recover the job by checking lastScanStatus.

Error Responses

  • 404 NOT_FOUND: the Bill of Materials doesn't exist, or belongs to another tenant. Both cases return the same response, so this endpoint won't confirm whether a resource exists in a tenant you don't own. No scan is queued.
  • 409 CONFLICT: a scan is already queued, in progress, or pending for this Bill of Materials. This is safe to receive and doesn't queue a duplicate job; treat it as a signal to back off rather than retry immediately.
  • 400 VALIDATION_FAILED: the scan was refused for a specific reason, returned in the message. The most common case is triggering a scan against a repository that hasn't changed since the last one (and the CodeSensor engine version hasn't moved either), which would just repeat the same result. Other cases: the Bill of Materials has no repository to scan, or its stored repository URL is invalid.
  • 401 UNAUTHORIZED: the request is missing a token, or the token's role lacks Api_BOM_Scan.
  • 500 INTERNAL_ERROR: an unexpected server error.
Did this answer your question?