Skip to main content

Passport product data model (UNTP)

The product object accepted by POST /v1/dpp/passports and by bulk import follows the UN Transparency Protocol (UNTP) Core Digital Product Passport model, v0.7.0 — specification, JSON-LD context. Keyban uses this model as its internal pivot: whatever the source — a manual create, a bulk import, or the Shopify catalogue sync — every passport's product ends up in this shape, and every downstream projection (the public passport page, the on-chain certificate, the verifiable credential) is derived from it.

Two identifiers are generated by Keyban and must not be sent by the caller: product.id and product.idScheme. Object type tuples (type: ['Product'], type: ['Claim'], …) default server-side and can be omitted from the payload.

Granularity drives which fields are required

Granularity is carried by product.idGranularity, not by a top-level discriminant field:

idGranularityIdentifiers required on product
modelmodelNumber
batchmodelNumber + batchNumber
itemmodelNumber + batchNumber + itemNumber

modelNumber, batchNumber and itemNumber are nullable at the schema level for all three granularities — the requirement above is enforced by the import/create service against idGranularity, not by a type union. Sending an item without batchNumber fails validation even though the field type itself allows null.

Core sections of product, and where they surface on the passport

SectionKey fieldsWhere it appears on the published passport
Identityname, modelNumber / batchNumber / itemNumberPage title, and the "Product identity" card
CategoryproductCategory[]"Category" field inside the "Product identity" card
Primary imageproductImageImage carousel at the top of the page
Technical specificationscharacteristics (free-form key/value)"Technical specifications" card
Origin and manufactureproducedAtFacility, countryOfProduction"Origin and manufacture" card; countryOfProduction is also shown in the hero on model passports
Production dateproductionDateHero of item passports only — not shown on model / batch
Dimensionsdimensions (weight, length, width, height, volume)"Product dimensions" card
Material compositionmaterialProvenance[]"Material composition" card (material, origin, mass, recycled share, hazardous)
Conformity claimsperformanceClaim[]"Evidence of sustainability" card
Related partiesrelatedParty[]"Actors involved" card (manufacturer, distributor, …)
Related documentsrelatedDocument[]"Documents" card
Product labelsproductLabel[]"Labels and certifications" card — images only, name / description are not rendered
PackagingpackagingNot rendered today. Accepted and stored, but the public passport viewer has no card for it yet.

This table covers what maps to a visible block on the passport, not the exhaustive field list — for that (including fields with no dedicated UI, like expiryDate), see the CreateDppPassportDto schema.

Full example

A model-granularity passport with a material breakdown and a conformity claim, trimmed from a real import payload:

{
"application": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"network": "StarknetMainnet",
"product": {
"name": "Organic cotton crewneck T-shirt — White",
"idGranularity": "model",
"modelNumber": "KB-TS-001",
"description": "100% GOTS-certified organic cotton, classic straight cut.",
"productImage": {
"linkURL": "https://ipfs.io/ipfs/QmNXXmCD9xzH8em8EbhirCyNrHai4SVTYBYpWAfhptBuRn",
"linkName": "Organic cotton crewneck T-shirt — White"
},
"characteristics": {
"Color": "White",
"Size range": "XS-XXL",
"Gender": "Unisex"
},
"productCategory": [
{
"code": "53102501",
"name": "T-shirts",
"schemeID": "https://vocabulary.uncefact.org/unspsc",
"schemeName": "UNSPSC"
}
],
"relatedParty": [
{
"role": "manufacturer",
"party": {
"id": "did:web:keyban.io",
"name": "Keyban",
"registeredId": "3760123450017",
"idScheme": {
"id": "https://id.gs1.org/417",
"name": "GS1 Global Location Number"
}
}
}
],
"dimensions": {
"weight": { "unit": "GRM", "value": 180 }
},
"materialProvenance": [
{
"name": "Organic cotton",
"originCountry": { "countryCode": "IN" },
"materialType": {
"code": "cotton-organic",
"name": "Organic cotton",
"schemeID": "https://vocabulary.uncefact.org/material",
"schemeName": "UN/CEFACT Material Vocabulary"
},
"massFraction": 1,
"recycledMassFraction": 0,
"hazardous": false
}
],
"performanceClaim": [
{
"id": "https://passport.keyban.io/credentials/dcc/kb-ts-001/gots",
"name": "Global Organic Textile Standard (GOTS) 7.0",
"description": "Certifies a high share of organic fibres and compliance with environmental and social criteria across the textile chain.",
"claimDate": "2026-02-10",
"referenceCriteria": [],
"claimedPerformance": [],
"conformityTopic": [
{
"id": "https://vocabulary.uncefact.org/conformityTopic#environment.material",
"name": "environment.material"
}
],
"referenceStandard": [
{
"id": "https://global-standard.org/",
"name": "Global Organic Textile Standard (GOTS) 7.0"
}
],
"evidence": [
{
"linkURL": "https://passport.keyban.io/credentials/dcc/kb-ts-001/gots",
"linkName": "DCC — GOTS certificate"
}
]
}
]
}
}

referenceCriteria and claimedPerformance are schema-valid as empty arrays, though at least one entry is expected in practice — reserve the empty form for a claim backed only by a third-party certificate (evidence) rather than a self-reported measurement.

Shopify sync vs. manual or bulk import

The Shopify catalogue sync auto-fills identity, images, and variant-derived fields (model / item) straight from the Shopify product. It has no native equivalent for the traceability and conformity sections — materialProvenance, performanceClaim, relatedParty, packaging — because Shopify's own product model doesn't carry them. Shopify-sourced passports (source = "shopify") are read-only through PATCH, so these fields stay empty unless populated at the source; passports created through POST /v1/dpp/passports or POST /v1/imports (source = "manual" / "import") can set the full model in one call. See Prepare your Shopify catalogue for how modelNumber is derived from the Shopify product identifier, and why the sync never produces batch-granularity passports.

API reference

For the exhaustive, always-current field list — including nested object shapes, optionality, and validation rules — see CreateDppPassportDto.