๐ Managing KPIs via REST API
This article explains how to record, update, and manage Key Performance Indicators (KPIs) automatically via the ValueStreamer REST API. The guide is intended for developers and IT staff who regularly transfer KPI data from third-party systems (e.g. ERP, MES, BI) to ValueStreamer โ including the forecast feature newly introduced in API v3.
๐ Contents
- Prerequisites
- Authentication
- Endpoint overview
- Create or update a record (PUT)
- Recording intervals (day, week, month)
- Notes on creating / updating data points
- Forecast actual values & adoption (NEW in v3)
- Query records (GET)
- Delete records (DELETE)
- Technical remarks
- Tips & Best Practices
- FAQ
Prerequisites
- ๐ API credentials (username + password for HTTP Basic Auth)
- ๐ Access to an execution environment (e.g. Power Automate, Python, Postman, Swagger UI, or your own integration solution)
- ๐งพ UUIDs for KPI, team, and optionally sub-tile/KPI value (can be retrieved via the meta endpoints)
๐ Authentication
Authentication is handled via HTTP Basic Auth.
Header example:
Authorization: Basic <Base64-encoded username:password>
โน๏ธ Note: Access is only possible for users with the corresponding API permission. ValueStreamer provides the username and password โ these must be passed Base64-encoded in the Authorization header.
๐ Endpoint overview
| Method | Endpoint | Description |
|---|---|---|
| GET | /exchange/kpi |
Retrieve a list of all KPIs (meta) |
| GET | /exchange/kpi/{kpi-id} |
Retrieve KPI details and recording teams (meta) |
| GET | /exchange/kpi-data |
Retrieve a list of KPI records |
| GET | /exchange/kpi-data/{date}/{team-id}/{kpi-id} |
Retrieve a single record |
| PUT | /exchange/kpi-data/{date}/{team-id}/{kpi-id} |
Create or update a KPI record |
| DELETE | /exchange/kpi-data/{date}/{team-id}/{kpi-id} |
Delete a KPI record |
For KPIs with sub-tiles, the sub-tile UUID is appended as an additional path parameter: /{sub-tile-id}
โน๏ธ Note: As of API v3, the correct content type is application/vs.v3.0+json. When v2 headers are used, new fields such as forecast or adoptActualsIfPossible are not supported.
๐ฅ Create or update a record (PUT)
Example call:
PUT /exchange/kpi-data/2022-11-01/8dca904d-9134-3bb0-95b7-3f72ae3dfacf/c3ba32c2-a13a-0000-0000-000000000000
Header:
Content-Type: application/vs.v3.0+json
Authorization: Basic <base64 credentials>
Body (example with actual and target value):
{
"values": [
{
"kpiValueId": "79cf2f74-0e9c-45b5-bc4d-f437079dde7c",
"value": 177
},
{
"kpiValueId": "fd2c7750-79e1-4514-89a2-e9c103db4d6b",
"value": 190
}
]
}
โจ Tip: You can also send individual values only (e.g. just the actual or just the target value) โ the API supplements or updates existing values intelligently. Missing values are pre-filled based on existing historical data or with 0.
๐ Recording intervals (day, week, month)
In the KPI editor, you define whether values are recorded daily, weekly, or monthly. The date format is yyyy-MM-dd in all cases.
Daily recording (DAY) Provide the date directly, e.g. 2022-11-01.
Weekly recording (WEEK) Always provide the date of the Monday of the respective calendar week.
- CW 52/2022 โ
2022-12-26 - CW 01/2023 โ
2023-01-02
Monthly recording (MONTH) Always provide the first day of the month.
- January 2022 โ
2022-01-01 - December 2022 โ
2022-12-01
โน๏ธ Note: The date format yyyy-MM-dd applies uniformly to all intervals. An incorrect date (e.g. a Wednesday for a weekly recording) results in an invalid entry.
๐ Notes on creating / updating data points
When making a PUT call, at least one kpiValue must be provided. Depending on which values you send, the API behaves as follows:
- Complete record (actual and target value): If an entry already exists for the KPI + team + date combination, it will be updated.
- Target value only for a future date: The missing actual value can be added later in a separate call.
- Not all actual values sent: The API checks whether data already exists for the missing values.
- If yes: existing values remain unchanged.
- If no: missing values are created with
0.
- Actual values only, no target value: The API checks whether a target value already exists for the KPI + team combination.
- If yes: the target value remains unchanged.
- If no: the API adopts the last known target value for that team. If none exists,
0is set.
โ ๏ธ Caution: If no target value is submitted and no historical target value exists, the API automatically sets 0. Therefore, check whether target values are already stored before your first import.
๐ฎ Forecast actual values & adoption (NEW in v3)
As of API v3, ValueStreamer supports recording forecast actual values โ that is, preliminary values for periods that still count as a forecast period.
What is a forecast actual value?
An actual value submitted for a forecast period is stored as a forecast actual value (preliminary, not yet adopted). As soon as the period is no longer a forecast period, the value can be adopted.
Each value in the GET response contains the new forecast field (read-only):
true= the value is a forecast actual value or a forecast target value (preliminary)false= the value is adopted / final
โน๏ธ Note: The forecast field is only available in API v3 (application/vs.v3.0+json). It is not returned for older content types.
What counts as a forecast period?
The behavior is controlled per KPI via the meta field kpiEnteringDefaultPeriod (retrievable via /exchange/kpi/{kpi-id}):
| Value | Meaning |
|---|---|
CURRENT |
Only periods strictly after the current day / week / month count as a forecast. Actual values for the current period are stored as final immediately. |
PREVIOUS |
The current day / week / month also counts as a forecast period. Actual values are stored as forecast actual values and must be adopted later. |
โน๏ธ Note: kpiEnteringDefaultPeriod also controls the default display in the KPI entry form within the user interface.
Adopt a forecast actual value (adoptActualsIfPossible)
To adopt a preliminary forecast actual value, set adoptActualsIfPossible: true in the PUT body:
{
"values": [
{
"kpiValueId": "15cc7cb5-f92e-4847-8054-8bd486dbf133",
"value": 4.0
},
{
"kpiValueId": "ac1aae6e-6733-4701-9df2-0a793ab2da63",
"value": 2.0
}
],
"adoptActualsIfPossible": true
}
The API adopts the forecast actual value as soon as the reference period is no longer a forecast period. The original forecast value is preserved in historicalForecastValues for traceability.
โจ Tip: If adoptActualsIfPossible is missing, false, or null, forecast actual values remain in forecast status โ no error is raised.
โ ๏ธ Caution: If the period is still a forecast period or the values have already been adopted, the adoptActualsIfPossible flag is silently ignored.
New fields in the GET response (v3, read-only)
| Field | Type | Meaning |
|---|---|---|
values[].forecast |
Boolean | true = forecast actual value or forecast target value |
historicalForecastValues[] |
Array | Forecast values before adoption (for traceability) |
historicalForecastResult |
Number | Calculated result of the historical forecast values |
Example response (after adoption):
{
"meta": {
"kpiId": "bac97bbb-8abc-4230-9ef4-1a230e240138",
"teamId": "e70ebfdd-760b-4f50-b69f-6564acb4a367",
"subTileId": null,
"date": "2025-07-01"
},
"values": [
{
"kpiValueId": "15cc7cb5-f92e-4847-8054-8bd486dbf133",
"value": 3.0,
"forecast": false
}
],
"historicalForecastValues": [
{
"kpiValueId": "15cc7cb5-f92e-4847-8054-8bd486dbf133",
"value": 1.0
}
],
"result": 6.0,
"historicalForecastResult": 2.0
}
โฑ๏ธ Note: KPIs with the unit "Time"
For KPIs with the unit "Time", the value is submitted as minutes since 00:00.
- 2:43 p.m. (14:43) โ
14 ร 60 + 43 = 883 - 8:00 a.m. โ
8 ร 60 = 480
{
"values": [
{
"kpiValueId": "79cf2f74-0e9c-45b5-bc4d-f437079dde7c",
"value": 883
}
]
}
๐ Query records (GET)
Example: Retrieve all values of a KPI within a time range:
GET /exchange/kpi-data?kpi-id={kpi-id}&team-id={team-id}&from=2022-10-01&to=2022-10-31
โน๏ธ Note: The time range may span a maximum of 31 days (daily recording), 6 months (weekly recording), or 24 months (monthly recording). Results are sorted by date in descending order.
The sub-tile-id parameter is optional and filters the results to a specific sub-tile.
โ Delete a record (DELETE)
DELETE /exchange/kpi-data/2022-11-01/8dca904d-9134-3bb0-95b7-3f72ae3dfacf/c3ba32c2-a13a-0000-0000-000000000000
โ ๏ธ Caution: Deleted entries cannot be restored.
๐ Technical remarks
- Each KPI record is uniquely identified by:
date + team + kpi(+ optionalsub-tile) - Only one record per combination is possible per day / week / month
- Date format:
yyyy-MM-dd(week = Monday, month = first day) - The API writes and reads data โ it does not actively transfer data to or from third-party systems (no push/pull)
- UUIDs for KPI, team, sub-tile, and KPI value are obtained via the meta endpoints
- For aggregated KPIs, values can only be entered at the lowest team level (leaf level) โ parent teams are aggregated automatically
โจ Tips & Best Practices
- ๐งช Start with tests in the Swagger Editor or Postman before putting the integration into production
- ๐ Update KPI values regularly to ensure consistent evaluations
- ๐งพ Check the UUIDs of KPI, team, sub-tile, and KPI value via the meta endpoints before your first import
- ๐ Use
adoptActualsIfPossible: truein automated imports to adopt forecast actual values directly once the period is complete - ๐ Check the
forecastfield in the GET response to identify whether a value is still preliminary
โ FAQ
How do I find the required UUIDs (KPI, team, KPI values)? Use the meta endpoints GET /exchange/kpi for all KPIs and GET /exchange/kpi/{kpi-id} for details including recording teams, sub-tiles, and KPI value IDs.
What happens if I send the same values again? The API recognizes existing combinations and overwrites existing values (PUT = Create or Update). No error is raised.
What is the difference between API v2 and v3? In v3 (application/vs.v3.0+json), forecast actual values, the forecast flag in the response, as well as adoptActualsIfPossible and historicalForecastValues are available. All new integrations should use v3 exclusively.
How do I know whether a value is still a forecast? The field values[].forecast in the GET response is true as long as the value has not yet been adopted. After adoption, it shows false, and the original forecast value is documented in historicalForecastValues.
How do I submit time-based KPI values? Submit the minutes since 00:00 as an integer. Example: 2:43 p.m. (14:43) = 14 ร 60 + 43 = 883.