> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thingidentity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Resolve a GS1 Digital Link

> Redirect a scan to the product page, or return the product's linkset.

The path is an uncompressed GS1 Digital Link URI: the GTIN, optionally followed by its key qualifiers.

```
/01/{gtin}[/22/{cpv}][/10/{lot}][/21/{serial}]
/01/{gtin}/235/{tpx}
```

The qualifiers keep this order, and any of them may be left out. The third-party serialised extension (`235`)
stands alone. Other GS1 Application Identifiers, such as the expiry date (`17`), go in the query string. A trailing
slash is ignored.

No authentication is needed. CORS, caching, error bodies and the linkset formats are described in the
[Overview](/api-reference/resolver/overview).

## Key qualifiers

The key qualifiers are optional path segments after the GTIN, each an Application Identifier followed by its value:

| Application Identifier | Qualifier                                                      | Value               |
| ---------------------- | -------------------------------------------------------------- | ------------------- |
| `22`                   | Consumer product variant (CPV)                                 | Up to 20 characters |
| `10`                   | Batch or lot number                                            | Up to 20 characters |
| `21`                   | Serial number                                                  | Up to 20 characters |
| `235`                  | Third-party controlled, serialised extension of the GTIN (TPX) | Up to 28 characters |

Qualifier values use GS1 character set 82: letters, digits and `!"%&'()*+,-./:;<=>?_`. Percent-encode the
characters that cannot appear in a URL path segment as they are, for example `/` as `%2F`.

## Link types

`linkType` takes:

* a GS1 link type the product has a page for, as a CURIE (`gs1:certificationInfo`) or as its full URI
  (`https://ref.gs1.org/voc/certificationInfo`, or the older `https://gs1.org/voc/certificationInfo` and
  `http://gs1.org/voc/certificationInfo`),
* the name of one of the product's pages, as it appears in the product page URL,
* `gs1:defaultLink`, the default page in the product's default language,
* `gs1:defaultLinkMulti`, the default page in the scanner's language,
* `linkset`, to get the linkset instead of a redirect.

The query string of the scan is passed on to the redirect target as it was sent, in the same order and with
repeated names. The resolver appends `10`, `21` and `17` (lot, serial and expiry date) when they are in the link
but not in the query, so the product page opens the version pinned to them in the dashboard.

## Invalid links

A request is `400` when:

* the GTIN is not 8, 12, 13 or 14 digits, or its check digit is wrong,
* a qualifier has no value,
* an Application Identifier in the path is not `22`, `10`, `21` or `235`,
* the qualifiers are out of order, or `235` is combined with another one,
* a value is too long or has a character outside character set 82,
* a qualifier is repeated with a different value,
* the path is not valid percent-encoding.

<RequestExample>
  ```bash Scan theme={null}
  curl -i https://thingidentity.com/01/00012345000058/10/LOT42/21/SN001
  ```

  ```bash Link type theme={null}
  curl -i "https://thingidentity.com/01/00012345000058?linkType=gs1:certificationInfo"
  ```

  ```bash Linkset theme={null}
  curl -H "Accept: application/linkset+json" https://thingidentity.com/01/00012345000058/21/SN001
  ```
</RequestExample>

<ResponseExample>
  ```http 307 theme={null}
  HTTP/2 307
  location: /en-us/acme/bubbles-for-levels/product-information-page?10=LOT42&21=SN001
  cache-control: public, s-maxage=600, stale-while-revalidate=600
  vary: Accept, Accept-Language
  access-control-allow-origin: *
  ```

  ```json 200 Linkset theme={null}
  {
    "linkset": [
      {
        "anchor": "https://thingidentity.com/01/00012345000058/21/SN001",
        "description": "babelki-do-poziomic",
        "https://ref.gs1.org/voc/defaultLink": [
          {
            "href": "https://thingidentity.com/pl-pl/acme/babelki-do-poziomic/informacje-o-produkcie?21=SN001",
            "title": "Informacje o produkcie"
          }
        ],
        "https://ref.gs1.org/voc/pip": [
          {
            "href": "https://thingidentity.com/pl-pl/acme/babelki-do-poziomic/informacje-o-produkcie?21=SN001",
            "title": "Informacje o produkcie",
            "hreflang": ["pl-PL"],
            "type": "text/html"
          },
          {
            "href": "https://thingidentity.com/en-us/acme/bubbles-for-levels/product-information-page?21=SN001",
            "title": "Product information page",
            "hreflang": ["en-US"],
            "type": "text/html"
          }
        ],
        "https://ref.gs1.org/voc/defaultLinkMulti": [
          {
            "href": "https://thingidentity.com/pl-pl/acme/babelki-do-poziomic/informacje-o-produkcie?21=SN001",
            "title": "Informacje o produkcie",
            "hreflang": ["pl-PL"],
            "type": "text/html"
          },
          {
            "href": "https://thingidentity.com/en-us/acme/bubbles-for-levels/product-information-page?21=SN001",
            "title": "Product information page",
            "hreflang": ["en-US"],
            "type": "text/html"
          }
        ]
      }
    ]
  }
  ```

  ```json 400 theme={null}
  { "status": 400, "error": "INVALID_GS1_DIGITAL_LINK" }
  ```

  ```json 404 theme={null}
  { "status": 404, "error": "NOT_FOUND" }
  ```
