Find the insights and best practices about our product.
Endpoint Reference: Bill of Materials Feeds

These endpoints return the items inside each Bill of Materials across your tenant: technologies, models, datasets, infrastructure and agentic systems. Use them to sync the contents of your Bills of Materials into your own systems without the Application UI.

Syncing Bill of Materials Items

All five feeds share the same authentication, permission, query parameters, pagination and sync rules. This section states them once. The sections that follow give the request, fields and a sample response for each feed.

Authentication

Bearer token. See Authentication & Generating Credentials.

Required Permission

Api_BOM_Read. This is the same permission used by List Bills of Materials.

Query Parameters

Parameter

Type

Value

billOfMaterialsId

GUID

Optional. Limits the feed to one Bill of Materials. Omit it to read items across all your Bills of Materials. An unknown id, or one in another tenant, returns an empty page rather than a 404.

limit

integer

Results per page. Default 100. Maximum 1,000. A higher value is rejected, not reduced to 1,000. A value of 0 or less is treated as the default of 100.

cursor

string

Sync cursor. Omit on the first call to begin from the beginning. Pass nextCursor from the previous response on subsequent calls. A cursor works only for the feed and the billOfMaterialsId it was issued for.

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. Cannot be sent together with cursor.

These feeds are cursor-paginated. The page parameter is not supported.

Pagination

Every response uses the same envelope.

Field

Type

Rules

data

array

The records on this page.

pagination.nextCursor

string

Cursor to send as cursor on the next call.

pagination.hasMore

boolean

true when more records are waiting. false at the end of the feed.

pagination.limit

integer

The page size you requested. Present only when limit was sent.

error

object or null

Null on success. On failure, holds code, message and traceId.

meta

object

requestId and timestamp for the request.

hasMore: false with a non-null nextCursor is the normal end-of-feed state. Keep the last nextCursor and send it on your next sync. That call returns only items added or changed since.

Keeping a Complete Copy

The cursor returns new and changed items. Three cases need extra handling.

  • Removed items are not reported. An item removed from a Bill of Materials does not appear in the feed again. Re-read each feed periodically without a cursor and treat items missing from that full read as removed.
  • Changed agentic systems get a new id. A rescan that changes an agentic system replaces it under a new agenticSystemId. The old id is not reported as removed. The periodic full read also catches these.
  • Late records can fall behind the cursor. Records saved late by a scan can appear behind a cursor already returned. For a complete incremental sync, use updatedAfter set a few minutes before the last updatedAt you received.

updatedAt on every feed is UTC, even though it is written without a trailing Z.

List Technologies

Returns the software packages and dependencies found in your Bills of Materials, with an AI label on each.

Request

GET /api/public/billofmaterials/technologies

Response Fields

Field

Type

Rules

billOfMaterialsItemId

GUID

Identifier for the technology record.

billOfMaterialsId

GUID

Bill of Materials the technology belongs to. Correlates with the Bills of Materials endpoint.

name

string

Package name.

version

string

Package version.

language

array of string

Languages the package was detected in, for example python.

dependencyType

string

Direct or Transitive.

dependencyDepth

integer or null

Depth of the dependency. 1 means the project declares the package directly. 2 or more means the package is transitive. The value is never 0. The value is null when CodeSensor cannot work out the dependency tree. This happens for Go and Java projects, for a manifest with no lockfile, for a library found only from a code import, for a package in the lockfile that nothing declares, and for a Bill of Materials that has not been rescanned since this field was added. A direct dependency can also have a null depth.

dependencyGroup

string or null

Dependency group the package was declared in, for example main, when known.

isAi

boolean or null

true when the technology matches Cranium's AI package list, false when it does not, null when it was not evaluated. Only Python, JavaScript and TypeScript, Java, C#, Go and Rust technologies are evaluated.

source

string

How the scan detected the technology, for example requirements. The value comes from the scan, so treat it as an open string.

filePath

array of string

Files where the technology was found.

updatedAt

timestamp (UTC)

The field the sync cursor and updatedAfter track.

Sample Response

