TAGBASE

API Reference

Verifications

Submit a scan and read back the authenticity verdict.

A verification is the platform’s verdict for a scan. When someone taps a tag, your solution forwards the scan to the platform and receives a verification that says whether the tag is genuine. This is the core call your integration makes.

How scanning works

Your solution owns the scan entry point. A tag’s chip is programmed with a URL that points at your app (https://<your-entry-point>/<tag_id>?<scan params>), so a tap arrives as a request to you, with the tag id in the path and the scan parameters in the query string. You then hand the scan to the platform, which validates it and records the verification.

Tap Your App POST /verifications Verdict

Fields

Field Type Notes
id string vrf_-prefixed, assigned by the platform.
status string The verdict (see below).
tamper_status string The seal reading (see below). null on a tag without a seal.
inserted_at string ISO 8601 timestamp (UTC, microsecond precision).

A verification also references its session and its tag as relationships.

Status values

Status Meaning
pending Scan accepted; the session hasn’t resolved to a final verdict yet.
valid Genuine: the tag verified successfully.
invalid Failed: the scan didn’t check out.

A verification you create comes back as exactly one of these three.

Seal readings

Some tags carry a tamper seal: a physical loop that the tag checks each time it is tapped to see whether the product has been opened. Every scan of such a tag returns the reading in tamper_status, alongside the verdict:

Reading Meaning
sealed The seal is intact; the product has not been opened.
resealed The seal was opened at some point and is now closed again.
open The seal is broken; the product has been opened.
invalid The tag could not read its seal.

tamper_status is null for a tag without a seal. Order a tag with one and the field starts carrying a reading; nothing else about your integration changes.

The seal is independent of status. A tag can verify as valid and still report open, which describes a genuine product in opened packaging. Treat the two as separate signals, and decide for yourself whether an opened seal changes what you show the customer.

Submit a scan

POST /api/v1/tags/:tag_id/verifications

:tag_id is the tag id of the scanned tag. The key you present must own that tag, or the platform responds 404.

This posts one scan at a time. If you already hold both scans of a tag, you can submit them together and resolve in a single call.

Request

The attributes are the tap URL’s query string, parsed into key/value pairs: every parameter, unchanged. When a tag is tapped, its chip produces a URL whose query string carries the data for that tap; your entry point receives it, and you copy the whole parsed query string into attributes. You never name or interpret those parameters: pass them through verbatim.

To continue a session an earlier verification returned, set the session relationship to its id; omit relationships entirely to start a fresh one.

Field Required Notes
attributes yes The scan parameters, copied from the tap URL’s query string.
relationships.session no The session to continue. Omit to start a new one.

Here’s a scan that starts a fresh session, with just the forwarded tap parameters and no session relationship (to continue a session you’d add one alongside them):

{
"data": {
"type": "verifications",
"attributes": {
"...": "...scan parameters copied from the tap URL..."
}
}
}

To continue a session, add the session relationship:

{
"data": {
"type": "verifications",
"attributes": {
"...": "...scan parameters copied from the tap URL..."
},
"relationships": {
"session": { "data": { "type": "sessions", "id": "ses_abcdef0123456789" } }
}
}
}
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..." } } }'

Response: 201 Created

{
"data": {
"type": "verifications",
"id": "vrf_abcdef0123456789",
"attributes": {
"status": "pending",
"tamper_status": "sealed",
"inserted_at": "2026-06-08T12:34:56.123456Z"
},
"relationships": {
"session": { "data": { "type": "sessions", "id": "ses_abcdef0123456789" } },
"tag": { "data": { "type": "tags", "id": "tag_abcdef0123456789" } }
}
}
}

Persist id, status, and the session id on your side as soon as you receive them; you can also re-fetch a verification by id later. Store tamper_status too if your tags carry a seal. The tag measures it at tap time, so re-fetching a verification later returns the reading from that tap rather than the state of the seal today.

Errors

Status When
400 The body has no data.attributes object.
401 Missing, invalid, or revoked key.
404 No such tag under your team, or the tag isn’t written to a chip yet.
422 The scan couldn’t be recorded; nothing was saved, so retrying the same request is safe. Not a failed security check.

Note that a tag that fails its security check still returns 201 with status: "invalid". That’s a successful verification with a negative verdict. 422 means the request itself couldn’t be processed, not that the tag is fake.

Sessions and resolution

  • A scan posted without a session relationship opens a new session: the verification comes back pending with a session id. Store that id against the scanning visitor (their session or a cookie). Scans are linked only because you re-present this id, not by anything the platform tracks about the device.
  • A scan posted with a session relationship continues that session, and the verdict resolves to valid or invalid.

A session stays open for the tag’s session_duration: 10 minutes unless you configured the tag otherwise. After that it expires; a later scan referencing it starts a fresh pending session instead of resolving the old one.

Submit both scans at once

The flow above spans two requests glued by a session. If you already hold both scans of a tag (for example a client that buffered taps while offline and is now syncing), you can submit them together and get the final verdict in a single call, with no pending step and no second round-trip.

Send data as an array of exactly two scans instead of a single object. Each entry is a verifications resource whose attributes are one scan’s tap parameters, copied verbatim, the same pass-through as a single scan. Order matters: the first entry is the first tap, the second is the second tap. You don’t set a session relationship; the call resolves on its own.

Request

{
"data": [
{ "type": "verifications", "attributes": { "...": "...first tap params..." } },
{ "type": "verifications", "attributes": { "...": "...second tap params..." } }
]
}
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": { "...": "...first tap params..." } },
{ "type": "verifications", "attributes": { "...": "...second tap params..." } }
] }'

Response: 201 Created

You get a data array of the verification records the call created, in scan order. The last entry carries the final verdict (valid or invalid). Read your authenticity result from it.

{
"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" } }
}
},
{
"type": "verifications",
"id": "vrf_bcdefa1234567890",
"attributes": { "status": "valid", "inserted_at": "2026-06-08T12:34:56.789012Z" },
"relationships": {
"session": { "data": { "type": "sessions", "id": "ses_abcdef0123456789" } },
"tag": { "data": { "type": "tags", "id": "tag_abcdef0123456789" } }
}
}
]
}

As with the single-scan call, persist each id and status on receipt; each is also retrievable by id.

Errors

Same as a single scan, plus one shape check:

Status When
400 data is an array but doesn’t hold exactly two scans, or an entry is missing its attributes.

Retrieve a verification

GET /api/v1/verifications/:id

Fetch a verification by id: its status and its session and tag relationships. The key you present must own the underlying tag, or the platform responds 404.

curl https://platform.tagbase.io/api/v1/verifications/vrf_abcdef0123456789 \
-H "Authorization: Bearer $TAGBASE_API_KEY" \
-H "Accept: application/vnd.api+json"

Response: 200 OK

{
"data": {
"type": "verifications",
"id": "vrf_abcdef0123456789",
"attributes": {
"status": "valid",
"inserted_at": "2026-06-08T12:34:56.123456Z"
},
"relationships": {
"session": { "data": { "type": "sessions", "id": "ses_abcdef0123456789" } },
"tag": { "data": { "type": "tags", "id": "tag_abcdef0123456789" } }
}
}
}

Errors

Status When
401 Missing, invalid, or revoked key.
404 No such verification under your team.
TAGBASE uses cookies to keep you signed in and protect against fraud. With your permission, we also measure how the site is used. Read our privacy policy for details.
Necessary
Analytics