</ResponseExample>

## Linkset contents

The linkset has one entry, for the scanned link:

* `anchor` is the uncompressed GS1 Digital Link on the scanned host, with its key qualifiers and without the
  query.
* `description` is the product name in its default language. Left out when the product has none.
* `https://ref.gs1.org/voc/defaultLink` holds one link: the default page in the default language, with `href` and
  `title` only.
* `https://ref.gs1.org/voc/defaultLinkMulti` holds the default page in every language it is published in.
* Every other key is the full URI of a link type, holding that page in every language it is published in. `title`
  is the page's name in that language, `hreflang` the language, and `type` is always `text/html`.

Links point to the brand's custom domain when it has one, and to `thingidentity.com` from `gtin.at`. When the scan carries a lot, serial or expiry date, in
the path or in the query, every `href` carries it too, so each link opens the same pinned version as the scan.


## OpenAPI

````yaml openapi.json GET /01/{gtin}
openapi: 3.1.0
info:
  title: Thing Identity Public API
  version: 1.0.0
  description: >-
    Machine-to-machine API for Thing Identity. Authenticate with client
    credentials, then call the endpoints below with the resulting bearer token.
servers:
  - url: https://api.thingidentity.com
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: Exchange client credentials for an access token.
  - name: Codes
    description: Generate GS1 barcode payloads and GS1 Digital Link URIs.
  - name: GS1 Resolver
    description: Resolve GS1 Digital Link URIs to product pages or linksets.
paths:
  /01/{gtin}:
    servers:
      - url: https://thingidentity.com
    get:
      tags:
        - GS1 Resolver
      summary: Resolve a GS1 Digital Link
      description: Redirect a scan to the product page, or return the product's linkset.
      operationId: resolveGtin
      parameters:
        - name: gtin
          in: path
          required: true
          description: >-
            The GTIN in 14 digits, with a valid check digit. GTIN-8, GTIN-12 and
            GTIN-13 are accepted too and read as the 14-digit GTIN padded with
            leading zeros.
          schema:
            type: string
          example: '00012345000058'
        - name: linkType
          in: query
          required: false
          description: >-
            The page to open instead of the default one. The name is read in any
            case (`linktype` too); the value is case-sensitive. A value that
            matches no page returns `404`.
          schema:
            type: string
        - name: Accept
          in: header
          required: false
          description: >-
            `application/linkset+json` returns the linkset instead of a
            redirect. With `linkType=linkset`, `application/json`,
            `application/ld+json` and `text/html` choose its format. Also
            chooses between JSON error bodies and an HTML error page.
          schema:
            type: string
        - name: Accept-Language
          in: header
          required: false
          description: >-
            The scanner's languages. The redirect opens the first one the
            product is published in.
          schema:
            type: string
      responses:
        '200':
          description: The linkset, when requested.
        '307':
          description: >-
            `Location` is the product page, `/{locale}/{brand}/{product}/{page}`
            followed by the query, on the scanned host (on `thingidentity.com`
            for a scan on `gtin.at`), or the same GS1 Digital Link on the
            brand's custom domain.
          headers:
            Location:
              schema:
                type: string
        '400':
          description: Not a valid GS1 Digital Link.
        '404':
          description: >-
            No published product for the GTIN on this host, or no page matching
            `linkType`.
      security: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: The `access_token` from `POST /oauth/token`.

````