Method GET/passport /01 /{gtin} /10 /{lot} /proof
Fetch the public proofs of a batch's passport: content hash, seal, anchoring of the document on Base without any minting, state of the signed credential. Public endpoint.
On this page
You fetch the public proofs of a production batch's passport. When you leave this page, you will know how to request these proofs, how to check by yourself that the batch's version is written on chain, and why no minting was needed.
Full address:
GET https://api.sealtrust.io/v1/passport/01/{gtin}/10/{lot}/proof#
None, public endpoint. The response is the same for everyone.
#Rate limit
600 calls per window of 60 seconds, counted per calling IP address, shared by
every read (GET) whose address starts with /passport.
#Path and query parameters
| Name | Type | Required | Description |
|---|---|---|---|
gtin | string | yes | The GTIN of the batch's model. Its check digit is verified. |
lot | string | yes | The lot number, compared exactly, case included. |
This endpoint has no query parameter.
#Request body
None. This request has no body.
#Example request
curl -i "https://api.sealtrust.io/v1/passport/01/03701234567891/10/LOT-26A/proof"const response = await fetch(
"https://api.sealtrust.io/v1/passport/01/03701234567891/10/LOT-26A/proof",
);
const proofs = await response.json();
console.log(proofs.level, proofs.batch_code, proofs.passport_anchor);import requests
response = requests.get(
"https://api.sealtrust.io/v1/passport/01/03701234567891/10/LOT-26A/proof",
timeout=30,
)
proofs = response.json()
print(proofs["level"], proofs["batch_code"], proofs.get("passport_anchor"))#Example response
HTTP code 200, for a version already anchored.
{
"passport_version": 2,
"data_hash": "9f2c1e7d4b8a6f0e3d5c2b1a9e8f7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e",
"passport_anchor": {
"type": "passport_anchor",
"chain": "base",
"chain_id": 8453,
"tx_hash": "0x5e1f0c2d3b4a59687766554433221100ffeeddccbbaa99887766554433221100",
"merkle_root": "0x0d1c2b3a49586776655443322110ffeeddccbbaa998877665544332211000f1e",
"leaf": "0x7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b",
"leaf_index": 3,
"proof": ["0x1122334455667788990011223344556677889900112233445566778899001122"],
"block_timestamp": "2026-09-26T09:00:02+00:00",
"passport_version": 2,
"data_hash_matches": true,
"anchored": true,
"proves": "content_existed_at_or_before_tx"
},
"seal": {"sealed": true, "linked": true, "chain_link_match": true},
"vc": {"issued": false},
"level": "batch",
"gtin": "03701234567891",
"batch_code": "LOT-26A"
}Every value in this example is fictitious, and the real response carries other
fields in passport_anchor and seal, described on
GET /passport/01/{gtin}/proof.
Two blocks are absent, and their absence is the right answer: anchor, which
dates an item, and verifications, which counts the reads of a physical label.
A batch is neither. As long as the version has not been taken by the sweep,
passport_anchor is absent too, and seal is enough to make any rewrite
visible in the meantime.
#Verifying the proof yourself
The leaf is keccak256(abi.encode(uint256 passportId, uint256 passportVersion, bytes32 dataHash)), where passportId is the id field of
GET /passport/01/{gtin}/10/{lot}.
Walking up from the leaf with each node of proof, two by two and in
ascending byte order, you get back merkle_root. The detail is on
Trust and proofs.
#Errors
| Code | Condition | What to do |
|---|---|---|
| 400 | The GTIN check digit does not match. | Copy the GTIN again from the barcode. |
| 404 | No published passport for this batch, a batch of another brand than the one of the called domain, or a batch of another brand than the one that publishes the model passport of this GTIN. | Check the lot number, case included, and the publication in the console. |
| 429 | More than 600 calls in 60 seconds from the same IP address. | Wait the number of seconds given by Retry-After. |
#See also
GET /passport/01/{gtin}/10/{lot}, the content of the batch's passport.- Trust and proofs, what each proof establishes and how to cross-check it.
Was this page helpful?
Your answer opens a pre-filled email in your mail app, addressed to contact@sealtrust.io. You read it over before sending it.