Mobile SDKs
There is no TAG IT mobile SDK package to install. This page documents what a mobile app can actually do today: read the chip with the platform NFC API, verify the tap server-side, and read asset state directly from the contract.
TAG IT does not publish a Swift package, a CocoaPod, a Maven/Gradle artifact, a React Native package or a Flutter plugin. Nothing named TagItSDK, network.tagit:sdk, @tagit/react-native-sdk or tagit_sdk exists in any registry. There is also no published @tagit/sdk npm package: the registry returns a 404 for it, so any install command you may have seen for it cannot succeed.
What does exist is a first-party scanner app plus two public HTTP surfaces and the contract itself. Everything below is verified working; the rest of this page is deliberately short because short and true beats long and plausible.
What exists today
Everything on TAG IT is currently deployed to the Base Sepolia testnet (chain ID 84532), and the contracts are unaudited. Do not treat any of the following as production infrastructure.
| Component | What it is | Status |
|---|---|---|
| ORACULAR app | First-party React Native (Expo) scanner. Tap a chip, verify, view the asset. | Internal builds only — not on the App Store or Google Play, and not distributed as a library |
verify.tagit.network/api/verify |
Server-side verification of an NTAG 424 DNA SUN tap | Live |
verify.tagit.network/api/dpp/... |
Digital Product Passport (W3C Verifiable Credential) for a GS1 Digital Link tap | Live |
api.tagit.network |
Verification API — GET /health and a paid POST /verify (x402) |
Live |
| TAGITCore contract | Direct on-chain read of asset owner, timestamp and lifecycle state | Live on Base Sepolia |
| Mobile SDK package | Installable iOS / Android / React Native / Flutter library | Does not exist |
Why a tap is verified server-side
TAG IT uses the NXP NTAG 424 DNA chip in SUN (Secure Unique NFC) mode. On every tap the chip regenerates its NDEF URL and appends two query parameters:
picc— 32 hex characters. The chip's UID and its monotonic tap counter, AES-encrypted with the chip's SDM key.cmac— 16 hex characters. A truncated AES-CMAC over that message, computed by the chip.
A phone reading the tag gets ciphertext and a MAC, and nothing else. It cannot decrypt the PICC or validate the CMAC on-device, because doing so requires the SDM key — and shipping that key inside an app binary would hand every attacker the ability to mint valid taps for every chip in the fleet. So the mobile app forwards picc and cmac to the verifier, which holds the key server-side, checks the CMAC, rejects replays via the tap counter, and resolves the on-chain twin.
Offline SUN verification is not an unimplemented feature — it is cryptographically impossible under this design without putting the SDM key on the device. An app with no connectivity can still show a cached previous result, but it cannot establish that a fresh tap is genuine.
The tap → verify flow
- Read the NDEF URI record from the chip using the platform NFC API.
- Parse
piccandcmacout of the URL's query string. GET https://verify.tagit.network/api/verify?picc=<32 hex>&cmac=<16 hex>- Render the JSON response.
Chips are personalized to a SUN landing URL that carries those parameters, for example:
https://verify.tagit.network/sun?picc=<32 hex>&cmac=<16 hex>
You can exercise the verification endpoint right now. With parameters that are not a genuine tap it returns HTTP 200 and a structured rejection:
curl -s "https://verify.tagit.network/api/verify?picc=00000000000000000000000000000000&cmac=0000000000000000"
{
"verified": false,
"reason": "unexpected PICC tag 0xba",
"chain": { "id": 84532, "name": "Base Sepolia" }
}
A genuine tap returns "verified": true together with the resolved asset. The fields the first-party app reads from that response are verified, uid, tapCounter, chain.id, chain.name, and an asset object containing tokenId, stateCode, lifecycleState, owner and timestamp — see src/services/sunVerify.ts in the ORACULAR app. Producing a verified: true response requires a physical chip: there is no way to synthesize a valid picc/cmac pair without one.
Reading the chip on device
Chip reading uses the ordinary platform NFC stack — there is no TAG IT layer involved, and nothing TAG IT-specific to install.
iOS
Use Core NFC (NFCNDEFReaderSession). NFC tag reading requires iOS 13+ and an iPhone 7 or later, and your app must declare the usage description:
<key>NFCReaderUsageDescription</key>
<string>Used to verify the authenticity of your TAG IT-chipped items.</string>
Android
Use android.nfc.NfcAdapter with foreground dispatch or the reader-mode API. Declare the permission in your manifest:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
React Native
The ORACULAR app is Expo + React Native and reads chips with the third-party react-native-nfc-manager package. This is that app's actual read path, condensed:
import NfcManager, { NfcTech, Ndef } from 'react-native-nfc-manager';
await NfcManager.start();
async function readTagUrl() {
await NfcManager.requestTechnology(NfcTech.Ndef, {
alertMessage: 'Hold your TAG IT chip near the top of your iPhone',
});
try {
const tag = await NfcManager.getTag();
if (!tag?.ndefMessage?.length) throw new Error('No NDEF message found on tag');
for (const record of tag.ndefMessage) {
if (record.tnf === Ndef.TNF_WELL_KNOWN) {
const uri = Ndef.uri.decodePayload(new Uint8Array(record.payload));
if (uri) return uri;
}
}
throw new Error('No URL record found in NDEF message');
} finally {
NfcManager.cancelTechnologyRequest().catch(() => {});
}
}
NFC does not work in the iOS Simulator, the Android emulator or Expo Go. You need a native development build on a physical device to test any of this.
Parsing the SUN URL and verifying
Once you have the URL string, the rest is a query-string parse and one fetch. This runs anywhere with URL and fetch — React Native, a browser, or Node 18+:
async function verifyTap(rawUrl) {
const params = new URL(rawUrl).searchParams;
const picc = params.get('picc'); // 32 hex — encrypted UID + counter
const cmac = params.get('cmac'); // 16 hex — truncated AES-CMAC
if (!picc || !cmac) throw new Error('Not a SUN URL: missing picc or cmac');
const res = await fetch(
`https://verify.tagit.network/api/verify?picc=${picc}&cmac=${cmac}`,
{ headers: { Accept: 'application/json' } }
);
return res.json();
}
That is the whole client-side integration. There is no API key, no SDK object and no initialization step, because the endpoint is public and the chip's CMAC is the credential.
Reading asset state directly on-chain
If you already know a token ID — from a verified tap, from a deep link, or from your own records — you can read its state straight from the contract with no TAG IT service in the path. TAGITCore is deployed on Base Sepolia at 0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D.
import { createPublicClient, http } from 'viem';
import { baseSepolia } from 'viem/chains';
const TAGIT_CORE = '0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D';
const getAssetAbi = [{
type: 'function',
name: 'getAsset',
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 client = createPublicClient({
chain: baseSepolia,
transport: http('https://sepolia.base.org'),
});
const [assetOwner, timestamp, state] = await client.readContract({
address: TAGIT_CORE,
abi: getAssetAbi,
functionName: 'getAsset',
args: [50n],
});
// Real result for token 50 on Base Sepolia:
// assetOwner 0x458B4d0c3a55006965Fd13D6af7B8509De51Cb3D
// timestamp 1784246184n
// state 4 (CLAIMED)
Hermes ships without crypto.getRandomValues and TextEncoder/TextDecoder, and viem fails deep inside its encoding paths without them. Install react-native-get-random-values and fast-text-encoding, and import both at the very top of your app entry file, before anything that touches viem.
Lifecycle states
The state byte returned by getAsset maps to the seven-state asset lifecycle:
| Value | State | Meaning |
|---|---|---|
| 0 | NONE | Token does not exist |
| 1 | MINTED | Digital twin created, no chip bound yet |
| 2 | BOUND | NFC chip cryptographically linked to the twin |
| 3 | ACTIVATED | Passed QA, ready for market |
| 4 | CLAIMED | Owned by an end consumer |
| 5 | FLAGGED | Lost, stolen or under investigation |
| 6 | RECYCLED | End of life, terminal |
All state-changing functions — mint, bindTag, activate, claim, flag, resolve, recycle and transferAsset — are gated on a BIDGES capability badge. None of them are open to arbitrary callers, so a consumer-facing mobile app is a read-and-verify client only.
Digital Product Passport
Chips personalized as a GS1 Digital Link resolve to a passport endpoint that returns a W3C Verifiable Credential for the tapped item:
curl -s "https://verify.tagit.network/api/dpp/01/<GTIN>/21/<serial>?picc=<32 hex>&cmac=<16 hex>"
Like /api/verify, it requires a real tap. Without valid SUN parameters it returns the same structured rejection:
{
"verified": false,
"reason": "unexpected PICC tag 0xba"
}
Human-readable fallback
Because a TAG IT chip emits a plain HTTPS URL, a tap on a phone with no app installed simply opens the verifier in the browser. These pages are live and are a legitimate destination for deep links out of your own app:
https://verify.tagit.network/asset/<tokenId>— asset detail by token IDhttps://verify.tagit.network/tag/<uid>— asset detail by chip UIDhttps://verify.tagit.network/01/<gtin>/21/<serial>— GS1 Digital Link landing page
Not available yet
The following do not exist. They are listed explicitly so that nobody plans around them:
- Installable mobile packages — no Swift Package Manager package, CocoaPod, Maven/Gradle artifact, React Native package or Flutter plugin.
- A published JavaScript package —
@tagit/sdkis not on npm. The source exists (TypeScript only, no Python and no Swift or Kotlin equivalent), and it is an agent identity / reputation / validation client with WTag and Voucher helpers — it does not register products, verify products or transfer ownership. Its default chain is still OP Sepolia (11155420), which was deprecated on 2026-06-27 in favour of Base Sepolia (84532). - Offline verification — see above; not possible without shipping the SDM key.
- A public app build — ORACULAR is not on the App Store or Google Play.
- Support for other chips — NTAG 424 DNA is the only chip TAG IT uses. Nothing here applies to NTAG 213/215/216, DESFire or ISO 15693 tags.
- Write access from a mobile client — every lifecycle write requires a capability badge.
Contracts are deployed to Base Sepolia (84532) and have not completed a third-party audit. Token IDs, addresses and endpoints shown here are testnet artifacts and may be reset. Do not build production or custody-bearing flows on them.
Deployed addresses are listed on the Contract Addresses page. For anything else, ask in our Discord community — if a capability you need is missing, tell us rather than assuming it is coming.