Rebuilding the Graph
This tutorial shows how to run a graph rebuild job: when to use one, how to choose a rebuild mode, how to keep the job scoped to the documents you mean, and how to follow it to completion. A rebuild job selects documents with an HXQL query and submits them to Context for reprocessing into the knowledge graph. Which documents are reprocessed depends on the rebuild mode.
Prerequisites
- A valid access token (see Authentication)
- The base URL of your environment
content-lake-api.graph-jobs.createandcontent-lake-api.graphs.editto submit a job, andcontent-lake-api.graph-jobs.readto monitor it (all three are in the Content Lake ECE Administrator role)- A graph database with ontology routes (see Setting Up the Knowledge Graph)
Set two variables before running the curl examples. The HTTP examples use the equivalent {{baseUrl}} and {{accessToken}} placeholders.
export BASE_URL="https://{environment_id}.content-lake.ai.experience.hyland.com"
export TOKEN="<access token from the identity provider>"
All endpoints require an authenticated caller with the permissions listed in the prerequisites. A caller without the required permissions receives 401 Unauthorized.
Tutorial Overview
In this tutorial, you'll learn to:
- Decide when to rebuild and which mode to use
- Scope a rebuild to one graph database
- Submit a rebuild job
- Poll the job until it finishes
- List jobs and filter by state
- Recognize the validation errors
Step 1: Choose When and How to Rebuild
Rebuild after you add or change ontology routes, so that documents already in the Cloud Content Repository are evaluated against them, or to recover the graph (bootstrap and disaster recovery).
| Mode | Description |
|---|---|
STANDARD | Evaluates the ontology rules again. An event is fired and submitted to Context for reprocessing only for documents whose ontology references were updated. Use after ontology or route changes. |
EVENT_ONLY | Fires events based on the results of the previous rule execution, without evaluating the rules again. Use when the rules have not changed but you want to reprocess the documents anyway. |
FORCE_REPROCESS | Fires an event and submits it to Context for reprocessing for every document that matches the ontology configuration, including documents whose ontology references did not change. Use to force extraction to run again. |
Step 2: Scope the Rebuild
A rebuild with no graphDBId and no query covers the routes of every configured graph database. To limit a rebuild to one graph database, pass its graphDBId. The generated query is then scoped to that graph database's route conditions only, and it never falls back to "all documents": if there are no routes, the request is rejected.
graphDBId only selects which documents the job processes. Each selected document is still evaluated against the routes of every graph database, so its graph properties can also reference other graph databases whose routes match it.
| Field | Type | Required | Description |
|---|---|---|---|
repository | string | No | Repository name. Defaults to "default". |
graphDBId | string | No | Limit the auto-generated query to the ontology routes of this graph database. If omitted, the routes of all configured graph databases are used. Cannot be combined with query. |
rebuildMode | string | No | One of the rebuild modes, case-insensitive. Defaults to STANDARD. |
query | string | No | HXQL query selecting the documents to rebuild. If omitted, the query is generated from the configured ontology routes. Cannot be combined with graphDBId. |
content. prefixThe generated query comes from the route conditions. A route condition that names a property without the content. prefix, such as sys_id == "...", makes the rebuild fail with 400 No global property: sys_id. See ontology routes.
Step 3: Submit the Rebuild Job
Start a new graph rebuild job. Requests must use Content-Type: application/json. All fields are optional.
To make retries safe, send an optional Idempotency-Key header with a value unique to this request. The job is then submitted at most once per key, and a repeat call with the same key returns the original result, marked with the Idempotent-Replay response header. Keys are scoped to the caller, so two users can't replay each other's results. The key alone identifies the request: a repeat with the same key but a different body (for example another rebuildMode) returns the original job and does not submit a new one.
- HTTP
- curl
POST {{baseUrl}}/api/v1/graph/rebuild
Authorization: Bearer {{accessToken}}
Accept: application/vnd.hxcs.v1+json
Content-Type: application/json
{ "graphDBId": "3f2b6c1e-8d4a-4b7e-9a51-2c6e0f9d7a10", "rebuildMode": "STANDARD" }
curl -X POST "$BASE_URL/api/v1/graph/rebuild" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.hxcs.v1+json" \
-H "Content-Type: application/json" \
--data @- <<'JSON'
{ "graphDBId": "3f2b6c1e-8d4a-4b7e-9a51-2c6e0f9d7a10", "rebuildMode": "STANDARD" }
JSON
201 Created. The response reports the resolved repository, rebuild mode and the query the job runs. Fields with no value (such as graphDBId when it was omitted) are left out.
The graph database below has a single route, content.sys_id == "251691fe-cb6a-415b-8372-3f421c47a570". The generated query shows the route translated into HXQL, so you can confirm the job's scope from the response.
{
"jobId": "kgRebuild:8a310c7a-87d7-4d35-a103-3caeab2a877a",
"status": "SUBMITTED",
"message": "Job submitted successfully",
"repository": "default",
"graphDBId": "3f2b6c1e-8d4a-4b7e-9a51-2c6e0f9d7a10",
"rebuildMode": "STANDARD",
"query": "SELECT * FROM SysContent WHERE (sys_id = '251691fe-cb6a-415b-8372-3f421c47a570')"
}
The create response reports SUBMITTED, which is not a job state; it confirms the job was accepted. There is no API to cancel a job.
Step 4: Poll the Job
Check the status of a specific rebuild job.
- HTTP
- curl
GET {{baseUrl}}/api/v1/graph/rebuild/{jobId}
Authorization: Bearer {{accessToken}}
Accept: application/vnd.hxcs.v1+json
curl -X GET "$BASE_URL/api/v1/graph/rebuild/{jobId}" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.hxcs.v1+json"
Shortly after the job above was submitted. Small jobs usually finish within seconds, but a job can stay SCHEDULED for a minute or more before it runs, so keep polling until it is COMPLETED or ABORTED:
{
"jobId": "kgRebuild:8a310c7a-87d7-4d35-a103-3caeab2a877a",
"status": "COMPLETED",
"username": "76dcdf7e-...",
"submitTime": "2026-10-01T11:57:35.076Z",
"repository": "default",
"graphDBId": "3f2b6c1e-8d4a-4b7e-9a51-2c6e0f9d7a10",
"rebuildMode": "STANDARD",
"query": "SELECT * FROM SysContent WHERE (sys_id = '251691fe-cb6a-415b-8372-3f421c47a570')"
}
COMPLETED means the job has finished submitting all matched documents for reprocessing. Graph extraction then happens downstream in Context.
Job Status Fields
| Field | Description |
|---|---|
jobId | The job ID. |
status | The current job state. |
username | The user who submitted the job. |
submitTime | When the job was submitted (ISO 8601). |
repository | The target repository. |
graphDBId | The graph database the query was generated for. Absent when the job covers all configured graph databases. |
rebuildMode | The rebuild mode used. |
query | The HXQL query the job runs. |
errorMessage | Error message, present only when the job reported an error. |
Fields with no value are left out. The job's request parameters (repository, graphDBId, rebuildMode, query) are kept for 90 days; after that only the status fields are returned.
Job States
| State | Description |
|---|---|
SCHEDULED | The job has been submitted but has not started. |
SCROLLING_RUNNING | The job is running its query and collecting the set of documents to process. |
RUNNING | The document set is known and the job is processing it. |
COMPLETED | The job has processed the whole document set. |
ABORTED | The job was aborted; it may have been partially applied. |
UNKNOWN | The job's status is unknown. |
Status Errors
| Status | When |
|---|---|
404 | No job with this ID, or its state is UNKNOWN. |
Example:
GET /api/v1/graph/rebuild/kgRebuild:00000000-0000-0000-0000-000000000000
404 {"entity-type":"exception","status":404,"message":"Rebuild graph task not found: kgRebuild:00000000-0000-0000-0000-000000000000"}
Step 5: List Jobs and Filter by State
Retrieve a page of graph rebuild jobs, sorted by submission time (most recent first).
- HTTP
- curl
GET {{baseUrl}}/api/v1/graph/rebuild?state=completed&limit=10
Authorization: Bearer {{accessToken}}
Accept: application/vnd.hxcs.v1+json
curl -X GET "$BASE_URL/api/v1/graph/rebuild?state=completed&limit=10" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.hxcs.v1+json"
List Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | No | Max results (default 10). Must not be negative. |
offset | query | integer | No | Results to skip (default 0). Must not be negative. |
state | query | string | No | Filter by job state: one of the job states, case-insensitive. |
List Response
{
"offset": 0,
"limit": 10,
"totalCount": 1,
"count": 1,
"jobs": [
{
"jobId": "kgRebuild:0c4b3546-ddcc-42d4-8002-64fc95e40b1d",
"status": "COMPLETED",
"username": "admin",
"submitTime": "2026-07-21T09:15:30Z",
"repository": "default",
"rebuildMode": "STANDARD",
"query": "SELECT * FROM SysContent WHERE cinctx_kgProcessingStates/*/ontologyId = '3f2b6c1e-8d4a-4b7e-9a51-2c6e0f9d7a10_c28a73bd-3212-47d7-a782-f0f7daae3679'"
}
]
}
This job was submitted with a custom query, so it has no graphDBId: the two cannot be combined (see Scope the Rebuild).
Each entry in jobs has the same fields as Get Job Status. totalCount is the number of matching jobs across all pages; count is the number on this page.
In cinctx_kgProcessingStates, each ontologyId value is the composite <graphDBId>_<ontologyId>, not the bare ontology ID, so a query for one ontology's documents needs both parts (or cinctx_kgProcessingStates/ontologyId LIKE '%<ontologyId>').
List Examples
No jobs (or none in the requested state)
GET /api/v1/graph/rebuild?state=completed
{"count":0,"jobs":[],"limit":10,"offset":0,"totalCount":0}
state is case-insensitive: completed and COMPLETED are equivalent.
A state that doesn't exist (there is no failed state; a failed job ends as ABORTED)
GET /api/v1/graph/rebuild?state=failed
400 {"entity-type":"exception","status":400,"message":"Unknown state 'failed'. Valid values: [UNKNOWN, SCHEDULED, SCROLLING_RUNNING, RUNNING, COMPLETED, ABORTED]"}
Negative paging values
GET /api/v1/graph/rebuild?limit=-1
400 {"entity-type":"exception","status":400,"message":"'limit' must not be negative"}
GET /api/v1/graph/rebuild?offset=-1
400 {"entity-type":"exception","status":400,"message":"'offset' must not be negative"}
Step 6: Recognize the Validation Errors
| Status | When |
|---|---|
415 | The request has no Content-Type: application/json header: "Content-Type is not supported". |
400 | rebuildMode is not a valid mode. |
400 | Both query and graphDBId are supplied. |
400 | query is not valid HXQL. |
400 | query is omitted and it can't be generated: no graph databases are configured, no graph database matches graphDBId, no ontology routes are configured, or no route produces a usable condition. |
400 | A route condition of the graph database can't be converted into a query, for example because it names a property without the content. prefix (see ontology routes). |
These validation errors were confirmed against a live environment; none of them creates a job.
Unknown mode ({"graphDBId": "...", "rebuildMode": "BOGUS"})
400 {"entity-type":"exception","status":400,"message":"Invalid rebuild mode: BOGUS"}
query together with graphDBId
{ "graphDBId": "3f2b6c1e-8d4a-4b7e-9a51-2c6e0f9d7a10", "query": "SELECT * FROM SysContent" }
400 {"entity-type":"exception","status":400,"message":"query and graphDBId cannot be combined: graphDBId only narrows the auto-generated query, so it has no effect on a query you supply yourself. Supply one or the other."}
Invalid HXQL ({"query": "SELECT * FROM"})
400 {"entity-type":"exception","status":400,"message":"Invalid query: At position 1:13 missing {IDENTIFIER, FROM_IDENTIFIER} at '<EOF>'"}
Unknown graph database
{ "graphDBId": "00000000-0000-0000-0000-000000000000" }
400 {"entity-type":"exception","status":400,"message":"Query is required (no graphDB matches graphDbId: 00000000-0000-0000-0000-000000000000)"}
Graph database without ontology routes
400 {"entity-type":"exception","status":400,"message":"Query is required (no ontology routes configured for auto-generation)"}
Route condition without the content. prefix (route sys_id == "..." instead of content.sys_id == "...")
400 {"entity-type":"exception","status":400,"message":"No global property: sys_id"}
Next Steps
- Setting Up the Knowledge Graph: graph databases, ontologies and routes
- Querying with HXQL: check documents' KG processing states after the rebuild
- API Reference: every endpoint and schema
- Error Reference: error formats and status codes