LLM-readable documentation index

Knowledge Graph API

Read entities and their relations across every document in a bucket

Hand off to an LLM

The Knowledge Graph API exposes the entity memory that bem builds as it parses documents. Where the File System API's find / open / xref ops let an agent walk entities one at a time, the Knowledge Graph endpoints let you read the graph itself — the entities (nodes) and the relations between them (edges) — either for a single entity or as a slice across a whole bucket.

GET /v3/entities/{id}/relations
GET /v3/knowledge-graph
x-api-key: <your API key>

Concepts

  • Entity — a canonical thing bem has recognized across documents: an organization, a person, a product, a location. Each entity has an id (ent_…), a canonical name, and a type.
  • Edge (relation) — a directed link between two entities, labeled with a relationType such as employs or acquired by. Every edge carries a mentionCount (how many parsed mentions support it) and a firstSeenAt timestamp.
  • Entity type — the category of an entity (organization, person, product, location, …). Used to filter the graph.
  • Bucket — a knowledge graph is scoped to a bucket (bkt_…). There is one knowledge graph per bucket. Pass bucket to read a single bucket's graph; omit it to read across all buckets in the account + environment.

These endpoints are the bulk-read counterpart to the File System memory ops: use find / open / xref when an agent is exploring one entity at a time, and the Knowledge Graph endpoints when you want the edges themselves — for example to render a graph or to walk relations programmatically.

GET /v3/entities/{id}/relations

Returns the inbound and outbound edges for a single entity.

ParamDefaultNotes
directionbothinbound, outbound, or both
relationTypeExact-match filter on the relation label
bucketall bucketsbkt_…; absent → all buckets in the account + environment
limit50Max 200
cursornextCursor from a previous response
curl "https://api.bem.ai/v3/entities/ent_acme/relations?direction=both&limit=50" \
  -H "x-api-key: $BEM_API_KEY"
{
  "inbound": [
    {
      "relationType": "owns",
      "sourceEntity": { "id": "ent_globex", "canonical": "Globex Holdings", "type": "organization" },
      "mentionCount": 3,
      "firstSeenAt": "2026-05-20T12:00:00Z"
    }
  ],
  "outbound": [
    {
      "relationType": "employs",
      "targetEntity": { "id": "ent_jane_doe", "canonical": "Jane Doe", "type": "person" },
      "mentionCount": 1,
      "firstSeenAt": "2026-05-21T08:30:00Z"
    }
  ],
  "nextCursor": "erl_1f3a9c"
}

Inbound edges point at the entity (the far end is sourceEntity); outbound edges point from it (the far end is targetEntity). Use direction to fetch one side only — direction=outbound omits the inbound array — and relationType to keep only edges with an exact label, e.g. ?relationType=employs.

Alias resolution. If {id} is an entity that was later merged away, the endpoint transparently resolves it to the surviving entity and returns that entity's edges. You never get an empty result just because you held onto an older, merged id.

GET /v3/knowledge-graph

Returns a slice of the graph — a set of nodes and the edges between them. Pagination is over edges (see below).

ParamDefaultNotes
typeall typesRepeatable: ?type=organization&type=person
searchSubstring match on entity canonical name
sinceRFC3339; edges first seen on or after this time
bucketall bucketsbkt_…; absent → all buckets in the account + environment
limit50Max 200
cursornextCursor from a previous response
curl "https://api.bem.ai/v3/knowledge-graph?type=organization&type=person&search=acme&limit=50" \
  -H "x-api-key: $BEM_API_KEY"
{
  "nodes": [
    { "id": "ent_acme", "canonical": "Acme Corporation", "type": "organization", "mentionCount": 12 }
  ],
  "edges": [
    { "sourceId": "ent_acme", "targetId": "ent_jane_doe", "relationType": "employs", "mentionCount": 4 }
  ],
  "nextCursor": "erl_8b2d0e"
}

Filter semantics

type[] and search filter entities, not edges directly. An edge appears in the response only when both of its endpoints survive the filter. So ?type=organization&type=person returns organization↔person, organization↔organization, and person↔person edges, but drops any edge with an endpoint that is neither an organization nor a person. search works the same way: both endpoints' canonical names are tested against the substring.

By design in Phase 1, an entity that has no edges does not appear as a node — the graph is built up from edges. (Use the File System API's find op to enumerate entities regardless of whether they participate in a relation.)

Edge pagination and node inclusion

Pagination is over edges. Each page returns up to limit edges, and the nodes array contains both endpoints of every edge on that page — even if the far endpoint's other edges fall on a later page. So a single node can appear across multiple pages whenever its edges span a page boundary; de-duplicate nodes by id if you are assembling the full graph client-side.

Pagination patterns

Both endpoints paginate by cursor. Read the first page, then pass the nextCursor you got back as the cursor of the next request:

# page 1
curl "https://api.bem.ai/v3/knowledge-graph?type=organization&limit=200" \
  -H "x-api-key: $BEM_API_KEY"

# page 2 — feed nextCursor from page 1 back in as cursor
curl "https://api.bem.ai/v3/knowledge-graph?type=organization&limit=200&cursor=erl_8b2d0e" \
  -H "x-api-key: $BEM_API_KEY"

A missing or empty nextCursor means you have reached the last page. limit defaults to 50 and is capped at 200; values above 200 are clamped.

The "find every document that mentions X" pattern — start from an entity, walk its relations, and follow the surviving endpoints — is already useful today via relations plus the File System API's xref. It becomes considerably more powerful once synonym resolution lands in Phase 4, when distinct surface forms of the same real-world thing collapse into a single entity and its edges.

See also

On this page