Once you run more than a few machines, “which one was db1 again” becomes a real question. Two small pieces of metadata answer it, and both are scriptable. A label is one friendly name for a machine. Tags are a set of short words you attach to group and filter. Neither changes anything the machine does; they are there to make a fleet legible to you and to your tooling.
Label: one name per machine
A label is a single human name that rides alongside the hostname in your lists. Set it with PUT /v1/servers/{id}/label and a servers.write key:
curl -s -X PUT https://api.amoni.app/v1/servers/955/label \
-H "Authorization: Bearer nr_live_..." -H "Content-Type: application/json" \
-d '{"label": "web-prod-1"}'
# { "success": true, "data": { "label": "web-prod-1", "message": "Label updated." } }
A label is at most 60 characters. Send an empty string to remove it. There is one label per server; setting a new one replaces the old.
Tags: a set you filter on
Tags are where fleet-wide organization happens: prod, web, a datacenter code, a customer name. Read them with GET /v1/servers/{id}/tags, and write them with PUT /v1/servers/{id}/tags. The write replaces the whole set, so send every tag the server should have, not just a new one:
curl -s -X PUT https://api.amoni.app/v1/servers/955/tags \
-H "Authorization: Bearer nr_live_..." -H "Content-Type: application/json" \
-d '{"tags": ["prod", "web", "fra"]}'
# { "success": true, "data": { "tags": ["prod", "web", "fra"], "message": "Tags updated." } }
To add a tag, read the current set, append, and write it back. To clear every tag, send an empty array. A read returns them sorted:
curl -s https://api.amoni.app/v1/servers/955/tags \
-H "Authorization: Bearer nr_live_..."
# { "success": true, "data": { "tags": ["fra", "prod", "web"] } }
A few rules keep tags tidy and machine-friendly. A server holds up to ten tags. Each is lower-cased and reduced to letters, digits and hyphens, so Prod Web is stored as prod-web. Each is at most 30 characters. Tags beginning with int-netr- are reserved for our own use and are refused with code reserved_tag.
Filter the fleet on them
The point of tags is asking the fleet a question. GET /v1/servers returns each server with its label and tags, so the filtering happens in your own code with no special query needed:
# every production web server, by tag
curl -s https://api.amoni.app/v1/servers \
-H "Authorization: Bearer nr_live_..." \
| jq -r '.data[] | select(.tags | index("prod") and index("web"))
| "\(.id)\t\(.label // .hostname)"'
From there the ids feed whatever you do next: a reinstall, a reverse-DNS pass, a power action. Tagging first and acting on the tag is how a script stays correct as the fleet changes, rather than carrying a hardcoded list of ids.
Cloud instances too
Cloud instances carry the same two fields under their own routes: PUT /v1/vms/{account}/{id}/label and PUT /v1/vms/{account}/{id}/tags, with a vms.write key. The rules are identical, so one tagging convention can cover bare metal and cloud together.
The same names show in the portal
Labels and tags set over the API are the same ones the portal shows; there is no separate API-only metadata. A label set from a script appears next to the hostname in your lists, and the two features complement each other: tags are lightweight and many-per-machine, while a project is a single grouping with running totals attached.
Questions we get
- Does the tag write merge or replace? Replace. Send the complete set every time. Read, change, write back to add or remove one.
- Why did my tag come back changed? Tags are normalized to lower-case letters, digits and hyphens.
DB-01becomesdb-01. That is expected, so filter on the normalized form. - What is the difference between a label and a tag? A label is one name for the machine. Tags are a set you group and filter on. Use both.
- Can I search the whole account for a tag? Yes, in your own code: list servers and filter on
tags. Every server carries its tags in the list response.
Still stuck?
Open a support ticket if a tag write is refused and the code is not reserved_tag. We can check what the server will accept.