REST API Reference
Everything TAG IT exposes over HTTP today. Every endpoint listed without a Planned marker is live and was verified by direct request on 26 July 2026 — you can call it right now, and most of it needs no key at all.
All contracts run on Base Sepolia testnet (chain ID 84532) and are unaudited. Verification results are suitable for integration and evaluation. Do not use them as the sole basis for a custody, payment or settlement decision.
What exists today
TAG IT has two HTTP hosts and one on-chain path. There is no single /v1 base URL — endpoints are grouped by the host that serves them.
| Endpoint | Auth | Callable by |
|---|---|---|
GET api.tagit.network/health |
None | Anyone |
POST api.tagit.network/verify |
x402 payment | Agents with USDC on Base |
GET verify.tagit.network/api/verify |
SUN cryptogram | A device that physically tapped the chip |
GET verify.tagit.network/api/dpp/… |
SUN cryptogram | A device that physically tapped the chip |
| Direct contract read (viem / ethers / cast) | None | Anyone, including AI agents |
Verification has two halves with deliberately opposite access rules. Attestation — proving a specific physical chip was present — requires a real NFC tap and a SUN cryptogram, and is intentionally not reachable without one. Assertion — reading the resulting on-chain state — is open to everyone, with no key, wallet or signup. If you are building an agent, the assertion half is what you want.
Reading state directly from the chain
The most reliable integration path requires no TAG IT credential at all: read the TAGITCore contract yourself over any public Base Sepolia RPC. You do not have to trust our API — you can re-derive every verdict independently.
| Contract | Address |
|---|---|
| TAGITCore | 0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D |
See Contract Addresses for the full deployment list.
// npm install viem
import { createPublicClient, http } from 'viem';
import { baseSepolia } from 'viem/chains';
const client = createPublicClient({ chain: baseSepolia, transport: http() });
const TAGITCoreABI = [{
name: 'getAsset', type: 'function', stateMutability: 'view',
inputs: [{ name: 'tokenId', type: 'uint256' }],
outputs: [
{ name: 'assetOwner', type: 'address' },
{ name: 'timestamp', type: 'uint64' },
{ name: 'state', type: 'uint8' },
{ name: 'flags', type: 'uint8' },
{ name: 'reserved', type: 'uint16' },
],
}];
const [owner, timestamp, state] = await client.readContract({
address: '0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D',
abi: TAGITCoreABI,
functionName: 'getAsset',
args: [50n],
});
console.log({ owner, timestamp, state });
// → { owner: '0x458B4d0c3a55006965Fd13D6af7B8509De51Cb3D',
// timestamp: 1784246184n, state: 4 } // 4 = CLAIMED
Lifecycle states
The state field is an integer from the asset lifecycle state machine:
| Code | State | Meaning |
|---|---|---|
0 | NONE | Token does not exist |
1 | MINTED | Digital twin created, no chip bound yet |
2 | BOUND | NFC chip cryptographically bound |
3 | ACTIVATED | QA passed, ready for distribution |
4 | CLAIMED | Owned by an end consumer |
5 | FLAGGED | Reported lost, stolen or recalled |
6 | RECYCLED | End of life, terminal |
GET /health
Gateway liveness check. No authentication.
curl https://api.tagit.network/health
{"status":"ok","timestamp":"2026-07-26T21:40:00.852Z","runtime":"vercel"}
POST /verify
Signed verification of an asset's on-chain state, gated by the x402 micropayment protocol. Calling it without a payment proof returns 402 Payment Required together with the payment requirements — that response is the protocol handshake, not an error.
curl -X POST "https://api.tagit.network/verify" \
-H "Content-Type: application/json" \
-d '{"assetId":"18","chain":"base-sepolia"}'
Response when no payment proof is attached:
{
"x402Version": 1,
"error": "Payment required",
"accepts": [{
"scheme": "exact",
"network": "base-sepolia",
"maxAmountRequired": "10000",
"resource": "https://api.tagit.network/verify",
"description": "TAG IT Asset Verification — BOUND state proof + ECDSA signature",
"mimeType": "application/json",
"maxTimeoutSeconds": 30
}]
}
With a valid X-PAYMENT header, the response carries the asset state plus an ECDSA signature over keccak256(tokenId, state, chainId, timestamp), so the verdict can be checked on-chain.
GET /api/verify
Verifies a physical NFC tap. NTAG 424 DNA chips emit an AES-encrypted PICC blob that cannot be decrypted on-device, so the tap's picc and cmac values are verified server-side and resolved to the on-chain twin. Both parameters come from the chip itself — they cannot be constructed without physically tapping it.
curl "https://verify.tagit.network/api/verify?picc=<32-hex>&cmac=<16-hex>"
| Outcome | Status | Body |
|---|---|---|
| Resolved | 200 | verified, bound: true, uid, tapCounter, asset, chain |
| Authentic but unbound | 200 | verified: false, bound: false, reason |
| Counterfeit | 200 | verified: false, reason |
| Missing parameters | 400 | error |
| Verifier not configured | 503 | error |
| Chain lookup failed | 502 | error |
This endpoint returns 200 for counterfeit and unbound outcomes, not an error status. The HTTP status reports whether the request succeeded; the verified field reports whether the chip is genuine. Branch on verified, never on the status code.
GET /api/dpp/…
Returns the asset's Digital Product Passport as a W3C Verifiable Credential (VCDM 2.0 JSON-LD, UNTP DigitalProductPassport profile), served as application/ld+json and CORS-open so external verifiers and GS1 resolvers can consume it. Like /api/verify, it requires a SUN cryptogram from a physical tap.
# By GS1 Digital Link identity
curl "https://verify.tagit.network/api/dpp/01/<GTIN>/21/<serial>?picc=<hex>&cmac=<hex>"
# By token ID
curl "https://verify.tagit.network/api/dpp/token/<tokenId>?picc=<hex>&cmac=<hex>"
The credential is unsigned in v1 — integrity comes from the on-chain anchor carried in its evidence field, which any consumer can re-derive from public RPC. The matching human-readable passport renders at verify.tagit.network/01/{GTIN}/21/{serial}. The same host serves an untapped, token-addressed page: check an asset on-chain on verify.tagit.network.
Planned
These are not yet available. They are listed so you can plan against them, and they will be documented here with working examples on the day they ship — not before.
| Capability | Status |
|---|---|
| Keyless public asset read by token ID (no tap, no payment) | Planned |
| MCP server for LLM tool use | Planned |
| OpenAPI 3.1 specification | Planned |
| A2A agent protocol endpoint | Planned |
| Agent registry and reputation lookup | Planned |
| Webhooks and GraphQL | Not planned |
Error codes
Error responses carry a JSON body with an error field describing the failure.
| Code | Status | When |
|---|---|---|
400 | Bad Request | Missing or malformed parameters — e.g. absent picc/cmac, or a non-numeric asset ID |
402 | Payment Required | x402 handshake on POST /verify. Expected, not a failure |
404 | Not Found | Unknown route on the gateway |
429 | Too Many Requests | Rate limit exceeded |
500 | Server Error | Verification failed unexpectedly |
502 | Bad Gateway | On-chain lookup failed after the chip verified |
503 | Unavailable | Verifier not configured |
Rate limiting
Public endpoints are rate limited per IP. There are no subscription tiers and no API keys today — if you need a higher limit for an integration, get in touch.
Edit this page on GitHub