Method GET/passport/{identifier}/vc/verify

Check the signature of the digital passport delivered as a verifiable credential, and read the data revealed at the access tier requested. No session is required for the public and end_user tiers.

On this page

You have the signature of a product's digital passport checked, and you get back the data that this signature covers. By the time you leave this page, you will know how to request this check from any product identifier, tell a check that fails apart from a request that fails, and know which data the response shows you depending on the access tier you request.

Full URL:

HTTP
GET https://api.sealtrust.io/v1/passport/{identifier}/vc/verify

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

The passport is delivered in the SD-JWT-VC format, a signed credential in which each field can be revealed or withheld separately. The issuer is the brand, identified by a did:web decentralized identifier. This endpoint reassembles the credential at the access tier you request, checks its signature, and returns the revealed data to you.

#Authorization

No API key scope is checked on this endpoint. Two checks apply all the same: the origin of your call, then the access tier you request.

#Where you call from

Call this endpoint from your server.

We refuse with a 403 any call that carries an Origin or Referer header designating a domain other than ours. The detail field is then Forbidden origin. A browser always sets one of these two headers, so a web page hosted anywhere other than with us cannot call this URL from its visitor's browser.

The session cookie only works from a page served by one of our domains. We refuse with a 403 a call that carries this cookie without an Origin or Referer header, with detail set to Origin or Referer header required. From a server, present the session token in the Authorization: Bearer header.

#The tier you request

The public and end_user tiers require no account. The four other values of the access_tier parameter require an account session, presented through the Authorization: Bearer <session token> header or through the session cookie set at sign-in.

Tier requestedWhat is needed
publicnothing
end_usernothing
repairera session, and an active repairer accreditation on the brand of the product
recyclera session, and an active recycler accreditation on the brand of the product
upstreama session with access to the brand of the product, or the authority role
authoritya session carrying the market surveillance authority role

A session with access to the brand of the product opens the three professional tiers on its own products. The market surveillance authority role opens them as well, on every product.

A partner API key opens nothing here. The token received in the Authorization header is decoded as a user account session token, and an API key is not one. The read fails silently and the call goes on as an anonymous call.

#Rate limit

60 calls per 60 second slice, counted per calling IP address. The window is fixed.

This ceiling is shared by every URL that starts with /passport. The /passport/… and /v1/passport/… forms feed the same counter, the /v1 prefix does not create a second budget.

Every accepted response carries three headers that describe this counter.

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

Going over returns 429, with the same three headers and a Retry-After. On this endpoint, Retry-After is worth the length of the window, that is 60 seconds.

#Path and query parameters

NameTypeRequiredDescription
identifierstringyesThe identifier of the product. Three forms are accepted, see below.
access_tierstringnoThe access tier requested. Is public by default. Six values accepted, listed further down. We refuse any other value with a 422.

#The three identifier forms accepted

FormWhat it looks likeWhere you find it
Serial number12 characters, digits and lettersPrinted on the product, it is what its QR carries
Token identifierA run of digits, often a very long oneReturned by our responses in the token_id field
Identifier hash0x followed by 64 hexadecimal charactersReturned by our responses in the uid_hash field

The identifier hash exists for a QR only product as much as for a product with an NFC chip. The server draws it at random for a QR only product. It derives it from the identifier of the chip for a product with an NFC chip. Both forms therefore look the same and are requested in the same way.

We recognize the form from the way it is written. A value that starts with 0x and is exactly 66 characters long, we look up as an identifier hash. Any other value, we look up first as a token identifier, then as a serial number when the first lookup found nothing.

You write the identifier hash in whatever case you want. You write the serial number in whatever case you want as well, and we canonicalize it the way the QR resolver does: in it we read the letters I and L as a 1, the letter O as a 0. So you can copy by hand a number read on a label.

The certificate of authenticity number is not accepted here.

A product destroyed on the chain or withdrawn from the catalog no longer resolves through this endpoint, and the response is then 404.

#The six values of access_tier

These tiers are different audiences, with no hierarchy between them. Each of the three professional tiers inherits the public tier and the end user tier, then adds what its profession requires.

ValueWhat it adds to the fields revealed
publicproduct identification, ESPR compliance, REACH and CE marking, recyclability percentage, recycled content percentage, labels, general battery specification
end_userenvironmental impact, full circularity, primary material, certified organic material, durability, energy efficiency, carbon footprint
repairerbill of materials, disassembly instructions, repairability index, battery state of health
recyclermaterial composition, substances of concern, disassembly instructions, battery state of health
upstreammaterial composition, substances of concern, manufacturing, supply chain
authoritythe whole of the data, with no filtering

A brand can replace these rules with its own. The table above describes what applies in the absence of rules specific to the brand.

#Headers

No header is required for the public and end_user tiers. The five other tiers require the Authorization header or the session cookie. In every case, respect the origin rule described above.

#Request body

None. This request has no body.

#Example request

Check of the credential of the product whose printed number is EXEMPLE00001, at the public tier.

The three examples run from a server. None of them works in a visitor's browser: the browser sets an Origin header that we refuse, and you receive a 403.

curl -i "https://api.sealtrust.io/v1/passport/EXEMPLE00001/vc/verify?access_tier=public"

#Example response

HTTP code 200. The signature is valid and the tier requested is public.