{
"data": [
{
"billOfMaterialsItemId": "3f6c2a1e-8b4d-4c2a-9e51-0d7a6b2c4f10",
"billOfMaterialsId": "a1b2c3d4-5e6f-4a1b-8c9d-0e1f2a3b4c5d",
"name": "langchain",
"version": "0.2.16",
"language": ["python"],
"dependencyType": "Direct",
"dependencyDepth": 1,
"dependencyGroup": "main",
"isAi": true,
"source": "requirements",
"filePath": ["services/agent/requirements.txt"],
"updatedAt": "2026-10-20T14:32:07.113226"
},
{
"billOfMaterialsItemId": "9d0e4b7a-2c31-4f8e-b6a2-5e1c7d9f0a32",
"billOfMaterialsId": "a1b2c3d4-5e6f-4a1b-8c9d-0e1f2a3b4c5d",
"name": "urllib3",
"version": "2.2.3",
"language": ["python"],
"dependencyType": "Transitive",
"dependencyDepth": 3,
"dependencyGroup": null,
"isAi": false,
"source": "requirements",
"filePath": ["services/agent/requirements.txt"],
"updatedAt": "2026-10-20T14:32:07.113226"
}
],
"pagination": {
"limit": 2,
"nextCursor": "eyJ1cGRhdGVkQXQiOiIyMDI2LTEwLTIwVDE0OjMyOjA3LjExMzIyNjAiLCJpZCI6IjlkMGU0YjdhLTJjMzEtNGY4ZS1iNmEyLTVlMWM3ZDlmMGEzMiJ9",
"hasMore": true
},
"error": null,
"meta": {
"requestId": "6b2f0c4e-1d3a-4f7b-9c8e-2a5d1e0f3b47",
"timestamp": "2026-10-22T15:04:11.5720000Z"
}
}

This sample was requested with limit=2. langchain is a direct dependency on Cranium's AI package list. urllib3 is a transitive dependency that is not.

List Models

Returns the AI models found in your Bills of Materials, with Cranium's confidence in each detection and a link to Cranium Arena when the model has a match there.

Request

GET /api/public/billofmaterials/models

Response Fields

Field

Type

Rules

billOfMaterialsItemId

GUID

Identifier for the model record.

billOfMaterialsId

GUID

Bill of Materials the model belongs to. Correlates with the Bills of Materials endpoint.

name

string

Model name as found in the code.

standardizedName

string

Standardized model name, for example all-MiniLM-L6-v2 for sentence-transformers/all-MiniLM-L6-v2.

confidenceLevel

string

Cranium's confidence in the detection. One of high, medium, low.

modelType

string

One of GenAI, DL, TradML, Unknown.

source

string

How the scan detected the model, for example llm. The value comes from the scan, so treat it as an open string.

referenceUrl

string

Link to the model's reference page.

filePath

array of string

Files where the model was found.

arenaModelId

GUID or null

Joins to modelId on the Arena Models endpoint. Null when the model has no Arena match.

updatedAt

timestamp (UTC)

The field the sync cursor and updatedAfter track.

Sample Response

{
"data": [
{
"billOfMaterialsItemId": "c4a7e2f1-6b3d-4e9a-8f2c-1d5b7a9e3c60",
"billOfMaterialsId": "a1b2c3d4-5e6f-4a1b-8c9d-0e1f2a3b4c5d",
"name": "gpt-4o",
"standardizedName": "gpt-4o",
"confidenceLevel": "high",
"modelType": "GenAI",
"source": "llm",
"referenceUrl": "https://platform.openai.com/docs/models/gpt-4o",
"filePath": ["services/agent/llm_client.py"],
"arenaModelId": "7e1d9c3b-2a4f-4b8e-9d6c-5f0a1b2c3d4e",
"updatedAt": "2026-10-20T14:32:07.113226"
},
{
"billOfMaterialsItemId": "e8b3d1c9-4f2a-4a6e-b7d5-3c9e1f0a2b81",
"billOfMaterialsId": "a1b2c3d4-5e6f-4a1b-8c9d-0e1f2a3b4c5d",
"name": "sentence-transformers/all-MiniLM-L6-v2",
"standardizedName": "all-MiniLM-L6-v2",
"confidenceLevel": "medium",
"modelType": "DL",
"source": "llm",
"referenceUrl": "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2",
"filePath": ["services/search/embeddings.py"],
"arenaModelId": null,
"updatedAt": "2026-10-20T14:32:07.113226"
}
],
"pagination": {
"limit": 2,
"nextCursor": "eyJ1cGRhdGVkQXQiOiIyMDI2LTEwLTIwVDE0OjMyOjA3LjExMzIyNjAiLCJpZCI6ImU4YjNkMWM5LTRmMmEtNGE2ZS1iN2Q1LTNjOWUxZjBhMmI4MSJ9",
"hasMore": true
},
"error": null,
"meta": {
"requestId": "0f3a9b2c-7e4d-4c1a-8b5f-6d2e9a1c0b38",
"timestamp": "2026-10-22T15:04:12.0410000Z"
}
}

gpt-4o has an Arena match, so arenaModelId is set. The second model has no Arena match, so arenaModelId is null.

List Datasets

