Documentation

REST API and structured data

The two endpoints DPTag adds to the WordPress REST API, the shape of a passport as JSON, and the schema.org block every public page carries.

Every published passport is readable as JSON, so that another system, a marketplace feed, a label printer's software or a future registry connector, can read the same data a customer reads on the page. The plugin adds two routes to the WordPress REST API under the dptag/v1 namespace, and every public page carries schema.org structured data.

One passport, public

GET /wp-json/dptag/v1/passport/{uuid}

Public, no authentication. The identifier is the permanent one the QR code encodes, the last segment of the public address. The response is the passport as the public page renders it, in its source language:

{
  "uuid": "3f2a9c1e-7b4d-4e8a-9c21-5d6f7a8b9c0d",
  "name": "Organic cotton T-shirt",
  "brand": "Linho & Co",
  "sku": "TS-001",
  "gtin": "",
  "image": "https://shop.example/wp-content/uploads/tee.jpg",
  "template": "textile",
  "updated": "2026-09-07",
  "data": {
    "materials": [
      { "name": "organic cotton", "percent": 95 },
      { "name": "elastane", "percent": 5 }
    ],
    "country_of_origin": "Portugal",
    "care_instructions": "Machine wash at 30°C. Do not tumble dry.",
    "recycling": "Drop off at any textile collection point.",
    "certifications": "GOTS"
  },
  "url": "https://shop.example/dpp/3f2a9c1e-7b4d-4e8a-9c21-5d6f7a8b9c0d/",
  "lang": "en",
  "source_lang": "en",
  "languages": ["en"]
}

data holds the template's fields by key, only the filled ones; the keys are those of the textile and furniture templates. brand is the site's title. gtin is the product's global unique identifier when WooCommerce has one. languages lists the languages the passport exists in; lang is the language of this response, which is always the source language on this route. A translated rendering is available on the public page itself, with ?lang= followed by the language code.

An unknown or unpublished identifier answers a 404 with a dptag_not_found code. Responses may be cached by intermediaries for up to an hour.

The list, for the site's users

GET /wp-json/dptag/v1/passports

Authenticated: the caller must be a logged-in user allowed to edit posts, through a cookie and nonce from the admin or an application password. It returns up to one hundred passports, drafts included, each as:

{
  "id": 1042,
  "title": "Organic cotton T-shirt",
  "status": "publish",
  "score": 100,
  "uuid": "3f2a9c1e-7b4d-4e8a-9c21-5d6f7a8b9c0d",
  "url": "https://shop.example/dpp/3f2a9c1e-7b4d-4e8a-9c21-5d6f7a8b9c0d/"
}

url is empty for a draft, which has no public page. A user only sees the passports they may edit, which is what the passports list shows them too. For a whole catalogue with every field, the Pro add-on's CSV export is the tool.

Structured data on the public page

Each public page embeds a schema.org Product in an application/ld+json block, built from the same payload:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Organic cotton T-shirt",
  "brand": { "@type": "Brand", "name": "Linho & Co" },
  "sku": "TS-001",
  "image": "https://shop.example/wp-content/uploads/tee.jpg",
  "material": "organic cotton 95%, elastane 5%",
  "countryOfOrigin": "Portugal",
  "url": "https://shop.example/dpp/3f2a9c1e-7b4d-4e8a-9c21-5d6f7a8b9c0d/",
  "inLanguage": "en"
}

gtin is added when the product has one, and empty values are left out. This is the block search engines read on any product page; it is what makes a passport findable by name and is not required by the regulation.

Stability

The route names, the field keys and the shape above are meant to stay. New templates add new keys under data; existing keys keep their meaning. When the delegated acts fix official formats, the plugin will add what they require rather than rename what is here, so that a consumer written today keeps working.