Migration from v2
The Technis API v3 is a REST API designed to replace the v2 API. v3 brings a simplified request and response structure that makes it easier to get your data as well as a real-time streaming. This guide maps each v2 concept to its v3 equivalent and shows side-by-side examples.
At a glance
| Area | v2 | v3 |
|---|---|---|
| Style | GraphQL | REST |
| Terminology | Installation KPIs | Sites Metrics |
| Base URL | https://api-application.technis.com/api/v2/graphql | https://api.technis.com/v3/ |
| Authentication | Bearer token in Authorization header | API key in x-api-key header |
| Topology | getCartographies query | GET /sites and GET /sites/:id |
| Historical data | getKPIs query | POST /metrics |
| Live data | getLiveKPIs query with polling | POST /v3/metrics with "live": true as an SSE stream |
| Resource IDs | numbers | strings |
Terminology
Three v2 names changed in v3:
- Installation → site. The same physical building, with the same zones and passages, but the resource is called site and the field is
siteId. - KPI → metric. v2 returned a
kpiNameenum value likeAFFLUENCE_IN;v3 accepts and returns a friendly metric key likeentrances. - Descriptor → filter. v2 had a typed
DescriptorsInputblock forgenders,ageCategories, etc. v3 currently exposes onlyzoneIdsandpassageIdsfilters; the broader descriptor surface is currently not available.
Metric names have also changed for consistency with names displayed in the product:
| V2 KPI name | V3 metric name |
|---|---|
AFFLUENCE_IN | entrances |
AFFLUENCE_OUT | exits |
INSIDE | visitorsInside |
DWELL | timeSpent |
Full list of supported metrics →
Authentication
Both the header and the creation flow change in v3.
v2: Authorization: Bearer <YOUR_TOKEN_HERE>
v3: x-api-key: <YOUR_API_KEY_HERE>
Existing v2 tokens are not valid against v3 - generate a new key and update every client to send x-api-key instead of Authorization: Bearer ... .
The v3 key has automatically a read-only access to all sites in the organization for which it's created.
Fetching topology (installations, zones, passages)
v2 exposed getCartographies, which returned every accessible installation with its zones, passages and users in one large nested payload. v3 splits this into a paginated list (GET /v3/sites) and a detailed lookup (GET /v3/sites/:id) that includes zones, passages and devices.
Request:
query GetCarto {
getCartographies {
installation { id name }
zones { id name parentIds childIds passageIds }
passages { id padIds name zoneOutIds zoneInIds }
}
}Response:
{
"data": {
"getCartographies": [
{
"installation": { "id": 1, "name": "Building Simulation" },
"zones": [
{ "id": 1, "name": "Building Simulation", "parentIds": [], "childIds": [1], "passageIds": [1] }
],
"passages": [
{ "id": 1, "padIds": ["Pad_1"], "name": "Building Simulation", "zoneOutIds": 1, "zoneInIds": 2 }
]
}
]
}
}Request list of sites:
curl https://api.technis.com/v3/sites \
-H "x-api-key: $TECHNIS_API_KEY"Then request details of a single site:
curl https://api.technis.com/v3/sites/1 \
-H "x-api-key: $TECHNIS_API_KEY"Response:
{
"data": {
"id": "1",
"name": "Building Simulation",
"zones": [
{ "id": "2", "name": "Main floor", "category": "room", "capacity": 100, "area": 200, "devices": [] }
],
"passages": [
{ "id": "3", "name": "Front door", "fromZoneId": null, "toZoneId": "2", "devices": [{ "id": "4", "name": "Pad 4", "status": "Online" }] }
]
},
"meta": { "warnings": [], "errors": [] }
}Notable shape changes:
- IDs are strings, not numbers.
- v2's
zoneInIds/zoneOutIds(arrays) become v3'stoZoneId/fromZoneId(single values).fromZoneId: null means the passage opens to the outside. - v2's
padIdsis replaced by a structured devices array on each passage, with current status included. - Users and tags are no longer returned by the topology endpoint.
Historical metrics
Request:
query GetHistoricalDataExample {
getKPIs(
zoneId: 1,
kpiName: AFFLUENCE_IN,
granularity: DAY,
dateBegin: "2023-09-20",
dateEnd: "2023-09-21"
)
}Response:
{
"data": {
"getKPIs": {
"kpiName": "AFFLUENCE_IN",
"timezone": "Europe/Zurich",
"dateBegin": "2023-09-20",
"dateEnd": "2023-09-21",
"granularity": "DAY",
"values": [
{ "value": 3688, "timestamp": "2023-09-20T00:00:00.000" },
{ "value": 3197, "timestamp": "2023-09-21T00:00:00.000" }
]
}
}
}
Request:
curl -X POST https://api.technis.com/v3/metrics \
-H "x-api-key: $TECHNIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": ["entrances"],
"siteId": "1",
"from": "2023-09-20 00:00:00",
"to": "2023-09-21 00:00:00",
"granularity": "day",
"filter": { "zoneIds": ["1"] }
}'Response:
{
"data": [
{ "timestamp": "2023-09-20T00:00:00+00:00", "metrics": { "entrances": 3688 } },
{ "timestamp": "2023-09-21T00:00:00+00:00", "metrics": { "entrances": 3197 } }
],
"meta": {
"inferredParams": {
"timezone": "Etc/UTC",
"granularity": "day",
"filter": { "zoneIds": ["1"] },
"live": false
}
}
}Notable differences:
- A request is now anchored on the site
siteId)rather than azoneId/passageId/deviceIdtriple. Drill down usingfilter.zoneIdsorfilter.passageIds. kpiName: AFFLUENCE_INbecomesmetrics: ["entrances"]. You can ask for multiple metrics in a single call.dateBegin/dateEnd(usingYYYY-MM-DDformat) becomefrom/to, which also accept relative expressions like"3 months ago","5 minutes ago","now"as well as ISO 8610 formatted time stamps.granularityis lowercase"day"instead ofDAY.- The response is a flat array of points; each point holds a metrics map so that asking for multiple metrics returns them side by side.
- The defaults the server applied are echoed in
meta.inferredParams.
Live metrics
getLiveKPIs returned a single value per call and was typically polled at the cadence the client wanted.
query GetLiveDataExample {
inside: getLiveKPIs(zoneId: 1, kpiName: INSIDE)
entries: getLiveKPIs(zoneId: 1, kpiName: AFFLUENCE_IN)
}Response:
{ "data": { "inside": 35, "entries": 130 } }The same endpoint as historical metrics, with "live": true in the body, switches into Server-Sent Events mode. The connection stays open and the server pushes one event per update — no polling needed.
curl -N -X POST https://api.technis.com/v3/metrics \
-H "x-api-key: $TECHNIS_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"metrics": ["entrances", "visitorsInside"],
"siteId": "1",
"live": true,
"filter": { "zoneIds": ["1"] }
}'Once connected latest value will be automatically pushed. data uses same format as in historical metrics.
event:
data: {"timestamp":"2026-05-29T08:42:00+00:00","metrics":{"entrances":130,"visitorsInside":35}}
data: {"timestamp":"2026-05-29T08:43:00+00:00","metrics":{"entrances":133,"visitorsInside":36}}If your client cannot consume SSE, you can still poll the non-live endpoint at the cadence you need, set "live": false (or omit it) and "from": "now", "to": "now" which will return the latest available value.
If you need the same behaviour of getting the latest value as one-shot request, for example in backend operations you can use the from: now, to:now shortcut.
curl -N -X POST https://api.technis.com/v3/metrics \
-H "x-api-key: $TECHNIS_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"metrics": ["entrances", "visitorsInside"],
"siteId": "1",
"from": "now",
"to": "now"
}'In this case the API responds with a single entry for each requested metric.
{
"data": [
{
"timestamp": "2026-06-11T08:24:20+00:00",
"metrics": {
"entrances": 12,
"visitorsInside": 9
},
"matchingFilters": {
"zoneIds": [
"5797"
]
}
}
],
"meta": {
"requestId": "583e6212-31f6-4fd0-8136-b7710baefb9b",
"serverTag": "v3.0.2",
"warnings": [],
"errors": [],
"inferredParams": {
"from": "2026-06-11T08:24:23",
"to": "2026-06-11T08:24:23",
"granularity": "minute",
"timezone": "Etc/UTC",
"live": false,
"filter": {
"zoneIds": [
"5797"
]
}
}
}
}Migration checklist
- Generate a new API key on app.technis.com. Update your client to send the key in
x-api-keyinstead ofAuthorization: Bearer…. - Replace
getCartographiescalls withGET /v3/sites(for the list) andGET /v3/sites/:id(for zones, passages, and devices). - Replace
getKPIsandgetLiveKPIscalls withPOST /v3/metrics, togglinglivefor streaming.- Use
fillter.zoneIdsorfilter.passageIds
- Use
- Update IDs to strings and stop triple.
- Translate
kpiNameenums to v3 metric keys. - Switch granularity literals to strings (
DAY→"day"). - Update response parsing to read from data and check
meta.errorsinstead of GraphQL's top-level errors. - Capture
meta.requestIdon errors so support can trace failures.
Updated about 2 months ago