Reading the Process History
The history of a business case is available from the business service as one list - the root process and all its sub-processes together. In a page you usually just drop in the EccProcessHistory widget. This page is for everything else: own timelines, reports, exports or checks in tests.
Request
GET /api/v1/process/{processInstanceId}/history
Authorization: Bearer eyJhbGciOi...
| path | id of a root instance | - | the id of a sub-process returns |
| query |
|
|
|
| query | comma-separated | none | adds business data or technical steps |
| query |
| none | prepares the list for a timeline |
In the frontend use the helper of the API layer. It always requests format=ui with the default order (newest first) and returns an empty list on errors:
import { fetchProcessHistory } from "@/ecc/services/ApiService";
import type { EccProcessHistoryEntry } from "@/ecc/types/taskTypes";
const entries: EccProcessHistoryEntry[] = await fetchProcessHistory(processInstanceId);
const withGateways = await fetchProcessHistory(processInstanceId, "gateway,subprocess");
Objects in this example: EccProcessHistoryEntry.
Other combinations (raw entries, sort=asc) are available directly over HTTP, e.g. for reports and exports:
curl -H "Authorization: Bearer $TOKEN" \
"https://[HOST]/api/v1/process/8c3e5f0a-1b2c-4d3e-9f4a-5b6c7d8e9f01/history?sort=asc&include=data"
Which entries you get
start of the case ( | yes | yes | yes |
custom entries ( | yes | yes | yes |
user tasks from the root and all sub-processes: task node entered/left ( | yes | yes | yes |
gateways ( | - | yes | - |
sub-processes ( | - | - | yes |
Not returned in any combination: the start of sub-processes, the end of instances (PROCESS_COMPLETED, PROCESS_ABORTED, PROCESS_ERROR), start and end events, script, service and rule tasks.
GET /api/v1/process/{id}/history?include=gateway,subprocess&sort=asc
Business data: include=data
| missing for user task entries and entries without | complete |
| only | complete |
| missing | complete |
| missing | complete |
| complete | complete |
Use include=data only where the data is really needed, e.g. for an audit export.
Display format: format=ui
fewer entries | a gateway appears once (its |
| an icon key per entry |
| for the entries of task nodes: |
Icon keys you can expect:
| start of the case |
| custom entry |
| task node entered, left |
| task claimed ( |
| task is open again, e.g. after a release |
| other task state changes: create, start, complete, skip, ... |
| other task events |
| gateways ( |
| sub-processes ( |
Response
The list comes in the standard response envelope; data holds the entries. Fields without a value are omitted.
{
"success": true,
"httpStatus": 200,
"array": true,
"arrayCount": 4,
"data": [ ... ]
}
Fields of an entry
| string | id of the event |
| string |
|
| string |
|
| date-time | when the step happened |
| number | technical sequence number, tie-breaker for equal timestamps |
| string |
|
| string, number |
|
| object | acting person |
| string | the instance of the step - for sub-process steps the sub-process |
| string | position in the case |
| string | readable label of the instance from the process model |
| string | node or task name, BPMN type ( |
| object |
|
| object |
|
| object | task state after the change: |
| object | what changed, e.g. |
| object |
|
| object | process data (see |
| number | time between entering and leaving the node, on |
| string, object |
|
The complete structure of node, userTask, change and all change.action values is listed in the System Handbook (History Document Reference 🔒).
Example: format=ui, newest first
[
{
"eventType": "USER_TASK_STATE",
"timestamp": "2026-09-30T08:05:11.402+00:00",
"seq": 1843,
"user": { "userId": "66f9e0c19c2d4a0012ab1111", "preferredUsername": "max.keller@example.org", "displayName": "Keller, Max" },
"processInstanceId": "1f2e3d4c-5b6a-4789-8a9b-0c1d2e3f4a5b",
"processId": "purchaseRelease",
"rootProcessInstanceId": "8c3e5f0a-1b2c-4d3e-9f4a-5b6c7d8e9f01",
"businessKey": "PR260930-3f9a1c2b",
"activityName": "Approve Request Level 1",
"activityType": "userTask",
"userTask": {
"id": "5f1c2a7e-8d34-4b8e-9a61-0c2f4e7b9d10",
"status": "Reserved",
"actualOwner": "max.keller@example.org",
"actualOwnerUserId": "f3a9c2d1-7b4e-4c8a-9e2f-1d6b5a4c3e21",
"actualOwnerDisplayName": "Keller, Max",
"potentialGroups": ["purchase-approval-level1"],
"nodeInstanceId": "c7d8e9f0-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
"outputs": {}
},
"change": { "action": "claim", "from": "Ready", "to": "Reserved" },
"icon": "userTask-claim"
},
{
"eventType": "ACTIVITY_STARTED",
"timestamp": "2026-09-30T07:41:12.912+00:00",
"seq": 1841,
"processInstanceId": "1f2e3d4c-5b6a-4789-8a9b-0c1d2e3f4a5b",
"activityName": "Approve Request Level 1",
"activityType": "userTask",
"node": { "nodeInstanceId": "c7d8e9f0-1a2b-4c3d-8e4f-5a6b7c8d9e0f", "bpmnType": "userTask", "engineType": "HumanTaskNode", "enteredAt": "2026-09-30T07:41:12.912+00:00" },
"workItem": { "id": "5f1c2a7e-8d34-4b8e-9a61-0c2f4e7b9d10", "input": { "TaskName": "ApproveRequestLevel1", "GroupId": "purchase-approval-level1", "Comment": "Approve request (level 1)", "Content": "Please check budget and cost center." } },
"icon": "userTask-started",
"task": { "comment": "Approve request (level 1)", "content": "Please check budget and cost center.", "groupId": "purchase-approval-level1", "taskName": "ApproveRequestLevel1" }
},
{
"eventType": "CUSTOM",
"timestamp": "2026-09-30T07:41:12.700+00:00",
"seq": 1840,
"processInstanceId": "1f2e3d4c-5b6a-4789-8a9b-0c1d2e3f4a5b",
"custom": { "type": "RULE", "message": "5k to 25k detected" },
"icon": "custom"
},
{
"eventType": "PROCESS_STARTED",
"timestamp": "2026-09-30T07:41:12.518+00:00",
"seq": 1836,
"user": { "userId": "66f9e0c19c2d4a0012ab2222", "preferredUsername": "anna.berger@example.org", "displayName": "Berger, Anna" },
"processInstanceId": "8c3e5f0a-1b2c-4d3e-9f4a-5b6c7d8e9f01",
"processId": "purchase",
"processInstanceDescription": "Purchase Request: Laptop for new team member",
"icon": "process_started"
}
]
(shortened - entries contain all process fields)
Tips
- Sort is applied by time of the step, so steps of sub-processes appear between the steps of the parent - no client-side sorting needed. Use
sort=ascfor a chronological report. seqis not contiguous and not a counter per case - use it only as a tie-breaker.- Identify a task across entries with
userTask.nodeInstanceId=node.nodeInstanceId. - For decisions of approval tasks read
userTask.outputsof thecompleteentry orworkItem.outputof theACTIVITY_COMPLETEDentry of the task node. change.actionnames the most likely transition;change.fromandchange.toare always exact.
On this page
- Reading the Process History