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 — not the internals of how a tag proves itself.
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": "<protocol>", "count": 1 } } }'
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: "<protocol>", count: 1 } },
}),
});
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" => "<protocol>", "count" => 1]],
],
]);
$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: "<protocol>", count: 1}}}
).body
{
"data": [ { "type": "tags", "id": "tag_abcdef0123456789" } ]
}
protocol is the tag protocol for your hardware — ask TAGBASE for the value to
use. See Tags for 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 first scan returns pending and opens a session. To
finish the check, forward a second tap with that session id as
tagbase_session_id:
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...", "tagbase_session_id": "ses_abcdef0123456789" } } }'
const attributes = { ...tapParams, tagbase_session_id: sessionId };
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();
$attributes = $tapParams + ["tagbase_session_id" => $sessionId];
$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);
attributes = Map.put(tap_params, "tagbase_session_id", session_id)
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_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, proven live. 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 two-scan 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 two-scan flow in full.
- Building a solution — an end-to-end walkthrough that puts it all together.