Identifiers — Key vs. ID
How to reference devices, variables, and other entities by id or by label.
This page explains the difference between identifying entities by a key versus an id.
The~convention below applies to the Platform API (/api/v2.0) only. The Data API (/api/v1.6) addresses entities differently — see Identifiers in the Data API further down.
Key as a path parameter
A key identifies an entity such as a Device, Event or Device Group. Key parameters in a path are written as <entity_key> — for example, <device_key>.
A key lets you identify an entity by either its id or its label. To identify by label, prefix it with ~. Ids are 24-character hex strings, and the ~ prefix is required — a bare label with no prefix returns 404.
# GET a specific device — URL definition
https://api.surfact.com/api/v2.0/devices/<device_key>/
# Identify using the device id
https://api.surfact.com/api/v2.0/devices/6a7c777c1da2efbc51f62ba9/
# Identify using the device label (note the ~ prefix)
https://api.surfact.com/api/v2.0/devices/~reefer-trailer-21/Variables are the exception
Device, Event, Device Group and Organization labels are unique across your account, so those entities accept ~label wherever they appear in a path.
Variable labels are unique only within a device — every reefer in a frozen fleet carries a variable labelled temperature — so a variable can be addressed by label only when it is nested under its device:
# ✅ Works — the device scopes the label
curl -X GET 'https://api.surfact.com/api/v2.0/devices/~reefer-trailer-21/variables/~temperature/?fields=id,label' \
-H 'X-Auth-Token: your_token_here'
# ❌ Rejected — /variables/ is account-wide, so a bare label is ambiguous
curl -X GET 'https://api.surfact.com/api/v2.0/variables/~temperature/' \
-H 'X-Auth-Token: your_token_here'The second call returns HTTP 400:
{
"code": 400001,
"message": "Validation Error.",
"detail": ["Label key is not allowed: `~temperature`"]
}The top-level /variables/<variable_id>/ path therefore takes the object id only. Look the id up through the device first: GET /devices/~reefer-trailer-21/variables/?fields=id,label.
The API Reference still names these path parameters{device_id}and{variable_id}even where they accept~label. Don't infer acceptance from the parameter name on those pages — read the parameter description, which states which forms are allowed.
ID as a path parameter
An id identifies an entity only by its id (never by label). Id parameters in a path are written as <entity_id> — for example, <log_id>. Most ids are 24-character hex strings; event log ids are integers.
# GET a specific event log — URL definition
https://api.surfact.com/api/v2.0/events/<event_key>/logs/<log_id>/
# Identify the log by its id
https://api.surfact.com/api/v2.0/events/<event_key>/logs/818171/Prefixing an id parameter with ~ is rejected with HTTP 400:
{
"code": 400001,
"message": "Validation Error.",
"detail": ["Label key is not allowed: `~818171`"]
}Identifiers in the Data API (v1.6)
The ~ prefix is a Platform API convention. In the Data API (/api/v1.6) it always returns 404, and the rules are effectively inverted:
| Path | What it takes | Example |
|---|---|---|
/devices/<device_label>/<variable_label>/values/ | The bare labels, with no prefix — an object id returns 404 | /api/v1.6/devices/reefer-trailer-21/temperature/values/ |
/variables/<variable_id>/values/ | The object id only — a bare label returns 404 | /api/v1.6/variables/6a7c777d97bcd84c851942c9/values/ |
There is also no /devices/ collection endpoint in v1.6 — list your fleet with the Platform API, then read its values here.
Never use the~prefix in a v1.6 path.GET /api/v1.6/devices/~reefer-trailer-21/temperature/values/returns{"code": 404001, "message": "The request was not found."}.
Key as a body parameter
Some POST requests take an entity parameter in the body. A good example is Create a device group, which accepts an organization key.
When creating a device group, the organization parameter can be sent in any of these forms:
curl -X POST 'https://api.surfact.com/api/v2.0/device_groups/' \
-H 'Content-Type: application/json' \
-H 'X-Auth-Token: your_token_here' \
-d '{
"label": "nordic-frozen-fleet",
"name": "Nordic Frozen Fleet",
"organization": "6601f0a1b458490306099001"
}'| Form | Example |
|---|---|
| By id | "organization": "6601f0a1b458490306099001" |
By label (with ~) | "organization": "~nordic-cold-chain" |
| As an object | "organization": {"id": "6601f0a1b458490306099001"} |
A key in a request body is not the same as a key in a query filter. The?organization=filter on/events/and/device_groups/accepts only the internal numeric organization id (for example?organization=30); passing the object id or a~labelthere returns400"Select a valid choice. That choice is not one of the available choices.".
Events do not expose anorganizationof their own — the field is absent from every event returned byGET /events/andGET /events/{event_key}/, so don't expect to read one back. Device Groups and Devices do return the owning organization as a nested object.
ID as a body parameter
It's simple: all entity parameters in a request body are keys. That means they can be identified by their id, by their label (with the ~ prefix), or as an object.
Updated 7 days ago