Returns the datasets found in your Bills of Materials.

Request

GET /api/public/billofmaterials/datasets

Response Fields

Field

Type

Rules

billOfMaterialsItemId

GUID

Identifier for the dataset record.

billOfMaterialsId

GUID

Bill of Materials the dataset belongs to. Correlates with the Bills of Materials endpoint.

name

string

Dataset name.

description

string or null

Description of the dataset.

source

string

How the scan detected the dataset, for example llm. The value comes from the scan, so treat it as an open string.

filePath

array of string

Files where the dataset was found.

updatedAt

timestamp (UTC)

The field the sync cursor and updatedAfter track.

Sample Response

This sample reads one Bill of Materials with billOfMaterialsId and no limit, so pagination has no limit field.

{
"data": [
{
"billOfMaterialsItemId": "5a2c8e1f-3b7d-4f9a-a6c4-2e8d0b1f7c93",
"billOfMaterialsId": "a1b2c3d4-5e6f-4a1b-8c9d-0e1f2a3b4c5d",
"name": "customer_support_transcripts",
"description": "Support conversation transcripts used to fine-tune the triage classifier.",
"source": "llm",
"filePath": ["training/prepare_dataset.py", "training/config.yaml"],
"updatedAt": "2026-10-20T14:32:07.113226"
}
],
"pagination": {
"nextCursor": "eyJ1cGRhdGVkQXQiOiIyMDI2LTEwLTIwVDE0OjMyOjA3LjExMzIyNjAiLCJpZCI6IjVhMmM4ZTFmLTNiN2QtNGY5YS1hNmM0LTJlOGQwYjFmN2M5MyJ9",
"hasMore": false
},
"error": null,
"meta": {
"requestId": "d7c1e4a9-2b6f-4e3d-8a0c-9f5b1d2e7a64",
"timestamp": "2026-10-22T15:04:12.6930000Z"
}
}

List Infrastructure

Returns the infrastructure components found in your Bills of Materials, such as hosted model endpoints.

Request

GET /api/public/billofmaterials/infrastructure

Response Fields

Field

Type

Rules

billOfMaterialsItemId

GUID

Identifier for the infrastructure record.

billOfMaterialsId

GUID

Bill of Materials the component belongs to. Correlates with the Bills of Materials endpoint.

name

string

Component name.

description

string or null

Description of the component.

source

string

How the scan detected the component, for example llm. The value comes from the scan, so treat it as an open string.

filePath

array of string

Files where the component was found.

updatedAt

timestamp (UTC)

The field the sync cursor and updatedAfter track.

Sample Response

{
"data": [
{
"billOfMaterialsItemId": "b6e0f3a2-9c4d-4b1e-8f7a-0d3c5e2a9b15",
"billOfMaterialsId": "a1b2c3d4-5e6f-4a1b-8c9d-0e1f2a3b4c5d",
"name": "Azure OpenAI",
"description": "Hosted model endpoint used for completions in the agent service.",
"source": "llm",
"filePath": ["infra/main.bicep"],
"updatedAt": "2026-10-20T14:32:07.113226"
}
],
"pagination": {
"limit": 1,
"nextCursor": "eyJ1cGRhdGVkQXQiOiIyMDI2LTEwLTIwVDE0OjMyOjA3LjExMzIyNjAiLCJpZCI6ImI2ZTBmM2EyLTljNGQtNGIxZS04ZjdhLTBkM2M1ZTJhOWIxNSJ9",
"hasMore": true
},
"error": null,
"meta": {
"requestId": "8a4d2f6b-1c9e-4a7d-b3f0-5e2c8d1a6b79",
"timestamp": "2026-10-22T15:04:13.2210000Z"
}
}

List Agentic Systems

Returns the agentic systems found in your Bills of Materials. Each record is one agentic system. Its agents and the relations between them are nested inside the record, not returned as separate records.

A rescan that changes an agentic system replaces it under a new agenticSystemId, and the old id is not reported as removed. See Keeping a Complete Copy above.

Request

GET /api/public/billofmaterials/agenticsystems

Response Fields

Field

Type

Rules

agenticSystemId

GUID

Identifier for the agentic system. Changes when a rescan changes the system.

billOfMaterialsId

GUID

Bill of Materials the agentic system belongs to. Correlates with the Bills of Materials endpoint.

name

string

Agentic system name.

framework

string

Agent framework the system is built on, for example openai-agents.

agents

array of object

Agents in the system. See Agent Fields.

relations

array of object

Connections between agents and the tools they use. See Relation Fields.

updatedAt

timestamp (UTC)

The field the sync cursor and updatedAfter track.

Agent Fields

Field

