Features Solutions Technology Tokenomics Docs About Launch App
Docs / SDK & Libraries / Python

Python

There is no TAG IT Python package. There is, however, a fully supported Python integration path — and it needs no TAG IT credential at all. Every snippet on this page was executed as written on 26 July 2026 and prints the output shown.

Testnet — not production

All contracts run on Base Sepolia testnet (chain ID 84532) and are unaudited. Results are suitable for integration and evaluation. Do not use them as the sole basis for a custody, payment or settlement decision.

There is no Python SDK

No TAG IT Python package exists in any form — not on PyPI, not in a private index, not in a pre-release branch. pip install tagit-sdk resolves to nothing on PyPI and fails. There is no TagIt class, no AsyncTagIt class, no tagit.django app, and no tagit.exceptions module.

Earlier versions of this page documented all of those. They were never implemented. The table below records what does not exist, so that code written against the old page can be identified and removed.

Referenced in old docs Reality
pip install tagit-sdkNo such package
from tagit import TagIt, AsyncTagItNo such module
client.products.register() / .verify() / .get()Never existed
client.transfers.initiate() / .confirm()Never existed
tagit.django app and middlewareNever existed
API key / API secret pairsNo key system exists; nothing on this page needs one
network="mainnet"There is no mainnet deployment. Base Sepolia testnet only
You do not need an SDK

TAG IT's verification data lives on a public chain. An SDK would only be a wrapper around a contract read that web3.py already does in six lines. Reading the chain yourself is the recommended integration path for every language — you do not have to trust our API, because you can re-derive every verdict independently.

Reading asset state with web3.py

This is the path that works today. It requires no signup, no key and no wallet — only a public Base Sepolia RPC endpoint.

Install

pip install web3

Verified against web3 7.16.0 on Python 3.14. Any 6.x or 7.x release exposes the same contract-call API.

Read TAGITCore.getAsset()

getAsset(uint256 tokenId) is a view function on the TAGITCore contract. It returns the asset's owner, its last state-change timestamp, and its lifecycle state.

ContractAddressChain
TAGITCore 0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D Base Sepolia (84532)

See Contract Addresses for the full deployment list.

# pip install web3
from web3 import Web3

RPC = "https://sepolia.base.org"          # Base Sepolia, chain ID 84532
TAGIT_CORE = "0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D"

GET_ASSET_ABI = [{
    "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"},
    ],
}]

STATES = {
    0: "NONE", 1: "MINTED", 2: "BOUND", 3: "ACTIVATED",
    4: "CLAIMED", 5: "FLAGGED", 6: "RECYCLED",
}

w3 = Web3(Web3.HTTPProvider(RPC))
core = w3.eth.contract(address=Web3.to_checksum_address(TAGIT_CORE), abi=GET_ASSET_ABI)

owner, timestamp, state, flags, reserved = core.functions.getAsset(50).call()

print("owner:", owner)
print("timestamp:", timestamp)
print("state:", state, STATES[state])

Output for token ID 50:

owner: 0x458B4d0c3a55006965Fd13D6af7B8509De51Cb3D
timestamp: 1784246184
state: 4 CLAIMED

A token that has never been minted is not an error — it returns the zero address and state 0. Branch on state, not on exceptions.

Lifecycle states

The state field is an integer from the asset lifecycle state machine:

CodeStateMeaning
0NONEToken does not exist
1MINTEDDigital twin created, no chip bound yet
2BOUNDNFC chip cryptographically bound
3ACTIVATEDQA passed, ready for distribution
4CLAIMEDOwned by an end consumer
5FLAGGEDReported lost, stolen or recalled
6RECYCLEDEnd of life, terminal

Without web3.py

If you cannot add a dependency, the same read is a plain JSON-RPC eth_call against the function selector 0xeac8f5b8, decodable with the standard library alone:

# No dependencies - Python 3 standard library only
import json
import urllib.request

RPC = "https://sepolia.base.org"
TAGIT_CORE = "0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D"
GET_ASSET_SELECTOR = "0xeac8f5b8"   # first 4 bytes of keccak256("getAsset(uint256)")

