Method GET/certificate/{identifier}

Read a product's certificate of authenticity from its certificate number, its UID hash, its token id or its printed serial number. Public endpoint.

On this page

You are reading a product's certificate of authenticity. When you leave this page, you will know which identifier to send, how to read the certificate status, and which responses to expect when the product or the certificate does not exist.

Full address:

HTTP
GET https://api.sealtrust.io/v1/certificate/{identifier}

The same endpoint also answers without the /v1 prefix, at https://api.sealtrust.io/certificate/{identifier}. Both addresses call the same code. Use the /v1 form for a new integration.

#Authorization

None, public endpoint. Send neither an API key nor a session token.

The response carries no internal brand or product identifier. It gives the certificate number, the status, the dates, the product name, the brand name and its styling. It gives no brand number, no product number, no contract address and no owner address.

#Rate limit

600 calls per 60-second window, counted per IP address.

This counter applies to reading the certificate, with or without the /v1 prefix. Downloading its PDF has its own counter, of 60 calls a minute: building the file costs far more than a read.

Every accepted response carries three headers.

HeaderContent
X-RateLimit-Limitthe limit applied over the window, here 600
X-RateLimit-Remainingwhat is left to you in the current window
X-RateLimit-Resetthe timestamp for the end of the window, in seconds

A refusal returns 429 with the same three headers, X-RateLimit-Remaining at 0, and Retry-After equal to 60.

#Path and query parameters

NameTypeRequiredDescription
identifierstringyesThe product or the certificate to read. Four forms are accepted, described below.

This endpoint has no query parameter.

#The four identifier forms

FormWhat it looks like
Certificate numberA string that starts with ST-CERT-, followed by 12 characters. It is the certificate_number field this same response returns.
UID hash0x followed by 64 hexadecimal characters, that is 66 characters in all. Case does not matter.
Token idThe token's whole number, written in digits. It has 77 or 78 digits.
Printed serial numberThe 12 characters carried on the product label, the ones found in the /p/{serial} address.

The server first looks for a certificate number. If it finds none, it looks at the shape of the string: 0x followed by 64 hexadecimal characters is treated as a UID hash, any other shape as a token id. As a last resort it looks for a printed serial number.

The server strips leading and trailing spaces before the lookup, whatever the form.

The server ignores the case of the serial number and brings the characters that are confused when read back to their canonical form before the lookup: I and L count as 1, O counts as 0. So you still find a number copied by hand from a label even if the person typed the letter O where the label carries the digit 0.

#Headers

NameTypeRequiredDescription
AcceptstringnoIf it contains text/html, the response is a 307 redirect to the public certificate page, readable by a human. Any other value, including */* and application/json, gives the JSON described below.

curl, requests and fetch send */* by default and therefore receive the JSON. The redirect exists so that a certificate link shared and opened in a browser displays the public certificate page.

#Request body

None. This request has no body.

#Example request

Reading the certificate whose number is ST-CERT-000000000000.

curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/ST-CERT-000000000000

The TypeScript SDK @sealtrust-io/sdk does not cover this endpoint. The example above uses fetch, available with no dependency.

The three other identifier forms are written the same way.

curl
# UID hash
curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/0x0000000000000000000000000000000000000000000000000000000000000000

# Token id
curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/10000000000000000000000000000000000000000000000000000000000000000000000000000

# Printed serial number
curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/00000000ABCD

#Example response

HTTP code 200.

JSON
{
  "certificate_number": "ST-CERT-000000000000",
  "status": "active",
  "issued_at": "2026-03-04T10:22:07.415000Z",
  "expires_at": null,
  "issuer_name": "Exemple SAS",
  "product_name": "Tote bag model 1",
  "brand_name": "Exemple SAS",
  "brand_logo_url": "https://example-sas.test/logo.svg",
  "brand_primary_color": "#1F2937",
  "brand_hide_powered_by": false,
  "brand_public_host": null,
  "brand_served_hosts": [],
  "custom_fields": {
    "atelier": "Atelier 3",
    "matiere": "cuir pleine fleur"
  }
}

The response has twelve fields and nothing else.

FieldTypeDescription
certificate_numberstringThe number of the certificate. It is the value to reuse as identifier to find this certificate directly.
statusstringThe status of the certificate. See below.
issued_atstringIssue date and time, in universal time, in ISO 8601 format.
expires_atstring or nullEnd of validity date. No certificate issued by the platform carries one today, the value is always null. Do not build your integration on an end date.
issuer_namestring or nullThe name of the brand that issued the certificate. The server computes this field at read time and always puts the brand name in it. null when the certificate is attached to no brand.
product_namestring or nullThe name of the product covered by the certificate.
brand_namestring or nullThe name of the issuing brand.
brand_logo_urlstring or nullThe address of the brand logo, to display the certificate in the brand's colors.
brand_primary_colorstring or nullThe primary color of the brand.
brand_hide_powered_bybooleantrue 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.
brand_public_hoststring or nullThe domain name under which the brand publishes its public pages, for example verify.example-sas.test. Populated only when the brand has white labeling and that domain has been verified, or, for a reseller's client brand with no domain of its own, when that reseller's shared domain is verified. Otherwise null. A page displaying this certificate uses it to declare its canonical address and its sharing previews under the brand's domain rather than ours.
brand_served_hostsarray of stringEvery verified domain name the brand's pages are served on: its own and its reseller's shared one. brand_public_host is only the preferred one. A page uses it to accept both, so that a label already printed on the reseller's domain keeps opening its page once the brand adopts a domain of its own. Empty list when the brand is served only on ours.
custom_fieldsobject or nullThe free fields the brand filled in when issuing the certificate. null when it filled in none. The content is specific to each brand, no key is imposed.

#How to read status

The server computes the status at read time. The value stored in the database is not copied as is.

status is either active or revoked.

  • A revoked certificate is returned as revoked forever. Revocation is a deliberate act and it prevails over every other rule. No endpoint returns a revoked certificate in the active status.
  • Every other certificate is returned as active.

The vocabulary of the API contains a third value, expired. The server computes it at read time from expires_at. Since no certificate carries an end date today, the API does not return it. Accept it in your code to stay robust if it appears one day, and build no business rule on its presence.

#Redirect to the readable page

If your request announces text/html in the Accept header, the response is a 307 whose Location header points to the public certificate page. The server returns no JSON body in that case.

The destination follows the brand: the domain the brand has declared and had verified when it has one, sealtrust.io otherwise. A certificate that cannot be found also redirects, to sealtrust.io, where the page says plainly that it found nothing. A browser therefore never receives a JSON 404 from this endpoint.

#Errors

The body of an error response carries a detail field.

CodeConditionWhat to do
404The requested path matches no route, for example because the identifier contains an unencoded slash. detail is Not Found.Encode the identifier before placing it in the address.
404No product matches this identifier, or the matching product has been destroyed, replaced or archived. detail is Product not found.Check the form of the identifier. A serial number is typed as it appears on the label, over 12 characters.
404The product exists, but no certificate has ever been issued for it. detail is No certificate found for this product.The product can be genuine without carrying a certificate. Use the product passport to display it.
404The call arrives on a brand's verified domain name, and the certificate 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.
429The limit of 600 calls per 60 seconds is reached for your IP address. detail is Rate limit exceeded: 600 requests per 60s. The Retry-After header and the X-RateLimit-* family accompany the response.Wait the number of seconds indicated by Retry-After, then try again. The PDF download has its own counter.
500An unexpected error occurred while your call was being processed. detail is Internal Server Error.Try again. If the error persists, contact support giving the time of the call.

#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