JavaScript SDK
There is no published TAG IT npm package. The supported JavaScript integration today is a direct on-chain read with viem — roughly fifteen lines, no API key, no signup. This page documents that path first, then describes honestly how far the in-development @tagit/sdk package has actually got.
The package is not published to npm — the registry returns 404 for @tagit/sdk, so any install command targeting it fails. Everything else on this page was verified by direct execution on 26 July 2026 and runs against Base Sepolia testnet (chain ID 84532) against unaudited contracts. Suitable for integration and evaluation; not a basis for a custody, payment or settlement decision.
What works from JavaScript today
Everything marked Live below can be called right now from Node or a browser. Everything marked Not available genuinely does not exist — there is no package, endpoint or method that provides it, and none is documented here.
| What you want to do | How, today | Status |
|---|---|---|
| Read an asset's owner, lifecycle state and timestamp | getAsset on TAGITCore via viem |
Live |
| Check the gateway is up | GET api.tagit.network/health |
Live |
| Get a signed verification verdict | POST api.tagit.network/verify (x402-paid) |
Live |
| Verify a physical NFC tap | GET verify.tagit.network/api/verify |
Live — needs a real tap |
| Fetch a Digital Product Passport credential | GET verify.tagit.network/api/dpp/… |
Live — needs a real tap |
| Register a product, bind a tag, activate or flag an asset | On-chain writes, gated by a BIDGES capability badge | Not available to the public |
| Install a TAG IT client library from npm | — | Not available |
| Subscribe to webhooks or a hosted event stream | — | Not available |
Installation
The only dependency you need for the live integration path is viem:
npm install viem
That is deliberate. TAG IT's read path is plain contract calls over a public RPC, so any Ethereum client works — viem, ethers, web3.js, or cast from Foundry. Nothing here depends on a TAG IT-authored package, an API key or a CDN bundle.
Reading asset state
The TAGITCore contract at 0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D on Base Sepolia exposes getAsset(uint256) as a view function. Anyone can call it — no credential, no wallet, no rate limit beyond your RPC provider's. You are not trusting a TAG IT server: you re-derive the verdict yourself.
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
That output is the real result for token 50, executed on 26 July 2026. Run it yourself and you should get the same owner and timestamp; only state can change, and only if the asset moves through the lifecycle.
Lifecycle states
state is an integer from the asset state machine. Branch on it rather than on any string label:
| 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 |
const STATES = ['NONE', 'MINTED', 'BOUND', 'ACTIVATED', 'CLAIMED', 'FLAGGED', 'RECYCLED'];
console.log(STATES[state]); // 'CLAIMED'
TypeScript
viem infers argument and return types from the ABI, so you get full type safety without any TAG IT-authored type package. The one thing to remember is as const — without it TypeScript widens the ABI to string and inference collapses:
import { createPublicClient, http, type Address } from 'viem';
import { baseSepolia } from 'viem/chains';
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' },
],
}] as const; // ← required for inference
const client = createPublicClient({ chain: baseSepolia, transport: http() });
// Inferred as readonly [Address, bigint, number, number, number]
const asset = await client.readContract({
address: '0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D',
abi: TAGITCoreABI,
functionName: 'getAsset',
args: [50n],
});
const owner: Address = asset[0];
const state: number = asset[2];
Calling the HTTP endpoints
Four HTTP endpoints are reachable from JavaScript. They are documented in full on the REST API page; the snippets here are the JavaScript form.
Gateway liveness
const res = await fetch('https://api.tagit.network/health');
const body = await res.json();
// → { status: 'ok', timestamp: '2026-07-26T21:40:00.852Z', runtime: 'vercel' }
Paid verification (x402)
POST /verify returns a signed verdict, gated by the x402 micropayment protocol. Calling it without a payment proof returns 402 together with the payment requirements — that response is the handshake, not a failure:
const res = await fetch('https://api.tagit.network/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ assetId: '18', chain: 'base-sepolia' }),
});
if (res.status === 402) {
const { accepts } = await res.json();
// accepts[0] describes what to pay, on which network, to which resource.
// Settle it with an x402-capable client, then repeat the request with proof attached.
console.log(accepts[0]);
}
Settling the payment requires an x402 client holding USDC on Base. TAG IT does not ship one; use any implementation of the protocol.
Verifying a physical tap
The tap endpoints take a SUN cryptogram emitted by an NTAG 424 DNA chip. The picc and cmac values come from the chip itself and cannot be constructed — without a real tap there is nothing to send, so these calls are not testable from a keyboard:
// picc and cmac are read from the chip by the tapping device
const url = new URL('https://verify.tagit.network/api/verify');
url.searchParams.set('picc', picc); // 32 hex chars
url.searchParams.set('cmac', cmac); // 16 hex chars
const { verified, bound, uid, asset } = await (await fetch(url)).json();
// Branch on `verified`, never on the HTTP status:
// counterfeit and unbound outcomes are both returned as 200.
if (!verified) handleCounterfeit();
The Digital Product Passport endpoint takes the same cryptogram and returns a W3C Verifiable Credential as application/ld+json:
const dpp = await fetch(
`https://verify.tagit.network/api/dpp/01/${gtin}/21/${serial}?picc=${picc}&cmac=${cmac}`
).then(r => r.json());
If your code needs to know what the chain says about an asset, use the direct getAsset read — it is open, keyless and independently verifiable. The tap endpoints answer a different question: was this specific physical chip present? That answer requires hardware and cannot be obtained over HTTP alone by design.
Error handling
There is no TAG IT error taxonomy to import, because there is no TAG IT package in your dependency tree. Failures come from the two layers you are actually talking to:
- RPC / transport — viem throws its own typed errors (
ContractFunctionExecutionError,HttpRequestErrorand friends). Catch them around thereadContractcall and retry against a different RPC endpoint if needed. - HTTP — the gateway returns a JSON body with an
errorfield. The full status table is on the REST API page. Two cases are easy to mishandle:402onPOST /verifyis the expected x402 handshake, and a counterfeit chip is reported as200withverified: false.
try {
const asset = await client.readContract({ /* … */ });
} catch (err) {
// viem error — RPC unreachable, bad address, revert, etc.
console.error(err.shortMessage ?? err.message);
}
Write operations
The lifecycle write functions on TAGITCore — mint, bindTag, activate, claim, flag, resolve and recycle — are not open to the public. Each requires the caller to hold the corresponding BIDGES capability badge, which is issued to verified manufacturers, retailers and authorities rather than to arbitrary wallets. The one exception is transferAsset, which takes no badge but reverts unless the caller is already the on-chain owner of an asset in the CLAIMED state — so it is not something an integrator can call speculatively either.
Consequently there is no JavaScript recipe for registering a product on this page, and none of these writes has been exercised end-to-end from a browser, so no example is presented as working. If you need write access, get in touch; the badge, not a library, is the gating factor.
The @tagit/sdk package — in development, not published
A TypeScript package does exist in the tagit-sdk repository at version 0.1.0. It is worth being precise about what it is, because it is not what an SDK page would usually imply:
- It is not on npm.
npm install @tagit/sdkfails withE404. - It is a client for agent identity, reputation and validation contracts (ERC-8004), plus WTag and Voucher helpers, an A2A protocol client and a bridge client.
- It does not do product registration, product verification or ownership transfer. Those are not in its surface at all.
- Its default chain is OP Sepolia (chain ID
11155420), which was deprecated on 27 June 2026 in favour of Base Sepolia (84532). The canonical TAGITCore deployment shown above is on Base Sepolia. - TypeScript / JavaScript only. There is no Python package and no Swift or Kotlin package.
enginesrequires Node 20 or newer.
Current export surface
These are the actual public runtime exports as of version 0.1.0, read from src/index.ts; TypeScript type-only exports are omitted. Nothing here is installable from npm yet:
| Area | Exports |
|---|---|
| Client factory | createAgentClient |
| Agent contracts | createAgentReader, createAgentWriter |
| WTag | createWTagReader, createWTagWriter |
| Vouchers | createVoucherReader, createVoucherWriter |
| Bridge | createBridgeClient |
| A2A protocol | A2AClient, A2AClientPool, fetchAgentCard, parseSSEStream, RPC_ERRORS |
| Enums | AgentStatus, RequestStatus |
| ABIs | agentIdentityAbi, agentReputationAbi, agentValidationAbi, wtagAbi, voucherAbi |
| Chains & addresses | getAddresses, opSepolia |
| Errors | SdkError, ContractError, ValidationError, A2AError, A2ATimeoutError, A2AConnectionError, A2AProtocolError |
| Validation | zod schemas and TypeScript types |
Until it is published you can build it from source, bearing in mind that its default deployment targets the deprecated OP Sepolia chain:
git clone https://github.com/TAG-IT-NETWORK/tagit-sdk.git
cd tagit-sdk
npm install
npm run build # emits dist/
When the package ships to npm, this page will document its methods with runnable examples — on the day it ships, not before.
What does not exist
Earlier revisions of this page described modules that were never built. To be unambiguous: there is no products, transfers, events, webhooks, nfc, chips, tags, storage, security or marketplace namespace in any TAG IT JavaScript package. There is no CDN bundle, no API key or secret, no mainnet deployment, no WebSocket event stream and no sandbox host. If you have code written against any of those, it never worked, and the direct on-chain read is what to replace it with.
Join our Discord community for real-time support, or see the REST API reference and contract addresses for the underlying endpoints.