Conventions¶
Behaviours that apply across the Kendis APIs. Where an API differs, it's called out explicitly — we document each API exactly as it behaves rather than papering over the differences.
Response envelope¶
All successful responses are JSON. List endpoints wrap results in a data array; some also include pagination metadata.
| API | Envelope | Pagination metadata |
|---|---|---|
| PI Board Items | { "data": [ … ] } |
In request body (pageStart / pageSize) |
| PI Objectives (legacy) | { "data": [ … ] } |
None — fetched per board |
| PI Objectives V1 | { "startAt", "pageLimit", "total", "Data": [ … ] } |
Yes — query params |
| Milestones & Phases | { "startAt", "pageLimit", "total", "Data": [ … ] } |
Yes — query params |
| Risk | { "startAt", "pageLimit", "total", "data": [ … ] } |
Yes — query params |
| Strategic Themes & OKRs | { "startAt", "pageLimit", "total", "Data": [ … ] } |
Yes — query params |
Envelope key casing differs between APIs
The Strategic Themes & OKRs, PI Objectives V1 and Milestones & Phases APIs (the /pi-boards routes) return the array under
Data (capital D). The other APIs, including GET /api/v1/boards, use lowercase data.
Read the key exactly as documented for each API; don't assume a single casing across all of them.
Detail (single-item) endpoints return the one object inside the same data / Data wrapper.
Null and empty fields¶
Kendis serialises responses non-null: fields whose value is null or empty are omitted from the
response rather than returned as null. If a documented field is missing from a payload, treat it as "not
set" — not as an API error.
Field selection (?fields=)¶
The newer APIs (Risk, Strategic Themes & OKRs, PI Objectives V1, Milestones & Phases) support a fields query parameter to control the projection
and reduce payload size on bulk exports:
| Usage | Result |
|---|---|
| omitted | A minimal default set (typically id, key, title) |
?fields=all |
All available fields, including computed ones |
?fields=key,title,status |
Only the listed fields |
The PI Board Items API uses a comparable mechanism in its POST body ("fields": [ … ]) — see its
Endpoints page.
Field selection changes only the projection — it does not change pagination or the underlying query.
Key-or-ID lookup¶
On the Strategic Themes & OKRs, PI Objectives V1 and Milestones & Phases APIs, path parameters written as {keyOrId} accept either:
- the item's human-readable key (e.g.
CV-20,OBJ-329,KR-141,portfolio-10), or - its internal ID (e.g.
69a14f04c30ac343f2796abb).
The API tries the key first, then falls back to the ID. The Risk API similarly accepts a register's ID or
its key on {registerIdOrKey} paths.
Dates and timestamps¶
- Epoch fields (e.g.
createdOn,startDate) are milliseconds since the Unix epoch as numbers. - Risk dates such as
raisedDate/resolutionDateare formatted strings —dd-MMM-yyyy(e.g.19-May-2026). - Custom-field
datepickervalues are ISO-8601 UTC strings (e.g.2026-03-25T11:43:00.000Z).
Converting epoch milliseconds to a readable date¶
Epoch milliseconds are timezone-safe and parse natively in every toolchain — convert them on the
consumer side. Using "createdOn": 1731337312029 as the example (→ 2024-11-11T14:21:52Z):
The API intentionally does not return pre-formatted date strings for these fields: a formatted string bakes in one timezone and one locale, while epoch milliseconds let every consumer render the same instant correctly in their own.
Identifiers¶
id values are stable internal Kendis identifiers that survive re-syncs. Source-system identifiers
(Azure DevOps tfsId, Jira jiraId / jiraKey) appear only on linked items and only for boards connected
to that source — see each API's field reference.