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

See, without a signature and without recording anything, the verifiable credential envelope and the JSON-LD document that a given access tier would expose for a passport.

On this page

This endpoint returns, without a signature and without recording anything, the verifiable credential envelope and the JSON-LD document that a given access tier would expose for a product's passport.

#Authorization

None for the public tier. This endpoint is then open, with no API key and no session.

The five other values of the access_tier parameter require an account session. From your server, present it in the header Authorization: Bearer <session token>. The access_token cookie opens the same tiers, only in a call that also carries an Origin or Referer header that we accept, that is, from our own pages. A partner API key does not work: this endpoint reads only a session token, in the Authorization header or in the cookie. An API key therefore opens no tier beyond public.

Tier requestedWhat you must present
publicnothing For a battery passport, the fields that point 1 of Annex XIII makes public are added: hazardous substances, critical raw materials, carbon footprint and its class, due diligence report, post-consumer recycled content per metal and share of renewable content. Conversely the part numbers, the battery status and the expected lifetime in cycles are removed: points 2 and 4 reserve them to persons with a legitimate interest. For a textile passport, the name and the percentage of each material are added, the fibre composition that Regulation (EU) No 1007/2011 requires on the label. For a footwear passport, the material of the upper, the lining, the insole and the sole, which Directive 94/11/EC puts on the shoe.
end_usera session, whatever the account
repairera session whose account holds an active repairer accreditation on the product's brand, a session of the brand itself, or a session carrying the market surveillance authority role
recyclera session whose account holds an active recycler accreditation on the product's brand, a session of the brand itself, or a session carrying the market surveillance authority role
upstreama session of the product's brand, or a session carrying the market surveillance authority role
authoritya session carrying the market surveillance authority role

We serve here only the passports with public visibility. A passport reserved for the product's owner answers 404 on this endpoint, including for that owner, whereas GET /v1/passport/{identifier} serves it to them. A passport reserved for the brand is never returned here.

#Origin check

This endpoint refuses any call whose Origin or Referer header designates a domain that is not ours, with 403 Forbidden origin. The refusal does not look at the nature of the client: a program launched on your server that sends a Referer receives the same 403 as a web page.

Two rules for calling from your server.

  • Do not send a Referer header. Most HTTP libraries send none until you ask for it.
  • Present your session in Authorization: Bearer <session token>. A server call that relies on the access_token cookie is refused with 403 Origin or Referer header required.

Do not call this address from your visitor's browser: a JavaScript call launched from a page hosted anywhere other than with us is refused.

#Rate limit

600 calls per 60 second window, counted per calling network address.

This counter is shared by every read (GET) whose path starts with /passport. The calls you address to one of them therefore eat into the budget of the others. The /v1 prefix does not create a second budget: /v1/passport/1042/vc/preview and /passport/1042/vc/preview fill the same counter.

Every accepted response carries three headers.

HeaderContents
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 of the end of the window, in seconds

A refusal returns 429, with those three headers and Retry-After. On this endpoint, Retry-After equals the duration of the window, that is 60 seconds.

#Path and query parameters

NameTypeRequiredDescription
identifierstringyesThe item you want the preview of. Three forms are accepted, see below.
access_tierstringnoThe access tier requested. Equals public by default. Six accepted values, listed below.

identifier accepts three forms, tried in this order.

FormAppearanceOrigin
Identifier hash0x followed by 64 hexadecimal charactersthe hash of the item's unique identifier. We read it on the chip for an NFC item, and we draw it at random at minting time for a QR item
Token identifiera number written in decimalthe item's identifier on the chain
Printed serial number12 characterswhat the QR code on the product carries, in the address /p/{serial}

You can write the serial number in lowercase or in uppercase. We reduce the characters that look alike to a single form before the lookup, so an I or an L entered by hand finds the 1, and an O finds the 0.

This endpoint resolves only the items still in the brand's catalog. An item destroyed on the chain, replaced by a later version or archived answers 404. GET /v1/passport/{identifier} behaves differently: it keeps serving the last published passport for those items.

#The six values of access_tier

These tiers do not form a scale. They describe six audiences whose needs differ. A recycler and a repairer see different data.

ValuePassport sections kept before rendering
publicproduct identity, ESPR compliance, REACH compliance, CE marking, recyclability rate, recycled material rate, labels, battery specification, the Article 13(4) and 13(5) markings, usable extinguishing agent, EU declaration of conformity, waste management information, and for a textile or a footwear passport the label mentions described above
end_userthe whole public tier, plus environmental impact, full circularity, primary material, certified organic material statement, durability, energy efficiency, carbon footprint
repairerthe whole end_user tier, plus bill of materials, link to the disassembly instructions, repairability index, battery state of health
recyclerthe whole end_user tier, plus full material composition, substances of concern, link to the disassembly instructions, battery state of health
upstreamthe whole end_user tier, plus full material composition, substances of concern, manufacturing, supply chain
authoritythe entirety of the data, with no filtering

The fields the console writes at the root of the passport each have their own tier, named one by one: see Passport access rules.