JSON
{
  "passport_id": 1,
  "issuer": "did:web:api.sealtrust.io:brand:4242",
  "vct": "https://schema.sealtrust.io/vct/digital-product-passport",
  "key_version": 1,
  "access_tier": "public",
  "verified": true,
  "error": null,
  "credential_subject": {
    "product_identity": {
      "gtin": "03701234567890",
      "model": "Cartable Exemple 32",
      "brand": "Exemple SAS",
      "made_in": "FR"
    },
    "compliance": {
      "eu_espr": true,
      "reach": true,
      "ce_marking": false
    },
    "circularity": {
      "recyclability_percentage": 62,
      "recycled_content_percentage": 0
    }
  }
}

The response has eight fields and nothing else.

FieldTypeDescription
passport_idintegerThe identifier of the passport version the check applied to.
issuerstringThe did:web decentralized identifier of the issuing brand. Always filled in on this endpoint.
vctstringThe credential type. Is https://schema.sealtrust.io/vct/digital-product-passport when the brand has not declared another one.
key_versioninteger or nullThe version number of the brand signing key that signed the credential. null when that number was not recorded at issuance.
access_tierstringThe access tier requested, carried over as is. This endpoint never changes the tier requested.
verifiedbooleantrue when the signature was checked successfully.
errorstring or nullnull when verified is true. Is verification_failed otherwise. That is the only possible value.
credential_subjectobject or nullThe data revealed at the tier requested, as the signature covers it. Is null as soon as verified is false.

#A check that fails is still a 200 response

That is the point to remember from this page. A check failure is not an HTTP error. The response stays 200 and carries the verdict.

JSON
{
  "passport_id": 1,
  "issuer": "did:web:api.sealtrust.io:brand:4242",
  "vct": "https://schema.sealtrust.io/vct/digital-product-passport",
  "key_version": 1,
  "access_tier": "public",
  "verified": false,
  "error": "verification_failed",
  "credential_subject": null
}

So always read verified. A 200 code says nothing on its own.

#What flips verified to false

CauseWhat it means
The signature does not match the contentThe credential was modified after it was issued.
The issuer written in the credential is not the one expected for this brandThe credential was issued under an identity other than that of the brand of the product.
The credential designates no readable key versionThe header of the credential carries no usable key version number.
The key version cited by the credential does not exist for this brandThe key that signed is not known.
That key version was revokedThe brand withdrew this key. The credentials it signed are no longer recognized.

The response does not say which of these causes applies. The error field is verification_failed in all of these cases.

#Checking the signature yourself

You are not required to ask us for this verdict. The brand publishes its public signing keys in a decentralized identity document, served publicly at GET https://api.sealtrust.io/brand/{brand_id}/did.json. A brand that hosts its identity on its own domain serves it at https://<its domain>/.well-known/did.json.

With that document and any off-the-shelf did:web and SD-JWT-VC library, you check the signature without going through us. That is what makes the passport enforceable without depending on our availability.

#Errors

The body of an error response carries a detail field.

The checks run in this order: origin of the call, resolution of the product, lookup of the published passport, check of the tier requested, presence of an issued credential, then identification of the issuing brand. The first step that fails gives the response.

CodeConditionWhat to do
401access_tier=authority is requested with no valid session. detail is Authority-tier access requires authentication.Sign in with an account carrying the market surveillance authority role. A partner API key will not do.
401access_tier is repairer, recycler or upstream, and the call carries no valid session. detail is Professional-tier access requires authentication.Present an account session token, or request the public or end_user tier.
403The call carries an Origin or Referer header that does not designate one of our domains, which happens for any call sent from a web page hosted elsewhere. detail is Forbidden origin.Call this endpoint from your server. A call sent by a visitor's browser cannot succeed.
403The call carries the session cookie and has neither an Origin header nor a Referer header, which happens when a browser cookie is replayed on the command line. detail is Origin or Referer header required.Remove the cookie and present the session token in the Authorization: Bearer header.
403access_tier=authority is requested by a signed-in account that does not carry this role. detail is Authority-tier access is restricted to market surveillance authorities.Request the tier that matches your clearance.
403A professional tier is requested by a signed-in account that has neither access to the brand of the product, nor the matching accreditation on that brand. detail is This tier is restricted to the product's brand, partners holding the matching accreditation, and market-surveillance authorities.Ask the brand for the accreditation that matches your profession, then request the tier of that profession.
404No product matches this identifier, under any of the three accepted forms. detail is Product not found.Check the identifier. A product destroyed on the chain or withdrawn from the catalog gives this same response.
404The product exists, but no public passport is published for it nor for its model. detail is No published passport found for this product.There is nothing to check. A passport reserved for the owner or for the brand also gives this response.
404A public passport exists, but no signed credential was issued for this version. detail is No VC issued for this passport yet.Ask the brand to issue the credential for this version of the passport. The passport stays readable through the read endpoints.
404The brand of the passport could not be found. detail is Brand not found.Contact support giving the identifier you called. No action on your side fixes this response.
422access_tier is not one of the six accepted values. detail is a list, each entry carrying loc, type and msg.Read loc to know which parameter is at fault, then fix its value.
429The ceiling of 60 calls per 60 seconds is reached for your IP address, across every path starting with /passport. detail is Rate limit exceeded: 60 requests per 60s.Wait the number of seconds given by Retry-After, then try again.
500An unexpected error occurred while your call was being processed. detail is Internal Server Error. The response carries an X-Request-Id header.Try again. If the error persists, contact support giving the value of X-Request-Id.

#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