Method GET/qr/verify

Verify an item from the signed parameters carried by a verification address of the old form. Public endpoint, no API key.

On this page

You get an authenticity verdict for an item, from the signed parameters of a verification address, without any API key.

The full address is https://api.sealtrust.io/v1/qr/verify. The same route exists without the /v1 prefix, and the /v1 form is the one recommended for a new integration.

This endpoint replies 200 even when the verdict is negative. A tampered QR code, a QR code that is too old, an item not yet minted: in all three cases the response is a 200 whose valid field is false. The 4xx and 5xx codes are reserved for the cases where no verdict can be returned.

#Authorization

None, public endpoint. It expects no API key, no session cookie, and no Authorization header.

Call it from your server. Our cross-origin sharing policy allows only the public site and the SealTrust console. From a web page hosted on another domain, the browser blocks the response, and the X-RateLimit-Remaining header is never exposed to a page script anyway.

What is authoritative here is the s value. It is the signature that we affixed when producing the verification address. Without it, or with a modified value, the verdict is negative.

#Call limit

30 calls per 60-second window, counted per calling IP address. The limit is shared by all the addresses that start with /qr, and it applies to /qr/verify as well as to /v1/qr/verify.

The responses carry the X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers, the last one giving the reset time in seconds since January 1, 1970. Going over returns 429 with Retry-After in addition, in seconds.

Do not make your code depend on the presence of these headers: read them if they are there, and carry on if they are missing.

This endpoint consumes no quota of your plan.

#Path and query parameters

This endpoint has no path parameter.

NameTypeRequiredDescription
ustringyesThe fingerprint of the item: 0x followed by 64 hexadecimal characters. Edge spaces are removed, case does not matter, and the 0x prefix is added if it is missing.
tsintegeryesThe timestamp written into the address at the moment it was produced, in seconds since January 1, 1970.
sstringyesThe signature, as it appears in the address.
tstringnoThe identifier of the token. Old addresses omit it. The server finds the real identifier from u anyway, and that is the one it returns.
cstringnoThe short reference of the contract carried by the address. This endpoint accepts it and never reads it. The presence or the absence of c changes nothing in the response.
srcstringnoPresent in the addresses of the old form, with the value qr. This endpoint does not declare it and takes no account of it.
latitudenumbernoLatitude transmitted by the scanning device, between -90 and 90. Rounded to two decimal places, that is cells of about 1.1 km, before any recording. The fine position exists at no moment on our side.
longitudenumbernoLongitude transmitted by the scanning device, between -180 and 180. Rounded the same way.

latitude and longitude go in pairs. If you send only one of them, it is discarded and the scan is recorded without coordinates.

The response never returns coordinates: at best an area label. When you send no coordinates, the city and the country of that label are deduced from the calling IP address, through a lookup database read on our side. Your IP address is sent to no outside service. If the position of the scan matters to you, send latitude and longitude. Otherwise, know that the recorded area will be that of the calling machine.

#Request body

None. This is a GET request, everything goes through the query parameters.

#Example request

curl -i -G https://api.sealtrust.io/v1/qr/verify \
  --data-urlencode "u=0x0000000000000000000000000000000000000000000000000000000000000000" \
  --data-urlencode "t=1024" \
  --data-urlencode "ts=1755000000" \
  --data-urlencode "c=0x00000000" \
  --data-urlencode "s=0000000000000000000000000000000000000000000000000000000000000000"

#Example response

HTTP code 200, positive verdict.

JSON
{
  "valid": true,
  "message": "Authentic product: QR code and blockchain verified.",
  "uid_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "token_id": "1024",
  "product_name": "Sac de voyage Exemple SAS",
  "brand_name": "Exemple SAS",
  "image_url": null,
  "contract_address": "0x0000000000000000000000000000000000000000",
  "scan_area": "Lyon, FR"
}

Here the item has no cover image, so image_url is null. When it has one, the field carries its public address. The scan_area field is filled in because the call could be located. It is null otherwise.

HTTP code 200 as well when the verdict is negative, and the response does not have the same shape depending on the verdict.

