Flagging devices with Asset Tags
An Asset Tag is a reusable label you can attach to a device — for example AwaitingPickup, RepairInProgress, or NeedsImaging. Because a device can carry a tag without being moved, checked out, or changed in any other way, Asset Tags are the natural way to represent workflow states: a device can be flagged "awaiting pickup" while it is still sitting in its home building.
An Asset Tag is a reusable label you can attach to a device — for example AwaitingPickup, RepairInProgress, or NeedsImaging. Because a device can carry a tag without being moved, checked out, or changed in any other way, Asset Tags are the natural way to represent workflow states: a device can be flagged "awaiting pickup" while it is still sitting in its home building.
This article covers adding and removing those flags through the API, and counting them for a dashboard.
Asset Tags vs. the Internal Tracking ID
Two things in k12panel sound similar; they are not the same:
| What it is | In the API | |
|---|---|---|
| Internal Tracking ID | The barcode / inventory number on one device. | The asset_tag field on an asset. |
| Asset Tag (this article) | A reusable label a device is a member of. | Set and cleared at /assets/{id}/tags. |
When this article says flag, it means an Asset Tag.
Create your tags first
An Asset Tag has to exist before you can put it on a device. Create the ones you need once, under Settings → Asset Tags in k12panel. Asking the API to apply a tag that does not exist returns an error rather than creating it — this keeps a typo in a script from silently adding a new label to your whole organization.
Give your flags clear, distinct names. Tag names are not required to be unique, but if two tags share a name, referring to one by name is ambiguous (see Handling errors); a unique name avoids that entirely.
The permission you need
Adding or removing an Asset Tag needs a key with the tags:write permission. This is separate from assets:write (which covers editing a device's site, notes, and state), so a key that only flags devices does not also have to be able to move them. An administrator sets a key's permissions under Settings → API Keys.
Add a flag to a device
POST to the device's tags collection, naming the tag by name or by id:
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"tag": {"name": "AwaitingPickup"}}' \
"$PANEL/api/public/v1/assets/4021/tags"
The response is the updated device, so you can see its current tags:
{
"id": 4021,
"name": "CB-4021",
"tags": ["RepairInProgress", "AwaitingPickup"],
"...": "..."
}
Adding a flag is idempotent: if the device already carries it, the call still succeeds and nothing is duplicated. Your automation can safely retry.
Remove a flag from a device
DELETE the tag from the device, by name or id:
curl -X DELETE -H "Authorization: Bearer $KEY" \
"$PANEL/api/public/v1/assets/4021/tags/AwaitingPickup"
This returns 204 No Content. It is also idempotent — clearing a flag the device does not currently carry is treated as success, so you never have to check first.
Finding the device id
The flag calls use the device's id in the URL. If your process starts from a serial number or Internal Tracking ID, look the device up first and read the id from the response:
# by serial
curl -H "Authorization: Bearer $KEY" "$PANEL/api/public/v1/assets?serial=5CD1234XYZ"
# by Internal Tracking ID
curl -H "Authorization: Bearer $KEY" "$PANEL/api/public/v1/assets?asset_tag=INV-00417"
Counting devices by flag
The whole point of a flag is usually to count it. The count endpoint groups by tag exactly like it groups by site or class, so you can build a "how many are waiting at each building" panel in a single request:
GET /api/public/v1/assets/count?group_by=site,tag&tag=AwaitingPickup&site=15,16,17,18&checked_out=false
{
"total": 6,
"results": [
{ "site": {"id":15,"name":"Library — Elem"}, "tag": {"id":9,"name":"AwaitingPickup"}, "count": 3 },
{ "site": {"id":16,"name":"Library — Int"}, "tag": {"id":9,"name":"AwaitingPickup"}, "count": 0 },
{ "site": {"id":17,"name":"Library — MS"}, "tag": {"id":9,"name":"AwaitingPickup"}, "count": 1 },
{ "site": {"id":18,"name":"Library — HS"}, "tag": {"id":9,"name":"AwaitingPickup"}, "count": 2 }
]
}
Because you named the tag, the zero-fill rule applies: every building comes back, and one with nothing waiting shows "count": 0 rather than dropping off the board. That lets a "0 waiting" tile render as a calm state instead of a missing entry.
Two things behave differently when you count by tag, because a device can carry several tags:
- A device with more than one flag is counted under each of them. So when you group by
tagwithout naming one (a wildcard), the row counts can add up to more thantotal.totalis always the number of distinct devices — trust it as the real figure. - Devices with no tags appear as a
"tag": nullrow, so they are visible rather than silently dropped. Filter to the tags you care about if you do not want them.
Listing the devices behind a count
To see which devices carry a flag — for a drill-down when someone clicks a tile — filter the device list by tag:
curl -H "Authorization: Bearer $KEY" \
"$PANEL/api/public/v1/assets?tag=AwaitingPickup&site=15"
Changing a device's state
Some workflow steps are not a flag but a real state change — for example, disposing of a device that came back "not repairable." A device's state is editable through the same PATCH call that edits its site and notes (it needs assets:write):
curl -X PATCH -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"state": "trashcan"}' \
"$PANEL/api/public/v1/assets/4021"
The valid states are listed at GET /api/public/v1/meta: active, inactive, archived, onramp, rejected, and trashcan.
A note on what tags can do
In k12panel, Asset Tags are not only labels — a tag can also be used to define a dynamic group, or to target a deployment. For everyday workflow flags this never comes up, but it is worth knowing that applying a tag whose name matches a group rule will add the device to that group. If you keep your workflow-flag names distinct from your group rules, the two never interact.