def get_asset(token_id: int):
    payload = {
        "jsonrpc": "2.0", "id": 1, "method": "eth_call",
        "params": [{
            "to": TAGIT_CORE,
            "data": GET_ASSET_SELECTOR + format(token_id, "064x"),
        }, "latest"],
    }
    req = urllib.request.Request(
        RPC, data=json.dumps(payload).encode(),
        headers={"Content-Type": "application/json", "User-Agent": "tagit-docs-example"},
    )
    with urllib.request.urlopen(req, timeout=10) as resp:
        result = json.load(resp)["result"]

    words = [result[2:][i:i + 64] for i in range(0, len(result) - 2, 64)]
    return {
        "owner": "0x" + words[0][24:],
        "timestamp": int(words[1], 16),
        "state": int(words[2], 16),
    }

print(get_asset(50))
{'owner': '0x458B4d0c3a55006965Fd13D6af7B8509De51Cb3D', 'timestamp': 1784246184, 'state': 4}

Two things to note. The User-Agent header is required — sepolia.base.org returns 403 Forbidden to urllib's default agent. And raw ABI decoding yields a lower-case address, not its EIP-55 checksummed form, so compare addresses case-insensitively or pass the value through eth_utils.to_checksum_address. If web3.py is already installed, eth_abi.decode(["address","uint64","uint8","uint8","uint16"], bytes.fromhex(result[2:])) replaces the manual word-slicing.

Calling the live HTTP endpoints

Two HTTP endpoints are reachable from Python with requests. Both were verified on 26 July 2026.

GET /health

Gateway liveness check. No authentication.

POST /verify

Signed verification gated by the x402 micropayment protocol. Calling it without a payment proof returns 402 Payment Required along with the payment requirements. That response is the protocol handshake, not a failure — treat 402 as a normal, expected branch.

# pip install requests
import requests

health = requests.get("https://api.tagit.network/health", timeout=10)
print(health.status_code, health.json())

resp = requests.post(
    "https://api.tagit.network/verify",
    json={"assetId": "18", "chain": "base-sepolia"},
    timeout=10,
)

if resp.status_code == 402:
    envelope = resp.json()
    for option in envelope["accepts"]:
        print(option["network"], option["maxAmountRequired"], option["description"])
else:
    print(resp.status_code, resp.json())
200 {'status': 'ok', 'timestamp': '2026-07-26T21:53:19.795Z', 'runtime': 'vercel'}
base-sepolia 10000 TAG IT Asset Verification — BOUND state proof + ECDSA signature

Settling the x402 payment requires signing a USDC transfer authorisation on Base and replaying the request with an X-PAYMENT header. There is no TAG IT Python helper for that step; use an x402 client library or construct the header yourself. With a valid payment the response carries the asset state plus an ECDSA signature over keccak256(tokenId, state, chainId, timestamp).

Endpoints Python cannot usefully call

The tap-verification endpoints require a SUN cryptogram emitted by an NTAG 424 DNA chip at the moment it is physically tapped. The picc and cmac values cannot be constructed, guessed or replayed from a server — that is the point of them.

GET https://verify.tagit.network/api/verify?picc=<32-hex>&cmac=<16-hex>
GET https://verify.tagit.network/api/dpp/01/<GTIN>/21/<serial>?picc=<32-hex>&cmac=<16-hex>

Without those parameters the endpoint returns 400 with {"verified": false, "error": "missing picc or cmac query params"}. A Python service can consume the result of a tap performed by a phone or reader, but it cannot originate one. To read state without a tap, use the contract read above.

Attestation vs assertion

Attestation — proving a specific physical chip was present — requires a real NFC tap and is intentionally unreachable without one. Assertion — reading the resulting on-chain state — is open to everyone, with no key, wallet or signup. Python belongs on the assertion side.

Writing to the chain

All state-changing functions on TAGITCoremint, bindTag, activate, claim, flag, resolve, recycle, transferAsset — require a BIDGES capability badge held by the calling address. None of them are open to the public, so there is no self-service write path to document from Python or any other language. If your integration needs to write, get in touch about badge issuance.

The one SDK that does exist

TAG IT has a single SDK, written in TypeScript. Two things about it matter before you consider bridging to it from Python:

Its default chain is also still OP Sepolia (11155420), which was retired on 27 June 2026 in favour of Base Sepolia (84532). See the JavaScript SDK page.

Planned

Not available today. Listed so you can plan against them; each will be documented here with working examples on the day it ships, and not before.

CapabilityStatus
Python package on PyPINot planned
Keyless public asset read over HTTP (no tap, no payment)Planned
OpenAPI 3.1 specificationPlanned
MCP server for LLM tool usePlanned
Webhooks and GraphQLNot planned
Edit this page on GitHub
Type to search documentation...