Skip to content
Concepts

GS1 Digital Link and resolver

The link on every QR code, and how the resolver sends browsers to the public page and machines to the public JSON.

Every passport has one web address that identifies the battery: a GS1 Digital Link. It is what the QR code on the battery carries. The same address serves people and machines: the resolver behind it decides what to return from the request.

https://batterypass.example.com/01/04012345000023/21/SV2027-000184
PartMeaning
https://batterypass.example.comThe resolver's origin: your BatteryPass address, or a separate resolver hostname your operator configured
/01/04012345000023GS1 application identifier 01: the model's GTIN, always with 14 digits
/21/SV2027-000184GS1 application identifier 21: the unit's serial number; a / in a serial number is sent percent-encoded (%2F)

The link is in gs1_digital_link of getPassport and is fixed once the identifiers are locked. getPassportQr renders exactly this link as PNG or SVG (error correction level M, a quiet zone of four modules). Always take the link from the API rather than building it yourself.

What the resolver returns

The resolver lives at the root of the origin (/01/…/21/…), not under /api/v1, and needs no key.

RequestAnswer
A browser (Accept: text/html, or no JSON preference)307 to the public passport page /pass/{passportId}
?linkType=describedby (or gs1:describedby)307 to the public JSON /api/v1/public/passports/{passportId}
?linkType=all, or Accept: application/json, application/linkset+json or application/ld+json without linkType200 with a linkset (application/linkset+json)
An unknown GTIN and serial number404: a short page for browsers, a Problem not_found for JSON clients
Too many requests from one address429 rate_limited with Retry-After

Every answer for a known passport also carries the links in a Link header, with the relations https://gs1.org/voc/pip (the page), describedby (the public JSON) and linkset. Answers are cacheable for five minutes and vary by Accept.

A passport whose identifiers are locked but that is not published yet, or one that was withdrawn, still resolves: its page explains the state, and the public JSON returns the status without content.

cURL
# The public JSON of the passport behind a QR code
curl -sL "https://batterypass.example.com/01/04012345000023/21/SV2027-000184?linkType=describedby"

# The linkset
curl -s -H "Accept: application/linkset+json" \
  "https://batterypass.example.com/01/04012345000023/21/SV2027-000184"

The linkset names the page and the public JSON:

Linkset
{
  "linkset": [
    {
      "anchor": "https://batterypass.example.com/01/04012345000023/21/SV2027-000184",
      "https://gs1.org/voc/pip": [
        { "href": "https://batterypass.example.com/pass/0192f0c4-7b1e-7c3a-9d2e-5a8b6c4d3e21", "type": "text/html", "title": "Battery passport" }
      ],
      "describedby": [
        { "href": "https://batterypass.example.com/api/v1/public/passports/0192f0c4-7b1e-7c3a-9d2e-5a8b6c4d3e21", "type": "application/json", "title": "Public passport (JSON)" }
      ]
    }
  ]
}

If you already know GTIN and serial number, you can skip the resolver and call getPublicPassportByProductId with {gtin}:{serial}, for example 04012345000023:SV2027-000184. The GTIN may have 8, 12, 13 or 14 digits there.

The resolver, the public passport reads and the public documents share one limit of 300 requests per minute per client address. A scanner app that resolves many codes should respect the cache headers; public passport reads may be cached for five minutes.

On this page