A tag is the dynamic NFC identity bound to a physical item. You provision tags under an account; later, each tag is written onto a physical chip and, once in the field, scanned to produce verifications.
Fields
| Field | Type | Notes |
|---|---|---|
id |
string | tag_-prefixed, assigned by the platform and returned at creation. |
protocol |
string | Required at creation. The tag protocol to provision (see below). |
url |
string | Required at creation. The address written to the chip and opened when the tag is scanned. You choose it. |
status |
string | Lifecycle state (see below). Returned when you retrieve a tag. |
configured_at |
string | ISO 8601 timestamp when the tag was written to a chip, or null. Returned when you retrieve a tag. |
A tag also carries a lifecycle status that advances as the tag is manufactured:
| Status | Meaning |
|---|---|
created |
Provisioned in the platform; not yet written to a chip. |
configured |
Written to a chip and ready to be scanned in the field. |
A tag can only be verified once it reaches configured — before that it has no
chip behind it, so a scan against it returns 404 (see
Verifications).
The protocol attribute
protocol selects which tag protocol the chip uses. The currently supported
values are:
| Value | Chip |
|---|---|
ntag_424_dna |
NTAG 424 DNA |
ntag_223_dna |
NTAG 223 DNA |
Use the identifier (left column) as the protocol value. Any other value is
rejected with 422.
The url attribute
url is the address written onto the chip and opened when the tag is scanned —
your verification landing page. You choose it freely — it can live on
your own custom domain, in whatever shape you like. The platform writes exactly
what you provide and enforces no format.
The platform assigns the id, so the URL can’t contain it. Keep your own
mapping from each url you send to the id returned for it.
Create tags
POST /api/v1/tags
Provision a batch of tags under the account whose key you present. Send a
protocol and url for each; the platform assigns an id and returns it. Tags
are stored in created status, and each one fires a
tag.created webhook.
Request
A JSON:API array under data, 1–500 resources per request. Each entry:
| Member | Type | Required | Notes |
|---|---|---|---|
attributes.protocol |
string | yes | The tag protocol identifier. |
attributes.url |
string | yes | The address to write to the chip. You choose it. |
{
"data": [
{
"type": "tags",
"attributes": {
"protocol": "ntag_424_dna",
"url": "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b"
}
}
]
}
curl https://platform.tagbase.io/api/v1/tags \
-X POST \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Content-Type: application/vnd.api+json" \
-d '{ "data": [ { "type": "tags", "attributes": { "protocol": "ntag_424_dna", "url": "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b" } } ] }'
const res = await fetch("https://platform.tagbase.io/api/v1/tags", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TAGBASE_API_KEY}`,
"Content-Type": "application/vnd.api+json",
},
body: JSON.stringify({
data: [
{
type: "tags",
attributes: {
protocol: "ntag_424_dna",
url: "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b",
},
},
],
}),
});
const tags = (await res.json()).data;
$response = $client->post("https://platform.tagbase.io/api/v1/tags", [
"headers" => [
"Authorization" => "Bearer " . getenv("TAGBASE_API_KEY"),
"Content-Type" => "application/vnd.api+json",
],
"json" => [
"data" => [[
"type" => "tags",
"attributes" => [
"protocol" => "ntag_424_dna",
"url" => "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b",
],
]],
],
]);
$tags = json_decode((string) $response->getBody(), true)["data"];
tags =
Req.post!("https://platform.tagbase.io/api/v1/tags",
headers: [
{"authorization", "Bearer #{System.fetch_env!("TAGBASE_API_KEY")}"},
{"content-type", "application/vnd.api+json"}
],
json: %{
data: [
%{
type: "tags",
attributes: %{
protocol: "ntag_424_dna",
url: "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b"
}
}
]
}
).body["data"]
Response — 201 Created
A JSON:API array of the created tags. Each entry pairs the platform-assigned
id with the url it was created from, so you can map them back to your records.
{
"data": [
{
"type": "tags",
"id": "tag_abcdef0123456789",
"attributes": { "url": "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b" }
}
]
}
Tags are returned in created status. Writing them onto physical chips happens
separately and asynchronously; your integration holds the ids in the meantime and
learns when each tag advances through webhooks —
tag.configured when it’s written and ready to scan, tag.configuration_failed
if a write fails.
Errors
| Status | When |
|---|---|
400 |
data is not an array of 1–500 entries, or any entry is missing protocol or url. |
401 |
Missing, invalid, or revoked key. |
422 |
Validation failed — e.g. a duplicate url or an unrecognized protocol. |
Retrieve a tag
GET /api/v1/tags/:id
Fetch a tag you provisioned, including its current lifecycle status. The key you
present must own the tag, or the platform responds 404.
curl https://platform.tagbase.io/api/v1/tags/tag_abcdef0123456789 \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Accept: application/vnd.api+json"
const res = await fetch(
"https://platform.tagbase.io/api/v1/tags/tag_abcdef0123456789",
{
headers: {
"Authorization": `Bearer ${process.env.TAGBASE_API_KEY}`,
"Accept": "application/vnd.api+json",
},
},
);
const tag = await res.json();
$response = $client->get("https://platform.tagbase.io/api/v1/tags/tag_abcdef0123456789", [
"headers" => [
"Authorization" => "Bearer " . getenv("TAGBASE_API_KEY"),
"Accept" => "application/vnd.api+json",
],
]);
$tag = json_decode((string) $response->getBody(), true);
tag =
Req.get!("https://platform.tagbase.io/api/v1/tags/tag_abcdef0123456789",
headers: [
{"authorization", "Bearer #{System.fetch_env!("TAGBASE_API_KEY")}"},
{"accept", "application/vnd.api+json"}
]
).body
Response — 200 OK
{
"data": {
"type": "tags",
"id": "tag_abcdef0123456789",
"attributes": {
"url": "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b",
"status": "configured",
"configured_at": "2026-06-08T12:34:56.123456Z"
}
}
}
Polling this endpoint is a fallback for tracking a tag’s lifecycle; webhooks are the push alternative and fire as the tag advances.
Errors
| Status | When |
|---|---|
401 |
Missing, invalid, or revoked key. |
404 |
No such tag under your account. |
Notes
- A tag can be fetched by id (above); there is no endpoint to list tags. Persist the returned ids when you create the batch.
- Tags belong to the account whose key created them. To keep tenants isolated, create each tenant’s tags with that tenant’s subaccount key.