This quickstart takes you from zero to a first verification using the live API. You’ll authenticate, provision a tag, and submit a scan. It covers the API surface and the verdicts you get back.
The whole public API is three POST endpoints under
https://platform.tagbase.io/api/v1. Every request carries your API key and the
JSON:API content type. Each call below is shown in curl, JavaScript (fetch),
PHP (Guzzle), and Elixir
(Req) — pick your language with the tabs.
1. Authenticate
You authenticate as an account with a bearer key. Put it in an environment variable so it never lands in your shell history:
export TAGBASE_API_KEY="key_abcdef0123456789:superstrongrandomsecret"
See Authentication for the key format and where keys come from.
2. Provision a tag
Create a tag under your account. You get back the tag’s id, which you’ll keep and reference when verifying scans.
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 tag = (await res.json()).data[0];
$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"]]],
],
]);
$tag = json_decode((string) $response->getBody(), true)["data"][0];
%{"data" => [tag]} =
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": [
{
"type": "tags",
"id": "tag_abcdef0123456789",
"attributes": { "url": "https://zannatherapeutics.com/verify/lonafen/8a3f9c2b" }
}
]
}
protocol selects the chip type. See Tags for the supported
values, the full request, and the tag lifecycle.
3. Run a verification
Once a tag has been written to a physical chip, a tap produces a URL with scan parameters in its query string. Forward those parameters to the platform and read back the verdict:
curl https://platform.tagbase.io/api/v1/tags/tag_abcdef0123456789/verifications \
-X POST \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Content-Type: application/vnd.api+json" \
-d '{ "data": { "type": "verifications", "attributes": { "...": "...tap URL params..." } } }'
const res = await fetch(
`https://platform.tagbase.io/api/v1/tags/${tagId}/verifications`,
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TAGBASE_API_KEY}`,
"Content-Type": "application/vnd.api+json",
},
body: JSON.stringify({ data: { type: "verifications", attributes } }),
},
);
const verification = await res.json();
$response = $client->post(
"https://platform.tagbase.io/api/v1/tags/{$tagId}/verifications",
[
"headers" => [
"Authorization" => "Bearer " . getenv("TAGBASE_API_KEY"),
"Content-Type" => "application/vnd.api+json",
],
"json" => ["data" => ["type" => "verifications", "attributes" => $attributes]],
],
);
$verification = json_decode((string) $response->getBody(), true);
verification =
Req.post!("https://platform.tagbase.io/api/v1/tags/#{tag_id}/verifications",
headers: [
{"authorization", "Bearer #{System.fetch_env!("TAGBASE_API_KEY")}"},
{"content-type", "application/vnd.api+json"}
],
json: %{data: %{type: "verifications", attributes: attributes}}
).body
{
"data": {
"type": "verifications",
"id": "vrf_abcdef0123456789",
"attributes": { "status": "pending", "inserted_at": "2026-06-08T12:34:56.123456Z" },
"relationships": {
"session": { "data": { "type": "sessions", "id": "ses_abcdef0123456789" } },
"tag": { "data": { "type": "tags", "id": "tag_abcdef0123456789" } }
}
}
}
The scan returns pending and opens a session. To finish
the check, forward another tap carrying that session id as the session
relationship:
curl https://platform.tagbase.io/api/v1/tags/tag_abcdef0123456789/verifications \
-X POST \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Content-Type: application/vnd.api+json" \
-d '{ "data": { "type": "verifications", "attributes": { "...": "...tap URL params..." }, "relationships": { "session": { "data": { "type": "sessions", "id": "ses_abcdef0123456789" } } } } }'
const res = await fetch(
`https://platform.tagbase.io/api/v1/tags/${tagId}/verifications`,
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TAGBASE_API_KEY}`,
"Content-Type": "application/vnd.api+json",
},
body: JSON.stringify({
data: {
type: "verifications",
attributes: tapParams,
relationships: { session: { data: { type: "sessions", id: sessionId } } },
},
}),
},
);
const verification = await res.json();
$response = $client->post(
"https://platform.tagbase.io/api/v1/tags/{$tagId}/verifications",
[
"headers" => [
"Authorization" => "Bearer " . getenv("TAGBASE_API_KEY"),
"Content-Type" => "application/vnd.api+json",
],
"json" => ["data" => [
"type" => "verifications",
"attributes" => $tapParams,
"relationships" => ["session" => ["data" => ["type" => "sessions", "id" => $sessionId]]],
]],
],
);
$verification = json_decode((string) $response->getBody(), true);
verification =
Req.post!("https://platform.tagbase.io/api/v1/tags/#{tag_id}/verifications",
headers: [
{"authorization", "Bearer #{System.fetch_env!("TAGBASE_API_KEY")}"},
{"content-type", "application/vnd.api+json"}
],
json: %{
data: %{
type: "verifications",
attributes: tap_params,
relationships: %{session: %{data: %{type: "sessions", id: session_id}}}
}
}
).body
{
"data": {
"type": "verifications",
"id": "vrf_MqiFaFwAs6U1pu5ALCxa5M",
"attributes": { "status": "valid", "inserted_at": "2026-06-08T12:34:58.654321Z" },
"relationships": {
"session": { "data": { "type": "sessions", "id": "ses_abcdef0123456789" } },
"tag": { "data": { "type": "tags", "id": "tag_abcdef0123456789" } }
}
}
}
status: "valid" — a genuine tag. That’s a complete verification.
Testing. Your own code is testable offline: since the verification
attributesare just the inbound query string passed through, you can unit-test your tap handler and session branching with any synthetic parameters. What you can’t fake is a realvalid/invalidverdict — that needs a tag TAGBASE has provisioned and written to a physical chip. There’s no public sandbox, so ask TAGBASE for test tags to exercise the flow end to end.
Next steps
- Resource model — how accounts, tags, sessions, and verifications relate.
- Verifications — the full scan-to-verdict sequence.
- Building a solution — an end-to-end walkthrough that puts it all together.