This table describes the filter applied before the conversion to JSON-LD. Several of these sections stay absent from the document returned, because this endpoint does not convert them. The callout further down lists them all.

A brand can tighten or widen these lists for its own products. The values above are the ones that apply when it has changed nothing.

#The full address and the alias without /v1

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

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

#What this preview does not prove

A verifiable credential is a document that its issuer signs, and that anyone can check afterwards without asking us for anything again. This endpoint shows its shape before signing.

#Request body

None. This request has no body.

#Example request

Public preview of the credential of the item whose printed serial number is EXEMPLE00001.

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

#Example response

HTTP code 200.

JSON
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://schema.sealtrust.io/dpp/v1"
  ],
  "type": ["VerifiableCredential", "DigitalProductPassport"],
  "issuer": "did:web:api.sealtrust.io:brand:4242",
  "vct": "https://schema.sealtrust.io/vct/digital-product-passport",
  "credentialSubject": {
    "@context": {
      "@vocab": "https://schema.org/",
      "gs1": "https://gs1.org/voc/",
      "espr": "https://data.europa.eu/espr/"
    },
    "@type": "Product",
    "identifier": "0x1111111111111111111111111111111111111111111111111111111111111111",
    "gtin": "03701234567891",
    "name": "Example Model 001",
    "brand": {
      "@type": "Brand",
      "name": "Exemple SAS",
      "identifier": "00000000000000000000",
      "url": "https://example.example"
    },
    "countryOfOrigin": "FR",
    "material": [],
    "additionalProperty": [
      {
        "@type": "PropertyValue",
        "name": "Recyclability (EN 45555)",
        "value": 82,
        "unitText": "percent"
      },
      {
        "@type": "PropertyValue",
        "name": "gs1:recycledContentPercentage",
        "value": 35,
        "unitText": "percent"
      }
    ],
    "espr:compliance": {
      "@type": "espr:ComplianceDeclaration",
      "espr:euEsprCompliant": true,
      "espr:reachCompliant": true,
      "espr:ceMarking": true
    }
  },
  "access_tier": "public",
  "signed": false,
  "note": "Unsigned preview — POST /vc/issue to mint the signed SD-JWT-VC."
}
FieldTypeDescription
@contextstring[]The two vocabularies of the document, in this order: the W3C verifiable credential model, then ours.
typestring[]Always ["VerifiableCredential", "DigitalProductPassport"].
issuerstringThe did:web identifier of the brand that would issue this credential. See below.
vctstringThe identifier of the credential type. Equals https://schema.sealtrust.io/vct/digital-product-passport when the brand has not defined another one.
credentialSubjectobjectThe passport rendered in JSON-LD, filtered at the tier requested. See below.
access_tierstringThe tier you requested.
signedbooleanAlways false on this endpoint.
notestringA fixed text, in English, that recalls that the preview is not signed. Do not hook any code on it.

The response's access_tier field and the X-DPP-Access-Tier header both repeat the tier you requested. The call succeeds at the tier requested or fails with 401 or 403. There is no silent fallback to a lower tier.

The response carries Cache-Control: private, no-store at a professional tier, and public, max-age=60, s-maxage=300 at the public tier only. No shared cache therefore keeps a response obtained at a professional tier.

#The issuer field

It is the identity of the issuer, in did:web form. It takes two forms depending on what the brand has chosen.

FormWhere the identity document is read
did:web:<host>:brand:<number>https://<host>/brand/<number>/did.json
did:web:<brand's domain>https://<brand's domain>/.well-known/did.json

The first form applies by default, and the brand has nothing to do to get it. The second requires the brand to declare its own domain and to publish its identity document there.

Read the value returned as it is. Do not rebuild it on your side: a brand can move from one form to the other.

#The credentialSubject field

It is the passport rendered in JSON-LD, with the Schema.org vocabulary, the GS1 web vocabulary and our ESPR extensions. It carries its own @context, which is an object, whereas the one at the top level is a list. The two coexist normally.

FieldTypePresenceDescription
@contextobjectalwaysThe three vocabularies used in this document.
@typestringalwaysAlways Product.
identifierstringalways for a minted itemThe hash of the item's unique identifier. It exists for a QR-only item as well as for a chipped item.
gtinstringif filled inThe product's GS1 trade item code.
namestringif filled inThe model declared in the passport. Failing that, the product's name.
brandobjectalwaysThe brand: name, and depending on what it has filled in identifier (its LEI code), url, address, email.
countryOfOriginstringif filled inThe declared country of manufacture.
gs1:productionFacilitystringif filled inThe declared production site.
espr:operatorIdentifierstringif filled inThe identifier of the economic operator in the sense of the ESPR.
espr:batteryPassportIdentifierstringif filled inThe battery passport identifier.
espr:uniqueBatteryIdentifierstringif filled inThe unique battery identifier.
espr:eprelRegistrationstringif filled in and visibleThe EPREL registration number of the energy label.
materialobject[]alwaysThe material composition. Empty list when no material is visible at the tier requested.
additionalPropertyobject[]alwaysThe environmental, circularity, battery and energy efficiency measurements, as name and value pairs. Empty list when none is visible.
maintenanceTechnicalDataUrlstringif filled in and visibleThe link to the disassembly instructions.
espr:complianceobjectif the compliance section is visibleThe compliance declarations kept at the tier requested.