Type

Rules

agentId

GUID

Identifier for the agent.

name

string

Agent name.

model

string or null

Model the agent uses.

description

string or null

Description of the agent.

instructions

string or null

Instructions given to the agent.

tools

array of string

Names of the tools the agent can call.

handoffs

array of string

Names of the agents this agent can hand off to.

inputGuardrails

array of string

Names of the guardrails applied to the agent's input.

outputGuardrails

array of string

Names of the guardrails applied to the agent's output.

mcpServers

array of string

Names of the MCP servers the agent connects to.

filePath

array of string

Files where the agent was found.

source

string

How the scan detected the agent, for example deterministic_ast. The value comes from the scan, so treat it as an open string.

language

string

Language the agent is written in, for example python. The value comes from the scan, so treat it as an open string.

Relation Fields

Field

Type

Rules

type

string

Kind of relation, for example handoff or tool. The value comes from the scan, so treat it as an open string.

source

object

Where the relation starts. Holds type (for example agent) and content (the name, for example Triage Agent).

destination

object

Where the relation ends. Holds type (for example agent or tool) and content (the name).

Sample Response

{
"data": [
{
"agenticSystemId": "2d9f7b1c-4e6a-4c3b-a8d2-7f1e0c5b9a46",
"billOfMaterialsId": "a1b2c3d4-5e6f-4a1b-8c9d-0e1f2a3b4c5d",
"name": "Support triage",
"framework": "openai-agents",
"agents": [
{
"agentId": "6c1e8a3f-2b9d-4f5a-b7e0-3d4c9a1f8e52",
"name": "Triage Agent",
"model": "gpt-4o",
"description": "Routes customer requests to the right specialist.",
"instructions": "Classify the request and hand off to the billing or technical agent.",
"tools": ["lookup_account"],
"handoffs": ["Billing Agent", "Technical Agent"],
"inputGuardrails": ["pii_filter"],
"outputGuardrails": [],
"mcpServers": [],
"filePath": ["services/agent/triage.py"],
"source": "deterministic_ast",
"language": "python"
},
{
"agentId": "f4b2d9e6-7a1c-4e8b-9c3d-0a5f2e7b1c68",
"name": "Billing Agent",
"model": "gpt-4o-mini",
"description": "Answers billing questions.",
"instructions": "Answer billing questions using the account tools.",
"tools": ["lookup_invoice", "issue_refund"],
"handoffs": [],
"inputGuardrails": [],
"outputGuardrails": [],
"mcpServers": ["billing-mcp"],
"filePath": ["services/agent/billing.py"],
"source": "deterministic_ast",
"language": "python"
}
],
"relations": [
{
"type": "handoff",
"source": { "type": "agent", "content": "Triage Agent" },
"destination": { "type": "agent", "content": "Billing Agent" }
},
{
"type": "tool",
"source": { "type": "agent", "content": "Billing Agent" },
"destination": { "type": "tool", "content": "issue_refund" }
}
],
"updatedAt": "2026-10-20T14:32:07.113226"
}
],
"pagination": {
"limit": 1,
"nextCursor": "eyJ1cGRhdGVkQXQiOiIyMDI2LTEwLTIwVDE0OjMyOjA3LjExMzIyNjAiLCJpZCI6IjJkOWY3YjFjLTRlNmEtNGMzYi1hOGQyLTdmMWUwYzViOWE0NiJ9",
"hasMore": false
},
"error": null,
"meta": {
"requestId": "3e7b0d5a-9f2c-4d6e-a1b8-4c0f7e2d9a13",
"timestamp": "2026-10-22T15:04:13.8050000Z"
}
}

Error Responses

All five feeds return the same errors.

  • 400 BAD_REQUEST: the request was rejected. The message says why.
    • limit must be 1000 or less.
    • cursor and updatedAfter are mutually exclusive.
    • page is not supported; this feed is cursor-paginated.
    • Invalid cursor value. The cursor is malformed, or it was issued for another feed or another billOfMaterialsId.
  • 401 UNAUTHORIZED: the request is missing a token, or the token lacks Api_BOM_Read.
  • 500 INTERNAL_ERROR: an unexpected server error.
{
"data": null,
"pagination": null,
"error": {
"code": "BAD_REQUEST",
"message": "limit must be 1000 or less.",
"traceId": "0HNOVC2K1R7QD:00000001"
},
"meta": {
"requestId": "c2e7a1d4-8b3f-4e6a-9d0c-5f1b2a7e4c83",
"timestamp": "2026-10-22T15:04:15.4470000Z"
}
}

Every error response includes error.traceId. Include it when reporting an issue to Cranium support.