Three negative verdicts are returned before any read on the chain: signature refused, address too old, item not yet minted. These three responses carry only uid_hash.

JSON
{
  "valid": false,
  "message": "Invalid QR code signature. This QR code may be tampered with.",
  "uid_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "token_id": null,
  "product_name": null,
  "brand_name": null,
  "image_url": null,
  "contract_address": null,
  "scan_area": null
}

The fourth negative verdict is returned after the read on the chain, when the fingerprint read does not match. This response describes the item, like the positive verdict. Only scan_area stays null, because the area is computed only on a positive verdict.

JSON
{
  "valid": false,
  "message": "Invalid product: blockchain verification failed.",
  "uid_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "token_id": "1024",
  "product_name": "Sac de voyage Exemple SAS",
  "brand_name": "Exemple SAS",
  "image_url": null,
  "contract_address": "0x0000000000000000000000000000000000000000",
  "scan_area": null
}

The nine fields of the response.

FieldTypeDescription
validbooleanThe verdict. It is the only field on which to build your logic.
messagestringA sentence in English that explains the verdict. Base your decisions on valid, never on this text.
uid_hashstring or nullThe fingerprint of the item, normalized: lowercase, 0x prefix. Filled in as soon as the item has been found, including on a negative verdict.
token_idstring or nullThe identifier of the token, in base 10, in the form of a string. It is the one recorded on our side, which can differ from the t that you sent. Filled in on a positive verdict and on the Invalid product: blockchain verification failed. verdict
product_namestring or nullThe name of the item. Same presence rule as token_id.
brand_namestring or nullThe name of the owning brand. Returned in the same cases as token_id, and null when the item is attached to no brand.
image_urlstring or nullThe public address of the cover image. null when the item and its model have none.
contract_addressstring or nullThe address of the contract that carries this token, in lowercase. Same presence rule as token_id.
scan_areastring or nullThe area of the scan. City, CC when the city and the two-letter country code are both known, for example Lyon, FR. When only one part is known, the field carries only that one, Lyon or FR. null when neither of the two is known. Filled in only on a positive verdict. Never coordinates, never a postal address.

#The six possible verdicts

validmessageWhat it means
trueAuthentic product: QR code and blockchain verified.The signature is recognized and the fingerprint recorded on the chain matches.
falseInvalid product: blockchain verification failed.The signature is recognized, but the fingerprint read on the chain does not match.
falseInvalid QR code signature. This QR code may be tampered with.The signature does not match the one we expect for this item.
falseQR code has expired. Please request a new QR code.The ts timestamp differs from the current time by more than 30 days, ahead as well as behind. Produce a new verification address from your console.
falseThis product has not been minted yet.The item exists on our side, its minting has never been submitted. Calling back later will change nothing.
falseMint submitted, waiting for on-chain confirmation.The minting has been submitted and is waiting for its confirmation. Call back in a few minutes.

#Errors

CodeConditionWhat to do
404No live item carries this fingerprint. Message Product not found for this QR code. The item has been destroyed, or withdrawn from the catalog.Check the value of u. If the item has been destroyed or withdrawn from the catalog, this code is final.
404The chain does not know this token. Message Unknown product: this token_id does not exist.Nothing to correct on the call side. Contact the brand: the item is recorded on our side with a token identifier that the contract does not carry.
422A required parameter is missing (u, ts or s), ts is not an integer, or latitude and longitude are out of their bounds.The body of the response lists the parameters at fault and the reason for each refusal. Correct and call again.
429More than 30 calls in 60 seconds from the same IP address. Message Rate limit exceeded: 30 requests per 60s.Wait the number of seconds given by Retry-After. Spread out your calls instead of sending them in bursts.
500Unexpected error on the server. Fixed body {"detail": "Internal Server Error"}.Try again. The X-Request-Id header identifies the call; send it to us if it repeats.
503The read on the chain failed. Message Error during blockchain verification.Try again in a few moments. No verdict was returned, and the scan was not recorded.

#See also

Your answer opens a pre-filled email in your mail app, addressed to contact@sealtrust.io. You read it over before sending it.

Suggest a correctionReport a problem