An entry of additionalProperty carries @type equal to PropertyValue, a name in English, a value, and a unitText when the quantity has a unit. The names are the ones of the vocabulary, for example Recyclability (EN 45555) or gs1:recycledContentPercentage. Hook your code on name, on the exact value, with no translation.

#Model or lot passport

A passport of a model, or of a production lot, is bound to no item. It therefore has no identifier to pass in {identifier}. Its unsigned preview is read at the GS1 address of the passport itself, next to the passport and its proof:

HTTP
GET https://api.sealtrust.io/v1/passport/01/{gtin}/vc/preview
GET https://api.sealtrust.io/v1/passport/01/{gtin}/10/{lot}/vc/preview

The first address targets the passport of the model that carries this GTIN. The second targets the passport of lot {lot} of that model. Like the other addresses of this page, each one also answers without the /v1 prefix.

NameTypeRequiredDescription
gtinstringyesThe GTIN of the model, 8, 12, 13 or 14 digits. Its check digit is verified.
lotstringon the second addressThe lot number (GS1 application identifier 10), as printed, upper and lower case included. A reserved character, such as /, is percent-encoded.

It is the only way to preview the credential of a brand on the Compliance offer, which registers no item.

The access tier, the authorization rules, the rate limit and the fields of the response are those of this page. The response adds two fields, and a third one for a lot.

FieldTypePresenceDescription
levelstringon these two addressesmodel for a model passport, batch for a lot passport.
gtinstringon these two addressesThe GTIN, brought to 14 digits.
batch_codestringon the lot addressThe lot number.

The preview of a model or a lot carries the identity of the model only. In credentialSubject, identifier is null.

The address of a lot targets the passport of that lot only. A lot without a published passport answers 404, and never with the preview of the model.

#Errors

The body of an error response carries a detail field.

CodeConditionWhat to do
401access_tier=end_user is requested without a valid session. detail equals End-user-tier access requires authentication.Log in with any account, or request the public tier.
401access_tier=authority is requested without a valid session. detail equals Authority-tier access requires authentication.Log in with an account carrying the market surveillance authority role. A partner API key does not work.
401access_tier equals repairer, recycler or upstream, and the call carries no valid session. detail equals Professional-tier access requires authentication.Present an account session token. An expired token is treated as the absence of a session. Otherwise, request the public tier.
403The call carries an Origin or Referer header that designates a domain that is not ours. detail equals Forbidden origin.From your server, stop sending a Referer header, or present your session in Authorization: Bearer <token>.
403The call sends neither Origin nor Referer, and carries an access_token cookie. detail equals Origin or Referer header required.From your server, present the session in Authorization: Bearer <token> instead of the cookie.
403access_tier=authority is requested by a logged-in account that does not carry that role. detail equals Authority-tier access is restricted to market surveillance authorities.Request the tier that matches your entitlement.
403access_tier equals repairer, recycler or upstream, and the logged-in account belongs neither to the product's brand nor to the authorities, and does not hold the matching accreditation on that brand. detail equals This tier is restricted to the product's brand, partners holding the matching accreditation, and market-surveillance authorities.Get accredited by the product's brand, then request the tier of your trade.
404No public passport answers to this identifier. Either no item in the catalog matches this identifier, or the item exists and carries no passport published with public visibility, neither directly nor through its model.Do not treat this response as a failure. Check your identifier, and handle the case of an item without a public passport. A passport reserved for the owner or for the brand gives the same response, as does an item destroyed on the chain, replaced or archived.
404The passport found refers to a brand that no longer exists. detail equals Brand not found.Report the case to support. No action on your side corrects this state.
404The 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.
400On the address of a model or a lot, the check digit of the GTIN is wrong. detail is Invalid GTIN: the check digit does not match.Copy the GTIN again from the label.
404On the address of a model or a lot: no passport published with public visibility answers for this GTIN or this lot, several brands publish a passport under this GTIN, or the call arrives on the verified domain of another brand. detail is Unknown GS1 Digital Link in all these cases.Check the GTIN and the lot number. The message is the same in all these cases, so as not to confirm that a GTIN exists.
422The value of access_tier is not one of the six accepted values. detail is a list, each entry carrying loc, type and msg.Read loc to find out which parameter is at fault, then correct its value.
429The limit of 600 calls per 60 seconds is reached for your network address, across all the /passport reads. detail equals Rate limit exceeded: 600 requests per 60s.Wait the number of seconds given by Retry-After, then retry. Space out your calls.
500An unexpected error occurred while processing your call. detail equals Internal Server Error. The response carries an X-Request-Id header.Retry. If the error persists, contact support, giving the value of X-Request-Id.

The code carries one last case, 422 with detail equal to Brand has no persisted id; cannot derive a did:web issuer. You will not meet it: every registered brand receives an issuer identity, did:web:api.sealtrust.io:brand:<number> when it has not declared its own domain.

#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