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.
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-sdk | No such package |
from tagit import TagIt, AsyncTagIt | No such module |
client.products.register() / .verify() / .get() | Never existed |
client.transfers.initiate() / .confirm() | Never existed |
tagit.django app and middleware | Never existed |
| API key / API secret pairs | No key system exists; nothing on this page needs one |
network="mainnet" | There is no mainnet deployment. Base Sepolia testnet only |
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.
| Contract | Address | Chain |
|---|---|---|
| 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:
| 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 |
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 — 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 TAGITCore — mint, 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:
- It is not published to any registry. It is consumed from source out of the
tagit-sdkrepository. - It covers agent identity, reputation and validation, plus WTag and Voucher helpers. It does not do product registration, verification or ownership transfer — so for asset verification it would give you nothing the contract read above does not.
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.
| Capability | Status |
|---|---|
| Python package on PyPI | Not planned |
| Keyless public asset read over HTTP (no tap, no payment) | Planned |
| OpenAPI 3.1 specification | Planned |
| MCP server for LLM tool use | Planned |
| Webhooks and GraphQL | Not planned |