Method GET/products /{uid} /public
Read the public information of a product from its identifier: name, brand, image, token, transaction, state and theft report. No API key.
On this page
You read the public information of a product from its identifier. By the end of this page, you will know how to retrieve its name, the name and logo of its brand, an image, its token number, its registration transaction, its state, and whether it is reported stolen.
Full address:
GET https://api.sealtrust.io/v1/products/{uid}/publicThe same endpoint also answers without the /v1 prefix, at
https://api.sealtrust.io/products/{uid}/public. Both addresses call the same
code. Use the /v1 form for a new integration.
#
None, public endpoint. This endpoint reads no API key, no token and no cookie.
The server never looks at the Authorization header you send here, and it
returns the same response to you with or without it.
#Call limit
600 calls per 60-second window, counted per calling network address. The limit
is wide because hundreds of visitors at a trade fair or on a mobile network
often share one address. This counter is this read's own. The /v1 prefix does
not create a second budget: /products/{uid}/public and
/v1/products/{uid}/public share the same counter.
Every response carries three headers.
#Path and query parameters
| Name | Type | Required | Description |
|---|---|---|---|
uid | string | yes | The identifier of the product, in one of the four accepted forms: the hash of its chip (0x followed by 64 hexadecimal characters), its token id, the serial number printed on the item, or its certificate number. |
lang | string | no | The language of the category name: fr or en. Failing that, the server reads the Accept-Language header, then falls back to en. |
The four forms are those of GET /resolve/{identifier}, described in detail on
the page of that endpoint. The server tries the chip hash first, then the token
id, then the serial number, then the certificate number, and returns the first
product it finds.
You can send the chip hash with or without the 0x prefix, in uppercase or in
lowercase. The server strips the leading and trailing spaces before searching,
puts the value in lowercase and adds the 0x prefix if it is missing. So these
spellings all designate the same product. The serial number too is accepted in
uppercase as well as in lowercase.
A single query parameter, lang, and it is optional. It changes one thing in the
response: the language of category_name. Everything else is identical whatever
its value.
The server picks the language in this order: the lang parameter when it is fr
or en, otherwise the first recognised tag of the Accept-Language header,
otherwise en. A value the server does not recognise is ignored without an
error: you get en, and not a 422.
#Headers
No header is required.
#Request body
None. This request has no body.
#Example request
Reading the product whose identifier is
0x1111111111111111111111111111111111111111111111111111111111111111.
curl -i "https://api.sealtrust.io/v1/products/0x1111111111111111111111111111111111111111111111111111111111111111/public"const uid =
"0x1111111111111111111111111111111111111111111111111111111111111111";
const response = await fetch(
`https://api.sealtrust.io/v1/products/${encodeURIComponent(uid)}/public`,
{ method: "GET" },
);
if (!response.ok) {
throw new Error(`SealTrust replied ${response.status}`);
}
const product = await response.json();
console.log(product.product_name, product.brand_name);
console.log(product.is_verified, product.declared_stolen);import requests
from urllib.parse import quote
uid = "0x1111111111111111111111111111111111111111111111111111111111111111"
response = requests.get(
f"https://api.sealtrust.io/v1/products/{quote(uid, safe='')}/public",
timeout=30,
)
print(response.status_code)
print(response.json())#Example response
HTTP code 200.
{
"product_name": "Example Model Bag",
"brand_name": "Exemple SAS",
"brand_logo_url": "https://example-sas.test/logo.png",
"brand_hide_powered_by": false,
"image_url": "https://example-sas.test/media/sac-modele-example.jpg",
"category_name": "Maroquinerie",
"token_id": "11111111111111111111111111111111111111111111111111111111111111111111111111111",
"tx_hash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"status": "written",
"declared_stolen": false,
"is_verified": true,
"registered_at": "2026-03-04T10:22:31.481000+00:00",
"verified_at": "2026-03-04T10:22:31.481000+00:00",
"certificate_status": "active",
"contract_address": "0x3333333333333333333333333333333333333333",
"chain": null
}The response has sixteen fields and nothing else.
| Field | Type | Description |
|---|---|---|
product_name | string | null | The name of the product. null when no name has been recorded. |
brand_name | string | null | The name of the brand that owns the product. null when the product is attached to no brand. |
brand_logo_url | string | null | The address of the brand's logo. null when the brand has not uploaded one. |
brand_hide_powered_by | boolean | true when the "Powered by SealTrust" wording must disappear. Two conditions, and both are required: the brand's plan includes white labeling and the brand has chosen to hide the wording in its console. By default the wording stays, including for a brand that has just subscribed to Inside and changed nothing. |
image_url | string | null | The public address of the cover image. It is looked for in this order: an image attached directly to the item, then the main image of its model, then the media of the model. null only when none of these three tracks succeeds. It is the light copy of the photo (WebP, 800 pixels at most on the long side, 100 KB at most, no EXIF data) when it exists, else the original. An address of another site is returned as given. |
category_name | string | null | The product's category name, in the caller's language. The language comes from the lang parameter (fr or en) or, failing that, from the Accept-Language header. A category whose translation is missing falls back to its English name, never to an empty string. null when no category is attached. |
token_id | string | null | The number of the token on the chain, written in base ten, in a character string. That number is too large for an ordinary integer, so read it as text and never as a number of your language. null as long as the registration on the chain is not confirmed. |
tx_hash | string | null | The hash of the transaction that registered the product on the chain. null as long as no transaction has been recorded. |
status | string | The technical state of the product. See below. |
declared_stolen | boolean | true when a theft report is open on this product. |
is_verified | boolean | true when status is mined or written. false in every other case. |
registered_at | string | null | Date and time the product's record was created on our side, in ISO 8601. null when unknown. Added on 30 September 2026. |
verified_at | string | null | The same value as registered_at, under a misleading name. Kept for integrations that already read it. See the warning below. |
certificate_status | string | null | The state of the product's certificate of authenticity in force: active, or null when the product has no certificate in force. It is the same reading as the certificate.status field of GET /resolve/{identifier}, made by the same server function. Added on 30 September 2026. |
contract_address | string | The address of the contract that carries the token. |
chain | null | This field is always null today. See below. |
#Reading the state of a product
status carries a technical value. This page documents two of them, because the
rest of the response depends on them: mined and written are the only two
values for which is_verified is true.
Read is_verified and declared_stolen rather than interpreting status
yourself. declared_stolen exists precisely for that: status carries the
value stolen at the moment of a fresh report, then takes the value written
back as soon as the theft case is closed, while declared_stolen says in a
field of its own whether a report is open.
#Errors
The body of an error response carries a detail field.
| Code | Condition | What to do |
|---|---|---|
| 404 | No product matches this identifier, in any of the four forms. detail is Product not found. | The server first looks for your cleaned identifier, put in lowercase and prefixed with 0x, then for your raw string as you sent it, then for the token id, the serial number and the certificate number. Check the value you sent. If the item has been destroyed, replaced or withdrawn from the catalogue, the hash of its chip alone will find it. |
| 404 | The call arrives on a brand's verified domain name, and the product belongs to another brand. detail is Product not found. | Call this address on the domain of the brand concerned, or on api.sealtrust.io. The message is the same as for an unknown identifier, so as not to confirm that it exists. |
| 429 | More than 600 calls in 60 seconds from your address. detail is Rate limit exceeded: 600 requests per 60s. The response carries the Retry-After header, in seconds. | Wait the number of seconds indicated by Retry-After, then try again. Spread out your calls instead of sending them in bursts. |
| 500 | An unexpected error occurred while handling your call. detail is Internal Server Error. The response carries an X-Request-Id header. | Try again. If the error persists, contact support giving this request identifier and the time of the call. |
This endpoint is public: it returns neither 401 nor 403.
#See also
GET /resolve/{identifier}, read in a single call everything a product page displays.GET /timeline/{identifier}, read the public history of a product.GET /certificate/{identifier}, read the certificate of authenticity of an item.- Core concepts, tell model, batch and item apart before ordering a single label.
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.