Get Entity Markers
Retrieves entity markers newer than a specified last marker ID, filtered by project, app, entity definition, and marker type.
Endpoint
GET /v1/domains/{domainKey}/projects/{projectId}/apps/{appName}/entitydefs/{entityDef}/markers/from/{lastMarker}
Path Parameters
| Property | Type | Description |
|---|---|---|
| domainKey | string | Required. Key identifying the domain containing the project. |
| projectId | integer | Required. Project identifier, used to filter markers by their domain partition. |
| appName | string | Required. Application name used to qualify the entity definition. |
| entityDef | string | Required. Entity definition name without the application prefix. The endpoint searches for the qualified name appName.entityDef. |
| lastMarker | integer | Required. Exclusive lower bound for marker IDs: only markers with an ID greater than this value are returned. Use 0 to request all available matching markers. No default is declared. |
Query Parameters
None.
Request Body
None.
Response Body
The response contains a single property named markers that is a JSON array of objects with the following properties:
| Property | Type | Description |
|---|---|---|
| id | integer | Marker identifier. Every returned ID is greater than lastMarker. Use the highest returned ID as the cursor for a subsequent request. |
| markerTime | string | Date/time recorded for the marker. Kahua uses the ISO 8601 standard to represent date/time values as a JSON string. |
| entityDefName | string | Qualified entity definition name, including the application prefix. |
| entityId | integer | Identifier of the entity associated with the change. |
| entityInstanceId | integer | Entity instance identifier recorded on the marker. |
| entityPartitionId | integer | Entity partition identifier recorded on the marker. |
| domainPartitionId | integer | Domain partition identifier used for project filtering; matches the requested projectId. |
| type | string | Type of marker. Defined marker types are Add, Delete, Move, Invalidate, and Update. |
All marker properties are populated from stored marker records. Numeric and date-time properties are non-nullable in the response model, and null string properties are omitted. The response contains change metadata, not entity contents.
The following table provides additional information about the marker type property.
| Marker Type | Description |
|---|---|
| Add | An entity was added or made active again, including activation or restoration of a previously deleted entity. |
| Delete | An entity was deleted or deactivated. This does not necessarily indicate permanent physical deletion. |
| Invalidate | Previously retrieved entity data or its location is no longer current and should be refreshed. This type differs from an Update because it represents an indirect changes, for example changing a parent document or linked WBS item since their item totals are now stale. |
| Move | An entity moved to another partition. The marker records the destination entity partition and domain partition. |
| Update | An existing entity was modified. You should retrieve the current data for the entity to incorporate the change. |
Markers are only stored for approximately the past 30 days. Sending zero as the last marker will only return changes made in the last 30 days.
Example
Request
This example shows a successful request that returns two matching markers.
GET /v1/domains/MagsevenBuilders/projects/62047326/apps/kahua_Issue/entitydefs/Issue/markers/from/6910000
Response
{
"markers": [
{
"id": 6913914,
"markerTime": "2020-12-15T00:53:55.573Z",
"entityDefName": "kahua_Issue.Issue",
"entityId": 6185478,
"entityInstanceId": 6185516,
"entityPartitionId": 1952888,
"domainPartitionId": 1952888,
"type": "Add"
},
{
"id": 6913915,
"markerTime": "2020-12-15T00:53:55.527Z",
"entityDefName": "kahua_Issue.Issue",
"entityId": 6185488,
"entityInstanceId": 6185515,
"entityPartitionId": 1952888,
"domainPartitionId": 1952888,
"type": "Update"
}
]
}
Here are the steps you can use to find changes in the Issues app.
-
Iterate over the list of project IDs and for each project ID.
-
Execute a GET request on the Marker endpoint for the kahua_Issue.Issue entity definition.
GET /v1/domains/MagsevenBuilders/projects/{projectId}/apps/kahua_Issue/entitydefs/Issue/markers/from/0
-
If the response is empty continue to the next project ID. This means no issues were recently changed in this project.
-
If the response is not empty, extract the largest Marker ID and the smallest MarkerTime.
Copy{
"markers": [
{
"id": 6913914,
"markerTime": "2020-12-15T00:53:55.573Z",
"entityDefName": "kahua_Issue.Issue",
"entityId": 6185478,
"entityInstanceId": 6185516,
"entityPartitionId": 1952888,
"domainPartitionId": 1952888,
"type": "Add"
},
{
"id": 6913915,
"markerTime": "2020-12-15T00:53:55.527Z",
"entityDefName": "kahua_Issue.Issue",
"entityId": 6185488,
"entityInstanceId": 6185515,
"entityPartitionId": 1952888,
"domainPartitionId": 1952888,
"type": "Update"
}
]
} -
Save the largest marker ID in your code as the "LargestMarkerId".
-
Use the entityId value with the Get Entity Info endpoint to get data as normal.
-
Continue to the next project ID and repeat using the original Marker ID in the request (For this example: 0). Compare your next non-empty response's largest Marker ID with the saved LargestMarkerId. If it is bigger then save it as the new LargestMarkerId.
-
-
After time passes and you are ready to make your next data pull from Kahua, use the LargestMarkerId you saved the last time. Use this in place of 0 for the next set of requests. Each time you execute a new set of data pulls from Kahua use the LargestMarkerId from your last data pull. You can use the same marker ID for your three groups of requests: contracts, change orders, and issues. Changes to the items are interpreted as changes to the parent entity, so you should only need to repeat step 1 above for those three entities.
-
GET /v1/domains/{domainKey}/projects/{projectId}/apps/kahua_Issue/entitydefs/Issue/markers/from/LargestMarkerId
-
GET /v1/domains/{domainKey}/projects/{projectId}/apps/kahua_Contract/entitydefs/Contract/markers/from/LargestMarkerId
-
GET /v1/domains/{domainKey}/projects/{projectId}/apps/kahua_ContractChangeOrder/entitydefs/ContractChangeOrder/markers/from/LargestMarkerId
-
The last marker would typically be saved from the previous call, and this would return a list of all changes to the given entity since that marker. You can start with a marker of zero.
GET /v1/domains/MagsevenBuilders/projects/0/apps/kahua_Contract/entitydefs/Contract/markers/from/0
Result:
{
"markers": []
}
After you add a contract, here is the result for the same call:
Result:
{
"markers": [
{
"id": 6446784,
"markerTime": "2020-10-02T14:14:38.16Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808097,
"entityInstanceId": 5808097,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Add"
},
{
"id": 6446786,
"markerTime": "2020-10-02T14:14:43.53Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808097,
"entityInstanceId": 5808097,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Invalidate"
},
{
"id": 6446787,
"markerTime": "2020-10-02T14:14:43.55Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808097,
"entityInstanceId": 5808097,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Invalidate"
}
]
}
You can then save the last marker in the list, 6446787, to detect changes that happen after that point. If you run it immediately before any activity, you'd still get an empty list:
GET /v1/domains/MagsevenBuilders/projects/0/apps/kahua_Contract/entitydefs/Contract/markers/from/6446787
If you then make more changes, that same call will return changes since the given marker:
{
"markers": [
{
"id": 6446788,
"markerTime": "2020-10-02T14:15:00.443Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808097,
"entityInstanceId": 5808099,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Update"
},
{
"id": 6446791,
"markerTime": "2020-10-02T14:18:35.873Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808102,
"entityInstanceId": 5808102,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Add"
},
{
"id": 6446793,
"markerTime": "2020-10-02T14:18:36.733Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808102,
"entityInstanceId": 5808102,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Invalidate"
},
{
"id": 6446794,
"markerTime": "2020-10-02T14:18:36.747Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808102,
"entityInstanceId": 5808102,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Invalidate"
},
{
"id": 6446795,
"markerTime": "2020-10-02T14:18:46.353Z",
"entityDefName": "kahua_Contract.Contract",
"entityId": 5808102,
"entityInstanceId": 5808104,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Update"
}
]
}
Markers are used across apps/entities, so this same marker can be used to detect changes in multiple different entities. Here's an issue you created after marker 6446787:
GET /v1/domains/MagsevenBuilders/projects/0/apps/kahua_Issue/entitydefs/Issue/markers/from/6446787
{
"markers": [
{
"id": 6446798,
"markerTime": "2020-10-02T14:19:42.837Z",
"entityDefName": "kahua_Issue.Issue",
"entityId": 5808107,
"entityInstanceId": 5808107,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Add"
},
{
"id": 6446803,
"markerTime": "2020-10-02T14:19:45.443Z",
"entityDefName": "kahua_Issue.Issue",
"entityId": 5808107,
"entityInstanceId": 5808107,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Invalidate"
},
{
"id": 6446804,
"markerTime": "2020-10-02T14:19:59.73Z",
"entityDefName": "kahua_Issue.Issue",
"entityId": 5808107,
"entityInstanceId": 5808110,
"entityPartitionId": 0,
"domainPartitionId": 0,
"type": "Update"
}
]
}